Merge branch 'igc-6.x' into 'stable-1.5'
Backport igc to stable-1.5 See merge request etherlab.org/ethercat!100
This commit is contained in:
commit
716fdb5f06
48
configure.ac
48
configure.ac
|
|
@ -527,6 +527,52 @@ if test "x${enableigb}" = "x1"; then
|
|||
fi
|
||||
|
||||
AC_SUBST(KERNEL_IGB,[$kerneligb])
|
||||
#------------------------------------------------------------------------------
|
||||
# igc driver
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
AC_ARG_ENABLE([igc],
|
||||
AS_HELP_STRING([--enable-igc],
|
||||
[Enable igc driver]),
|
||||
[
|
||||
case "${enableval}" in
|
||||
yes) enableigc=1
|
||||
;;
|
||||
no) enableigc=0
|
||||
;;
|
||||
*) AC_MSG_ERROR([Invalid value for --enable-igc])
|
||||
;;
|
||||
esac
|
||||
],
|
||||
[enableigc=0] # disabled by default
|
||||
)
|
||||
|
||||
AM_CONDITIONAL(ENABLE_IGC, test "x$enableigc" = "x1")
|
||||
AC_SUBST(ENABLE_IGC,[$enableigc])
|
||||
|
||||
AC_ARG_WITH([igc-kernel],
|
||||
AS_HELP_STRING([--with-igc-kernel=<X.Y.Z>],
|
||||
[igc kernel (only if differing)]
|
||||
),
|
||||
[
|
||||
kerneligc=[$withval]
|
||||
],
|
||||
[
|
||||
kerneligc=$linuxversion
|
||||
]
|
||||
)
|
||||
|
||||
if test "x${enableigc}" = "x1"; then
|
||||
AC_MSG_CHECKING([for kernel for igc driver])
|
||||
|
||||
if test ! -f "${srcdir}/devices/igc/igc_main-${kerneligc}-orig.c"; then
|
||||
AC_MSG_ERROR([kernel $kerneligc not available for igc driver!])
|
||||
fi
|
||||
|
||||
AC_MSG_RESULT([$kerneligc])
|
||||
fi
|
||||
|
||||
AC_SUBST(KERNEL_IGC,[$kerneligc])
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# r8169 driver
|
||||
|
|
@ -1174,6 +1220,8 @@ AC_CONFIG_FILES([
|
|||
devices/genet/Makefile
|
||||
devices/igb/Kbuild
|
||||
devices/igb/Makefile
|
||||
devices/igc/Kbuild
|
||||
devices/igc/Makefile
|
||||
ethercat.spec
|
||||
examples/Kbuild
|
||||
examples/Makefile
|
||||
|
|
|
|||
|
|
@ -78,6 +78,10 @@ ifeq (@ENABLE_IGB@,1)
|
|||
obj-m += igb/
|
||||
endif
|
||||
|
||||
ifeq (@ENABLE_IGC@,1)
|
||||
obj-m += igc/
|
||||
endif
|
||||
|
||||
ifeq (@ENABLE_R8169@,1)
|
||||
EC_R8169_OBJ := r8169-@KERNEL_R8169@-ethercat.o
|
||||
obj-m += ec_r8169.o
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ SUBDIRS = \
|
|||
e1000 \
|
||||
e1000e \
|
||||
genet \
|
||||
igb
|
||||
igb \
|
||||
igc
|
||||
|
||||
# using HEADERS to enable tags target
|
||||
noinst_HEADERS = \
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ DRIVER_MAP=(
|
|||
("e1000e", "e1000e", "netdev"),
|
||||
("genet", "bcmgenet", "bcmgenet"),
|
||||
("igb", "igb", "igb_main"),
|
||||
("igc", "igc", "igc_main"),
|
||||
(".", "r8169", "r8169"),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# Copyright (C) 2006-2017 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
#
|
||||
# This file is part of the IgH EtherCAT Master.
|
||||
#
|
||||
# The IgH EtherCAT Master is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 2, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# The IgH EtherCAT Master is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with the IgH EtherCAT Master; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ---
|
||||
#
|
||||
# The license mentioned above concerns the source code only. Using the
|
||||
# EtherCAT technology and brand is only permitted in compliance with the
|
||||
# industrial property and similar rights of Beckhoff Automation GmbH.
|
||||
#
|
||||
# ---
|
||||
#
|
||||
# vim: syntax=make
|
||||
#
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
TOPDIR := $(src)/../..
|
||||
|
||||
REV := $(shell if test -s $(TOPDIR)/revision; then \
|
||||
cat $(TOPDIR)/revision; \
|
||||
else \
|
||||
git -C $(TOPDIR) describe 2>/dev/null || echo "unknown"; \
|
||||
fi)
|
||||
|
||||
ifeq (@ENABLE_IGC@,1)
|
||||
obj-m += ec_igc.o
|
||||
|
||||
ec_igc-objs := \
|
||||
igc_xdp-@KERNEL_IGC@-ethercat.o \
|
||||
igc_tsn-@KERNEL_IGC@-ethercat.o \
|
||||
igc_base-@KERNEL_IGC@-ethercat.o \
|
||||
igc_dump-@KERNEL_IGC@-ethercat.o \
|
||||
igc_main-@KERNEL_IGC@-ethercat.o \
|
||||
igc_ptp-@KERNEL_IGC@-ethercat.o \
|
||||
igc_diag-@KERNEL_IGC@-ethercat.o \
|
||||
igc_i225-@KERNEL_IGC@-ethercat.o \
|
||||
igc_mac-@KERNEL_IGC@-ethercat.o \
|
||||
igc_phy-@KERNEL_IGC@-ethercat.o \
|
||||
igc_ethtool-@KERNEL_IGC@-ethercat.o \
|
||||
igc_nvm-@KERNEL_IGC@-ethercat.o
|
||||
|
||||
CFLAGS_igc_main-@KERNEL_IGC@-ethercat.o = -DREV=$(REV)
|
||||
endif
|
||||
|
||||
KBUILD_EXTRA_SYMBOLS := \
|
||||
@abs_top_builddir@/$(LINUX_SYMVERS) \
|
||||
@abs_top_builddir@/master/$(LINUX_SYMVERS)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2006-2021 Florian Pose, Ingenieurgemeinschaft IgH
|
||||
#
|
||||
# This file is part of the IgH EtherCAT Master.
|
||||
#
|
||||
# The IgH EtherCAT Master is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 2, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# The IgH EtherCAT Master is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with the IgH EtherCAT Master; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ---
|
||||
#
|
||||
# The license mentioned above concerns the source code only. Using the
|
||||
# EtherCAT technology and brand is only permitted in compliance with the
|
||||
# industrial property and similar rights of Beckhoff Automation GmbH.
|
||||
#
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
include $(top_srcdir)/Makefile.kbuild
|
||||
|
||||
EXTRiA_DIST = igc-6.6-ethercat.h \
|
||||
igc_base-6.6-orig.h \
|
||||
igc_diag-6.6-orig.c \
|
||||
igc_ethtool-6.6-orig.c \
|
||||
igc_i225-6.6-orig.c \
|
||||
igc_mac-6.6-orig.c \
|
||||
igc_nvm-6.6-ethercat.h \
|
||||
igc_phy-6.6-orig.c \
|
||||
igc_regs-6.6-orig.h \
|
||||
igc_xdp-6.6-ethercat.c \
|
||||
igc-6.6-orig.h \
|
||||
igc_defines-6.6-ethercat.h \
|
||||
igc_diag-6.6-orig.h \
|
||||
igc_hw-6.6-ethercat.h \
|
||||
igc_i225-6.6-orig.h \
|
||||
igc_mac-6.6-orig.h \
|
||||
igc_nvm-6.6-orig.c \
|
||||
igc_phy-6.6-orig.h \
|
||||
igc_tsn-6.6-ethercat.c \
|
||||
igc_xdp-6.6-ethercat.h \
|
||||
igc_base-6.6-ethercat.c \
|
||||
igc_defines-6.6-orig.h \
|
||||
igc_dump-6.6-ethercat.c \
|
||||
igc_hw-6.6-orig.h \
|
||||
igc_main-6.6-ethercat.c \
|
||||
igc_nvm-6.6-orig.h \
|
||||
igc_ptp-6.6-ethercat.c \
|
||||
igc_tsn-6.6-ethercat.h \
|
||||
igc_xdp-6.6-orig.c\
|
||||
igc_base-6.6-ethercat.h \
|
||||
igc_diag-6.6-ethercat.c \
|
||||
igc_dump-6.6-orig.c \
|
||||
igc_i225-6.6-ethercat.c \
|
||||
igc_mac-6.6-ethercat.c \
|
||||
igc_main-6.6-orig.c \
|
||||
igc_phy-6.6-ethercat.c \
|
||||
igc_ptp-6.6-orig.c \
|
||||
igc_tsn-6.6-orig.c \
|
||||
igc_xdp-6.6-orig.h\
|
||||
igc_base-6.6-orig.c \
|
||||
igc_diag-6.6-ethercat.h \
|
||||
igc_ethtool-6.6-ethercat.c \
|
||||
igc_i225-6.6-ethercat.h \
|
||||
igc_mac-6.6-ethercat.h \
|
||||
igc_nvm-6.6-ethercat.c \
|
||||
igc_phy-6.6-ethercat.h \
|
||||
igc_regs-6.6-ethercat.h \
|
||||
igc_tsn-6.6-orig.h \
|
||||
igc-6.4-ethercat.h \
|
||||
igc_base-6.4-orig.h \
|
||||
igc_diag-6.4-orig.c \
|
||||
igc_ethtool-6.4-orig.c \
|
||||
igc_i225-6.4-orig.c \
|
||||
igc_mac-6.4-orig.c \
|
||||
igc_nvm-6.4-ethercat.h \
|
||||
igc_phy-6.4-orig.c \
|
||||
igc_regs-6.4-orig.h \
|
||||
igc_xdp-6.4-ethercat.c \
|
||||
igc-6.4-orig.h \
|
||||
igc_defines-6.4-ethercat.h \
|
||||
igc_diag-6.4-orig.h \
|
||||
igc_hw-6.4-ethercat.h \
|
||||
igc_i225-6.4-orig.h \
|
||||
igc_mac-6.4-orig.h \
|
||||
igc_nvm-6.4-orig.c \
|
||||
igc_phy-6.4-orig.h \
|
||||
igc_tsn-6.4-ethercat.c \
|
||||
igc_xdp-6.4-ethercat.h \
|
||||
igc_base-6.4-ethercat.c \
|
||||
igc_defines-6.4-orig.h \
|
||||
igc_dump-6.4-ethercat.c \
|
||||
igc_hw-6.4-orig.h \
|
||||
igc_main-6.4-ethercat.c \
|
||||
igc_nvm-6.4-orig.h \
|
||||
igc_ptp-6.4-ethercat.c \
|
||||
igc_tsn-6.4-ethercat.h \
|
||||
igc_xdp-6.4-orig.c\
|
||||
igc_base-6.4-ethercat.h \
|
||||
igc_diag-6.4-ethercat.c \
|
||||
igc_dump-6.4-orig.c \
|
||||
igc_i225-6.4-ethercat.c \
|
||||
igc_mac-6.4-ethercat.c \
|
||||
igc_main-6.4-orig.c \
|
||||
igc_phy-6.4-ethercat.c \
|
||||
igc_ptp-6.4-orig.c \
|
||||
igc_tsn-6.4-orig.c \
|
||||
igc_xdp-6.4-orig.h\
|
||||
igc_base-6.4-orig.c \
|
||||
igc_diag-6.4-ethercat.h \
|
||||
igc_ethtool-6.4-ethercat.c \
|
||||
igc_i225-6.4-ethercat.h \
|
||||
igc_mac-6.4-ethercat.h \
|
||||
igc_nvm-6.4-ethercat.c \
|
||||
igc_phy-6.4-ethercat.h \
|
||||
igc_regs-6.4-ethercat.h \
|
||||
igc_tsn-6.4-orig.h
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,699 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_H_
|
||||
#define _IGC_H_
|
||||
#include "../ecdev.h"
|
||||
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/sctp.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/timecounter.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/hrtimer.h>
|
||||
|
||||
#include "igc_hw-6.4-ethercat.h"
|
||||
|
||||
void igc_ethtool_set_ops(struct net_device *);
|
||||
|
||||
/* Transmit and receive queues */
|
||||
#define IGC_MAX_RX_QUEUES 4
|
||||
#define IGC_MAX_TX_QUEUES 4
|
||||
|
||||
#define MAX_Q_VECTORS 8
|
||||
#define MAX_STD_JUMBO_FRAME_SIZE 9216
|
||||
|
||||
#define MAX_ETYPE_FILTER 8
|
||||
#define IGC_RETA_SIZE 128
|
||||
|
||||
/* SDP support */
|
||||
#define IGC_N_EXTTS 2
|
||||
#define IGC_N_PEROUT 2
|
||||
#define IGC_N_SDP 4
|
||||
|
||||
#define MAX_FLEX_FILTER 32
|
||||
|
||||
enum igc_mac_filter_type {
|
||||
IGC_MAC_FILTER_TYPE_DST = 0,
|
||||
IGC_MAC_FILTER_TYPE_SRC
|
||||
};
|
||||
|
||||
struct igc_tx_queue_stats {
|
||||
u64 packets;
|
||||
u64 bytes;
|
||||
u64 restart_queue;
|
||||
u64 restart_queue2;
|
||||
};
|
||||
|
||||
struct igc_rx_queue_stats {
|
||||
u64 packets;
|
||||
u64 bytes;
|
||||
u64 drops;
|
||||
u64 csum_err;
|
||||
u64 alloc_failed;
|
||||
};
|
||||
|
||||
struct igc_rx_packet_stats {
|
||||
u64 ipv4_packets; /* IPv4 headers processed */
|
||||
u64 ipv4e_packets; /* IPv4E headers with extensions processed */
|
||||
u64 ipv6_packets; /* IPv6 headers processed */
|
||||
u64 ipv6e_packets; /* IPv6E headers with extensions processed */
|
||||
u64 tcp_packets; /* TCP headers processed */
|
||||
u64 udp_packets; /* UDP headers processed */
|
||||
u64 sctp_packets; /* SCTP headers processed */
|
||||
u64 nfs_packets; /* NFS headers processe */
|
||||
u64 other_packets;
|
||||
};
|
||||
|
||||
struct igc_ring_container {
|
||||
struct igc_ring *ring; /* pointer to linked list of rings */
|
||||
unsigned int total_bytes; /* total bytes processed this int */
|
||||
unsigned int total_packets; /* total packets processed this int */
|
||||
u16 work_limit; /* total work allowed per interrupt */
|
||||
u8 count; /* total number of rings in vector */
|
||||
u8 itr; /* current ITR setting for ring */
|
||||
};
|
||||
|
||||
struct igc_ring {
|
||||
struct igc_q_vector *q_vector; /* backlink to q_vector */
|
||||
struct net_device *netdev; /* back pointer to net_device */
|
||||
struct device *dev; /* device for dma mapping */
|
||||
union { /* array of buffer info structs */
|
||||
struct igc_tx_buffer *tx_buffer_info;
|
||||
struct igc_rx_buffer *rx_buffer_info;
|
||||
};
|
||||
void *desc; /* descriptor ring memory */
|
||||
unsigned long flags; /* ring specific flags */
|
||||
void __iomem *tail; /* pointer to ring tail register */
|
||||
dma_addr_t dma; /* phys address of the ring */
|
||||
unsigned int size; /* length of desc. ring in bytes */
|
||||
|
||||
u16 count; /* number of desc. in the ring */
|
||||
u8 queue_index; /* logical index of the ring*/
|
||||
u8 reg_idx; /* physical index of the ring */
|
||||
bool launchtime_enable; /* true if LaunchTime is enabled */
|
||||
ktime_t last_tx_cycle; /* end of the cycle with a launchtime transmission */
|
||||
ktime_t last_ff_cycle; /* Last cycle with an active first flag */
|
||||
|
||||
u32 start_time;
|
||||
u32 end_time;
|
||||
u32 max_sdu;
|
||||
bool oper_gate_closed; /* Operating gate. True if the TX Queue is closed */
|
||||
bool admin_gate_closed; /* Future gate. True if the TX Queue will be closed */
|
||||
|
||||
/* CBS parameters */
|
||||
bool cbs_enable; /* indicates if CBS is enabled */
|
||||
s32 idleslope; /* idleSlope in kbps */
|
||||
s32 sendslope; /* sendSlope in kbps */
|
||||
s32 hicredit; /* hiCredit in bytes */
|
||||
s32 locredit; /* loCredit in bytes */
|
||||
|
||||
/* everything past this point are written often */
|
||||
u16 next_to_clean;
|
||||
u16 next_to_use;
|
||||
u16 next_to_alloc;
|
||||
|
||||
union {
|
||||
/* TX */
|
||||
struct {
|
||||
struct igc_tx_queue_stats tx_stats;
|
||||
struct u64_stats_sync tx_syncp;
|
||||
struct u64_stats_sync tx_syncp2;
|
||||
};
|
||||
/* RX */
|
||||
struct {
|
||||
struct igc_rx_queue_stats rx_stats;
|
||||
struct igc_rx_packet_stats pkt_stats;
|
||||
struct u64_stats_sync rx_syncp;
|
||||
struct sk_buff *skb;
|
||||
};
|
||||
};
|
||||
|
||||
struct xdp_rxq_info xdp_rxq;
|
||||
struct xsk_buff_pool *xsk_pool;
|
||||
} ____cacheline_internodealigned_in_smp;
|
||||
|
||||
/* Board specific private data structure */
|
||||
struct igc_adapter {
|
||||
struct net_device *netdev;
|
||||
|
||||
struct ethtool_eee eee;
|
||||
u16 eee_advert;
|
||||
|
||||
unsigned long state;
|
||||
unsigned int flags;
|
||||
unsigned int num_q_vectors;
|
||||
|
||||
struct msix_entry *msix_entries;
|
||||
|
||||
/* TX */
|
||||
u16 tx_work_limit;
|
||||
u32 tx_timeout_count;
|
||||
int num_tx_queues;
|
||||
struct igc_ring *tx_ring[IGC_MAX_TX_QUEUES];
|
||||
|
||||
/* RX */
|
||||
int num_rx_queues;
|
||||
struct igc_ring *rx_ring[IGC_MAX_RX_QUEUES];
|
||||
|
||||
struct timer_list watchdog_timer;
|
||||
struct timer_list dma_err_timer;
|
||||
struct timer_list phy_info_timer;
|
||||
struct hrtimer hrtimer;
|
||||
|
||||
u32 wol;
|
||||
u32 en_mng_pt;
|
||||
u16 link_speed;
|
||||
u16 link_duplex;
|
||||
|
||||
u8 port_num;
|
||||
|
||||
u8 __iomem *io_addr;
|
||||
/* Interrupt Throttle Rate */
|
||||
u32 rx_itr_setting;
|
||||
u32 tx_itr_setting;
|
||||
|
||||
struct work_struct reset_task;
|
||||
struct work_struct watchdog_task;
|
||||
struct work_struct dma_err_task;
|
||||
bool fc_autoneg;
|
||||
|
||||
u8 tx_timeout_factor;
|
||||
|
||||
int msg_enable;
|
||||
u32 max_frame_size;
|
||||
u32 min_frame_size;
|
||||
|
||||
int tc_setup_type;
|
||||
ktime_t base_time;
|
||||
ktime_t cycle_time;
|
||||
bool taprio_offload_enable;
|
||||
u32 qbv_config_change_errors;
|
||||
bool qbv_transition;
|
||||
unsigned int qbv_count;
|
||||
|
||||
/* OS defined structs */
|
||||
struct pci_dev *pdev;
|
||||
/* lock for statistics */
|
||||
spinlock_t stats64_lock;
|
||||
struct rtnl_link_stats64 stats64;
|
||||
|
||||
/* structs defined in igc_hw.h */
|
||||
struct igc_hw hw;
|
||||
struct igc_hw_stats stats;
|
||||
|
||||
struct igc_q_vector *q_vector[MAX_Q_VECTORS];
|
||||
u32 eims_enable_mask;
|
||||
u32 eims_other;
|
||||
|
||||
u16 tx_ring_count;
|
||||
u16 rx_ring_count;
|
||||
|
||||
u32 tx_hwtstamp_timeouts;
|
||||
u32 tx_hwtstamp_skipped;
|
||||
u32 rx_hwtstamp_cleared;
|
||||
|
||||
u32 rss_queues;
|
||||
u32 rss_indir_tbl_init;
|
||||
|
||||
/* Any access to elements in nfc_rule_list is protected by the
|
||||
* nfc_rule_lock.
|
||||
*/
|
||||
struct mutex nfc_rule_lock;
|
||||
struct list_head nfc_rule_list;
|
||||
unsigned int nfc_rule_count;
|
||||
|
||||
u8 rss_indir_tbl[IGC_RETA_SIZE];
|
||||
|
||||
unsigned long link_check_timeout;
|
||||
struct igc_info ei;
|
||||
|
||||
u32 test_icr;
|
||||
|
||||
struct ptp_clock *ptp_clock;
|
||||
struct ptp_clock_info ptp_caps;
|
||||
/* Access to ptp_tx_skb and ptp_tx_start are protected by the
|
||||
* ptp_tx_lock.
|
||||
*/
|
||||
spinlock_t ptp_tx_lock;
|
||||
struct sk_buff *ptp_tx_skb;
|
||||
struct hwtstamp_config tstamp_config;
|
||||
unsigned long ptp_tx_start;
|
||||
unsigned int ptp_flags;
|
||||
/* System time value lock */
|
||||
spinlock_t tmreg_lock;
|
||||
struct cyclecounter cc;
|
||||
struct timecounter tc;
|
||||
struct timespec64 prev_ptp_time; /* Pre-reset PTP clock */
|
||||
ktime_t ptp_reset_start; /* Reset time in clock mono */
|
||||
struct system_time_snapshot snapshot;
|
||||
|
||||
char fw_version[32];
|
||||
|
||||
struct bpf_prog *xdp_prog;
|
||||
|
||||
bool pps_sys_wrap_on;
|
||||
|
||||
struct ptp_pin_desc sdp_config[IGC_N_SDP];
|
||||
struct {
|
||||
struct timespec64 start;
|
||||
struct timespec64 period;
|
||||
} perout[IGC_N_PEROUT];
|
||||
|
||||
/* EtherCAT device variables */
|
||||
ec_device_t *ecdev;
|
||||
unsigned long ec_watchdog_jiffies;
|
||||
};
|
||||
|
||||
void igc_up(struct igc_adapter *adapter);
|
||||
void igc_down(struct igc_adapter *adapter);
|
||||
int igc_open(struct net_device *netdev);
|
||||
int igc_close(struct net_device *netdev);
|
||||
int igc_setup_tx_resources(struct igc_ring *ring);
|
||||
int igc_setup_rx_resources(struct igc_ring *ring);
|
||||
void igc_free_tx_resources(struct igc_ring *ring);
|
||||
void igc_free_rx_resources(struct igc_ring *ring);
|
||||
unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter);
|
||||
void igc_set_flag_queue_pairs(struct igc_adapter *adapter,
|
||||
const u32 max_rss_queues);
|
||||
int igc_reinit_queues(struct igc_adapter *adapter);
|
||||
void igc_write_rss_indir_tbl(struct igc_adapter *adapter);
|
||||
bool igc_has_link(struct igc_adapter *adapter);
|
||||
void igc_reset(struct igc_adapter *adapter);
|
||||
void igc_update_stats(struct igc_adapter *adapter);
|
||||
void igc_disable_rx_ring(struct igc_ring *ring);
|
||||
void igc_enable_rx_ring(struct igc_ring *ring);
|
||||
void igc_disable_tx_ring(struct igc_ring *ring);
|
||||
void igc_enable_tx_ring(struct igc_ring *ring);
|
||||
int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags);
|
||||
|
||||
/* igc_dump declarations */
|
||||
void igc_rings_dump(struct igc_adapter *adapter);
|
||||
void igc_regs_dump(struct igc_adapter *adapter);
|
||||
|
||||
extern char igc_driver_name[];
|
||||
|
||||
#define IGC_REGS_LEN 740
|
||||
|
||||
/* flags controlling PTP/1588 function */
|
||||
#define IGC_PTP_ENABLED BIT(0)
|
||||
|
||||
/* Flags definitions */
|
||||
#define IGC_FLAG_HAS_MSI BIT(0)
|
||||
#define IGC_FLAG_QUEUE_PAIRS BIT(3)
|
||||
#define IGC_FLAG_DMAC BIT(4)
|
||||
#define IGC_FLAG_PTP BIT(8)
|
||||
#define IGC_FLAG_WOL_SUPPORTED BIT(8)
|
||||
#define IGC_FLAG_NEED_LINK_UPDATE BIT(9)
|
||||
#define IGC_FLAG_HAS_MSIX BIT(13)
|
||||
#define IGC_FLAG_EEE BIT(14)
|
||||
#define IGC_FLAG_VLAN_PROMISC BIT(15)
|
||||
#define IGC_FLAG_RX_LEGACY BIT(16)
|
||||
#define IGC_FLAG_TSN_QBV_ENABLED BIT(17)
|
||||
#define IGC_FLAG_TSN_QAV_ENABLED BIT(18)
|
||||
|
||||
#define IGC_FLAG_TSN_ANY_ENABLED \
|
||||
(IGC_FLAG_TSN_QBV_ENABLED | IGC_FLAG_TSN_QAV_ENABLED)
|
||||
|
||||
#define IGC_FLAG_RSS_FIELD_IPV4_UDP BIT(6)
|
||||
#define IGC_FLAG_RSS_FIELD_IPV6_UDP BIT(7)
|
||||
|
||||
#define IGC_MRQC_ENABLE_RSS_MQ 0x00000002
|
||||
#define IGC_MRQC_RSS_FIELD_IPV4_UDP 0x00400000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6_UDP 0x00800000
|
||||
|
||||
/* RX-desc Write-Back format RSS Type's */
|
||||
enum igc_rss_type_num {
|
||||
IGC_RSS_TYPE_NO_HASH = 0,
|
||||
IGC_RSS_TYPE_HASH_TCP_IPV4 = 1,
|
||||
IGC_RSS_TYPE_HASH_IPV4 = 2,
|
||||
IGC_RSS_TYPE_HASH_TCP_IPV6 = 3,
|
||||
IGC_RSS_TYPE_HASH_IPV6_EX = 4,
|
||||
IGC_RSS_TYPE_HASH_IPV6 = 5,
|
||||
IGC_RSS_TYPE_HASH_TCP_IPV6_EX = 6,
|
||||
IGC_RSS_TYPE_HASH_UDP_IPV4 = 7,
|
||||
IGC_RSS_TYPE_HASH_UDP_IPV6 = 8,
|
||||
IGC_RSS_TYPE_HASH_UDP_IPV6_EX = 9,
|
||||
IGC_RSS_TYPE_MAX = 10,
|
||||
};
|
||||
#define IGC_RSS_TYPE_MAX_TABLE 16
|
||||
#define IGC_RSS_TYPE_MASK GENMASK(3,0) /* 4-bits (3:0) = mask 0x0F */
|
||||
|
||||
/* igc_rss_type - Rx descriptor RSS type field */
|
||||
static inline u32 igc_rss_type(const union igc_adv_rx_desc *rx_desc)
|
||||
{
|
||||
/* RSS Type 4-bits (3:0) number: 0-9 (above 9 is reserved)
|
||||
* Accessing the same bits via u16 (wb.lower.lo_dword.hs_rss.pkt_info)
|
||||
* is slightly slower than via u32 (wb.lower.lo_dword.data)
|
||||
*/
|
||||
return le32_get_bits(rx_desc->wb.lower.lo_dword.data, IGC_RSS_TYPE_MASK);
|
||||
}
|
||||
|
||||
/* Interrupt defines */
|
||||
#define IGC_START_ITR 648 /* ~6000 ints/sec */
|
||||
#define IGC_4K_ITR 980
|
||||
#define IGC_20K_ITR 196
|
||||
#define IGC_70K_ITR 56
|
||||
|
||||
#define IGC_DEFAULT_ITR 3 /* dynamic */
|
||||
#define IGC_MAX_ITR_USECS 10000
|
||||
#define IGC_MIN_ITR_USECS 10
|
||||
#define NON_Q_VECTORS 1
|
||||
#define MAX_MSIX_ENTRIES 10
|
||||
|
||||
/* TX/RX descriptor defines */
|
||||
#define IGC_DEFAULT_TXD 256
|
||||
#define IGC_DEFAULT_TX_WORK 128
|
||||
#define IGC_MIN_TXD 80
|
||||
#define IGC_MAX_TXD 4096
|
||||
|
||||
#define IGC_DEFAULT_RXD 256
|
||||
#define IGC_MIN_RXD 80
|
||||
#define IGC_MAX_RXD 4096
|
||||
|
||||
/* Supported Rx Buffer Sizes */
|
||||
#define IGC_RXBUFFER_256 256
|
||||
#define IGC_RXBUFFER_2048 2048
|
||||
#define IGC_RXBUFFER_3072 3072
|
||||
|
||||
#define AUTO_ALL_MODES 0
|
||||
#define IGC_RX_HDR_LEN IGC_RXBUFFER_256
|
||||
|
||||
/* Transmit and receive latency (for PTP timestamps) */
|
||||
#define IGC_I225_TX_LATENCY_10 240
|
||||
#define IGC_I225_TX_LATENCY_100 58
|
||||
#define IGC_I225_TX_LATENCY_1000 80
|
||||
#define IGC_I225_TX_LATENCY_2500 1325
|
||||
#define IGC_I225_RX_LATENCY_10 6450
|
||||
#define IGC_I225_RX_LATENCY_100 185
|
||||
#define IGC_I225_RX_LATENCY_1000 300
|
||||
#define IGC_I225_RX_LATENCY_2500 1485
|
||||
|
||||
/* RX and TX descriptor control thresholds.
|
||||
* PTHRESH - MAC will consider prefetch if it has fewer than this number of
|
||||
* descriptors available in its onboard memory.
|
||||
* Setting this to 0 disables RX descriptor prefetch.
|
||||
* HTHRESH - MAC will only prefetch if there are at least this many descriptors
|
||||
* available in host memory.
|
||||
* If PTHRESH is 0, this should also be 0.
|
||||
* WTHRESH - RX descriptor writeback threshold - MAC will delay writing back
|
||||
* descriptors until either it has this many to write back, or the
|
||||
* ITR timer expires.
|
||||
*/
|
||||
#define IGC_RX_PTHRESH 8
|
||||
#define IGC_RX_HTHRESH 8
|
||||
#define IGC_TX_PTHRESH 8
|
||||
#define IGC_TX_HTHRESH 1
|
||||
#define IGC_RX_WTHRESH 4
|
||||
#define IGC_TX_WTHRESH 16
|
||||
|
||||
#define IGC_RX_DMA_ATTR \
|
||||
(DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
|
||||
|
||||
#define IGC_TS_HDR_LEN 16
|
||||
|
||||
#define IGC_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN)
|
||||
|
||||
#if (PAGE_SIZE < 8192)
|
||||
#define IGC_MAX_FRAME_BUILD_SKB \
|
||||
(SKB_WITH_OVERHEAD(IGC_RXBUFFER_2048) - IGC_SKB_PAD - IGC_TS_HDR_LEN)
|
||||
#else
|
||||
#define IGC_MAX_FRAME_BUILD_SKB (IGC_RXBUFFER_2048 - IGC_TS_HDR_LEN)
|
||||
#endif
|
||||
|
||||
/* How many Rx Buffers do we bundle into one write to the hardware ? */
|
||||
#define IGC_RX_BUFFER_WRITE 16 /* Must be power of 2 */
|
||||
|
||||
/* VLAN info */
|
||||
#define IGC_TX_FLAGS_VLAN_MASK 0xffff0000
|
||||
#define IGC_TX_FLAGS_VLAN_SHIFT 16
|
||||
|
||||
/* igc_test_staterr - tests bits within Rx descriptor status and error fields */
|
||||
static inline __le32 igc_test_staterr(union igc_adv_rx_desc *rx_desc,
|
||||
const u32 stat_err_bits)
|
||||
{
|
||||
return rx_desc->wb.upper.status_error & cpu_to_le32(stat_err_bits);
|
||||
}
|
||||
|
||||
enum igc_state_t {
|
||||
__IGC_TESTING,
|
||||
__IGC_RESETTING,
|
||||
__IGC_DOWN,
|
||||
};
|
||||
|
||||
enum igc_tx_flags {
|
||||
/* cmd_type flags */
|
||||
IGC_TX_FLAGS_VLAN = 0x01,
|
||||
IGC_TX_FLAGS_TSO = 0x02,
|
||||
IGC_TX_FLAGS_TSTAMP = 0x04,
|
||||
|
||||
/* olinfo flags */
|
||||
IGC_TX_FLAGS_IPV4 = 0x10,
|
||||
IGC_TX_FLAGS_CSUM = 0x20,
|
||||
};
|
||||
|
||||
enum igc_boards {
|
||||
board_base,
|
||||
};
|
||||
|
||||
/* The largest size we can write to the descriptor is 65535. In order to
|
||||
* maintain a power of two alignment we have to limit ourselves to 32K.
|
||||
*/
|
||||
#define IGC_MAX_TXD_PWR 15
|
||||
#define IGC_MAX_DATA_PER_TXD BIT(IGC_MAX_TXD_PWR)
|
||||
|
||||
/* Tx Descriptors needed, worst case */
|
||||
#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IGC_MAX_DATA_PER_TXD)
|
||||
#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
|
||||
|
||||
enum igc_tx_buffer_type {
|
||||
IGC_TX_BUFFER_TYPE_SKB,
|
||||
IGC_TX_BUFFER_TYPE_XDP,
|
||||
IGC_TX_BUFFER_TYPE_XSK,
|
||||
};
|
||||
|
||||
/* wrapper around a pointer to a socket buffer,
|
||||
* so a DMA handle can be stored along with the buffer
|
||||
*/
|
||||
struct igc_tx_buffer {
|
||||
union igc_adv_tx_desc *next_to_watch;
|
||||
unsigned long time_stamp;
|
||||
enum igc_tx_buffer_type type;
|
||||
union {
|
||||
struct sk_buff *skb;
|
||||
struct xdp_frame *xdpf;
|
||||
};
|
||||
unsigned int bytecount;
|
||||
u16 gso_segs;
|
||||
__be16 protocol;
|
||||
|
||||
DEFINE_DMA_UNMAP_ADDR(dma);
|
||||
DEFINE_DMA_UNMAP_LEN(len);
|
||||
u32 tx_flags;
|
||||
};
|
||||
|
||||
struct igc_rx_buffer {
|
||||
union {
|
||||
struct {
|
||||
dma_addr_t dma;
|
||||
struct page *page;
|
||||
#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
|
||||
__u32 page_offset;
|
||||
#else
|
||||
__u16 page_offset;
|
||||
#endif
|
||||
__u16 pagecnt_bias;
|
||||
};
|
||||
struct xdp_buff *xdp;
|
||||
};
|
||||
};
|
||||
|
||||
/* context wrapper around xdp_buff to provide access to descriptor metadata */
|
||||
struct igc_xdp_buff {
|
||||
struct xdp_buff xdp;
|
||||
union igc_adv_rx_desc *rx_desc;
|
||||
};
|
||||
|
||||
struct igc_q_vector {
|
||||
struct igc_adapter *adapter; /* backlink */
|
||||
void __iomem *itr_register;
|
||||
u32 eims_value; /* EIMS mask value */
|
||||
|
||||
u16 itr_val;
|
||||
u8 set_itr;
|
||||
|
||||
struct igc_ring_container rx, tx;
|
||||
|
||||
struct napi_struct napi;
|
||||
|
||||
struct rcu_head rcu; /* to avoid race with update stats on free */
|
||||
char name[IFNAMSIZ + 9];
|
||||
struct net_device poll_dev;
|
||||
|
||||
/* for dynamic allocation of rings associated with this q_vector */
|
||||
struct igc_ring ring[] ____cacheline_internodealigned_in_smp;
|
||||
};
|
||||
|
||||
enum igc_filter_match_flags {
|
||||
IGC_FILTER_FLAG_ETHER_TYPE = BIT(0),
|
||||
IGC_FILTER_FLAG_VLAN_TCI = BIT(1),
|
||||
IGC_FILTER_FLAG_SRC_MAC_ADDR = BIT(2),
|
||||
IGC_FILTER_FLAG_DST_MAC_ADDR = BIT(3),
|
||||
IGC_FILTER_FLAG_USER_DATA = BIT(4),
|
||||
IGC_FILTER_FLAG_VLAN_ETYPE = BIT(5),
|
||||
};
|
||||
|
||||
struct igc_nfc_filter {
|
||||
u8 match_flags;
|
||||
u16 etype;
|
||||
__be16 vlan_etype;
|
||||
u16 vlan_tci;
|
||||
u8 src_addr[ETH_ALEN];
|
||||
u8 dst_addr[ETH_ALEN];
|
||||
u8 user_data[8];
|
||||
u8 user_mask[8];
|
||||
u8 flex_index;
|
||||
u8 rx_queue;
|
||||
u8 prio;
|
||||
u8 immediate_irq;
|
||||
u8 drop;
|
||||
};
|
||||
|
||||
struct igc_nfc_rule {
|
||||
struct list_head list;
|
||||
struct igc_nfc_filter filter;
|
||||
u32 location;
|
||||
u16 action;
|
||||
bool flex;
|
||||
};
|
||||
|
||||
/* IGC supports a total of 32 NFC rules: 16 MAC address based, 8 VLAN priority
|
||||
* based, 8 ethertype based and 32 Flex filter based rules.
|
||||
*/
|
||||
#define IGC_MAX_RXNFC_RULES 64
|
||||
|
||||
struct igc_flex_filter {
|
||||
u8 index;
|
||||
u8 data[128];
|
||||
u8 mask[16];
|
||||
u8 length;
|
||||
u8 rx_queue;
|
||||
u8 prio;
|
||||
u8 immediate_irq;
|
||||
u8 drop;
|
||||
};
|
||||
|
||||
/* igc_desc_unused - calculate if we have unused descriptors */
|
||||
static inline u16 igc_desc_unused(const struct igc_ring *ring)
|
||||
{
|
||||
u16 ntc = ring->next_to_clean;
|
||||
u16 ntu = ring->next_to_use;
|
||||
|
||||
return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1;
|
||||
}
|
||||
|
||||
static inline s32 igc_get_phy_info(struct igc_hw *hw)
|
||||
{
|
||||
if (hw->phy.ops.get_phy_info)
|
||||
return hw->phy.ops.get_phy_info(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline s32 igc_reset_phy(struct igc_hw *hw)
|
||||
{
|
||||
if (hw->phy.ops.reset)
|
||||
return hw->phy.ops.reset(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct netdev_queue *txring_txq(const struct igc_ring *tx_ring)
|
||||
{
|
||||
return netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index);
|
||||
}
|
||||
|
||||
enum igc_ring_flags_t {
|
||||
IGC_RING_FLAG_RX_3K_BUFFER,
|
||||
IGC_RING_FLAG_RX_BUILD_SKB_ENABLED,
|
||||
IGC_RING_FLAG_RX_SCTP_CSUM,
|
||||
IGC_RING_FLAG_RX_LB_VLAN_BSWAP,
|
||||
IGC_RING_FLAG_TX_CTX_IDX,
|
||||
IGC_RING_FLAG_TX_DETECT_HANG,
|
||||
IGC_RING_FLAG_AF_XDP_ZC,
|
||||
IGC_RING_FLAG_TX_HWTSTAMP,
|
||||
};
|
||||
|
||||
#define ring_uses_large_buffer(ring) \
|
||||
test_bit(IGC_RING_FLAG_RX_3K_BUFFER, &(ring)->flags)
|
||||
#define set_ring_uses_large_buffer(ring) \
|
||||
set_bit(IGC_RING_FLAG_RX_3K_BUFFER, &(ring)->flags)
|
||||
#define clear_ring_uses_large_buffer(ring) \
|
||||
clear_bit(IGC_RING_FLAG_RX_3K_BUFFER, &(ring)->flags)
|
||||
|
||||
#define ring_uses_build_skb(ring) \
|
||||
test_bit(IGC_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
|
||||
|
||||
static inline unsigned int igc_rx_bufsz(struct igc_ring *ring)
|
||||
{
|
||||
#if (PAGE_SIZE < 8192)
|
||||
if (ring_uses_large_buffer(ring))
|
||||
return IGC_RXBUFFER_3072;
|
||||
|
||||
if (ring_uses_build_skb(ring))
|
||||
return IGC_MAX_FRAME_BUILD_SKB + IGC_TS_HDR_LEN;
|
||||
#endif
|
||||
return IGC_RXBUFFER_2048;
|
||||
}
|
||||
|
||||
static inline unsigned int igc_rx_pg_order(struct igc_ring *ring)
|
||||
{
|
||||
#if (PAGE_SIZE < 8192)
|
||||
if (ring_uses_large_buffer(ring))
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline 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 -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
void igc_reinit_locked(struct igc_adapter *);
|
||||
struct igc_nfc_rule *igc_get_nfc_rule(struct igc_adapter *adapter,
|
||||
u32 location);
|
||||
int igc_add_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule);
|
||||
void igc_del_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule);
|
||||
|
||||
void igc_ptp_init(struct igc_adapter *adapter);
|
||||
void igc_ptp_reset(struct igc_adapter *adapter);
|
||||
void igc_ptp_suspend(struct igc_adapter *adapter);
|
||||
void igc_ptp_stop(struct igc_adapter *adapter);
|
||||
ktime_t igc_ptp_rx_pktstamp(struct igc_adapter *adapter, __le32 *buf);
|
||||
int igc_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr);
|
||||
int igc_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr);
|
||||
void igc_ptp_tx_hang(struct igc_adapter *adapter);
|
||||
void igc_ptp_read(struct igc_adapter *adapter, struct timespec64 *ts);
|
||||
void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter);
|
||||
|
||||
#define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring))
|
||||
|
||||
#define IGC_TXD_DCMD (IGC_ADVTXD_DCMD_EOP | IGC_ADVTXD_DCMD_RS)
|
||||
|
||||
#define IGC_RX_DESC(R, i) \
|
||||
(&(((union igc_adv_rx_desc *)((R)->desc))[i]))
|
||||
#define IGC_TX_DESC(R, i) \
|
||||
(&(((union igc_adv_tx_desc *)((R)->desc))[i]))
|
||||
#define IGC_TX_CTXTDESC(R, i) \
|
||||
(&(((struct igc_adv_tx_context_desc *)((R)->desc))[i]))
|
||||
|
||||
#endif /* _IGC_H_ */
|
||||
|
|
@ -0,0 +1,694 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_H_
|
||||
#define _IGC_H_
|
||||
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/sctp.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/timecounter.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/hrtimer.h>
|
||||
|
||||
#include "igc_hw.h"
|
||||
|
||||
void igc_ethtool_set_ops(struct net_device *);
|
||||
|
||||
/* Transmit and receive queues */
|
||||
#define IGC_MAX_RX_QUEUES 4
|
||||
#define IGC_MAX_TX_QUEUES 4
|
||||
|
||||
#define MAX_Q_VECTORS 8
|
||||
#define MAX_STD_JUMBO_FRAME_SIZE 9216
|
||||
|
||||
#define MAX_ETYPE_FILTER 8
|
||||
#define IGC_RETA_SIZE 128
|
||||
|
||||
/* SDP support */
|
||||
#define IGC_N_EXTTS 2
|
||||
#define IGC_N_PEROUT 2
|
||||
#define IGC_N_SDP 4
|
||||
|
||||
#define MAX_FLEX_FILTER 32
|
||||
|
||||
enum igc_mac_filter_type {
|
||||
IGC_MAC_FILTER_TYPE_DST = 0,
|
||||
IGC_MAC_FILTER_TYPE_SRC
|
||||
};
|
||||
|
||||
struct igc_tx_queue_stats {
|
||||
u64 packets;
|
||||
u64 bytes;
|
||||
u64 restart_queue;
|
||||
u64 restart_queue2;
|
||||
};
|
||||
|
||||
struct igc_rx_queue_stats {
|
||||
u64 packets;
|
||||
u64 bytes;
|
||||
u64 drops;
|
||||
u64 csum_err;
|
||||
u64 alloc_failed;
|
||||
};
|
||||
|
||||
struct igc_rx_packet_stats {
|
||||
u64 ipv4_packets; /* IPv4 headers processed */
|
||||
u64 ipv4e_packets; /* IPv4E headers with extensions processed */
|
||||
u64 ipv6_packets; /* IPv6 headers processed */
|
||||
u64 ipv6e_packets; /* IPv6E headers with extensions processed */
|
||||
u64 tcp_packets; /* TCP headers processed */
|
||||
u64 udp_packets; /* UDP headers processed */
|
||||
u64 sctp_packets; /* SCTP headers processed */
|
||||
u64 nfs_packets; /* NFS headers processe */
|
||||
u64 other_packets;
|
||||
};
|
||||
|
||||
struct igc_ring_container {
|
||||
struct igc_ring *ring; /* pointer to linked list of rings */
|
||||
unsigned int total_bytes; /* total bytes processed this int */
|
||||
unsigned int total_packets; /* total packets processed this int */
|
||||
u16 work_limit; /* total work allowed per interrupt */
|
||||
u8 count; /* total number of rings in vector */
|
||||
u8 itr; /* current ITR setting for ring */
|
||||
};
|
||||
|
||||
struct igc_ring {
|
||||
struct igc_q_vector *q_vector; /* backlink to q_vector */
|
||||
struct net_device *netdev; /* back pointer to net_device */
|
||||
struct device *dev; /* device for dma mapping */
|
||||
union { /* array of buffer info structs */
|
||||
struct igc_tx_buffer *tx_buffer_info;
|
||||
struct igc_rx_buffer *rx_buffer_info;
|
||||
};
|
||||
void *desc; /* descriptor ring memory */
|
||||
unsigned long flags; /* ring specific flags */
|
||||
void __iomem *tail; /* pointer to ring tail register */
|
||||
dma_addr_t dma; /* phys address of the ring */
|
||||
unsigned int size; /* length of desc. ring in bytes */
|
||||
|
||||
u16 count; /* number of desc. in the ring */
|
||||
u8 queue_index; /* logical index of the ring*/
|
||||
u8 reg_idx; /* physical index of the ring */
|
||||
bool launchtime_enable; /* true if LaunchTime is enabled */
|
||||
ktime_t last_tx_cycle; /* end of the cycle with a launchtime transmission */
|
||||
ktime_t last_ff_cycle; /* Last cycle with an active first flag */
|
||||
|
||||
u32 start_time;
|
||||
u32 end_time;
|
||||
u32 max_sdu;
|
||||
bool oper_gate_closed; /* Operating gate. True if the TX Queue is closed */
|
||||
bool admin_gate_closed; /* Future gate. True if the TX Queue will be closed */
|
||||
|
||||
/* CBS parameters */
|
||||
bool cbs_enable; /* indicates if CBS is enabled */
|
||||
s32 idleslope; /* idleSlope in kbps */
|
||||
s32 sendslope; /* sendSlope in kbps */
|
||||
s32 hicredit; /* hiCredit in bytes */
|
||||
s32 locredit; /* loCredit in bytes */
|
||||
|
||||
/* everything past this point are written often */
|
||||
u16 next_to_clean;
|
||||
u16 next_to_use;
|
||||
u16 next_to_alloc;
|
||||
|
||||
union {
|
||||
/* TX */
|
||||
struct {
|
||||
struct igc_tx_queue_stats tx_stats;
|
||||
struct u64_stats_sync tx_syncp;
|
||||
struct u64_stats_sync tx_syncp2;
|
||||
};
|
||||
/* RX */
|
||||
struct {
|
||||
struct igc_rx_queue_stats rx_stats;
|
||||
struct igc_rx_packet_stats pkt_stats;
|
||||
struct u64_stats_sync rx_syncp;
|
||||
struct sk_buff *skb;
|
||||
};
|
||||
};
|
||||
|
||||
struct xdp_rxq_info xdp_rxq;
|
||||
struct xsk_buff_pool *xsk_pool;
|
||||
} ____cacheline_internodealigned_in_smp;
|
||||
|
||||
/* Board specific private data structure */
|
||||
struct igc_adapter {
|
||||
struct net_device *netdev;
|
||||
|
||||
struct ethtool_eee eee;
|
||||
u16 eee_advert;
|
||||
|
||||
unsigned long state;
|
||||
unsigned int flags;
|
||||
unsigned int num_q_vectors;
|
||||
|
||||
struct msix_entry *msix_entries;
|
||||
|
||||
/* TX */
|
||||
u16 tx_work_limit;
|
||||
u32 tx_timeout_count;
|
||||
int num_tx_queues;
|
||||
struct igc_ring *tx_ring[IGC_MAX_TX_QUEUES];
|
||||
|
||||
/* RX */
|
||||
int num_rx_queues;
|
||||
struct igc_ring *rx_ring[IGC_MAX_RX_QUEUES];
|
||||
|
||||
struct timer_list watchdog_timer;
|
||||
struct timer_list dma_err_timer;
|
||||
struct timer_list phy_info_timer;
|
||||
struct hrtimer hrtimer;
|
||||
|
||||
u32 wol;
|
||||
u32 en_mng_pt;
|
||||
u16 link_speed;
|
||||
u16 link_duplex;
|
||||
|
||||
u8 port_num;
|
||||
|
||||
u8 __iomem *io_addr;
|
||||
/* Interrupt Throttle Rate */
|
||||
u32 rx_itr_setting;
|
||||
u32 tx_itr_setting;
|
||||
|
||||
struct work_struct reset_task;
|
||||
struct work_struct watchdog_task;
|
||||
struct work_struct dma_err_task;
|
||||
bool fc_autoneg;
|
||||
|
||||
u8 tx_timeout_factor;
|
||||
|
||||
int msg_enable;
|
||||
u32 max_frame_size;
|
||||
u32 min_frame_size;
|
||||
|
||||
int tc_setup_type;
|
||||
ktime_t base_time;
|
||||
ktime_t cycle_time;
|
||||
bool taprio_offload_enable;
|
||||
u32 qbv_config_change_errors;
|
||||
bool qbv_transition;
|
||||
unsigned int qbv_count;
|
||||
|
||||
/* OS defined structs */
|
||||
struct pci_dev *pdev;
|
||||
/* lock for statistics */
|
||||
spinlock_t stats64_lock;
|
||||
struct rtnl_link_stats64 stats64;
|
||||
|
||||
/* structs defined in igc_hw.h */
|
||||
struct igc_hw hw;
|
||||
struct igc_hw_stats stats;
|
||||
|
||||
struct igc_q_vector *q_vector[MAX_Q_VECTORS];
|
||||
u32 eims_enable_mask;
|
||||
u32 eims_other;
|
||||
|
||||
u16 tx_ring_count;
|
||||
u16 rx_ring_count;
|
||||
|
||||
u32 tx_hwtstamp_timeouts;
|
||||
u32 tx_hwtstamp_skipped;
|
||||
u32 rx_hwtstamp_cleared;
|
||||
|
||||
u32 rss_queues;
|
||||
u32 rss_indir_tbl_init;
|
||||
|
||||
/* Any access to elements in nfc_rule_list is protected by the
|
||||
* nfc_rule_lock.
|
||||
*/
|
||||
struct mutex nfc_rule_lock;
|
||||
struct list_head nfc_rule_list;
|
||||
unsigned int nfc_rule_count;
|
||||
|
||||
u8 rss_indir_tbl[IGC_RETA_SIZE];
|
||||
|
||||
unsigned long link_check_timeout;
|
||||
struct igc_info ei;
|
||||
|
||||
u32 test_icr;
|
||||
|
||||
struct ptp_clock *ptp_clock;
|
||||
struct ptp_clock_info ptp_caps;
|
||||
/* Access to ptp_tx_skb and ptp_tx_start are protected by the
|
||||
* ptp_tx_lock.
|
||||
*/
|
||||
spinlock_t ptp_tx_lock;
|
||||
struct sk_buff *ptp_tx_skb;
|
||||
struct hwtstamp_config tstamp_config;
|
||||
unsigned long ptp_tx_start;
|
||||
unsigned int ptp_flags;
|
||||
/* System time value lock */
|
||||
spinlock_t tmreg_lock;
|
||||
struct cyclecounter cc;
|
||||
struct timecounter tc;
|
||||
struct timespec64 prev_ptp_time; /* Pre-reset PTP clock */
|
||||
ktime_t ptp_reset_start; /* Reset time in clock mono */
|
||||
struct system_time_snapshot snapshot;
|
||||
|
||||
char fw_version[32];
|
||||
|
||||
struct bpf_prog *xdp_prog;
|
||||
|
||||
bool pps_sys_wrap_on;
|
||||
|
||||
struct ptp_pin_desc sdp_config[IGC_N_SDP];
|
||||
struct {
|
||||
struct timespec64 start;
|
||||
struct timespec64 period;
|
||||
} perout[IGC_N_PEROUT];
|
||||
};
|
||||
|
||||
void igc_up(struct igc_adapter *adapter);
|
||||
void igc_down(struct igc_adapter *adapter);
|
||||
int igc_open(struct net_device *netdev);
|
||||
int igc_close(struct net_device *netdev);
|
||||
int igc_setup_tx_resources(struct igc_ring *ring);
|
||||
int igc_setup_rx_resources(struct igc_ring *ring);
|
||||
void igc_free_tx_resources(struct igc_ring *ring);
|
||||
void igc_free_rx_resources(struct igc_ring *ring);
|
||||
unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter);
|
||||
void igc_set_flag_queue_pairs(struct igc_adapter *adapter,
|
||||
const u32 max_rss_queues);
|
||||
int igc_reinit_queues(struct igc_adapter *adapter);
|
||||
void igc_write_rss_indir_tbl(struct igc_adapter *adapter);
|
||||
bool igc_has_link(struct igc_adapter *adapter);
|
||||
void igc_reset(struct igc_adapter *adapter);
|
||||
void igc_update_stats(struct igc_adapter *adapter);
|
||||
void igc_disable_rx_ring(struct igc_ring *ring);
|
||||
void igc_enable_rx_ring(struct igc_ring *ring);
|
||||
void igc_disable_tx_ring(struct igc_ring *ring);
|
||||
void igc_enable_tx_ring(struct igc_ring *ring);
|
||||
int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags);
|
||||
|
||||
/* igc_dump declarations */
|
||||
void igc_rings_dump(struct igc_adapter *adapter);
|
||||
void igc_regs_dump(struct igc_adapter *adapter);
|
||||
|
||||
extern char igc_driver_name[];
|
||||
|
||||
#define IGC_REGS_LEN 740
|
||||
|
||||
/* flags controlling PTP/1588 function */
|
||||
#define IGC_PTP_ENABLED BIT(0)
|
||||
|
||||
/* Flags definitions */
|
||||
#define IGC_FLAG_HAS_MSI BIT(0)
|
||||
#define IGC_FLAG_QUEUE_PAIRS BIT(3)
|
||||
#define IGC_FLAG_DMAC BIT(4)
|
||||
#define IGC_FLAG_PTP BIT(8)
|
||||
#define IGC_FLAG_WOL_SUPPORTED BIT(8)
|
||||
#define IGC_FLAG_NEED_LINK_UPDATE BIT(9)
|
||||
#define IGC_FLAG_HAS_MSIX BIT(13)
|
||||
#define IGC_FLAG_EEE BIT(14)
|
||||
#define IGC_FLAG_VLAN_PROMISC BIT(15)
|
||||
#define IGC_FLAG_RX_LEGACY BIT(16)
|
||||
#define IGC_FLAG_TSN_QBV_ENABLED BIT(17)
|
||||
#define IGC_FLAG_TSN_QAV_ENABLED BIT(18)
|
||||
|
||||
#define IGC_FLAG_TSN_ANY_ENABLED \
|
||||
(IGC_FLAG_TSN_QBV_ENABLED | IGC_FLAG_TSN_QAV_ENABLED)
|
||||
|
||||
#define IGC_FLAG_RSS_FIELD_IPV4_UDP BIT(6)
|
||||
#define IGC_FLAG_RSS_FIELD_IPV6_UDP BIT(7)
|
||||
|
||||
#define IGC_MRQC_ENABLE_RSS_MQ 0x00000002
|
||||
#define IGC_MRQC_RSS_FIELD_IPV4_UDP 0x00400000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6_UDP 0x00800000
|
||||
|
||||
/* RX-desc Write-Back format RSS Type's */
|
||||
enum igc_rss_type_num {
|
||||
IGC_RSS_TYPE_NO_HASH = 0,
|
||||
IGC_RSS_TYPE_HASH_TCP_IPV4 = 1,
|
||||
IGC_RSS_TYPE_HASH_IPV4 = 2,
|
||||
IGC_RSS_TYPE_HASH_TCP_IPV6 = 3,
|
||||
IGC_RSS_TYPE_HASH_IPV6_EX = 4,
|
||||
IGC_RSS_TYPE_HASH_IPV6 = 5,
|
||||
IGC_RSS_TYPE_HASH_TCP_IPV6_EX = 6,
|
||||
IGC_RSS_TYPE_HASH_UDP_IPV4 = 7,
|
||||
IGC_RSS_TYPE_HASH_UDP_IPV6 = 8,
|
||||
IGC_RSS_TYPE_HASH_UDP_IPV6_EX = 9,
|
||||
IGC_RSS_TYPE_MAX = 10,
|
||||
};
|
||||
#define IGC_RSS_TYPE_MAX_TABLE 16
|
||||
#define IGC_RSS_TYPE_MASK GENMASK(3,0) /* 4-bits (3:0) = mask 0x0F */
|
||||
|
||||
/* igc_rss_type - Rx descriptor RSS type field */
|
||||
static inline u32 igc_rss_type(const union igc_adv_rx_desc *rx_desc)
|
||||
{
|
||||
/* RSS Type 4-bits (3:0) number: 0-9 (above 9 is reserved)
|
||||
* Accessing the same bits via u16 (wb.lower.lo_dword.hs_rss.pkt_info)
|
||||
* is slightly slower than via u32 (wb.lower.lo_dword.data)
|
||||
*/
|
||||
return le32_get_bits(rx_desc->wb.lower.lo_dword.data, IGC_RSS_TYPE_MASK);
|
||||
}
|
||||
|
||||
/* Interrupt defines */
|
||||
#define IGC_START_ITR 648 /* ~6000 ints/sec */
|
||||
#define IGC_4K_ITR 980
|
||||
#define IGC_20K_ITR 196
|
||||
#define IGC_70K_ITR 56
|
||||
|
||||
#define IGC_DEFAULT_ITR 3 /* dynamic */
|
||||
#define IGC_MAX_ITR_USECS 10000
|
||||
#define IGC_MIN_ITR_USECS 10
|
||||
#define NON_Q_VECTORS 1
|
||||
#define MAX_MSIX_ENTRIES 10
|
||||
|
||||
/* TX/RX descriptor defines */
|
||||
#define IGC_DEFAULT_TXD 256
|
||||
#define IGC_DEFAULT_TX_WORK 128
|
||||
#define IGC_MIN_TXD 80
|
||||
#define IGC_MAX_TXD 4096
|
||||
|
||||
#define IGC_DEFAULT_RXD 256
|
||||
#define IGC_MIN_RXD 80
|
||||
#define IGC_MAX_RXD 4096
|
||||
|
||||
/* Supported Rx Buffer Sizes */
|
||||
#define IGC_RXBUFFER_256 256
|
||||
#define IGC_RXBUFFER_2048 2048
|
||||
#define IGC_RXBUFFER_3072 3072
|
||||
|
||||
#define AUTO_ALL_MODES 0
|
||||
#define IGC_RX_HDR_LEN IGC_RXBUFFER_256
|
||||
|
||||
/* Transmit and receive latency (for PTP timestamps) */
|
||||
#define IGC_I225_TX_LATENCY_10 240
|
||||
#define IGC_I225_TX_LATENCY_100 58
|
||||
#define IGC_I225_TX_LATENCY_1000 80
|
||||
#define IGC_I225_TX_LATENCY_2500 1325
|
||||
#define IGC_I225_RX_LATENCY_10 6450
|
||||
#define IGC_I225_RX_LATENCY_100 185
|
||||
#define IGC_I225_RX_LATENCY_1000 300
|
||||
#define IGC_I225_RX_LATENCY_2500 1485
|
||||
|
||||
/* RX and TX descriptor control thresholds.
|
||||
* PTHRESH - MAC will consider prefetch if it has fewer than this number of
|
||||
* descriptors available in its onboard memory.
|
||||
* Setting this to 0 disables RX descriptor prefetch.
|
||||
* HTHRESH - MAC will only prefetch if there are at least this many descriptors
|
||||
* available in host memory.
|
||||
* If PTHRESH is 0, this should also be 0.
|
||||
* WTHRESH - RX descriptor writeback threshold - MAC will delay writing back
|
||||
* descriptors until either it has this many to write back, or the
|
||||
* ITR timer expires.
|
||||
*/
|
||||
#define IGC_RX_PTHRESH 8
|
||||
#define IGC_RX_HTHRESH 8
|
||||
#define IGC_TX_PTHRESH 8
|
||||
#define IGC_TX_HTHRESH 1
|
||||
#define IGC_RX_WTHRESH 4
|
||||
#define IGC_TX_WTHRESH 16
|
||||
|
||||
#define IGC_RX_DMA_ATTR \
|
||||
(DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
|
||||
|
||||
#define IGC_TS_HDR_LEN 16
|
||||
|
||||
#define IGC_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN)
|
||||
|
||||
#if (PAGE_SIZE < 8192)
|
||||
#define IGC_MAX_FRAME_BUILD_SKB \
|
||||
(SKB_WITH_OVERHEAD(IGC_RXBUFFER_2048) - IGC_SKB_PAD - IGC_TS_HDR_LEN)
|
||||
#else
|
||||
#define IGC_MAX_FRAME_BUILD_SKB (IGC_RXBUFFER_2048 - IGC_TS_HDR_LEN)
|
||||
#endif
|
||||
|
||||
/* How many Rx Buffers do we bundle into one write to the hardware ? */
|
||||
#define IGC_RX_BUFFER_WRITE 16 /* Must be power of 2 */
|
||||
|
||||
/* VLAN info */
|
||||
#define IGC_TX_FLAGS_VLAN_MASK 0xffff0000
|
||||
#define IGC_TX_FLAGS_VLAN_SHIFT 16
|
||||
|
||||
/* igc_test_staterr - tests bits within Rx descriptor status and error fields */
|
||||
static inline __le32 igc_test_staterr(union igc_adv_rx_desc *rx_desc,
|
||||
const u32 stat_err_bits)
|
||||
{
|
||||
return rx_desc->wb.upper.status_error & cpu_to_le32(stat_err_bits);
|
||||
}
|
||||
|
||||
enum igc_state_t {
|
||||
__IGC_TESTING,
|
||||
__IGC_RESETTING,
|
||||
__IGC_DOWN,
|
||||
};
|
||||
|
||||
enum igc_tx_flags {
|
||||
/* cmd_type flags */
|
||||
IGC_TX_FLAGS_VLAN = 0x01,
|
||||
IGC_TX_FLAGS_TSO = 0x02,
|
||||
IGC_TX_FLAGS_TSTAMP = 0x04,
|
||||
|
||||
/* olinfo flags */
|
||||
IGC_TX_FLAGS_IPV4 = 0x10,
|
||||
IGC_TX_FLAGS_CSUM = 0x20,
|
||||
};
|
||||
|
||||
enum igc_boards {
|
||||
board_base,
|
||||
};
|
||||
|
||||
/* The largest size we can write to the descriptor is 65535. In order to
|
||||
* maintain a power of two alignment we have to limit ourselves to 32K.
|
||||
*/
|
||||
#define IGC_MAX_TXD_PWR 15
|
||||
#define IGC_MAX_DATA_PER_TXD BIT(IGC_MAX_TXD_PWR)
|
||||
|
||||
/* Tx Descriptors needed, worst case */
|
||||
#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IGC_MAX_DATA_PER_TXD)
|
||||
#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
|
||||
|
||||
enum igc_tx_buffer_type {
|
||||
IGC_TX_BUFFER_TYPE_SKB,
|
||||
IGC_TX_BUFFER_TYPE_XDP,
|
||||
IGC_TX_BUFFER_TYPE_XSK,
|
||||
};
|
||||
|
||||
/* wrapper around a pointer to a socket buffer,
|
||||
* so a DMA handle can be stored along with the buffer
|
||||
*/
|
||||
struct igc_tx_buffer {
|
||||
union igc_adv_tx_desc *next_to_watch;
|
||||
unsigned long time_stamp;
|
||||
enum igc_tx_buffer_type type;
|
||||
union {
|
||||
struct sk_buff *skb;
|
||||
struct xdp_frame *xdpf;
|
||||
};
|
||||
unsigned int bytecount;
|
||||
u16 gso_segs;
|
||||
__be16 protocol;
|
||||
|
||||
DEFINE_DMA_UNMAP_ADDR(dma);
|
||||
DEFINE_DMA_UNMAP_LEN(len);
|
||||
u32 tx_flags;
|
||||
};
|
||||
|
||||
struct igc_rx_buffer {
|
||||
union {
|
||||
struct {
|
||||
dma_addr_t dma;
|
||||
struct page *page;
|
||||
#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
|
||||
__u32 page_offset;
|
||||
#else
|
||||
__u16 page_offset;
|
||||
#endif
|
||||
__u16 pagecnt_bias;
|
||||
};
|
||||
struct xdp_buff *xdp;
|
||||
};
|
||||
};
|
||||
|
||||
/* context wrapper around xdp_buff to provide access to descriptor metadata */
|
||||
struct igc_xdp_buff {
|
||||
struct xdp_buff xdp;
|
||||
union igc_adv_rx_desc *rx_desc;
|
||||
};
|
||||
|
||||
struct igc_q_vector {
|
||||
struct igc_adapter *adapter; /* backlink */
|
||||
void __iomem *itr_register;
|
||||
u32 eims_value; /* EIMS mask value */
|
||||
|
||||
u16 itr_val;
|
||||
u8 set_itr;
|
||||
|
||||
struct igc_ring_container rx, tx;
|
||||
|
||||
struct napi_struct napi;
|
||||
|
||||
struct rcu_head rcu; /* to avoid race with update stats on free */
|
||||
char name[IFNAMSIZ + 9];
|
||||
struct net_device poll_dev;
|
||||
|
||||
/* for dynamic allocation of rings associated with this q_vector */
|
||||
struct igc_ring ring[] ____cacheline_internodealigned_in_smp;
|
||||
};
|
||||
|
||||
enum igc_filter_match_flags {
|
||||
IGC_FILTER_FLAG_ETHER_TYPE = BIT(0),
|
||||
IGC_FILTER_FLAG_VLAN_TCI = BIT(1),
|
||||
IGC_FILTER_FLAG_SRC_MAC_ADDR = BIT(2),
|
||||
IGC_FILTER_FLAG_DST_MAC_ADDR = BIT(3),
|
||||
IGC_FILTER_FLAG_USER_DATA = BIT(4),
|
||||
IGC_FILTER_FLAG_VLAN_ETYPE = BIT(5),
|
||||
};
|
||||
|
||||
struct igc_nfc_filter {
|
||||
u8 match_flags;
|
||||
u16 etype;
|
||||
__be16 vlan_etype;
|
||||
u16 vlan_tci;
|
||||
u8 src_addr[ETH_ALEN];
|
||||
u8 dst_addr[ETH_ALEN];
|
||||
u8 user_data[8];
|
||||
u8 user_mask[8];
|
||||
u8 flex_index;
|
||||
u8 rx_queue;
|
||||
u8 prio;
|
||||
u8 immediate_irq;
|
||||
u8 drop;
|
||||
};
|
||||
|
||||
struct igc_nfc_rule {
|
||||
struct list_head list;
|
||||
struct igc_nfc_filter filter;
|
||||
u32 location;
|
||||
u16 action;
|
||||
bool flex;
|
||||
};
|
||||
|
||||
/* IGC supports a total of 32 NFC rules: 16 MAC address based, 8 VLAN priority
|
||||
* based, 8 ethertype based and 32 Flex filter based rules.
|
||||
*/
|
||||
#define IGC_MAX_RXNFC_RULES 64
|
||||
|
||||
struct igc_flex_filter {
|
||||
u8 index;
|
||||
u8 data[128];
|
||||
u8 mask[16];
|
||||
u8 length;
|
||||
u8 rx_queue;
|
||||
u8 prio;
|
||||
u8 immediate_irq;
|
||||
u8 drop;
|
||||
};
|
||||
|
||||
/* igc_desc_unused - calculate if we have unused descriptors */
|
||||
static inline u16 igc_desc_unused(const struct igc_ring *ring)
|
||||
{
|
||||
u16 ntc = ring->next_to_clean;
|
||||
u16 ntu = ring->next_to_use;
|
||||
|
||||
return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1;
|
||||
}
|
||||
|
||||
static inline s32 igc_get_phy_info(struct igc_hw *hw)
|
||||
{
|
||||
if (hw->phy.ops.get_phy_info)
|
||||
return hw->phy.ops.get_phy_info(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline s32 igc_reset_phy(struct igc_hw *hw)
|
||||
{
|
||||
if (hw->phy.ops.reset)
|
||||
return hw->phy.ops.reset(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct netdev_queue *txring_txq(const struct igc_ring *tx_ring)
|
||||
{
|
||||
return netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index);
|
||||
}
|
||||
|
||||
enum igc_ring_flags_t {
|
||||
IGC_RING_FLAG_RX_3K_BUFFER,
|
||||
IGC_RING_FLAG_RX_BUILD_SKB_ENABLED,
|
||||
IGC_RING_FLAG_RX_SCTP_CSUM,
|
||||
IGC_RING_FLAG_RX_LB_VLAN_BSWAP,
|
||||
IGC_RING_FLAG_TX_CTX_IDX,
|
||||
IGC_RING_FLAG_TX_DETECT_HANG,
|
||||
IGC_RING_FLAG_AF_XDP_ZC,
|
||||
IGC_RING_FLAG_TX_HWTSTAMP,
|
||||
};
|
||||
|
||||
#define ring_uses_large_buffer(ring) \
|
||||
test_bit(IGC_RING_FLAG_RX_3K_BUFFER, &(ring)->flags)
|
||||
#define set_ring_uses_large_buffer(ring) \
|
||||
set_bit(IGC_RING_FLAG_RX_3K_BUFFER, &(ring)->flags)
|
||||
#define clear_ring_uses_large_buffer(ring) \
|
||||
clear_bit(IGC_RING_FLAG_RX_3K_BUFFER, &(ring)->flags)
|
||||
|
||||
#define ring_uses_build_skb(ring) \
|
||||
test_bit(IGC_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
|
||||
|
||||
static inline unsigned int igc_rx_bufsz(struct igc_ring *ring)
|
||||
{
|
||||
#if (PAGE_SIZE < 8192)
|
||||
if (ring_uses_large_buffer(ring))
|
||||
return IGC_RXBUFFER_3072;
|
||||
|
||||
if (ring_uses_build_skb(ring))
|
||||
return IGC_MAX_FRAME_BUILD_SKB + IGC_TS_HDR_LEN;
|
||||
#endif
|
||||
return IGC_RXBUFFER_2048;
|
||||
}
|
||||
|
||||
static inline unsigned int igc_rx_pg_order(struct igc_ring *ring)
|
||||
{
|
||||
#if (PAGE_SIZE < 8192)
|
||||
if (ring_uses_large_buffer(ring))
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline 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 -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
void igc_reinit_locked(struct igc_adapter *);
|
||||
struct igc_nfc_rule *igc_get_nfc_rule(struct igc_adapter *adapter,
|
||||
u32 location);
|
||||
int igc_add_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule);
|
||||
void igc_del_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule);
|
||||
|
||||
void igc_ptp_init(struct igc_adapter *adapter);
|
||||
void igc_ptp_reset(struct igc_adapter *adapter);
|
||||
void igc_ptp_suspend(struct igc_adapter *adapter);
|
||||
void igc_ptp_stop(struct igc_adapter *adapter);
|
||||
ktime_t igc_ptp_rx_pktstamp(struct igc_adapter *adapter, __le32 *buf);
|
||||
int igc_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr);
|
||||
int igc_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr);
|
||||
void igc_ptp_tx_hang(struct igc_adapter *adapter);
|
||||
void igc_ptp_read(struct igc_adapter *adapter, struct timespec64 *ts);
|
||||
void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter);
|
||||
|
||||
#define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring))
|
||||
|
||||
#define IGC_TXD_DCMD (IGC_ADVTXD_DCMD_EOP | IGC_ADVTXD_DCMD_RS)
|
||||
|
||||
#define IGC_RX_DESC(R, i) \
|
||||
(&(((union igc_adv_rx_desc *)((R)->desc))[i]))
|
||||
#define IGC_TX_DESC(R, i) \
|
||||
(&(((union igc_adv_tx_desc *)((R)->desc))[i]))
|
||||
#define IGC_TX_CTXTDESC(R, i) \
|
||||
(&(((struct igc_adv_tx_context_desc *)((R)->desc))[i]))
|
||||
|
||||
#endif /* _IGC_H_ */
|
||||
|
|
@ -0,0 +1,719 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_H_
|
||||
#define _IGC_H_
|
||||
#include "../ecdev.h"
|
||||
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/sctp.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/timecounter.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <net/xdp.h>
|
||||
|
||||
#include "igc_hw-6.6-ethercat.h"
|
||||
|
||||
void igc_ethtool_set_ops(struct net_device *);
|
||||
|
||||
/* Transmit and receive queues */
|
||||
#define IGC_MAX_RX_QUEUES 4
|
||||
#define IGC_MAX_TX_QUEUES 4
|
||||
|
||||
#define MAX_Q_VECTORS 8
|
||||
#define MAX_STD_JUMBO_FRAME_SIZE 9216
|
||||
|
||||
#define MAX_ETYPE_FILTER 8
|
||||
#define IGC_RETA_SIZE 128
|
||||
|
||||
/* SDP support */
|
||||
#define IGC_N_EXTTS 2
|
||||
#define IGC_N_PEROUT 2
|
||||
#define IGC_N_SDP 4
|
||||
|
||||
#define MAX_FLEX_FILTER 32
|
||||
|
||||
#define IGC_MAX_TX_TSTAMP_REGS 4
|
||||
|
||||
enum igc_mac_filter_type {
|
||||
IGC_MAC_FILTER_TYPE_DST = 0,
|
||||
IGC_MAC_FILTER_TYPE_SRC
|
||||
};
|
||||
|
||||
struct igc_tx_queue_stats {
|
||||
u64 packets;
|
||||
u64 bytes;
|
||||
u64 restart_queue;
|
||||
u64 restart_queue2;
|
||||
};
|
||||
|
||||
struct igc_rx_queue_stats {
|
||||
u64 packets;
|
||||
u64 bytes;
|
||||
u64 drops;
|
||||
u64 csum_err;
|
||||
u64 alloc_failed;
|
||||
};
|
||||
|
||||
struct igc_rx_packet_stats {
|
||||
u64 ipv4_packets; /* IPv4 headers processed */
|
||||
u64 ipv4e_packets; /* IPv4E headers with extensions processed */
|
||||
u64 ipv6_packets; /* IPv6 headers processed */
|
||||
u64 ipv6e_packets; /* IPv6E headers with extensions processed */
|
||||
u64 tcp_packets; /* TCP headers processed */
|
||||
u64 udp_packets; /* UDP headers processed */
|
||||
u64 sctp_packets; /* SCTP headers processed */
|
||||
u64 nfs_packets; /* NFS headers processe */
|
||||
u64 other_packets;
|
||||
};
|
||||
|
||||
struct igc_tx_timestamp_request {
|
||||
struct sk_buff *skb; /* reference to the packet being timestamped */
|
||||
unsigned long start; /* when the tstamp request started (jiffies) */
|
||||
u32 mask; /* _TSYNCTXCTL_TXTT_{X} bit for this request */
|
||||
u32 regl; /* which TXSTMPL_{X} register should be used */
|
||||
u32 regh; /* which TXSTMPH_{X} register should be used */
|
||||
u32 flags; /* flags that should be added to the tx_buffer */
|
||||
};
|
||||
|
||||
struct igc_ring_container {
|
||||
struct igc_ring *ring; /* pointer to linked list of rings */
|
||||
unsigned int total_bytes; /* total bytes processed this int */
|
||||
unsigned int total_packets; /* total packets processed this int */
|
||||
u16 work_limit; /* total work allowed per interrupt */
|
||||
u8 count; /* total number of rings in vector */
|
||||
u8 itr; /* current ITR setting for ring */
|
||||
};
|
||||
|
||||
struct igc_ring {
|
||||
struct igc_q_vector *q_vector; /* backlink to q_vector */
|
||||
struct net_device *netdev; /* back pointer to net_device */
|
||||
struct device *dev; /* device for dma mapping */
|
||||
union { /* array of buffer info structs */
|
||||
struct igc_tx_buffer *tx_buffer_info;
|
||||
struct igc_rx_buffer *rx_buffer_info;
|
||||
};
|
||||
void *desc; /* descriptor ring memory */
|
||||
unsigned long flags; /* ring specific flags */
|
||||
void __iomem *tail; /* pointer to ring tail register */
|
||||
dma_addr_t dma; /* phys address of the ring */
|
||||
unsigned int size; /* length of desc. ring in bytes */
|
||||
|
||||
u16 count; /* number of desc. in the ring */
|
||||
u8 queue_index; /* logical index of the ring*/
|
||||
u8 reg_idx; /* physical index of the ring */
|
||||
bool launchtime_enable; /* true if LaunchTime is enabled */
|
||||
ktime_t last_tx_cycle; /* end of the cycle with a launchtime transmission */
|
||||
ktime_t last_ff_cycle; /* Last cycle with an active first flag */
|
||||
|
||||
u32 start_time;
|
||||
u32 end_time;
|
||||
u32 max_sdu;
|
||||
bool oper_gate_closed; /* Operating gate. True if the TX Queue is closed */
|
||||
bool admin_gate_closed; /* Future gate. True if the TX Queue will be closed */
|
||||
|
||||
/* CBS parameters */
|
||||
bool cbs_enable; /* indicates if CBS is enabled */
|
||||
s32 idleslope; /* idleSlope in kbps */
|
||||
s32 sendslope; /* sendSlope in kbps */
|
||||
s32 hicredit; /* hiCredit in bytes */
|
||||
s32 locredit; /* loCredit in bytes */
|
||||
|
||||
/* everything past this point are written often */
|
||||
u16 next_to_clean;
|
||||
u16 next_to_use;
|
||||
u16 next_to_alloc;
|
||||
|
||||
union {
|
||||
/* TX */
|
||||
struct {
|
||||
struct igc_tx_queue_stats tx_stats;
|
||||
struct u64_stats_sync tx_syncp;
|
||||
struct u64_stats_sync tx_syncp2;
|
||||
};
|
||||
/* RX */
|
||||
struct {
|
||||
struct igc_rx_queue_stats rx_stats;
|
||||
struct igc_rx_packet_stats pkt_stats;
|
||||
struct u64_stats_sync rx_syncp;
|
||||
struct sk_buff *skb;
|
||||
};
|
||||
};
|
||||
|
||||
struct xdp_rxq_info xdp_rxq;
|
||||
struct xsk_buff_pool *xsk_pool;
|
||||
} ____cacheline_internodealigned_in_smp;
|
||||
|
||||
/* Board specific private data structure */
|
||||
struct igc_adapter {
|
||||
struct net_device *netdev;
|
||||
|
||||
struct ethtool_eee eee;
|
||||
u16 eee_advert;
|
||||
|
||||
unsigned long state;
|
||||
unsigned int flags;
|
||||
unsigned int num_q_vectors;
|
||||
|
||||
struct msix_entry *msix_entries;
|
||||
|
||||
/* TX */
|
||||
u16 tx_work_limit;
|
||||
u32 tx_timeout_count;
|
||||
int num_tx_queues;
|
||||
struct igc_ring *tx_ring[IGC_MAX_TX_QUEUES];
|
||||
|
||||
/* RX */
|
||||
int num_rx_queues;
|
||||
struct igc_ring *rx_ring[IGC_MAX_RX_QUEUES];
|
||||
|
||||
struct timer_list watchdog_timer;
|
||||
struct timer_list dma_err_timer;
|
||||
struct timer_list phy_info_timer;
|
||||
struct hrtimer hrtimer;
|
||||
|
||||
u32 wol;
|
||||
u32 en_mng_pt;
|
||||
u16 link_speed;
|
||||
u16 link_duplex;
|
||||
|
||||
u8 port_num;
|
||||
|
||||
u8 __iomem *io_addr;
|
||||
/* Interrupt Throttle Rate */
|
||||
u32 rx_itr_setting;
|
||||
u32 tx_itr_setting;
|
||||
|
||||
struct work_struct reset_task;
|
||||
struct work_struct watchdog_task;
|
||||
struct work_struct dma_err_task;
|
||||
bool fc_autoneg;
|
||||
|
||||
u8 tx_timeout_factor;
|
||||
|
||||
int msg_enable;
|
||||
u32 max_frame_size;
|
||||
u32 min_frame_size;
|
||||
|
||||
int tc_setup_type;
|
||||
ktime_t base_time;
|
||||
ktime_t cycle_time;
|
||||
bool taprio_offload_enable;
|
||||
u32 qbv_config_change_errors;
|
||||
bool qbv_transition;
|
||||
unsigned int qbv_count;
|
||||
/* Access to oper_gate_closed, admin_gate_closed and qbv_transition
|
||||
* are protected by the qbv_tx_lock.
|
||||
*/
|
||||
spinlock_t qbv_tx_lock;
|
||||
|
||||
/* OS defined structs */
|
||||
struct pci_dev *pdev;
|
||||
/* lock for statistics */
|
||||
spinlock_t stats64_lock;
|
||||
struct rtnl_link_stats64 stats64;
|
||||
|
||||
/* structs defined in igc_hw.h */
|
||||
struct igc_hw hw;
|
||||
struct igc_hw_stats stats;
|
||||
|
||||
struct igc_q_vector *q_vector[MAX_Q_VECTORS];
|
||||
u32 eims_enable_mask;
|
||||
u32 eims_other;
|
||||
|
||||
u16 tx_ring_count;
|
||||
u16 rx_ring_count;
|
||||
|
||||
u32 tx_hwtstamp_timeouts;
|
||||
u32 tx_hwtstamp_skipped;
|
||||
u32 rx_hwtstamp_cleared;
|
||||
|
||||
u32 rss_queues;
|
||||
u32 rss_indir_tbl_init;
|
||||
|
||||
/* Any access to elements in nfc_rule_list is protected by the
|
||||
* nfc_rule_lock.
|
||||
*/
|
||||
struct mutex nfc_rule_lock;
|
||||
struct list_head nfc_rule_list;
|
||||
unsigned int nfc_rule_count;
|
||||
|
||||
u8 rss_indir_tbl[IGC_RETA_SIZE];
|
||||
|
||||
unsigned long link_check_timeout;
|
||||
struct igc_info ei;
|
||||
|
||||
u32 test_icr;
|
||||
|
||||
struct ptp_clock *ptp_clock;
|
||||
struct ptp_clock_info ptp_caps;
|
||||
/* Access to ptp_tx_skb and ptp_tx_start are protected by the
|
||||
* ptp_tx_lock.
|
||||
*/
|
||||
spinlock_t ptp_tx_lock;
|
||||
struct igc_tx_timestamp_request tx_tstamp[IGC_MAX_TX_TSTAMP_REGS];
|
||||
struct hwtstamp_config tstamp_config;
|
||||
unsigned int ptp_flags;
|
||||
/* System time value lock */
|
||||
spinlock_t tmreg_lock;
|
||||
struct cyclecounter cc;
|
||||
struct timecounter tc;
|
||||
struct timespec64 prev_ptp_time; /* Pre-reset PTP clock */
|
||||
ktime_t ptp_reset_start; /* Reset time in clock mono */
|
||||
struct system_time_snapshot snapshot;
|
||||
|
||||
char fw_version[32];
|
||||
|
||||
struct bpf_prog *xdp_prog;
|
||||
|
||||
bool pps_sys_wrap_on;
|
||||
|
||||
struct ptp_pin_desc sdp_config[IGC_N_SDP];
|
||||
struct {
|
||||
struct timespec64 start;
|
||||
struct timespec64 period;
|
||||
} perout[IGC_N_PEROUT];
|
||||
|
||||
/* EtherCAT device variables */
|
||||
ec_device_t *ecdev;
|
||||
unsigned long ec_watchdog_jiffies;
|
||||
};
|
||||
|
||||
void igc_up(struct igc_adapter *adapter);
|
||||
void igc_down(struct igc_adapter *adapter);
|
||||
int igc_open(struct net_device *netdev);
|
||||
int igc_close(struct net_device *netdev);
|
||||
int igc_setup_tx_resources(struct igc_ring *ring);
|
||||
int igc_setup_rx_resources(struct igc_ring *ring);
|
||||
void igc_free_tx_resources(struct igc_ring *ring);
|
||||
void igc_free_rx_resources(struct igc_ring *ring);
|
||||
unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter);
|
||||
void igc_set_flag_queue_pairs(struct igc_adapter *adapter,
|
||||
const u32 max_rss_queues);
|
||||
int igc_reinit_queues(struct igc_adapter *adapter);
|
||||
void igc_write_rss_indir_tbl(struct igc_adapter *adapter);
|
||||
bool igc_has_link(struct igc_adapter *adapter);
|
||||
void igc_reset(struct igc_adapter *adapter);
|
||||
void igc_update_stats(struct igc_adapter *adapter);
|
||||
void igc_disable_rx_ring(struct igc_ring *ring);
|
||||
void igc_enable_rx_ring(struct igc_ring *ring);
|
||||
void igc_disable_tx_ring(struct igc_ring *ring);
|
||||
void igc_enable_tx_ring(struct igc_ring *ring);
|
||||
int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags);
|
||||
|
||||
/* igc_dump declarations */
|
||||
void igc_rings_dump(struct igc_adapter *adapter);
|
||||
void igc_regs_dump(struct igc_adapter *adapter);
|
||||
|
||||
extern char igc_driver_name[];
|
||||
|
||||
#define IGC_REGS_LEN 740
|
||||
|
||||
/* flags controlling PTP/1588 function */
|
||||
#define IGC_PTP_ENABLED BIT(0)
|
||||
|
||||
/* Flags definitions */
|
||||
#define IGC_FLAG_HAS_MSI BIT(0)
|
||||
#define IGC_FLAG_QUEUE_PAIRS BIT(3)
|
||||
#define IGC_FLAG_DMAC BIT(4)
|
||||
#define IGC_FLAG_PTP BIT(8)
|
||||
#define IGC_FLAG_WOL_SUPPORTED BIT(8)
|
||||
#define IGC_FLAG_NEED_LINK_UPDATE BIT(9)
|
||||
#define IGC_FLAG_HAS_MSIX BIT(13)
|
||||
#define IGC_FLAG_EEE BIT(14)
|
||||
#define IGC_FLAG_VLAN_PROMISC BIT(15)
|
||||
#define IGC_FLAG_RX_LEGACY BIT(16)
|
||||
#define IGC_FLAG_TSN_QBV_ENABLED BIT(17)
|
||||
#define IGC_FLAG_TSN_QAV_ENABLED BIT(18)
|
||||
|
||||
#define IGC_FLAG_TSN_ANY_ENABLED \
|
||||
(IGC_FLAG_TSN_QBV_ENABLED | IGC_FLAG_TSN_QAV_ENABLED)
|
||||
|
||||
#define IGC_FLAG_RSS_FIELD_IPV4_UDP BIT(6)
|
||||
#define IGC_FLAG_RSS_FIELD_IPV6_UDP BIT(7)
|
||||
|
||||
#define IGC_MRQC_ENABLE_RSS_MQ 0x00000002
|
||||
#define IGC_MRQC_RSS_FIELD_IPV4_UDP 0x00400000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6_UDP 0x00800000
|
||||
|
||||
/* RX-desc Write-Back format RSS Type's */
|
||||
enum igc_rss_type_num {
|
||||
IGC_RSS_TYPE_NO_HASH = 0,
|
||||
IGC_RSS_TYPE_HASH_TCP_IPV4 = 1,
|
||||
IGC_RSS_TYPE_HASH_IPV4 = 2,
|
||||
IGC_RSS_TYPE_HASH_TCP_IPV6 = 3,
|
||||
IGC_RSS_TYPE_HASH_IPV6_EX = 4,
|
||||
IGC_RSS_TYPE_HASH_IPV6 = 5,
|
||||
IGC_RSS_TYPE_HASH_TCP_IPV6_EX = 6,
|
||||
IGC_RSS_TYPE_HASH_UDP_IPV4 = 7,
|
||||
IGC_RSS_TYPE_HASH_UDP_IPV6 = 8,
|
||||
IGC_RSS_TYPE_HASH_UDP_IPV6_EX = 9,
|
||||
IGC_RSS_TYPE_MAX = 10,
|
||||
};
|
||||
#define IGC_RSS_TYPE_MAX_TABLE 16
|
||||
#define IGC_RSS_TYPE_MASK GENMASK(3,0) /* 4-bits (3:0) = mask 0x0F */
|
||||
|
||||
/* igc_rss_type - Rx descriptor RSS type field */
|
||||
static inline u32 igc_rss_type(const union igc_adv_rx_desc *rx_desc)
|
||||
{
|
||||
/* RSS Type 4-bits (3:0) number: 0-9 (above 9 is reserved)
|
||||
* Accessing the same bits via u16 (wb.lower.lo_dword.hs_rss.pkt_info)
|
||||
* is slightly slower than via u32 (wb.lower.lo_dword.data)
|
||||
*/
|
||||
return le32_get_bits(rx_desc->wb.lower.lo_dword.data, IGC_RSS_TYPE_MASK);
|
||||
}
|
||||
|
||||
/* Interrupt defines */
|
||||
#define IGC_START_ITR 648 /* ~6000 ints/sec */
|
||||
#define IGC_4K_ITR 980
|
||||
#define IGC_20K_ITR 196
|
||||
#define IGC_70K_ITR 56
|
||||
|
||||
#define IGC_DEFAULT_ITR 3 /* dynamic */
|
||||
#define IGC_MAX_ITR_USECS 10000
|
||||
#define IGC_MIN_ITR_USECS 10
|
||||
#define NON_Q_VECTORS 1
|
||||
#define MAX_MSIX_ENTRIES 10
|
||||
|
||||
/* TX/RX descriptor defines */
|
||||
#define IGC_DEFAULT_TXD 256
|
||||
#define IGC_DEFAULT_TX_WORK 128
|
||||
#define IGC_MIN_TXD 64
|
||||
#define IGC_MAX_TXD 4096
|
||||
|
||||
#define IGC_DEFAULT_RXD 256
|
||||
#define IGC_MIN_RXD 64
|
||||
#define IGC_MAX_RXD 4096
|
||||
|
||||
/* Supported Rx Buffer Sizes */
|
||||
#define IGC_RXBUFFER_256 256
|
||||
#define IGC_RXBUFFER_2048 2048
|
||||
#define IGC_RXBUFFER_3072 3072
|
||||
|
||||
#define AUTO_ALL_MODES 0
|
||||
#define IGC_RX_HDR_LEN IGC_RXBUFFER_256
|
||||
|
||||
/* Transmit and receive latency (for PTP timestamps) */
|
||||
#define IGC_I225_TX_LATENCY_10 240
|
||||
#define IGC_I225_TX_LATENCY_100 58
|
||||
#define IGC_I225_TX_LATENCY_1000 80
|
||||
#define IGC_I225_TX_LATENCY_2500 1325
|
||||
#define IGC_I225_RX_LATENCY_10 6450
|
||||
#define IGC_I225_RX_LATENCY_100 185
|
||||
#define IGC_I225_RX_LATENCY_1000 300
|
||||
#define IGC_I225_RX_LATENCY_2500 1485
|
||||
|
||||
/* RX and TX descriptor control thresholds.
|
||||
* PTHRESH - MAC will consider prefetch if it has fewer than this number of
|
||||
* descriptors available in its onboard memory.
|
||||
* Setting this to 0 disables RX descriptor prefetch.
|
||||
* HTHRESH - MAC will only prefetch if there are at least this many descriptors
|
||||
* available in host memory.
|
||||
* If PTHRESH is 0, this should also be 0.
|
||||
* WTHRESH - RX descriptor writeback threshold - MAC will delay writing back
|
||||
* descriptors until either it has this many to write back, or the
|
||||
* ITR timer expires.
|
||||
*/
|
||||
#define IGC_RX_PTHRESH 8
|
||||
#define IGC_RX_HTHRESH 8
|
||||
#define IGC_TX_PTHRESH 8
|
||||
#define IGC_TX_HTHRESH 1
|
||||
#define IGC_RX_WTHRESH 4
|
||||
#define IGC_TX_WTHRESH 16
|
||||
|
||||
#define IGC_RX_DMA_ATTR \
|
||||
(DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
|
||||
|
||||
#define IGC_TS_HDR_LEN 16
|
||||
|
||||
#define IGC_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN)
|
||||
|
||||
#if (PAGE_SIZE < 8192)
|
||||
#define IGC_MAX_FRAME_BUILD_SKB \
|
||||
(SKB_WITH_OVERHEAD(IGC_RXBUFFER_2048) - IGC_SKB_PAD - IGC_TS_HDR_LEN)
|
||||
#else
|
||||
#define IGC_MAX_FRAME_BUILD_SKB (IGC_RXBUFFER_2048 - IGC_TS_HDR_LEN)
|
||||
#endif
|
||||
|
||||
/* How many Rx Buffers do we bundle into one write to the hardware ? */
|
||||
#define IGC_RX_BUFFER_WRITE 16 /* Must be power of 2 */
|
||||
|
||||
/* VLAN info */
|
||||
#define IGC_TX_FLAGS_VLAN_MASK 0xffff0000
|
||||
#define IGC_TX_FLAGS_VLAN_SHIFT 16
|
||||
|
||||
/* igc_test_staterr - tests bits within Rx descriptor status and error fields */
|
||||
static inline __le32 igc_test_staterr(union igc_adv_rx_desc *rx_desc,
|
||||
const u32 stat_err_bits)
|
||||
{
|
||||
return rx_desc->wb.upper.status_error & cpu_to_le32(stat_err_bits);
|
||||
}
|
||||
|
||||
enum igc_state_t {
|
||||
__IGC_TESTING,
|
||||
__IGC_RESETTING,
|
||||
__IGC_DOWN,
|
||||
};
|
||||
|
||||
enum igc_tx_flags {
|
||||
/* cmd_type flags */
|
||||
IGC_TX_FLAGS_VLAN = 0x01,
|
||||
IGC_TX_FLAGS_TSO = 0x02,
|
||||
IGC_TX_FLAGS_TSTAMP = 0x04,
|
||||
|
||||
/* olinfo flags */
|
||||
IGC_TX_FLAGS_IPV4 = 0x10,
|
||||
IGC_TX_FLAGS_CSUM = 0x20,
|
||||
|
||||
IGC_TX_FLAGS_TSTAMP_1 = 0x100,
|
||||
IGC_TX_FLAGS_TSTAMP_2 = 0x200,
|
||||
IGC_TX_FLAGS_TSTAMP_3 = 0x400,
|
||||
};
|
||||
|
||||
enum igc_boards {
|
||||
board_base,
|
||||
};
|
||||
|
||||
/* The largest size we can write to the descriptor is 65535. In order to
|
||||
* maintain a power of two alignment we have to limit ourselves to 32K.
|
||||
*/
|
||||
#define IGC_MAX_TXD_PWR 15
|
||||
#define IGC_MAX_DATA_PER_TXD BIT(IGC_MAX_TXD_PWR)
|
||||
|
||||
/* Tx Descriptors needed, worst case */
|
||||
#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IGC_MAX_DATA_PER_TXD)
|
||||
#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
|
||||
|
||||
enum igc_tx_buffer_type {
|
||||
IGC_TX_BUFFER_TYPE_SKB,
|
||||
IGC_TX_BUFFER_TYPE_XDP,
|
||||
IGC_TX_BUFFER_TYPE_XSK,
|
||||
};
|
||||
|
||||
/* wrapper around a pointer to a socket buffer,
|
||||
* so a DMA handle can be stored along with the buffer
|
||||
*/
|
||||
struct igc_tx_buffer {
|
||||
union igc_adv_tx_desc *next_to_watch;
|
||||
unsigned long time_stamp;
|
||||
enum igc_tx_buffer_type type;
|
||||
union {
|
||||
struct sk_buff *skb;
|
||||
struct xdp_frame *xdpf;
|
||||
};
|
||||
unsigned int bytecount;
|
||||
u16 gso_segs;
|
||||
__be16 protocol;
|
||||
|
||||
DEFINE_DMA_UNMAP_ADDR(dma);
|
||||
DEFINE_DMA_UNMAP_LEN(len);
|
||||
u32 tx_flags;
|
||||
};
|
||||
|
||||
struct igc_rx_buffer {
|
||||
union {
|
||||
struct {
|
||||
dma_addr_t dma;
|
||||
struct page *page;
|
||||
#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
|
||||
__u32 page_offset;
|
||||
#else
|
||||
__u16 page_offset;
|
||||
#endif
|
||||
__u16 pagecnt_bias;
|
||||
};
|
||||
struct xdp_buff *xdp;
|
||||
};
|
||||
};
|
||||
|
||||
/* context wrapper around xdp_buff to provide access to descriptor metadata */
|
||||
struct igc_xdp_buff {
|
||||
struct xdp_buff xdp;
|
||||
union igc_adv_rx_desc *rx_desc;
|
||||
ktime_t rx_ts; /* data indication bit IGC_RXDADV_STAT_TSIP */
|
||||
};
|
||||
|
||||
struct igc_q_vector {
|
||||
struct igc_adapter *adapter; /* backlink */
|
||||
void __iomem *itr_register;
|
||||
u32 eims_value; /* EIMS mask value */
|
||||
|
||||
u16 itr_val;
|
||||
u8 set_itr;
|
||||
|
||||
struct igc_ring_container rx, tx;
|
||||
|
||||
struct napi_struct napi;
|
||||
|
||||
struct rcu_head rcu; /* to avoid race with update stats on free */
|
||||
char name[IFNAMSIZ + 9];
|
||||
struct net_device poll_dev;
|
||||
|
||||
/* for dynamic allocation of rings associated with this q_vector */
|
||||
struct igc_ring ring[] ____cacheline_internodealigned_in_smp;
|
||||
};
|
||||
|
||||
enum igc_filter_match_flags {
|
||||
IGC_FILTER_FLAG_ETHER_TYPE = BIT(0),
|
||||
IGC_FILTER_FLAG_VLAN_TCI = BIT(1),
|
||||
IGC_FILTER_FLAG_SRC_MAC_ADDR = BIT(2),
|
||||
IGC_FILTER_FLAG_DST_MAC_ADDR = BIT(3),
|
||||
IGC_FILTER_FLAG_USER_DATA = BIT(4),
|
||||
IGC_FILTER_FLAG_VLAN_ETYPE = BIT(5),
|
||||
};
|
||||
|
||||
struct igc_nfc_filter {
|
||||
u8 match_flags;
|
||||
u16 etype;
|
||||
__be16 vlan_etype;
|
||||
u16 vlan_tci;
|
||||
u8 src_addr[ETH_ALEN];
|
||||
u8 dst_addr[ETH_ALEN];
|
||||
u8 user_data[8];
|
||||
u8 user_mask[8];
|
||||
u8 flex_index;
|
||||
u8 rx_queue;
|
||||
u8 prio;
|
||||
u8 immediate_irq;
|
||||
u8 drop;
|
||||
};
|
||||
|
||||
struct igc_nfc_rule {
|
||||
struct list_head list;
|
||||
struct igc_nfc_filter filter;
|
||||
u32 location;
|
||||
u16 action;
|
||||
bool flex;
|
||||
};
|
||||
|
||||
/* IGC supports a total of 32 NFC rules: 16 MAC address based, 8 VLAN priority
|
||||
* based, 8 ethertype based and 32 Flex filter based rules.
|
||||
*/
|
||||
#define IGC_MAX_RXNFC_RULES 64
|
||||
|
||||
struct igc_flex_filter {
|
||||
u8 index;
|
||||
u8 data[128];
|
||||
u8 mask[16];
|
||||
u8 length;
|
||||
u8 rx_queue;
|
||||
u8 prio;
|
||||
u8 immediate_irq;
|
||||
u8 drop;
|
||||
};
|
||||
|
||||
/* igc_desc_unused - calculate if we have unused descriptors */
|
||||
static inline u16 igc_desc_unused(const struct igc_ring *ring)
|
||||
{
|
||||
u16 ntc = ring->next_to_clean;
|
||||
u16 ntu = ring->next_to_use;
|
||||
|
||||
return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1;
|
||||
}
|
||||
|
||||
static inline s32 igc_get_phy_info(struct igc_hw *hw)
|
||||
{
|
||||
if (hw->phy.ops.get_phy_info)
|
||||
return hw->phy.ops.get_phy_info(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline s32 igc_reset_phy(struct igc_hw *hw)
|
||||
{
|
||||
if (hw->phy.ops.reset)
|
||||
return hw->phy.ops.reset(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct netdev_queue *txring_txq(const struct igc_ring *tx_ring)
|
||||
{
|
||||
return netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index);
|
||||
}
|
||||
|
||||
enum igc_ring_flags_t {
|
||||
IGC_RING_FLAG_RX_3K_BUFFER,
|
||||
IGC_RING_FLAG_RX_BUILD_SKB_ENABLED,
|
||||
IGC_RING_FLAG_RX_SCTP_CSUM,
|
||||
IGC_RING_FLAG_RX_LB_VLAN_BSWAP,
|
||||
IGC_RING_FLAG_TX_CTX_IDX,
|
||||
IGC_RING_FLAG_TX_DETECT_HANG,
|
||||
IGC_RING_FLAG_AF_XDP_ZC,
|
||||
IGC_RING_FLAG_TX_HWTSTAMP,
|
||||
};
|
||||
|
||||
#define ring_uses_large_buffer(ring) \
|
||||
test_bit(IGC_RING_FLAG_RX_3K_BUFFER, &(ring)->flags)
|
||||
#define set_ring_uses_large_buffer(ring) \
|
||||
set_bit(IGC_RING_FLAG_RX_3K_BUFFER, &(ring)->flags)
|
||||
#define clear_ring_uses_large_buffer(ring) \
|
||||
clear_bit(IGC_RING_FLAG_RX_3K_BUFFER, &(ring)->flags)
|
||||
|
||||
#define ring_uses_build_skb(ring) \
|
||||
test_bit(IGC_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
|
||||
|
||||
static inline unsigned int igc_rx_bufsz(struct igc_ring *ring)
|
||||
{
|
||||
#if (PAGE_SIZE < 8192)
|
||||
if (ring_uses_large_buffer(ring))
|
||||
return IGC_RXBUFFER_3072;
|
||||
|
||||
if (ring_uses_build_skb(ring))
|
||||
return IGC_MAX_FRAME_BUILD_SKB + IGC_TS_HDR_LEN;
|
||||
#endif
|
||||
return IGC_RXBUFFER_2048;
|
||||
}
|
||||
|
||||
static inline unsigned int igc_rx_pg_order(struct igc_ring *ring)
|
||||
{
|
||||
#if (PAGE_SIZE < 8192)
|
||||
if (ring_uses_large_buffer(ring))
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline 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 -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
void igc_reinit_locked(struct igc_adapter *);
|
||||
struct igc_nfc_rule *igc_get_nfc_rule(struct igc_adapter *adapter,
|
||||
u32 location);
|
||||
int igc_add_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule);
|
||||
void igc_del_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule);
|
||||
|
||||
void igc_ptp_init(struct igc_adapter *adapter);
|
||||
void igc_ptp_reset(struct igc_adapter *adapter);
|
||||
void igc_ptp_suspend(struct igc_adapter *adapter);
|
||||
void igc_ptp_stop(struct igc_adapter *adapter);
|
||||
ktime_t igc_ptp_rx_pktstamp(struct igc_adapter *adapter, __le32 *buf);
|
||||
int igc_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr);
|
||||
int igc_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr);
|
||||
void igc_ptp_tx_hang(struct igc_adapter *adapter);
|
||||
void igc_ptp_read(struct igc_adapter *adapter, struct timespec64 *ts);
|
||||
void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter);
|
||||
|
||||
#define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring))
|
||||
|
||||
#define IGC_TXD_DCMD (IGC_ADVTXD_DCMD_EOP | IGC_ADVTXD_DCMD_RS)
|
||||
|
||||
#define IGC_RX_DESC(R, i) \
|
||||
(&(((union igc_adv_rx_desc *)((R)->desc))[i]))
|
||||
#define IGC_TX_DESC(R, i) \
|
||||
(&(((union igc_adv_tx_desc *)((R)->desc))[i]))
|
||||
#define IGC_TX_CTXTDESC(R, i) \
|
||||
(&(((struct igc_adv_tx_context_desc *)((R)->desc))[i]))
|
||||
|
||||
#endif /* _IGC_H_ */
|
||||
|
|
@ -0,0 +1,714 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_H_
|
||||
#define _IGC_H_
|
||||
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/sctp.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/timecounter.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <net/xdp.h>
|
||||
|
||||
#include "igc_hw.h"
|
||||
|
||||
void igc_ethtool_set_ops(struct net_device *);
|
||||
|
||||
/* Transmit and receive queues */
|
||||
#define IGC_MAX_RX_QUEUES 4
|
||||
#define IGC_MAX_TX_QUEUES 4
|
||||
|
||||
#define MAX_Q_VECTORS 8
|
||||
#define MAX_STD_JUMBO_FRAME_SIZE 9216
|
||||
|
||||
#define MAX_ETYPE_FILTER 8
|
||||
#define IGC_RETA_SIZE 128
|
||||
|
||||
/* SDP support */
|
||||
#define IGC_N_EXTTS 2
|
||||
#define IGC_N_PEROUT 2
|
||||
#define IGC_N_SDP 4
|
||||
|
||||
#define MAX_FLEX_FILTER 32
|
||||
|
||||
#define IGC_MAX_TX_TSTAMP_REGS 4
|
||||
|
||||
enum igc_mac_filter_type {
|
||||
IGC_MAC_FILTER_TYPE_DST = 0,
|
||||
IGC_MAC_FILTER_TYPE_SRC
|
||||
};
|
||||
|
||||
struct igc_tx_queue_stats {
|
||||
u64 packets;
|
||||
u64 bytes;
|
||||
u64 restart_queue;
|
||||
u64 restart_queue2;
|
||||
};
|
||||
|
||||
struct igc_rx_queue_stats {
|
||||
u64 packets;
|
||||
u64 bytes;
|
||||
u64 drops;
|
||||
u64 csum_err;
|
||||
u64 alloc_failed;
|
||||
};
|
||||
|
||||
struct igc_rx_packet_stats {
|
||||
u64 ipv4_packets; /* IPv4 headers processed */
|
||||
u64 ipv4e_packets; /* IPv4E headers with extensions processed */
|
||||
u64 ipv6_packets; /* IPv6 headers processed */
|
||||
u64 ipv6e_packets; /* IPv6E headers with extensions processed */
|
||||
u64 tcp_packets; /* TCP headers processed */
|
||||
u64 udp_packets; /* UDP headers processed */
|
||||
u64 sctp_packets; /* SCTP headers processed */
|
||||
u64 nfs_packets; /* NFS headers processe */
|
||||
u64 other_packets;
|
||||
};
|
||||
|
||||
struct igc_tx_timestamp_request {
|
||||
struct sk_buff *skb; /* reference to the packet being timestamped */
|
||||
unsigned long start; /* when the tstamp request started (jiffies) */
|
||||
u32 mask; /* _TSYNCTXCTL_TXTT_{X} bit for this request */
|
||||
u32 regl; /* which TXSTMPL_{X} register should be used */
|
||||
u32 regh; /* which TXSTMPH_{X} register should be used */
|
||||
u32 flags; /* flags that should be added to the tx_buffer */
|
||||
};
|
||||
|
||||
struct igc_ring_container {
|
||||
struct igc_ring *ring; /* pointer to linked list of rings */
|
||||
unsigned int total_bytes; /* total bytes processed this int */
|
||||
unsigned int total_packets; /* total packets processed this int */
|
||||
u16 work_limit; /* total work allowed per interrupt */
|
||||
u8 count; /* total number of rings in vector */
|
||||
u8 itr; /* current ITR setting for ring */
|
||||
};
|
||||
|
||||
struct igc_ring {
|
||||
struct igc_q_vector *q_vector; /* backlink to q_vector */
|
||||
struct net_device *netdev; /* back pointer to net_device */
|
||||
struct device *dev; /* device for dma mapping */
|
||||
union { /* array of buffer info structs */
|
||||
struct igc_tx_buffer *tx_buffer_info;
|
||||
struct igc_rx_buffer *rx_buffer_info;
|
||||
};
|
||||
void *desc; /* descriptor ring memory */
|
||||
unsigned long flags; /* ring specific flags */
|
||||
void __iomem *tail; /* pointer to ring tail register */
|
||||
dma_addr_t dma; /* phys address of the ring */
|
||||
unsigned int size; /* length of desc. ring in bytes */
|
||||
|
||||
u16 count; /* number of desc. in the ring */
|
||||
u8 queue_index; /* logical index of the ring*/
|
||||
u8 reg_idx; /* physical index of the ring */
|
||||
bool launchtime_enable; /* true if LaunchTime is enabled */
|
||||
ktime_t last_tx_cycle; /* end of the cycle with a launchtime transmission */
|
||||
ktime_t last_ff_cycle; /* Last cycle with an active first flag */
|
||||
|
||||
u32 start_time;
|
||||
u32 end_time;
|
||||
u32 max_sdu;
|
||||
bool oper_gate_closed; /* Operating gate. True if the TX Queue is closed */
|
||||
bool admin_gate_closed; /* Future gate. True if the TX Queue will be closed */
|
||||
|
||||
/* CBS parameters */
|
||||
bool cbs_enable; /* indicates if CBS is enabled */
|
||||
s32 idleslope; /* idleSlope in kbps */
|
||||
s32 sendslope; /* sendSlope in kbps */
|
||||
s32 hicredit; /* hiCredit in bytes */
|
||||
s32 locredit; /* loCredit in bytes */
|
||||
|
||||
/* everything past this point are written often */
|
||||
u16 next_to_clean;
|
||||
u16 next_to_use;
|
||||
u16 next_to_alloc;
|
||||
|
||||
union {
|
||||
/* TX */
|
||||
struct {
|
||||
struct igc_tx_queue_stats tx_stats;
|
||||
struct u64_stats_sync tx_syncp;
|
||||
struct u64_stats_sync tx_syncp2;
|
||||
};
|
||||
/* RX */
|
||||
struct {
|
||||
struct igc_rx_queue_stats rx_stats;
|
||||
struct igc_rx_packet_stats pkt_stats;
|
||||
struct u64_stats_sync rx_syncp;
|
||||
struct sk_buff *skb;
|
||||
};
|
||||
};
|
||||
|
||||
struct xdp_rxq_info xdp_rxq;
|
||||
struct xsk_buff_pool *xsk_pool;
|
||||
} ____cacheline_internodealigned_in_smp;
|
||||
|
||||
/* Board specific private data structure */
|
||||
struct igc_adapter {
|
||||
struct net_device *netdev;
|
||||
|
||||
struct ethtool_eee eee;
|
||||
u16 eee_advert;
|
||||
|
||||
unsigned long state;
|
||||
unsigned int flags;
|
||||
unsigned int num_q_vectors;
|
||||
|
||||
struct msix_entry *msix_entries;
|
||||
|
||||
/* TX */
|
||||
u16 tx_work_limit;
|
||||
u32 tx_timeout_count;
|
||||
int num_tx_queues;
|
||||
struct igc_ring *tx_ring[IGC_MAX_TX_QUEUES];
|
||||
|
||||
/* RX */
|
||||
int num_rx_queues;
|
||||
struct igc_ring *rx_ring[IGC_MAX_RX_QUEUES];
|
||||
|
||||
struct timer_list watchdog_timer;
|
||||
struct timer_list dma_err_timer;
|
||||
struct timer_list phy_info_timer;
|
||||
struct hrtimer hrtimer;
|
||||
|
||||
u32 wol;
|
||||
u32 en_mng_pt;
|
||||
u16 link_speed;
|
||||
u16 link_duplex;
|
||||
|
||||
u8 port_num;
|
||||
|
||||
u8 __iomem *io_addr;
|
||||
/* Interrupt Throttle Rate */
|
||||
u32 rx_itr_setting;
|
||||
u32 tx_itr_setting;
|
||||
|
||||
struct work_struct reset_task;
|
||||
struct work_struct watchdog_task;
|
||||
struct work_struct dma_err_task;
|
||||
bool fc_autoneg;
|
||||
|
||||
u8 tx_timeout_factor;
|
||||
|
||||
int msg_enable;
|
||||
u32 max_frame_size;
|
||||
u32 min_frame_size;
|
||||
|
||||
int tc_setup_type;
|
||||
ktime_t base_time;
|
||||
ktime_t cycle_time;
|
||||
bool taprio_offload_enable;
|
||||
u32 qbv_config_change_errors;
|
||||
bool qbv_transition;
|
||||
unsigned int qbv_count;
|
||||
/* Access to oper_gate_closed, admin_gate_closed and qbv_transition
|
||||
* are protected by the qbv_tx_lock.
|
||||
*/
|
||||
spinlock_t qbv_tx_lock;
|
||||
|
||||
/* OS defined structs */
|
||||
struct pci_dev *pdev;
|
||||
/* lock for statistics */
|
||||
spinlock_t stats64_lock;
|
||||
struct rtnl_link_stats64 stats64;
|
||||
|
||||
/* structs defined in igc_hw.h */
|
||||
struct igc_hw hw;
|
||||
struct igc_hw_stats stats;
|
||||
|
||||
struct igc_q_vector *q_vector[MAX_Q_VECTORS];
|
||||
u32 eims_enable_mask;
|
||||
u32 eims_other;
|
||||
|
||||
u16 tx_ring_count;
|
||||
u16 rx_ring_count;
|
||||
|
||||
u32 tx_hwtstamp_timeouts;
|
||||
u32 tx_hwtstamp_skipped;
|
||||
u32 rx_hwtstamp_cleared;
|
||||
|
||||
u32 rss_queues;
|
||||
u32 rss_indir_tbl_init;
|
||||
|
||||
/* Any access to elements in nfc_rule_list is protected by the
|
||||
* nfc_rule_lock.
|
||||
*/
|
||||
struct mutex nfc_rule_lock;
|
||||
struct list_head nfc_rule_list;
|
||||
unsigned int nfc_rule_count;
|
||||
|
||||
u8 rss_indir_tbl[IGC_RETA_SIZE];
|
||||
|
||||
unsigned long link_check_timeout;
|
||||
struct igc_info ei;
|
||||
|
||||
u32 test_icr;
|
||||
|
||||
struct ptp_clock *ptp_clock;
|
||||
struct ptp_clock_info ptp_caps;
|
||||
/* Access to ptp_tx_skb and ptp_tx_start are protected by the
|
||||
* ptp_tx_lock.
|
||||
*/
|
||||
spinlock_t ptp_tx_lock;
|
||||
struct igc_tx_timestamp_request tx_tstamp[IGC_MAX_TX_TSTAMP_REGS];
|
||||
struct hwtstamp_config tstamp_config;
|
||||
unsigned int ptp_flags;
|
||||
/* System time value lock */
|
||||
spinlock_t tmreg_lock;
|
||||
struct cyclecounter cc;
|
||||
struct timecounter tc;
|
||||
struct timespec64 prev_ptp_time; /* Pre-reset PTP clock */
|
||||
ktime_t ptp_reset_start; /* Reset time in clock mono */
|
||||
struct system_time_snapshot snapshot;
|
||||
|
||||
char fw_version[32];
|
||||
|
||||
struct bpf_prog *xdp_prog;
|
||||
|
||||
bool pps_sys_wrap_on;
|
||||
|
||||
struct ptp_pin_desc sdp_config[IGC_N_SDP];
|
||||
struct {
|
||||
struct timespec64 start;
|
||||
struct timespec64 period;
|
||||
} perout[IGC_N_PEROUT];
|
||||
};
|
||||
|
||||
void igc_up(struct igc_adapter *adapter);
|
||||
void igc_down(struct igc_adapter *adapter);
|
||||
int igc_open(struct net_device *netdev);
|
||||
int igc_close(struct net_device *netdev);
|
||||
int igc_setup_tx_resources(struct igc_ring *ring);
|
||||
int igc_setup_rx_resources(struct igc_ring *ring);
|
||||
void igc_free_tx_resources(struct igc_ring *ring);
|
||||
void igc_free_rx_resources(struct igc_ring *ring);
|
||||
unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter);
|
||||
void igc_set_flag_queue_pairs(struct igc_adapter *adapter,
|
||||
const u32 max_rss_queues);
|
||||
int igc_reinit_queues(struct igc_adapter *adapter);
|
||||
void igc_write_rss_indir_tbl(struct igc_adapter *adapter);
|
||||
bool igc_has_link(struct igc_adapter *adapter);
|
||||
void igc_reset(struct igc_adapter *adapter);
|
||||
void igc_update_stats(struct igc_adapter *adapter);
|
||||
void igc_disable_rx_ring(struct igc_ring *ring);
|
||||
void igc_enable_rx_ring(struct igc_ring *ring);
|
||||
void igc_disable_tx_ring(struct igc_ring *ring);
|
||||
void igc_enable_tx_ring(struct igc_ring *ring);
|
||||
int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags);
|
||||
|
||||
/* igc_dump declarations */
|
||||
void igc_rings_dump(struct igc_adapter *adapter);
|
||||
void igc_regs_dump(struct igc_adapter *adapter);
|
||||
|
||||
extern char igc_driver_name[];
|
||||
|
||||
#define IGC_REGS_LEN 740
|
||||
|
||||
/* flags controlling PTP/1588 function */
|
||||
#define IGC_PTP_ENABLED BIT(0)
|
||||
|
||||
/* Flags definitions */
|
||||
#define IGC_FLAG_HAS_MSI BIT(0)
|
||||
#define IGC_FLAG_QUEUE_PAIRS BIT(3)
|
||||
#define IGC_FLAG_DMAC BIT(4)
|
||||
#define IGC_FLAG_PTP BIT(8)
|
||||
#define IGC_FLAG_WOL_SUPPORTED BIT(8)
|
||||
#define IGC_FLAG_NEED_LINK_UPDATE BIT(9)
|
||||
#define IGC_FLAG_HAS_MSIX BIT(13)
|
||||
#define IGC_FLAG_EEE BIT(14)
|
||||
#define IGC_FLAG_VLAN_PROMISC BIT(15)
|
||||
#define IGC_FLAG_RX_LEGACY BIT(16)
|
||||
#define IGC_FLAG_TSN_QBV_ENABLED BIT(17)
|
||||
#define IGC_FLAG_TSN_QAV_ENABLED BIT(18)
|
||||
|
||||
#define IGC_FLAG_TSN_ANY_ENABLED \
|
||||
(IGC_FLAG_TSN_QBV_ENABLED | IGC_FLAG_TSN_QAV_ENABLED)
|
||||
|
||||
#define IGC_FLAG_RSS_FIELD_IPV4_UDP BIT(6)
|
||||
#define IGC_FLAG_RSS_FIELD_IPV6_UDP BIT(7)
|
||||
|
||||
#define IGC_MRQC_ENABLE_RSS_MQ 0x00000002
|
||||
#define IGC_MRQC_RSS_FIELD_IPV4_UDP 0x00400000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6_UDP 0x00800000
|
||||
|
||||
/* RX-desc Write-Back format RSS Type's */
|
||||
enum igc_rss_type_num {
|
||||
IGC_RSS_TYPE_NO_HASH = 0,
|
||||
IGC_RSS_TYPE_HASH_TCP_IPV4 = 1,
|
||||
IGC_RSS_TYPE_HASH_IPV4 = 2,
|
||||
IGC_RSS_TYPE_HASH_TCP_IPV6 = 3,
|
||||
IGC_RSS_TYPE_HASH_IPV6_EX = 4,
|
||||
IGC_RSS_TYPE_HASH_IPV6 = 5,
|
||||
IGC_RSS_TYPE_HASH_TCP_IPV6_EX = 6,
|
||||
IGC_RSS_TYPE_HASH_UDP_IPV4 = 7,
|
||||
IGC_RSS_TYPE_HASH_UDP_IPV6 = 8,
|
||||
IGC_RSS_TYPE_HASH_UDP_IPV6_EX = 9,
|
||||
IGC_RSS_TYPE_MAX = 10,
|
||||
};
|
||||
#define IGC_RSS_TYPE_MAX_TABLE 16
|
||||
#define IGC_RSS_TYPE_MASK GENMASK(3,0) /* 4-bits (3:0) = mask 0x0F */
|
||||
|
||||
/* igc_rss_type - Rx descriptor RSS type field */
|
||||
static inline u32 igc_rss_type(const union igc_adv_rx_desc *rx_desc)
|
||||
{
|
||||
/* RSS Type 4-bits (3:0) number: 0-9 (above 9 is reserved)
|
||||
* Accessing the same bits via u16 (wb.lower.lo_dword.hs_rss.pkt_info)
|
||||
* is slightly slower than via u32 (wb.lower.lo_dword.data)
|
||||
*/
|
||||
return le32_get_bits(rx_desc->wb.lower.lo_dword.data, IGC_RSS_TYPE_MASK);
|
||||
}
|
||||
|
||||
/* Interrupt defines */
|
||||
#define IGC_START_ITR 648 /* ~6000 ints/sec */
|
||||
#define IGC_4K_ITR 980
|
||||
#define IGC_20K_ITR 196
|
||||
#define IGC_70K_ITR 56
|
||||
|
||||
#define IGC_DEFAULT_ITR 3 /* dynamic */
|
||||
#define IGC_MAX_ITR_USECS 10000
|
||||
#define IGC_MIN_ITR_USECS 10
|
||||
#define NON_Q_VECTORS 1
|
||||
#define MAX_MSIX_ENTRIES 10
|
||||
|
||||
/* TX/RX descriptor defines */
|
||||
#define IGC_DEFAULT_TXD 256
|
||||
#define IGC_DEFAULT_TX_WORK 128
|
||||
#define IGC_MIN_TXD 64
|
||||
#define IGC_MAX_TXD 4096
|
||||
|
||||
#define IGC_DEFAULT_RXD 256
|
||||
#define IGC_MIN_RXD 64
|
||||
#define IGC_MAX_RXD 4096
|
||||
|
||||
/* Supported Rx Buffer Sizes */
|
||||
#define IGC_RXBUFFER_256 256
|
||||
#define IGC_RXBUFFER_2048 2048
|
||||
#define IGC_RXBUFFER_3072 3072
|
||||
|
||||
#define AUTO_ALL_MODES 0
|
||||
#define IGC_RX_HDR_LEN IGC_RXBUFFER_256
|
||||
|
||||
/* Transmit and receive latency (for PTP timestamps) */
|
||||
#define IGC_I225_TX_LATENCY_10 240
|
||||
#define IGC_I225_TX_LATENCY_100 58
|
||||
#define IGC_I225_TX_LATENCY_1000 80
|
||||
#define IGC_I225_TX_LATENCY_2500 1325
|
||||
#define IGC_I225_RX_LATENCY_10 6450
|
||||
#define IGC_I225_RX_LATENCY_100 185
|
||||
#define IGC_I225_RX_LATENCY_1000 300
|
||||
#define IGC_I225_RX_LATENCY_2500 1485
|
||||
|
||||
/* RX and TX descriptor control thresholds.
|
||||
* PTHRESH - MAC will consider prefetch if it has fewer than this number of
|
||||
* descriptors available in its onboard memory.
|
||||
* Setting this to 0 disables RX descriptor prefetch.
|
||||
* HTHRESH - MAC will only prefetch if there are at least this many descriptors
|
||||
* available in host memory.
|
||||
* If PTHRESH is 0, this should also be 0.
|
||||
* WTHRESH - RX descriptor writeback threshold - MAC will delay writing back
|
||||
* descriptors until either it has this many to write back, or the
|
||||
* ITR timer expires.
|
||||
*/
|
||||
#define IGC_RX_PTHRESH 8
|
||||
#define IGC_RX_HTHRESH 8
|
||||
#define IGC_TX_PTHRESH 8
|
||||
#define IGC_TX_HTHRESH 1
|
||||
#define IGC_RX_WTHRESH 4
|
||||
#define IGC_TX_WTHRESH 16
|
||||
|
||||
#define IGC_RX_DMA_ATTR \
|
||||
(DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
|
||||
|
||||
#define IGC_TS_HDR_LEN 16
|
||||
|
||||
#define IGC_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN)
|
||||
|
||||
#if (PAGE_SIZE < 8192)
|
||||
#define IGC_MAX_FRAME_BUILD_SKB \
|
||||
(SKB_WITH_OVERHEAD(IGC_RXBUFFER_2048) - IGC_SKB_PAD - IGC_TS_HDR_LEN)
|
||||
#else
|
||||
#define IGC_MAX_FRAME_BUILD_SKB (IGC_RXBUFFER_2048 - IGC_TS_HDR_LEN)
|
||||
#endif
|
||||
|
||||
/* How many Rx Buffers do we bundle into one write to the hardware ? */
|
||||
#define IGC_RX_BUFFER_WRITE 16 /* Must be power of 2 */
|
||||
|
||||
/* VLAN info */
|
||||
#define IGC_TX_FLAGS_VLAN_MASK 0xffff0000
|
||||
#define IGC_TX_FLAGS_VLAN_SHIFT 16
|
||||
|
||||
/* igc_test_staterr - tests bits within Rx descriptor status and error fields */
|
||||
static inline __le32 igc_test_staterr(union igc_adv_rx_desc *rx_desc,
|
||||
const u32 stat_err_bits)
|
||||
{
|
||||
return rx_desc->wb.upper.status_error & cpu_to_le32(stat_err_bits);
|
||||
}
|
||||
|
||||
enum igc_state_t {
|
||||
__IGC_TESTING,
|
||||
__IGC_RESETTING,
|
||||
__IGC_DOWN,
|
||||
};
|
||||
|
||||
enum igc_tx_flags {
|
||||
/* cmd_type flags */
|
||||
IGC_TX_FLAGS_VLAN = 0x01,
|
||||
IGC_TX_FLAGS_TSO = 0x02,
|
||||
IGC_TX_FLAGS_TSTAMP = 0x04,
|
||||
|
||||
/* olinfo flags */
|
||||
IGC_TX_FLAGS_IPV4 = 0x10,
|
||||
IGC_TX_FLAGS_CSUM = 0x20,
|
||||
|
||||
IGC_TX_FLAGS_TSTAMP_1 = 0x100,
|
||||
IGC_TX_FLAGS_TSTAMP_2 = 0x200,
|
||||
IGC_TX_FLAGS_TSTAMP_3 = 0x400,
|
||||
};
|
||||
|
||||
enum igc_boards {
|
||||
board_base,
|
||||
};
|
||||
|
||||
/* The largest size we can write to the descriptor is 65535. In order to
|
||||
* maintain a power of two alignment we have to limit ourselves to 32K.
|
||||
*/
|
||||
#define IGC_MAX_TXD_PWR 15
|
||||
#define IGC_MAX_DATA_PER_TXD BIT(IGC_MAX_TXD_PWR)
|
||||
|
||||
/* Tx Descriptors needed, worst case */
|
||||
#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IGC_MAX_DATA_PER_TXD)
|
||||
#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
|
||||
|
||||
enum igc_tx_buffer_type {
|
||||
IGC_TX_BUFFER_TYPE_SKB,
|
||||
IGC_TX_BUFFER_TYPE_XDP,
|
||||
IGC_TX_BUFFER_TYPE_XSK,
|
||||
};
|
||||
|
||||
/* wrapper around a pointer to a socket buffer,
|
||||
* so a DMA handle can be stored along with the buffer
|
||||
*/
|
||||
struct igc_tx_buffer {
|
||||
union igc_adv_tx_desc *next_to_watch;
|
||||
unsigned long time_stamp;
|
||||
enum igc_tx_buffer_type type;
|
||||
union {
|
||||
struct sk_buff *skb;
|
||||
struct xdp_frame *xdpf;
|
||||
};
|
||||
unsigned int bytecount;
|
||||
u16 gso_segs;
|
||||
__be16 protocol;
|
||||
|
||||
DEFINE_DMA_UNMAP_ADDR(dma);
|
||||
DEFINE_DMA_UNMAP_LEN(len);
|
||||
u32 tx_flags;
|
||||
};
|
||||
|
||||
struct igc_rx_buffer {
|
||||
union {
|
||||
struct {
|
||||
dma_addr_t dma;
|
||||
struct page *page;
|
||||
#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
|
||||
__u32 page_offset;
|
||||
#else
|
||||
__u16 page_offset;
|
||||
#endif
|
||||
__u16 pagecnt_bias;
|
||||
};
|
||||
struct xdp_buff *xdp;
|
||||
};
|
||||
};
|
||||
|
||||
/* context wrapper around xdp_buff to provide access to descriptor metadata */
|
||||
struct igc_xdp_buff {
|
||||
struct xdp_buff xdp;
|
||||
union igc_adv_rx_desc *rx_desc;
|
||||
ktime_t rx_ts; /* data indication bit IGC_RXDADV_STAT_TSIP */
|
||||
};
|
||||
|
||||
struct igc_q_vector {
|
||||
struct igc_adapter *adapter; /* backlink */
|
||||
void __iomem *itr_register;
|
||||
u32 eims_value; /* EIMS mask value */
|
||||
|
||||
u16 itr_val;
|
||||
u8 set_itr;
|
||||
|
||||
struct igc_ring_container rx, tx;
|
||||
|
||||
struct napi_struct napi;
|
||||
|
||||
struct rcu_head rcu; /* to avoid race with update stats on free */
|
||||
char name[IFNAMSIZ + 9];
|
||||
struct net_device poll_dev;
|
||||
|
||||
/* for dynamic allocation of rings associated with this q_vector */
|
||||
struct igc_ring ring[] ____cacheline_internodealigned_in_smp;
|
||||
};
|
||||
|
||||
enum igc_filter_match_flags {
|
||||
IGC_FILTER_FLAG_ETHER_TYPE = BIT(0),
|
||||
IGC_FILTER_FLAG_VLAN_TCI = BIT(1),
|
||||
IGC_FILTER_FLAG_SRC_MAC_ADDR = BIT(2),
|
||||
IGC_FILTER_FLAG_DST_MAC_ADDR = BIT(3),
|
||||
IGC_FILTER_FLAG_USER_DATA = BIT(4),
|
||||
IGC_FILTER_FLAG_VLAN_ETYPE = BIT(5),
|
||||
};
|
||||
|
||||
struct igc_nfc_filter {
|
||||
u8 match_flags;
|
||||
u16 etype;
|
||||
__be16 vlan_etype;
|
||||
u16 vlan_tci;
|
||||
u8 src_addr[ETH_ALEN];
|
||||
u8 dst_addr[ETH_ALEN];
|
||||
u8 user_data[8];
|
||||
u8 user_mask[8];
|
||||
u8 flex_index;
|
||||
u8 rx_queue;
|
||||
u8 prio;
|
||||
u8 immediate_irq;
|
||||
u8 drop;
|
||||
};
|
||||
|
||||
struct igc_nfc_rule {
|
||||
struct list_head list;
|
||||
struct igc_nfc_filter filter;
|
||||
u32 location;
|
||||
u16 action;
|
||||
bool flex;
|
||||
};
|
||||
|
||||
/* IGC supports a total of 32 NFC rules: 16 MAC address based, 8 VLAN priority
|
||||
* based, 8 ethertype based and 32 Flex filter based rules.
|
||||
*/
|
||||
#define IGC_MAX_RXNFC_RULES 64
|
||||
|
||||
struct igc_flex_filter {
|
||||
u8 index;
|
||||
u8 data[128];
|
||||
u8 mask[16];
|
||||
u8 length;
|
||||
u8 rx_queue;
|
||||
u8 prio;
|
||||
u8 immediate_irq;
|
||||
u8 drop;
|
||||
};
|
||||
|
||||
/* igc_desc_unused - calculate if we have unused descriptors */
|
||||
static inline u16 igc_desc_unused(const struct igc_ring *ring)
|
||||
{
|
||||
u16 ntc = ring->next_to_clean;
|
||||
u16 ntu = ring->next_to_use;
|
||||
|
||||
return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1;
|
||||
}
|
||||
|
||||
static inline s32 igc_get_phy_info(struct igc_hw *hw)
|
||||
{
|
||||
if (hw->phy.ops.get_phy_info)
|
||||
return hw->phy.ops.get_phy_info(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline s32 igc_reset_phy(struct igc_hw *hw)
|
||||
{
|
||||
if (hw->phy.ops.reset)
|
||||
return hw->phy.ops.reset(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct netdev_queue *txring_txq(const struct igc_ring *tx_ring)
|
||||
{
|
||||
return netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index);
|
||||
}
|
||||
|
||||
enum igc_ring_flags_t {
|
||||
IGC_RING_FLAG_RX_3K_BUFFER,
|
||||
IGC_RING_FLAG_RX_BUILD_SKB_ENABLED,
|
||||
IGC_RING_FLAG_RX_SCTP_CSUM,
|
||||
IGC_RING_FLAG_RX_LB_VLAN_BSWAP,
|
||||
IGC_RING_FLAG_TX_CTX_IDX,
|
||||
IGC_RING_FLAG_TX_DETECT_HANG,
|
||||
IGC_RING_FLAG_AF_XDP_ZC,
|
||||
IGC_RING_FLAG_TX_HWTSTAMP,
|
||||
};
|
||||
|
||||
#define ring_uses_large_buffer(ring) \
|
||||
test_bit(IGC_RING_FLAG_RX_3K_BUFFER, &(ring)->flags)
|
||||
#define set_ring_uses_large_buffer(ring) \
|
||||
set_bit(IGC_RING_FLAG_RX_3K_BUFFER, &(ring)->flags)
|
||||
#define clear_ring_uses_large_buffer(ring) \
|
||||
clear_bit(IGC_RING_FLAG_RX_3K_BUFFER, &(ring)->flags)
|
||||
|
||||
#define ring_uses_build_skb(ring) \
|
||||
test_bit(IGC_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
|
||||
|
||||
static inline unsigned int igc_rx_bufsz(struct igc_ring *ring)
|
||||
{
|
||||
#if (PAGE_SIZE < 8192)
|
||||
if (ring_uses_large_buffer(ring))
|
||||
return IGC_RXBUFFER_3072;
|
||||
|
||||
if (ring_uses_build_skb(ring))
|
||||
return IGC_MAX_FRAME_BUILD_SKB + IGC_TS_HDR_LEN;
|
||||
#endif
|
||||
return IGC_RXBUFFER_2048;
|
||||
}
|
||||
|
||||
static inline unsigned int igc_rx_pg_order(struct igc_ring *ring)
|
||||
{
|
||||
#if (PAGE_SIZE < 8192)
|
||||
if (ring_uses_large_buffer(ring))
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline 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 -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
void igc_reinit_locked(struct igc_adapter *);
|
||||
struct igc_nfc_rule *igc_get_nfc_rule(struct igc_adapter *adapter,
|
||||
u32 location);
|
||||
int igc_add_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule);
|
||||
void igc_del_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule);
|
||||
|
||||
void igc_ptp_init(struct igc_adapter *adapter);
|
||||
void igc_ptp_reset(struct igc_adapter *adapter);
|
||||
void igc_ptp_suspend(struct igc_adapter *adapter);
|
||||
void igc_ptp_stop(struct igc_adapter *adapter);
|
||||
ktime_t igc_ptp_rx_pktstamp(struct igc_adapter *adapter, __le32 *buf);
|
||||
int igc_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr);
|
||||
int igc_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr);
|
||||
void igc_ptp_tx_hang(struct igc_adapter *adapter);
|
||||
void igc_ptp_read(struct igc_adapter *adapter, struct timespec64 *ts);
|
||||
void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter);
|
||||
|
||||
#define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring))
|
||||
|
||||
#define IGC_TXD_DCMD (IGC_ADVTXD_DCMD_EOP | IGC_ADVTXD_DCMD_RS)
|
||||
|
||||
#define IGC_RX_DESC(R, i) \
|
||||
(&(((union igc_adv_rx_desc *)((R)->desc))[i]))
|
||||
#define IGC_TX_DESC(R, i) \
|
||||
(&(((union igc_adv_tx_desc *)((R)->desc))[i]))
|
||||
#define IGC_TX_CTXTDESC(R, i) \
|
||||
(&(((struct igc_adv_tx_context_desc *)((R)->desc))[i]))
|
||||
|
||||
#endif /* _IGC_H_ */
|
||||
|
|
@ -0,0 +1,448 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "igc_hw-6.4-ethercat.h"
|
||||
#include "igc_i225-6.4-ethercat.h"
|
||||
#include "igc_mac-6.4-ethercat.h"
|
||||
#include "igc_base-6.4-ethercat.h"
|
||||
#include "igc-6.4-ethercat.h"
|
||||
|
||||
/**
|
||||
* igc_reset_hw_base - 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 the api module.
|
||||
*/
|
||||
static s32 igc_reset_hw_base(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val;
|
||||
u32 ctrl;
|
||||
|
||||
/* Prevent the PCI-E bus from sticking if there is no TLP connection
|
||||
* on the last TLP read/write transaction when MAC is reset.
|
||||
*/
|
||||
ret_val = igc_disable_pcie_master(hw);
|
||||
if (ret_val)
|
||||
hw_dbg("PCI-E Master disable polling has failed\n");
|
||||
|
||||
hw_dbg("Masking off all interrupts\n");
|
||||
wr32(IGC_IMC, 0xffffffff);
|
||||
|
||||
wr32(IGC_RCTL, 0);
|
||||
wr32(IGC_TCTL, IGC_TCTL_PSP);
|
||||
wrfl();
|
||||
|
||||
usleep_range(10000, 20000);
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
|
||||
hw_dbg("Issuing a global reset to MAC\n");
|
||||
wr32(IGC_CTRL, ctrl | IGC_CTRL_RST);
|
||||
|
||||
ret_val = igc_get_auto_rd_done(hw);
|
||||
if (ret_val) {
|
||||
/* When auto config read does not complete, do not
|
||||
* return with an error. This can happen in situations
|
||||
* where there is no eeprom and prevents getting link.
|
||||
*/
|
||||
hw_dbg("Auto Read Done did not complete\n");
|
||||
}
|
||||
|
||||
/* Clear any pending interrupt events. */
|
||||
wr32(IGC_IMC, 0xffffffff);
|
||||
rd32(IGC_ICR);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_nvm_params_base - Init NVM func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_init_nvm_params_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_nvm_info *nvm = &hw->nvm;
|
||||
u32 eecd = rd32(IGC_EECD);
|
||||
u16 size;
|
||||
|
||||
size = (u16)((eecd & IGC_EECD_SIZE_EX_MASK) >>
|
||||
IGC_EECD_SIZE_EX_SHIFT);
|
||||
|
||||
/* Added to a constant, "size" becomes the left-shift value
|
||||
* for setting word_size.
|
||||
*/
|
||||
size += NVM_WORD_SIZE_BASE_SHIFT;
|
||||
|
||||
/* Just in case size is out of range, cap it to the largest
|
||||
* EEPROM size supported
|
||||
*/
|
||||
if (size > 15)
|
||||
size = 15;
|
||||
|
||||
nvm->type = igc_nvm_eeprom_spi;
|
||||
nvm->word_size = BIT(size);
|
||||
nvm->opcode_bits = 8;
|
||||
nvm->delay_usec = 1;
|
||||
|
||||
nvm->page_size = eecd & IGC_EECD_ADDR_BITS ? 32 : 8;
|
||||
nvm->address_bits = eecd & IGC_EECD_ADDR_BITS ?
|
||||
16 : 8;
|
||||
|
||||
if (nvm->word_size == BIT(15))
|
||||
nvm->page_size = 128;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_setup_copper_link_base - Configure copper link settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Configures the link for auto-neg or forced speed and duplex. Then we check
|
||||
* for link, once link is established calls to configure collision distance
|
||||
* and flow control are called.
|
||||
*/
|
||||
static s32 igc_setup_copper_link_base(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
ctrl |= IGC_CTRL_SLU;
|
||||
ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX);
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
|
||||
ret_val = igc_setup_copper_link(hw);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_mac_params_base - Init MAC func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_init_mac_params_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_dev_spec_base *dev_spec = &hw->dev_spec._base;
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
|
||||
/* Set mta register count */
|
||||
mac->mta_reg_count = 128;
|
||||
mac->rar_entry_count = IGC_RAR_ENTRIES;
|
||||
|
||||
/* reset */
|
||||
mac->ops.reset_hw = igc_reset_hw_base;
|
||||
|
||||
mac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225;
|
||||
mac->ops.release_swfw_sync = igc_release_swfw_sync_i225;
|
||||
|
||||
/* Allow a single clear of the SW semaphore on I225 */
|
||||
if (mac->type == igc_i225)
|
||||
dev_spec->clear_semaphore_once = true;
|
||||
|
||||
/* physical interface link setup */
|
||||
mac->ops.setup_physical_interface = igc_setup_copper_link_base;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_phy_params_base - Init PHY func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_init_phy_params_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
s32 ret_val = 0;
|
||||
|
||||
phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT_2500;
|
||||
phy->reset_delay_us = 100;
|
||||
|
||||
/* set lan id */
|
||||
hw->bus.func = (rd32(IGC_STATUS) & IGC_STATUS_FUNC_MASK) >>
|
||||
IGC_STATUS_FUNC_SHIFT;
|
||||
|
||||
/* Make sure the PHY is in a good state. Several people have reported
|
||||
* firmware leaving the PHY's page select register set to something
|
||||
* other than the default of zero, which causes the PHY ID read to
|
||||
* access something other than the intended register.
|
||||
*/
|
||||
ret_val = hw->phy.ops.reset(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error resetting the PHY\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_val = igc_get_phy_id(hw);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
igc_check_for_copper_link(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static s32 igc_get_invariants_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
s32 ret_val = 0;
|
||||
|
||||
switch (hw->device_id) {
|
||||
case IGC_DEV_ID_I225_LM:
|
||||
case IGC_DEV_ID_I225_V:
|
||||
case IGC_DEV_ID_I225_I:
|
||||
case IGC_DEV_ID_I220_V:
|
||||
case IGC_DEV_ID_I225_K:
|
||||
case IGC_DEV_ID_I225_K2:
|
||||
case IGC_DEV_ID_I226_K:
|
||||
case IGC_DEV_ID_I225_LMVP:
|
||||
case IGC_DEV_ID_I226_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:
|
||||
return -IGC_ERR_MAC_INIT;
|
||||
}
|
||||
|
||||
hw->phy.media_type = igc_media_type_copper;
|
||||
|
||||
/* mac initialization and operations */
|
||||
ret_val = igc_init_mac_params_base(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* NVM initialization */
|
||||
ret_val = igc_init_nvm_params_base(hw);
|
||||
switch (hw->mac.type) {
|
||||
case igc_i225:
|
||||
ret_val = igc_init_nvm_params_i225(hw);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* setup PHY parameters */
|
||||
ret_val = igc_init_phy_params_base(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_acquire_phy_base - Acquire rights to access PHY
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Acquire access rights to the correct PHY. This is a
|
||||
* function pointer entry point called by the api module.
|
||||
*/
|
||||
static s32 igc_acquire_phy_base(struct igc_hw *hw)
|
||||
{
|
||||
u16 mask = IGC_SWFW_PHY0_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. This is a
|
||||
* function pointer entry point called by the api module.
|
||||
*/
|
||||
static void igc_release_phy_base(struct igc_hw *hw)
|
||||
{
|
||||
u16 mask = IGC_SWFW_PHY0_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.
|
||||
*/
|
||||
static s32 igc_init_hw_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
u16 i, rar_count = mac->rar_entry_count;
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* Setup the receive address */
|
||||
igc_init_rx_addrs(hw, rar_count);
|
||||
|
||||
/* Zero out the Multicast HASH table */
|
||||
hw_dbg("Zeroing the MTA\n");
|
||||
for (i = 0; i < mac->mta_reg_count; i++)
|
||||
array_wr32(IGC_MTA, i, 0);
|
||||
|
||||
/* Zero out the Unicast HASH table */
|
||||
hw_dbg("Zeroing the UTA\n");
|
||||
for (i = 0; i < mac->uta_reg_count; i++)
|
||||
array_wr32(IGC_UTA, i, 0);
|
||||
|
||||
/* Setup link and flow control */
|
||||
ret_val = igc_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(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)
|
||||
{
|
||||
/* If the management interface is not enabled, then power down */
|
||||
if (!(igc_enable_mng_pass_thru(hw) || igc_check_reset_block(hw)))
|
||||
igc_power_down_phy_copper(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/* disable IPv6 options as per hardware errata */
|
||||
rfctl = rd32(IGC_RFCTL);
|
||||
rfctl |= IGC_RFCTL_IPV6_EX_DIS;
|
||||
wr32(IGC_RFCTL, rfctl);
|
||||
|
||||
if (!(rd32(IGC_MANC) & IGC_MANC_RCV_TCO_EN))
|
||||
return;
|
||||
|
||||
/* Disable all Rx queues */
|
||||
for (i = 0; i < 4; i++) {
|
||||
rxdctl[i] = rd32(IGC_RXDCTL(i));
|
||||
wr32(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++) {
|
||||
usleep_range(1000, 2000);
|
||||
rx_enabled = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
rx_enabled |= rd32(IGC_RXDCTL(i));
|
||||
if (!(rx_enabled & IGC_RXDCTL_QUEUE_ENABLE))
|
||||
break;
|
||||
}
|
||||
|
||||
if (ms_wait == 10)
|
||||
hw_dbg("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
|
||||
*/
|
||||
wr32(IGC_RFCTL, rfctl & ~IGC_RFCTL_LEF);
|
||||
|
||||
rlpml = rd32(IGC_RLPML);
|
||||
wr32(IGC_RLPML, 0);
|
||||
|
||||
rctl = rd32(IGC_RCTL);
|
||||
temp_rctl = rctl & ~(IGC_RCTL_EN | IGC_RCTL_SBP);
|
||||
temp_rctl |= IGC_RCTL_LPE;
|
||||
|
||||
wr32(IGC_RCTL, temp_rctl);
|
||||
wr32(IGC_RCTL, temp_rctl | IGC_RCTL_EN);
|
||||
wrfl();
|
||||
usleep_range(2000, 3000);
|
||||
|
||||
/* Enable Rx queues that were previously enabled and restore our
|
||||
* previous state
|
||||
*/
|
||||
for (i = 0; i < 4; i++)
|
||||
wr32(IGC_RXDCTL(i), rxdctl[i]);
|
||||
wr32(IGC_RCTL, rctl);
|
||||
wrfl();
|
||||
|
||||
wr32(IGC_RLPML, rlpml);
|
||||
wr32(IGC_RFCTL, rfctl);
|
||||
|
||||
/* Flush receive errors generated by workaround */
|
||||
rd32(IGC_ROC);
|
||||
rd32(IGC_RNBC);
|
||||
rd32(IGC_MPC);
|
||||
}
|
||||
|
||||
bool igc_is_device_id_i225(struct igc_hw *hw)
|
||||
{
|
||||
switch (hw->device_id) {
|
||||
case IGC_DEV_ID_I225_LM:
|
||||
case IGC_DEV_ID_I225_V:
|
||||
case IGC_DEV_ID_I225_I:
|
||||
case IGC_DEV_ID_I225_K:
|
||||
case IGC_DEV_ID_I225_K2:
|
||||
case IGC_DEV_ID_I225_LMVP:
|
||||
case IGC_DEV_ID_I225_IT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool igc_is_device_id_i226(struct igc_hw *hw)
|
||||
{
|
||||
switch (hw->device_id) {
|
||||
case IGC_DEV_ID_I226_LM:
|
||||
case IGC_DEV_ID_I226_V:
|
||||
case IGC_DEV_ID_I226_K:
|
||||
case IGC_DEV_ID_I226_IT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static struct igc_mac_operations igc_mac_ops_base = {
|
||||
.init_hw = igc_init_hw_base,
|
||||
.check_for_link = igc_check_for_copper_link,
|
||||
.rar_set = igc_rar_set,
|
||||
.read_mac_addr = igc_read_mac_addr,
|
||||
.get_speed_and_duplex = igc_get_speed_and_duplex_copper,
|
||||
};
|
||||
|
||||
static const struct igc_phy_operations igc_phy_ops_base = {
|
||||
.acquire = igc_acquire_phy_base,
|
||||
.release = igc_release_phy_base,
|
||||
.reset = igc_phy_hw_reset,
|
||||
.read_reg = igc_read_phy_reg_gpy,
|
||||
.write_reg = igc_write_phy_reg_gpy,
|
||||
};
|
||||
|
||||
const struct igc_info igc_base_info = {
|
||||
.get_invariants = igc_get_invariants_base,
|
||||
.mac_ops = &igc_mac_ops_base,
|
||||
.phy_ops = &igc_phy_ops_base,
|
||||
};
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_BASE_H_
|
||||
#define _IGC_BASE_H_
|
||||
|
||||
/* forward declaration */
|
||||
void igc_rx_fifo_flush_base(struct igc_hw *hw);
|
||||
void igc_power_down_phy_copper_base(struct igc_hw *hw);
|
||||
bool igc_is_device_id_i225(struct igc_hw *hw);
|
||||
bool igc_is_device_id_i226(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;
|
||||
__le32 launch_time;
|
||||
__le32 type_tucmd_mlhl;
|
||||
__le32 mss_l4len_idx;
|
||||
};
|
||||
|
||||
/* Adv Transmit Descriptor Config Masks */
|
||||
#define IGC_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp packet */
|
||||
#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_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_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
|
||||
|
||||
#define IGC_RAR_ENTRIES 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 */
|
||||
#define IGC_TXDCTL_SWFLUSH 0x04000000 /* Transmit Software Flush */
|
||||
|
||||
/* Additional Receive Descriptor Control definitions */
|
||||
#define IGC_RXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Rx Queue */
|
||||
#define IGC_RXDCTL_SWFLUSH 0x04000000 /* Receive Software Flush */
|
||||
|
||||
/* SRRCTL bit definitions */
|
||||
#define IGC_SRRCTL_BSIZEPKT_MASK GENMASK(6, 0)
|
||||
#define IGC_SRRCTL_BSIZEPKT(x) FIELD_PREP(IGC_SRRCTL_BSIZEPKT_MASK, \
|
||||
(x) / 1024) /* in 1 KB resolution */
|
||||
#define IGC_SRRCTL_BSIZEHDR_MASK GENMASK(13, 8)
|
||||
#define IGC_SRRCTL_BSIZEHDR(x) FIELD_PREP(IGC_SRRCTL_BSIZEHDR_MASK, \
|
||||
(x) / 64) /* in 64 bytes resolution */
|
||||
#define IGC_SRRCTL_DESCTYPE_MASK GENMASK(27, 25)
|
||||
#define IGC_SRRCTL_DESCTYPE_ADV_ONEBUF FIELD_PREP(IGC_SRRCTL_DESCTYPE_MASK, 1)
|
||||
|
||||
#endif /* _IGC_BASE_H */
|
||||
|
|
@ -0,0 +1,448 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "igc_hw.h"
|
||||
#include "igc_i225.h"
|
||||
#include "igc_mac.h"
|
||||
#include "igc_base.h"
|
||||
#include "igc.h"
|
||||
|
||||
/**
|
||||
* igc_reset_hw_base - 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 the api module.
|
||||
*/
|
||||
static s32 igc_reset_hw_base(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val;
|
||||
u32 ctrl;
|
||||
|
||||
/* Prevent the PCI-E bus from sticking if there is no TLP connection
|
||||
* on the last TLP read/write transaction when MAC is reset.
|
||||
*/
|
||||
ret_val = igc_disable_pcie_master(hw);
|
||||
if (ret_val)
|
||||
hw_dbg("PCI-E Master disable polling has failed\n");
|
||||
|
||||
hw_dbg("Masking off all interrupts\n");
|
||||
wr32(IGC_IMC, 0xffffffff);
|
||||
|
||||
wr32(IGC_RCTL, 0);
|
||||
wr32(IGC_TCTL, IGC_TCTL_PSP);
|
||||
wrfl();
|
||||
|
||||
usleep_range(10000, 20000);
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
|
||||
hw_dbg("Issuing a global reset to MAC\n");
|
||||
wr32(IGC_CTRL, ctrl | IGC_CTRL_RST);
|
||||
|
||||
ret_val = igc_get_auto_rd_done(hw);
|
||||
if (ret_val) {
|
||||
/* When auto config read does not complete, do not
|
||||
* return with an error. This can happen in situations
|
||||
* where there is no eeprom and prevents getting link.
|
||||
*/
|
||||
hw_dbg("Auto Read Done did not complete\n");
|
||||
}
|
||||
|
||||
/* Clear any pending interrupt events. */
|
||||
wr32(IGC_IMC, 0xffffffff);
|
||||
rd32(IGC_ICR);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_nvm_params_base - Init NVM func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_init_nvm_params_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_nvm_info *nvm = &hw->nvm;
|
||||
u32 eecd = rd32(IGC_EECD);
|
||||
u16 size;
|
||||
|
||||
size = (u16)((eecd & IGC_EECD_SIZE_EX_MASK) >>
|
||||
IGC_EECD_SIZE_EX_SHIFT);
|
||||
|
||||
/* Added to a constant, "size" becomes the left-shift value
|
||||
* for setting word_size.
|
||||
*/
|
||||
size += NVM_WORD_SIZE_BASE_SHIFT;
|
||||
|
||||
/* Just in case size is out of range, cap it to the largest
|
||||
* EEPROM size supported
|
||||
*/
|
||||
if (size > 15)
|
||||
size = 15;
|
||||
|
||||
nvm->type = igc_nvm_eeprom_spi;
|
||||
nvm->word_size = BIT(size);
|
||||
nvm->opcode_bits = 8;
|
||||
nvm->delay_usec = 1;
|
||||
|
||||
nvm->page_size = eecd & IGC_EECD_ADDR_BITS ? 32 : 8;
|
||||
nvm->address_bits = eecd & IGC_EECD_ADDR_BITS ?
|
||||
16 : 8;
|
||||
|
||||
if (nvm->word_size == BIT(15))
|
||||
nvm->page_size = 128;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_setup_copper_link_base - Configure copper link settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Configures the link for auto-neg or forced speed and duplex. Then we check
|
||||
* for link, once link is established calls to configure collision distance
|
||||
* and flow control are called.
|
||||
*/
|
||||
static s32 igc_setup_copper_link_base(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
ctrl |= IGC_CTRL_SLU;
|
||||
ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX);
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
|
||||
ret_val = igc_setup_copper_link(hw);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_mac_params_base - Init MAC func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_init_mac_params_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_dev_spec_base *dev_spec = &hw->dev_spec._base;
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
|
||||
/* Set mta register count */
|
||||
mac->mta_reg_count = 128;
|
||||
mac->rar_entry_count = IGC_RAR_ENTRIES;
|
||||
|
||||
/* reset */
|
||||
mac->ops.reset_hw = igc_reset_hw_base;
|
||||
|
||||
mac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225;
|
||||
mac->ops.release_swfw_sync = igc_release_swfw_sync_i225;
|
||||
|
||||
/* Allow a single clear of the SW semaphore on I225 */
|
||||
if (mac->type == igc_i225)
|
||||
dev_spec->clear_semaphore_once = true;
|
||||
|
||||
/* physical interface link setup */
|
||||
mac->ops.setup_physical_interface = igc_setup_copper_link_base;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_phy_params_base - Init PHY func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_init_phy_params_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
s32 ret_val = 0;
|
||||
|
||||
phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT_2500;
|
||||
phy->reset_delay_us = 100;
|
||||
|
||||
/* set lan id */
|
||||
hw->bus.func = (rd32(IGC_STATUS) & IGC_STATUS_FUNC_MASK) >>
|
||||
IGC_STATUS_FUNC_SHIFT;
|
||||
|
||||
/* Make sure the PHY is in a good state. Several people have reported
|
||||
* firmware leaving the PHY's page select register set to something
|
||||
* other than the default of zero, which causes the PHY ID read to
|
||||
* access something other than the intended register.
|
||||
*/
|
||||
ret_val = hw->phy.ops.reset(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error resetting the PHY\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_val = igc_get_phy_id(hw);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
igc_check_for_copper_link(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static s32 igc_get_invariants_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
s32 ret_val = 0;
|
||||
|
||||
switch (hw->device_id) {
|
||||
case IGC_DEV_ID_I225_LM:
|
||||
case IGC_DEV_ID_I225_V:
|
||||
case IGC_DEV_ID_I225_I:
|
||||
case IGC_DEV_ID_I220_V:
|
||||
case IGC_DEV_ID_I225_K:
|
||||
case IGC_DEV_ID_I225_K2:
|
||||
case IGC_DEV_ID_I226_K:
|
||||
case IGC_DEV_ID_I225_LMVP:
|
||||
case IGC_DEV_ID_I226_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:
|
||||
return -IGC_ERR_MAC_INIT;
|
||||
}
|
||||
|
||||
hw->phy.media_type = igc_media_type_copper;
|
||||
|
||||
/* mac initialization and operations */
|
||||
ret_val = igc_init_mac_params_base(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* NVM initialization */
|
||||
ret_val = igc_init_nvm_params_base(hw);
|
||||
switch (hw->mac.type) {
|
||||
case igc_i225:
|
||||
ret_val = igc_init_nvm_params_i225(hw);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* setup PHY parameters */
|
||||
ret_val = igc_init_phy_params_base(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_acquire_phy_base - Acquire rights to access PHY
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Acquire access rights to the correct PHY. This is a
|
||||
* function pointer entry point called by the api module.
|
||||
*/
|
||||
static s32 igc_acquire_phy_base(struct igc_hw *hw)
|
||||
{
|
||||
u16 mask = IGC_SWFW_PHY0_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. This is a
|
||||
* function pointer entry point called by the api module.
|
||||
*/
|
||||
static void igc_release_phy_base(struct igc_hw *hw)
|
||||
{
|
||||
u16 mask = IGC_SWFW_PHY0_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.
|
||||
*/
|
||||
static s32 igc_init_hw_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
u16 i, rar_count = mac->rar_entry_count;
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* Setup the receive address */
|
||||
igc_init_rx_addrs(hw, rar_count);
|
||||
|
||||
/* Zero out the Multicast HASH table */
|
||||
hw_dbg("Zeroing the MTA\n");
|
||||
for (i = 0; i < mac->mta_reg_count; i++)
|
||||
array_wr32(IGC_MTA, i, 0);
|
||||
|
||||
/* Zero out the Unicast HASH table */
|
||||
hw_dbg("Zeroing the UTA\n");
|
||||
for (i = 0; i < mac->uta_reg_count; i++)
|
||||
array_wr32(IGC_UTA, i, 0);
|
||||
|
||||
/* Setup link and flow control */
|
||||
ret_val = igc_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(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)
|
||||
{
|
||||
/* If the management interface is not enabled, then power down */
|
||||
if (!(igc_enable_mng_pass_thru(hw) || igc_check_reset_block(hw)))
|
||||
igc_power_down_phy_copper(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/* disable IPv6 options as per hardware errata */
|
||||
rfctl = rd32(IGC_RFCTL);
|
||||
rfctl |= IGC_RFCTL_IPV6_EX_DIS;
|
||||
wr32(IGC_RFCTL, rfctl);
|
||||
|
||||
if (!(rd32(IGC_MANC) & IGC_MANC_RCV_TCO_EN))
|
||||
return;
|
||||
|
||||
/* Disable all Rx queues */
|
||||
for (i = 0; i < 4; i++) {
|
||||
rxdctl[i] = rd32(IGC_RXDCTL(i));
|
||||
wr32(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++) {
|
||||
usleep_range(1000, 2000);
|
||||
rx_enabled = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
rx_enabled |= rd32(IGC_RXDCTL(i));
|
||||
if (!(rx_enabled & IGC_RXDCTL_QUEUE_ENABLE))
|
||||
break;
|
||||
}
|
||||
|
||||
if (ms_wait == 10)
|
||||
hw_dbg("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
|
||||
*/
|
||||
wr32(IGC_RFCTL, rfctl & ~IGC_RFCTL_LEF);
|
||||
|
||||
rlpml = rd32(IGC_RLPML);
|
||||
wr32(IGC_RLPML, 0);
|
||||
|
||||
rctl = rd32(IGC_RCTL);
|
||||
temp_rctl = rctl & ~(IGC_RCTL_EN | IGC_RCTL_SBP);
|
||||
temp_rctl |= IGC_RCTL_LPE;
|
||||
|
||||
wr32(IGC_RCTL, temp_rctl);
|
||||
wr32(IGC_RCTL, temp_rctl | IGC_RCTL_EN);
|
||||
wrfl();
|
||||
usleep_range(2000, 3000);
|
||||
|
||||
/* Enable Rx queues that were previously enabled and restore our
|
||||
* previous state
|
||||
*/
|
||||
for (i = 0; i < 4; i++)
|
||||
wr32(IGC_RXDCTL(i), rxdctl[i]);
|
||||
wr32(IGC_RCTL, rctl);
|
||||
wrfl();
|
||||
|
||||
wr32(IGC_RLPML, rlpml);
|
||||
wr32(IGC_RFCTL, rfctl);
|
||||
|
||||
/* Flush receive errors generated by workaround */
|
||||
rd32(IGC_ROC);
|
||||
rd32(IGC_RNBC);
|
||||
rd32(IGC_MPC);
|
||||
}
|
||||
|
||||
bool igc_is_device_id_i225(struct igc_hw *hw)
|
||||
{
|
||||
switch (hw->device_id) {
|
||||
case IGC_DEV_ID_I225_LM:
|
||||
case IGC_DEV_ID_I225_V:
|
||||
case IGC_DEV_ID_I225_I:
|
||||
case IGC_DEV_ID_I225_K:
|
||||
case IGC_DEV_ID_I225_K2:
|
||||
case IGC_DEV_ID_I225_LMVP:
|
||||
case IGC_DEV_ID_I225_IT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool igc_is_device_id_i226(struct igc_hw *hw)
|
||||
{
|
||||
switch (hw->device_id) {
|
||||
case IGC_DEV_ID_I226_LM:
|
||||
case IGC_DEV_ID_I226_V:
|
||||
case IGC_DEV_ID_I226_K:
|
||||
case IGC_DEV_ID_I226_IT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static struct igc_mac_operations igc_mac_ops_base = {
|
||||
.init_hw = igc_init_hw_base,
|
||||
.check_for_link = igc_check_for_copper_link,
|
||||
.rar_set = igc_rar_set,
|
||||
.read_mac_addr = igc_read_mac_addr,
|
||||
.get_speed_and_duplex = igc_get_speed_and_duplex_copper,
|
||||
};
|
||||
|
||||
static const struct igc_phy_operations igc_phy_ops_base = {
|
||||
.acquire = igc_acquire_phy_base,
|
||||
.release = igc_release_phy_base,
|
||||
.reset = igc_phy_hw_reset,
|
||||
.read_reg = igc_read_phy_reg_gpy,
|
||||
.write_reg = igc_write_phy_reg_gpy,
|
||||
};
|
||||
|
||||
const struct igc_info igc_base_info = {
|
||||
.get_invariants = igc_get_invariants_base,
|
||||
.mac_ops = &igc_mac_ops_base,
|
||||
.phy_ops = &igc_phy_ops_base,
|
||||
};
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_BASE_H_
|
||||
#define _IGC_BASE_H_
|
||||
|
||||
/* forward declaration */
|
||||
void igc_rx_fifo_flush_base(struct igc_hw *hw);
|
||||
void igc_power_down_phy_copper_base(struct igc_hw *hw);
|
||||
bool igc_is_device_id_i225(struct igc_hw *hw);
|
||||
bool igc_is_device_id_i226(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;
|
||||
__le32 launch_time;
|
||||
__le32 type_tucmd_mlhl;
|
||||
__le32 mss_l4len_idx;
|
||||
};
|
||||
|
||||
/* Adv Transmit Descriptor Config Masks */
|
||||
#define IGC_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp packet */
|
||||
#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_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_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
|
||||
|
||||
#define IGC_RAR_ENTRIES 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 */
|
||||
#define IGC_TXDCTL_SWFLUSH 0x04000000 /* Transmit Software Flush */
|
||||
|
||||
/* Additional Receive Descriptor Control definitions */
|
||||
#define IGC_RXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Rx Queue */
|
||||
#define IGC_RXDCTL_SWFLUSH 0x04000000 /* Receive Software Flush */
|
||||
|
||||
/* SRRCTL bit definitions */
|
||||
#define IGC_SRRCTL_BSIZEPKT_MASK GENMASK(6, 0)
|
||||
#define IGC_SRRCTL_BSIZEPKT(x) FIELD_PREP(IGC_SRRCTL_BSIZEPKT_MASK, \
|
||||
(x) / 1024) /* in 1 KB resolution */
|
||||
#define IGC_SRRCTL_BSIZEHDR_MASK GENMASK(13, 8)
|
||||
#define IGC_SRRCTL_BSIZEHDR(x) FIELD_PREP(IGC_SRRCTL_BSIZEHDR_MASK, \
|
||||
(x) / 64) /* in 64 bytes resolution */
|
||||
#define IGC_SRRCTL_DESCTYPE_MASK GENMASK(27, 25)
|
||||
#define IGC_SRRCTL_DESCTYPE_ADV_ONEBUF FIELD_PREP(IGC_SRRCTL_DESCTYPE_MASK, 1)
|
||||
|
||||
#endif /* _IGC_BASE_H */
|
||||
|
|
@ -0,0 +1,448 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "igc_hw-6.6-ethercat.h"
|
||||
#include "igc_i225-6.6-ethercat.h"
|
||||
#include "igc_mac-6.6-ethercat.h"
|
||||
#include "igc_base-6.6-ethercat.h"
|
||||
#include "igc-6.6-ethercat.h"
|
||||
|
||||
/**
|
||||
* igc_reset_hw_base - 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 the api module.
|
||||
*/
|
||||
static s32 igc_reset_hw_base(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val;
|
||||
u32 ctrl;
|
||||
|
||||
/* Prevent the PCI-E bus from sticking if there is no TLP connection
|
||||
* on the last TLP read/write transaction when MAC is reset.
|
||||
*/
|
||||
ret_val = igc_disable_pcie_master(hw);
|
||||
if (ret_val)
|
||||
hw_dbg("PCI-E Master disable polling has failed\n");
|
||||
|
||||
hw_dbg("Masking off all interrupts\n");
|
||||
wr32(IGC_IMC, 0xffffffff);
|
||||
|
||||
wr32(IGC_RCTL, 0);
|
||||
wr32(IGC_TCTL, IGC_TCTL_PSP);
|
||||
wrfl();
|
||||
|
||||
usleep_range(10000, 20000);
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
|
||||
hw_dbg("Issuing a global reset to MAC\n");
|
||||
wr32(IGC_CTRL, ctrl | IGC_CTRL_RST);
|
||||
|
||||
ret_val = igc_get_auto_rd_done(hw);
|
||||
if (ret_val) {
|
||||
/* When auto config read does not complete, do not
|
||||
* return with an error. This can happen in situations
|
||||
* where there is no eeprom and prevents getting link.
|
||||
*/
|
||||
hw_dbg("Auto Read Done did not complete\n");
|
||||
}
|
||||
|
||||
/* Clear any pending interrupt events. */
|
||||
wr32(IGC_IMC, 0xffffffff);
|
||||
rd32(IGC_ICR);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_nvm_params_base - Init NVM func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_init_nvm_params_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_nvm_info *nvm = &hw->nvm;
|
||||
u32 eecd = rd32(IGC_EECD);
|
||||
u16 size;
|
||||
|
||||
size = (u16)((eecd & IGC_EECD_SIZE_EX_MASK) >>
|
||||
IGC_EECD_SIZE_EX_SHIFT);
|
||||
|
||||
/* Added to a constant, "size" becomes the left-shift value
|
||||
* for setting word_size.
|
||||
*/
|
||||
size += NVM_WORD_SIZE_BASE_SHIFT;
|
||||
|
||||
/* Just in case size is out of range, cap it to the largest
|
||||
* EEPROM size supported
|
||||
*/
|
||||
if (size > 15)
|
||||
size = 15;
|
||||
|
||||
nvm->type = igc_nvm_eeprom_spi;
|
||||
nvm->word_size = BIT(size);
|
||||
nvm->opcode_bits = 8;
|
||||
nvm->delay_usec = 1;
|
||||
|
||||
nvm->page_size = eecd & IGC_EECD_ADDR_BITS ? 32 : 8;
|
||||
nvm->address_bits = eecd & IGC_EECD_ADDR_BITS ?
|
||||
16 : 8;
|
||||
|
||||
if (nvm->word_size == BIT(15))
|
||||
nvm->page_size = 128;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_setup_copper_link_base - Configure copper link settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Configures the link for auto-neg or forced speed and duplex. Then we check
|
||||
* for link, once link is established calls to configure collision distance
|
||||
* and flow control are called.
|
||||
*/
|
||||
static s32 igc_setup_copper_link_base(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
ctrl |= IGC_CTRL_SLU;
|
||||
ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX);
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
|
||||
ret_val = igc_setup_copper_link(hw);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_mac_params_base - Init MAC func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_init_mac_params_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_dev_spec_base *dev_spec = &hw->dev_spec._base;
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
|
||||
/* Set mta register count */
|
||||
mac->mta_reg_count = 128;
|
||||
mac->rar_entry_count = IGC_RAR_ENTRIES;
|
||||
|
||||
/* reset */
|
||||
mac->ops.reset_hw = igc_reset_hw_base;
|
||||
|
||||
mac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225;
|
||||
mac->ops.release_swfw_sync = igc_release_swfw_sync_i225;
|
||||
|
||||
/* Allow a single clear of the SW semaphore on I225 */
|
||||
if (mac->type == igc_i225)
|
||||
dev_spec->clear_semaphore_once = true;
|
||||
|
||||
/* physical interface link setup */
|
||||
mac->ops.setup_physical_interface = igc_setup_copper_link_base;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_phy_params_base - Init PHY func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_init_phy_params_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
s32 ret_val = 0;
|
||||
|
||||
phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT_2500;
|
||||
phy->reset_delay_us = 100;
|
||||
|
||||
/* set lan id */
|
||||
hw->bus.func = (rd32(IGC_STATUS) & IGC_STATUS_FUNC_MASK) >>
|
||||
IGC_STATUS_FUNC_SHIFT;
|
||||
|
||||
/* Make sure the PHY is in a good state. Several people have reported
|
||||
* firmware leaving the PHY's page select register set to something
|
||||
* other than the default of zero, which causes the PHY ID read to
|
||||
* access something other than the intended register.
|
||||
*/
|
||||
ret_val = hw->phy.ops.reset(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error resetting the PHY\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_val = igc_get_phy_id(hw);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
igc_check_for_copper_link(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static s32 igc_get_invariants_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
s32 ret_val = 0;
|
||||
|
||||
switch (hw->device_id) {
|
||||
case IGC_DEV_ID_I225_LM:
|
||||
case IGC_DEV_ID_I225_V:
|
||||
case IGC_DEV_ID_I225_I:
|
||||
case IGC_DEV_ID_I220_V:
|
||||
case IGC_DEV_ID_I225_K:
|
||||
case IGC_DEV_ID_I225_K2:
|
||||
case IGC_DEV_ID_I226_K:
|
||||
case IGC_DEV_ID_I225_LMVP:
|
||||
case IGC_DEV_ID_I226_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:
|
||||
return -IGC_ERR_MAC_INIT;
|
||||
}
|
||||
|
||||
hw->phy.media_type = igc_media_type_copper;
|
||||
|
||||
/* mac initialization and operations */
|
||||
ret_val = igc_init_mac_params_base(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* NVM initialization */
|
||||
ret_val = igc_init_nvm_params_base(hw);
|
||||
switch (hw->mac.type) {
|
||||
case igc_i225:
|
||||
ret_val = igc_init_nvm_params_i225(hw);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* setup PHY parameters */
|
||||
ret_val = igc_init_phy_params_base(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_acquire_phy_base - Acquire rights to access PHY
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Acquire access rights to the correct PHY. This is a
|
||||
* function pointer entry point called by the api module.
|
||||
*/
|
||||
static s32 igc_acquire_phy_base(struct igc_hw *hw)
|
||||
{
|
||||
u16 mask = IGC_SWFW_PHY0_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. This is a
|
||||
* function pointer entry point called by the api module.
|
||||
*/
|
||||
static void igc_release_phy_base(struct igc_hw *hw)
|
||||
{
|
||||
u16 mask = IGC_SWFW_PHY0_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.
|
||||
*/
|
||||
static s32 igc_init_hw_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
u16 i, rar_count = mac->rar_entry_count;
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* Setup the receive address */
|
||||
igc_init_rx_addrs(hw, rar_count);
|
||||
|
||||
/* Zero out the Multicast HASH table */
|
||||
hw_dbg("Zeroing the MTA\n");
|
||||
for (i = 0; i < mac->mta_reg_count; i++)
|
||||
array_wr32(IGC_MTA, i, 0);
|
||||
|
||||
/* Zero out the Unicast HASH table */
|
||||
hw_dbg("Zeroing the UTA\n");
|
||||
for (i = 0; i < mac->uta_reg_count; i++)
|
||||
array_wr32(IGC_UTA, i, 0);
|
||||
|
||||
/* Setup link and flow control */
|
||||
ret_val = igc_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(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)
|
||||
{
|
||||
/* If the management interface is not enabled, then power down */
|
||||
if (!(igc_enable_mng_pass_thru(hw) || igc_check_reset_block(hw)))
|
||||
igc_power_down_phy_copper(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/* disable IPv6 options as per hardware errata */
|
||||
rfctl = rd32(IGC_RFCTL);
|
||||
rfctl |= IGC_RFCTL_IPV6_EX_DIS;
|
||||
wr32(IGC_RFCTL, rfctl);
|
||||
|
||||
if (!(rd32(IGC_MANC) & IGC_MANC_RCV_TCO_EN))
|
||||
return;
|
||||
|
||||
/* Disable all Rx queues */
|
||||
for (i = 0; i < 4; i++) {
|
||||
rxdctl[i] = rd32(IGC_RXDCTL(i));
|
||||
wr32(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++) {
|
||||
usleep_range(1000, 2000);
|
||||
rx_enabled = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
rx_enabled |= rd32(IGC_RXDCTL(i));
|
||||
if (!(rx_enabled & IGC_RXDCTL_QUEUE_ENABLE))
|
||||
break;
|
||||
}
|
||||
|
||||
if (ms_wait == 10)
|
||||
hw_dbg("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
|
||||
*/
|
||||
wr32(IGC_RFCTL, rfctl & ~IGC_RFCTL_LEF);
|
||||
|
||||
rlpml = rd32(IGC_RLPML);
|
||||
wr32(IGC_RLPML, 0);
|
||||
|
||||
rctl = rd32(IGC_RCTL);
|
||||
temp_rctl = rctl & ~(IGC_RCTL_EN | IGC_RCTL_SBP);
|
||||
temp_rctl |= IGC_RCTL_LPE;
|
||||
|
||||
wr32(IGC_RCTL, temp_rctl);
|
||||
wr32(IGC_RCTL, temp_rctl | IGC_RCTL_EN);
|
||||
wrfl();
|
||||
usleep_range(2000, 3000);
|
||||
|
||||
/* Enable Rx queues that were previously enabled and restore our
|
||||
* previous state
|
||||
*/
|
||||
for (i = 0; i < 4; i++)
|
||||
wr32(IGC_RXDCTL(i), rxdctl[i]);
|
||||
wr32(IGC_RCTL, rctl);
|
||||
wrfl();
|
||||
|
||||
wr32(IGC_RLPML, rlpml);
|
||||
wr32(IGC_RFCTL, rfctl);
|
||||
|
||||
/* Flush receive errors generated by workaround */
|
||||
rd32(IGC_ROC);
|
||||
rd32(IGC_RNBC);
|
||||
rd32(IGC_MPC);
|
||||
}
|
||||
|
||||
bool igc_is_device_id_i225(struct igc_hw *hw)
|
||||
{
|
||||
switch (hw->device_id) {
|
||||
case IGC_DEV_ID_I225_LM:
|
||||
case IGC_DEV_ID_I225_V:
|
||||
case IGC_DEV_ID_I225_I:
|
||||
case IGC_DEV_ID_I225_K:
|
||||
case IGC_DEV_ID_I225_K2:
|
||||
case IGC_DEV_ID_I225_LMVP:
|
||||
case IGC_DEV_ID_I225_IT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool igc_is_device_id_i226(struct igc_hw *hw)
|
||||
{
|
||||
switch (hw->device_id) {
|
||||
case IGC_DEV_ID_I226_LM:
|
||||
case IGC_DEV_ID_I226_V:
|
||||
case IGC_DEV_ID_I226_K:
|
||||
case IGC_DEV_ID_I226_IT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static struct igc_mac_operations igc_mac_ops_base = {
|
||||
.init_hw = igc_init_hw_base,
|
||||
.check_for_link = igc_check_for_copper_link,
|
||||
.rar_set = igc_rar_set,
|
||||
.read_mac_addr = igc_read_mac_addr,
|
||||
.get_speed_and_duplex = igc_get_speed_and_duplex_copper,
|
||||
};
|
||||
|
||||
static const struct igc_phy_operations igc_phy_ops_base = {
|
||||
.acquire = igc_acquire_phy_base,
|
||||
.release = igc_release_phy_base,
|
||||
.reset = igc_phy_hw_reset,
|
||||
.read_reg = igc_read_phy_reg_gpy,
|
||||
.write_reg = igc_write_phy_reg_gpy,
|
||||
};
|
||||
|
||||
const struct igc_info igc_base_info = {
|
||||
.get_invariants = igc_get_invariants_base,
|
||||
.mac_ops = &igc_mac_ops_base,
|
||||
.phy_ops = &igc_phy_ops_base,
|
||||
};
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_BASE_H_
|
||||
#define _IGC_BASE_H_
|
||||
|
||||
/* forward declaration */
|
||||
void igc_rx_fifo_flush_base(struct igc_hw *hw);
|
||||
void igc_power_down_phy_copper_base(struct igc_hw *hw);
|
||||
bool igc_is_device_id_i225(struct igc_hw *hw);
|
||||
bool igc_is_device_id_i226(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;
|
||||
__le32 launch_time;
|
||||
__le32 type_tucmd_mlhl;
|
||||
__le32 mss_l4len_idx;
|
||||
};
|
||||
|
||||
/* Adv Transmit Descriptor Config Masks */
|
||||
#define IGC_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp packet */
|
||||
#define IGC_ADVTXD_TSTAMP_REG_1 0x00010000 /* Select register 1 for timestamp */
|
||||
#define IGC_ADVTXD_TSTAMP_REG_2 0x00020000 /* Select register 2 for timestamp */
|
||||
#define IGC_ADVTXD_TSTAMP_REG_3 0x00030000 /* Select register 3 for timestamp */
|
||||
#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_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_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
|
||||
|
||||
#define IGC_RAR_ENTRIES 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 */
|
||||
#define IGC_TXDCTL_SWFLUSH 0x04000000 /* Transmit Software Flush */
|
||||
|
||||
/* Additional Receive Descriptor Control definitions */
|
||||
#define IGC_RXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Rx Queue */
|
||||
#define IGC_RXDCTL_SWFLUSH 0x04000000 /* Receive Software Flush */
|
||||
|
||||
/* SRRCTL bit definitions */
|
||||
#define IGC_SRRCTL_BSIZEPKT_MASK GENMASK(6, 0)
|
||||
#define IGC_SRRCTL_BSIZEPKT(x) FIELD_PREP(IGC_SRRCTL_BSIZEPKT_MASK, \
|
||||
(x) / 1024) /* in 1 KB resolution */
|
||||
#define IGC_SRRCTL_BSIZEHDR_MASK GENMASK(13, 8)
|
||||
#define IGC_SRRCTL_BSIZEHDR(x) FIELD_PREP(IGC_SRRCTL_BSIZEHDR_MASK, \
|
||||
(x) / 64) /* in 64 bytes resolution */
|
||||
#define IGC_SRRCTL_DESCTYPE_MASK GENMASK(27, 25)
|
||||
#define IGC_SRRCTL_DESCTYPE_ADV_ONEBUF FIELD_PREP(IGC_SRRCTL_DESCTYPE_MASK, 1)
|
||||
|
||||
#endif /* _IGC_BASE_H */
|
||||
|
|
@ -0,0 +1,448 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "igc_hw.h"
|
||||
#include "igc_i225.h"
|
||||
#include "igc_mac.h"
|
||||
#include "igc_base.h"
|
||||
#include "igc.h"
|
||||
|
||||
/**
|
||||
* igc_reset_hw_base - 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 the api module.
|
||||
*/
|
||||
static s32 igc_reset_hw_base(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val;
|
||||
u32 ctrl;
|
||||
|
||||
/* Prevent the PCI-E bus from sticking if there is no TLP connection
|
||||
* on the last TLP read/write transaction when MAC is reset.
|
||||
*/
|
||||
ret_val = igc_disable_pcie_master(hw);
|
||||
if (ret_val)
|
||||
hw_dbg("PCI-E Master disable polling has failed\n");
|
||||
|
||||
hw_dbg("Masking off all interrupts\n");
|
||||
wr32(IGC_IMC, 0xffffffff);
|
||||
|
||||
wr32(IGC_RCTL, 0);
|
||||
wr32(IGC_TCTL, IGC_TCTL_PSP);
|
||||
wrfl();
|
||||
|
||||
usleep_range(10000, 20000);
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
|
||||
hw_dbg("Issuing a global reset to MAC\n");
|
||||
wr32(IGC_CTRL, ctrl | IGC_CTRL_RST);
|
||||
|
||||
ret_val = igc_get_auto_rd_done(hw);
|
||||
if (ret_val) {
|
||||
/* When auto config read does not complete, do not
|
||||
* return with an error. This can happen in situations
|
||||
* where there is no eeprom and prevents getting link.
|
||||
*/
|
||||
hw_dbg("Auto Read Done did not complete\n");
|
||||
}
|
||||
|
||||
/* Clear any pending interrupt events. */
|
||||
wr32(IGC_IMC, 0xffffffff);
|
||||
rd32(IGC_ICR);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_nvm_params_base - Init NVM func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_init_nvm_params_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_nvm_info *nvm = &hw->nvm;
|
||||
u32 eecd = rd32(IGC_EECD);
|
||||
u16 size;
|
||||
|
||||
size = (u16)((eecd & IGC_EECD_SIZE_EX_MASK) >>
|
||||
IGC_EECD_SIZE_EX_SHIFT);
|
||||
|
||||
/* Added to a constant, "size" becomes the left-shift value
|
||||
* for setting word_size.
|
||||
*/
|
||||
size += NVM_WORD_SIZE_BASE_SHIFT;
|
||||
|
||||
/* Just in case size is out of range, cap it to the largest
|
||||
* EEPROM size supported
|
||||
*/
|
||||
if (size > 15)
|
||||
size = 15;
|
||||
|
||||
nvm->type = igc_nvm_eeprom_spi;
|
||||
nvm->word_size = BIT(size);
|
||||
nvm->opcode_bits = 8;
|
||||
nvm->delay_usec = 1;
|
||||
|
||||
nvm->page_size = eecd & IGC_EECD_ADDR_BITS ? 32 : 8;
|
||||
nvm->address_bits = eecd & IGC_EECD_ADDR_BITS ?
|
||||
16 : 8;
|
||||
|
||||
if (nvm->word_size == BIT(15))
|
||||
nvm->page_size = 128;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_setup_copper_link_base - Configure copper link settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Configures the link for auto-neg or forced speed and duplex. Then we check
|
||||
* for link, once link is established calls to configure collision distance
|
||||
* and flow control are called.
|
||||
*/
|
||||
static s32 igc_setup_copper_link_base(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
ctrl |= IGC_CTRL_SLU;
|
||||
ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX);
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
|
||||
ret_val = igc_setup_copper_link(hw);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_mac_params_base - Init MAC func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_init_mac_params_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_dev_spec_base *dev_spec = &hw->dev_spec._base;
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
|
||||
/* Set mta register count */
|
||||
mac->mta_reg_count = 128;
|
||||
mac->rar_entry_count = IGC_RAR_ENTRIES;
|
||||
|
||||
/* reset */
|
||||
mac->ops.reset_hw = igc_reset_hw_base;
|
||||
|
||||
mac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225;
|
||||
mac->ops.release_swfw_sync = igc_release_swfw_sync_i225;
|
||||
|
||||
/* Allow a single clear of the SW semaphore on I225 */
|
||||
if (mac->type == igc_i225)
|
||||
dev_spec->clear_semaphore_once = true;
|
||||
|
||||
/* physical interface link setup */
|
||||
mac->ops.setup_physical_interface = igc_setup_copper_link_base;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_phy_params_base - Init PHY func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_init_phy_params_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
s32 ret_val = 0;
|
||||
|
||||
phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT_2500;
|
||||
phy->reset_delay_us = 100;
|
||||
|
||||
/* set lan id */
|
||||
hw->bus.func = (rd32(IGC_STATUS) & IGC_STATUS_FUNC_MASK) >>
|
||||
IGC_STATUS_FUNC_SHIFT;
|
||||
|
||||
/* Make sure the PHY is in a good state. Several people have reported
|
||||
* firmware leaving the PHY's page select register set to something
|
||||
* other than the default of zero, which causes the PHY ID read to
|
||||
* access something other than the intended register.
|
||||
*/
|
||||
ret_val = hw->phy.ops.reset(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error resetting the PHY\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_val = igc_get_phy_id(hw);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
igc_check_for_copper_link(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static s32 igc_get_invariants_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
s32 ret_val = 0;
|
||||
|
||||
switch (hw->device_id) {
|
||||
case IGC_DEV_ID_I225_LM:
|
||||
case IGC_DEV_ID_I225_V:
|
||||
case IGC_DEV_ID_I225_I:
|
||||
case IGC_DEV_ID_I220_V:
|
||||
case IGC_DEV_ID_I225_K:
|
||||
case IGC_DEV_ID_I225_K2:
|
||||
case IGC_DEV_ID_I226_K:
|
||||
case IGC_DEV_ID_I225_LMVP:
|
||||
case IGC_DEV_ID_I226_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:
|
||||
return -IGC_ERR_MAC_INIT;
|
||||
}
|
||||
|
||||
hw->phy.media_type = igc_media_type_copper;
|
||||
|
||||
/* mac initialization and operations */
|
||||
ret_val = igc_init_mac_params_base(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* NVM initialization */
|
||||
ret_val = igc_init_nvm_params_base(hw);
|
||||
switch (hw->mac.type) {
|
||||
case igc_i225:
|
||||
ret_val = igc_init_nvm_params_i225(hw);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* setup PHY parameters */
|
||||
ret_val = igc_init_phy_params_base(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_acquire_phy_base - Acquire rights to access PHY
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Acquire access rights to the correct PHY. This is a
|
||||
* function pointer entry point called by the api module.
|
||||
*/
|
||||
static s32 igc_acquire_phy_base(struct igc_hw *hw)
|
||||
{
|
||||
u16 mask = IGC_SWFW_PHY0_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. This is a
|
||||
* function pointer entry point called by the api module.
|
||||
*/
|
||||
static void igc_release_phy_base(struct igc_hw *hw)
|
||||
{
|
||||
u16 mask = IGC_SWFW_PHY0_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.
|
||||
*/
|
||||
static s32 igc_init_hw_base(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
u16 i, rar_count = mac->rar_entry_count;
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* Setup the receive address */
|
||||
igc_init_rx_addrs(hw, rar_count);
|
||||
|
||||
/* Zero out the Multicast HASH table */
|
||||
hw_dbg("Zeroing the MTA\n");
|
||||
for (i = 0; i < mac->mta_reg_count; i++)
|
||||
array_wr32(IGC_MTA, i, 0);
|
||||
|
||||
/* Zero out the Unicast HASH table */
|
||||
hw_dbg("Zeroing the UTA\n");
|
||||
for (i = 0; i < mac->uta_reg_count; i++)
|
||||
array_wr32(IGC_UTA, i, 0);
|
||||
|
||||
/* Setup link and flow control */
|
||||
ret_val = igc_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(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)
|
||||
{
|
||||
/* If the management interface is not enabled, then power down */
|
||||
if (!(igc_enable_mng_pass_thru(hw) || igc_check_reset_block(hw)))
|
||||
igc_power_down_phy_copper(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/* disable IPv6 options as per hardware errata */
|
||||
rfctl = rd32(IGC_RFCTL);
|
||||
rfctl |= IGC_RFCTL_IPV6_EX_DIS;
|
||||
wr32(IGC_RFCTL, rfctl);
|
||||
|
||||
if (!(rd32(IGC_MANC) & IGC_MANC_RCV_TCO_EN))
|
||||
return;
|
||||
|
||||
/* Disable all Rx queues */
|
||||
for (i = 0; i < 4; i++) {
|
||||
rxdctl[i] = rd32(IGC_RXDCTL(i));
|
||||
wr32(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++) {
|
||||
usleep_range(1000, 2000);
|
||||
rx_enabled = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
rx_enabled |= rd32(IGC_RXDCTL(i));
|
||||
if (!(rx_enabled & IGC_RXDCTL_QUEUE_ENABLE))
|
||||
break;
|
||||
}
|
||||
|
||||
if (ms_wait == 10)
|
||||
hw_dbg("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
|
||||
*/
|
||||
wr32(IGC_RFCTL, rfctl & ~IGC_RFCTL_LEF);
|
||||
|
||||
rlpml = rd32(IGC_RLPML);
|
||||
wr32(IGC_RLPML, 0);
|
||||
|
||||
rctl = rd32(IGC_RCTL);
|
||||
temp_rctl = rctl & ~(IGC_RCTL_EN | IGC_RCTL_SBP);
|
||||
temp_rctl |= IGC_RCTL_LPE;
|
||||
|
||||
wr32(IGC_RCTL, temp_rctl);
|
||||
wr32(IGC_RCTL, temp_rctl | IGC_RCTL_EN);
|
||||
wrfl();
|
||||
usleep_range(2000, 3000);
|
||||
|
||||
/* Enable Rx queues that were previously enabled and restore our
|
||||
* previous state
|
||||
*/
|
||||
for (i = 0; i < 4; i++)
|
||||
wr32(IGC_RXDCTL(i), rxdctl[i]);
|
||||
wr32(IGC_RCTL, rctl);
|
||||
wrfl();
|
||||
|
||||
wr32(IGC_RLPML, rlpml);
|
||||
wr32(IGC_RFCTL, rfctl);
|
||||
|
||||
/* Flush receive errors generated by workaround */
|
||||
rd32(IGC_ROC);
|
||||
rd32(IGC_RNBC);
|
||||
rd32(IGC_MPC);
|
||||
}
|
||||
|
||||
bool igc_is_device_id_i225(struct igc_hw *hw)
|
||||
{
|
||||
switch (hw->device_id) {
|
||||
case IGC_DEV_ID_I225_LM:
|
||||
case IGC_DEV_ID_I225_V:
|
||||
case IGC_DEV_ID_I225_I:
|
||||
case IGC_DEV_ID_I225_K:
|
||||
case IGC_DEV_ID_I225_K2:
|
||||
case IGC_DEV_ID_I225_LMVP:
|
||||
case IGC_DEV_ID_I225_IT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool igc_is_device_id_i226(struct igc_hw *hw)
|
||||
{
|
||||
switch (hw->device_id) {
|
||||
case IGC_DEV_ID_I226_LM:
|
||||
case IGC_DEV_ID_I226_V:
|
||||
case IGC_DEV_ID_I226_K:
|
||||
case IGC_DEV_ID_I226_IT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static struct igc_mac_operations igc_mac_ops_base = {
|
||||
.init_hw = igc_init_hw_base,
|
||||
.check_for_link = igc_check_for_copper_link,
|
||||
.rar_set = igc_rar_set,
|
||||
.read_mac_addr = igc_read_mac_addr,
|
||||
.get_speed_and_duplex = igc_get_speed_and_duplex_copper,
|
||||
};
|
||||
|
||||
static const struct igc_phy_operations igc_phy_ops_base = {
|
||||
.acquire = igc_acquire_phy_base,
|
||||
.release = igc_release_phy_base,
|
||||
.reset = igc_phy_hw_reset,
|
||||
.read_reg = igc_read_phy_reg_gpy,
|
||||
.write_reg = igc_write_phy_reg_gpy,
|
||||
};
|
||||
|
||||
const struct igc_info igc_base_info = {
|
||||
.get_invariants = igc_get_invariants_base,
|
||||
.mac_ops = &igc_mac_ops_base,
|
||||
.phy_ops = &igc_phy_ops_base,
|
||||
};
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_BASE_H_
|
||||
#define _IGC_BASE_H_
|
||||
|
||||
/* forward declaration */
|
||||
void igc_rx_fifo_flush_base(struct igc_hw *hw);
|
||||
void igc_power_down_phy_copper_base(struct igc_hw *hw);
|
||||
bool igc_is_device_id_i225(struct igc_hw *hw);
|
||||
bool igc_is_device_id_i226(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;
|
||||
__le32 launch_time;
|
||||
__le32 type_tucmd_mlhl;
|
||||
__le32 mss_l4len_idx;
|
||||
};
|
||||
|
||||
/* Adv Transmit Descriptor Config Masks */
|
||||
#define IGC_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp packet */
|
||||
#define IGC_ADVTXD_TSTAMP_REG_1 0x00010000 /* Select register 1 for timestamp */
|
||||
#define IGC_ADVTXD_TSTAMP_REG_2 0x00020000 /* Select register 2 for timestamp */
|
||||
#define IGC_ADVTXD_TSTAMP_REG_3 0x00030000 /* Select register 3 for timestamp */
|
||||
#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_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_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
|
||||
|
||||
#define IGC_RAR_ENTRIES 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 */
|
||||
#define IGC_TXDCTL_SWFLUSH 0x04000000 /* Transmit Software Flush */
|
||||
|
||||
/* Additional Receive Descriptor Control definitions */
|
||||
#define IGC_RXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Rx Queue */
|
||||
#define IGC_RXDCTL_SWFLUSH 0x04000000 /* Receive Software Flush */
|
||||
|
||||
/* SRRCTL bit definitions */
|
||||
#define IGC_SRRCTL_BSIZEPKT_MASK GENMASK(6, 0)
|
||||
#define IGC_SRRCTL_BSIZEPKT(x) FIELD_PREP(IGC_SRRCTL_BSIZEPKT_MASK, \
|
||||
(x) / 1024) /* in 1 KB resolution */
|
||||
#define IGC_SRRCTL_BSIZEHDR_MASK GENMASK(13, 8)
|
||||
#define IGC_SRRCTL_BSIZEHDR(x) FIELD_PREP(IGC_SRRCTL_BSIZEHDR_MASK, \
|
||||
(x) / 64) /* in 64 bytes resolution */
|
||||
#define IGC_SRRCTL_DESCTYPE_MASK GENMASK(27, 25)
|
||||
#define IGC_SRRCTL_DESCTYPE_ADV_ONEBUF FIELD_PREP(IGC_SRRCTL_DESCTYPE_MASK, 1)
|
||||
|
||||
#endif /* _IGC_BASE_H */
|
||||
|
|
@ -0,0 +1,680 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_DEFINES_H_
|
||||
#define _IGC_DEFINES_H_
|
||||
|
||||
/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
|
||||
#define REQ_TX_DESCRIPTOR_MULTIPLE 8
|
||||
#define REQ_RX_DESCRIPTOR_MULTIPLE 8
|
||||
|
||||
#define IGC_CTRL_EXT_SDP2_DIR 0x00000400 /* SDP2 Data direction */
|
||||
#define IGC_CTRL_EXT_SDP3_DIR 0x00000800 /* SDP3 Data direction */
|
||||
#define IGC_CTRL_EXT_DRV_LOAD 0x10000000 /* Drv loaded bit for FW */
|
||||
|
||||
/* Definitions for power management and wakeup registers */
|
||||
/* Wake Up Control */
|
||||
#define IGC_WUC_PME_EN 0x00000002 /* PME Enable */
|
||||
|
||||
/* Wake Up Filter Control */
|
||||
#define IGC_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
|
||||
#define IGC_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */
|
||||
#define IGC_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */
|
||||
#define IGC_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */
|
||||
#define IGC_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
|
||||
#define IGC_WUFC_FLEX_HQ BIT(14) /* Flex Filters Host Queuing */
|
||||
#define IGC_WUFC_FLX0 BIT(16) /* Flexible Filter 0 Enable */
|
||||
#define IGC_WUFC_FLX1 BIT(17) /* Flexible Filter 1 Enable */
|
||||
#define IGC_WUFC_FLX2 BIT(18) /* Flexible Filter 2 Enable */
|
||||
#define IGC_WUFC_FLX3 BIT(19) /* Flexible Filter 3 Enable */
|
||||
#define IGC_WUFC_FLX4 BIT(20) /* Flexible Filter 4 Enable */
|
||||
#define IGC_WUFC_FLX5 BIT(21) /* Flexible Filter 5 Enable */
|
||||
#define IGC_WUFC_FLX6 BIT(22) /* Flexible Filter 6 Enable */
|
||||
#define IGC_WUFC_FLX7 BIT(23) /* Flexible Filter 7 Enable */
|
||||
|
||||
#define IGC_WUFC_FILTER_MASK GENMASK(23, 14)
|
||||
|
||||
#define IGC_CTRL_ADVD3WUC 0x00100000 /* D3 WUC */
|
||||
|
||||
/* Wake Up Status */
|
||||
#define IGC_WUS_EX 0x00000004 /* Directed Exact */
|
||||
#define IGC_WUS_ARPD 0x00000020 /* Directed ARP Request */
|
||||
#define IGC_WUS_IPV4 0x00000040 /* Directed IPv4 */
|
||||
#define IGC_WUS_IPV6 0x00000080 /* Directed IPv6 */
|
||||
#define IGC_WUS_NSD 0x00000400 /* Directed IPv6 Neighbor Solicitation */
|
||||
|
||||
/* Packet types that are enabled for wake packet delivery */
|
||||
#define WAKE_PKT_WUS ( \
|
||||
IGC_WUS_EX | \
|
||||
IGC_WUS_ARPD | \
|
||||
IGC_WUS_IPV4 | \
|
||||
IGC_WUS_IPV6 | \
|
||||
IGC_WUS_NSD)
|
||||
|
||||
/* Wake Up Packet Length */
|
||||
#define IGC_WUPL_MASK 0x00000FFF
|
||||
|
||||
/* Wake Up Packet Memory stores the first 128 bytes of the wake up packet */
|
||||
#define IGC_WUPM_BYTES 128
|
||||
|
||||
/* Wakeup Filter Control Extended */
|
||||
#define IGC_WUFC_EXT_FLX8 BIT(8) /* Flexible Filter 8 Enable */
|
||||
#define IGC_WUFC_EXT_FLX9 BIT(9) /* Flexible Filter 9 Enable */
|
||||
#define IGC_WUFC_EXT_FLX10 BIT(10) /* Flexible Filter 10 Enable */
|
||||
#define IGC_WUFC_EXT_FLX11 BIT(11) /* Flexible Filter 11 Enable */
|
||||
#define IGC_WUFC_EXT_FLX12 BIT(12) /* Flexible Filter 12 Enable */
|
||||
#define IGC_WUFC_EXT_FLX13 BIT(13) /* Flexible Filter 13 Enable */
|
||||
#define IGC_WUFC_EXT_FLX14 BIT(14) /* Flexible Filter 14 Enable */
|
||||
#define IGC_WUFC_EXT_FLX15 BIT(15) /* Flexible Filter 15 Enable */
|
||||
#define IGC_WUFC_EXT_FLX16 BIT(16) /* Flexible Filter 16 Enable */
|
||||
#define IGC_WUFC_EXT_FLX17 BIT(17) /* Flexible Filter 17 Enable */
|
||||
#define IGC_WUFC_EXT_FLX18 BIT(18) /* Flexible Filter 18 Enable */
|
||||
#define IGC_WUFC_EXT_FLX19 BIT(19) /* Flexible Filter 19 Enable */
|
||||
#define IGC_WUFC_EXT_FLX20 BIT(20) /* Flexible Filter 20 Enable */
|
||||
#define IGC_WUFC_EXT_FLX21 BIT(21) /* Flexible Filter 21 Enable */
|
||||
#define IGC_WUFC_EXT_FLX22 BIT(22) /* Flexible Filter 22 Enable */
|
||||
#define IGC_WUFC_EXT_FLX23 BIT(23) /* Flexible Filter 23 Enable */
|
||||
#define IGC_WUFC_EXT_FLX24 BIT(24) /* Flexible Filter 24 Enable */
|
||||
#define IGC_WUFC_EXT_FLX25 BIT(25) /* Flexible Filter 25 Enable */
|
||||
#define IGC_WUFC_EXT_FLX26 BIT(26) /* Flexible Filter 26 Enable */
|
||||
#define IGC_WUFC_EXT_FLX27 BIT(27) /* Flexible Filter 27 Enable */
|
||||
#define IGC_WUFC_EXT_FLX28 BIT(28) /* Flexible Filter 28 Enable */
|
||||
#define IGC_WUFC_EXT_FLX29 BIT(29) /* Flexible Filter 29 Enable */
|
||||
#define IGC_WUFC_EXT_FLX30 BIT(30) /* Flexible Filter 30 Enable */
|
||||
#define IGC_WUFC_EXT_FLX31 BIT(31) /* Flexible Filter 31 Enable */
|
||||
|
||||
#define IGC_WUFC_EXT_FILTER_MASK GENMASK(31, 8)
|
||||
|
||||
/* Loop limit on how long we wait for auto-negotiation to complete */
|
||||
#define COPPER_LINK_UP_LIMIT 10
|
||||
#define PHY_AUTO_NEG_LIMIT 45
|
||||
|
||||
/* Number of 100 microseconds we wait for PCI Express master disable */
|
||||
#define MASTER_DISABLE_TIMEOUT 800
|
||||
/*Blocks new Master requests */
|
||||
#define IGC_CTRL_GIO_MASTER_DISABLE 0x00000004
|
||||
/* Status of Master requests. */
|
||||
#define IGC_STATUS_GIO_MASTER_ENABLE 0x00080000
|
||||
|
||||
/* Receive Address
|
||||
* Number of high/low register pairs in the RAR. The RAR (Receive Address
|
||||
* Registers) holds the directed and multicast addresses that we monitor.
|
||||
* Technically, we have 16 spots. However, we reserve one of these spots
|
||||
* (RAR[15]) for our directed address used by controllers with
|
||||
* manageability enabled, allowing us room for 15 multicast addresses.
|
||||
*/
|
||||
#define IGC_RAH_RAH_MASK 0x0000FFFF
|
||||
#define IGC_RAH_ASEL_MASK 0x00030000
|
||||
#define IGC_RAH_ASEL_SRC_ADDR BIT(16)
|
||||
#define IGC_RAH_QSEL_MASK 0x000C0000
|
||||
#define IGC_RAH_QSEL_SHIFT 18
|
||||
#define IGC_RAH_QSEL_ENABLE BIT(28)
|
||||
#define IGC_RAH_AV 0x80000000 /* Receive descriptor valid */
|
||||
|
||||
#define IGC_RAL_MAC_ADDR_LEN 4
|
||||
#define IGC_RAH_MAC_ADDR_LEN 2
|
||||
|
||||
/* Error Codes */
|
||||
#define IGC_SUCCESS 0
|
||||
#define IGC_ERR_NVM 1
|
||||
#define IGC_ERR_PHY 2
|
||||
#define IGC_ERR_CONFIG 3
|
||||
#define IGC_ERR_PARAM 4
|
||||
#define IGC_ERR_MAC_INIT 5
|
||||
#define IGC_ERR_RESET 9
|
||||
#define IGC_ERR_MASTER_REQUESTS_PENDING 10
|
||||
#define IGC_ERR_BLK_PHY_RESET 12
|
||||
#define IGC_ERR_SWFW_SYNC 13
|
||||
|
||||
/* Device Control */
|
||||
#define IGC_CTRL_RST 0x04000000 /* Global reset */
|
||||
|
||||
#define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */
|
||||
#define IGC_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
|
||||
#define IGC_CTRL_FRCSPD 0x00000800 /* Force Speed */
|
||||
#define IGC_CTRL_FRCDPX 0x00001000 /* Force Duplex */
|
||||
#define IGC_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
|
||||
|
||||
#define IGC_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
|
||||
#define IGC_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
|
||||
|
||||
#define IGC_CTRL_SDP0_DIR 0x00400000 /* SDP0 Data direction */
|
||||
#define IGC_CTRL_SDP1_DIR 0x00800000 /* SDP1 Data direction */
|
||||
|
||||
/* As per the EAS the maximum supported size is 9.5KB (9728 bytes) */
|
||||
#define MAX_JUMBO_FRAME_SIZE 0x2600
|
||||
|
||||
/* PBA constants */
|
||||
#define IGC_PBA_34K 0x0022
|
||||
|
||||
/* SW Semaphore Register */
|
||||
#define IGC_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
|
||||
#define IGC_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
|
||||
|
||||
/* SWFW_SYNC Definitions */
|
||||
#define IGC_SWFW_EEP_SM 0x1
|
||||
#define IGC_SWFW_PHY0_SM 0x2
|
||||
|
||||
/* Autoneg Advertisement Register */
|
||||
#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
|
||||
#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
|
||||
#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
|
||||
#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
|
||||
#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
|
||||
#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
|
||||
|
||||
/* Link Partner Ability Register (Base Page) */
|
||||
#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
|
||||
#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
|
||||
|
||||
/* 1000BASE-T Control Register */
|
||||
#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
|
||||
#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
|
||||
|
||||
/* 1000BASE-T Status Register */
|
||||
#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
|
||||
|
||||
/* PHY GPY 211 registers */
|
||||
#define STANDARD_AN_REG_MASK 0x0007 /* MMD */
|
||||
#define ANEG_MULTIGBT_AN_CTRL 0x0020 /* MULTI GBT AN Control Register */
|
||||
#define MMD_DEVADDR_SHIFT 16 /* Shift MMD to higher bits */
|
||||
#define CR_2500T_FD_CAPS 0x0080 /* Advertise 2500T FD capability */
|
||||
|
||||
/* NVM Control */
|
||||
/* Number of milliseconds for NVM auto read done after MAC reset. */
|
||||
#define AUTO_READ_DONE_TIMEOUT 10
|
||||
#define IGC_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */
|
||||
#define IGC_EECD_REQ 0x00000040 /* NVM Access Request */
|
||||
#define IGC_EECD_GNT 0x00000080 /* NVM Access Grant */
|
||||
/* NVM Addressing bits based on type 0=small, 1=large */
|
||||
#define IGC_EECD_ADDR_BITS 0x00000400
|
||||
#define IGC_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */
|
||||
#define IGC_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */
|
||||
#define IGC_EECD_SIZE_EX_SHIFT 11
|
||||
#define IGC_EECD_FLUPD_I225 0x00800000 /* Update FLASH */
|
||||
#define IGC_EECD_FLUDONE_I225 0x04000000 /* Update FLASH done*/
|
||||
#define IGC_EECD_FLASH_DETECTED_I225 0x00080000 /* FLASH detected */
|
||||
#define IGC_FLUDONE_ATTEMPTS 20000
|
||||
#define IGC_EERD_EEWR_MAX_COUNT 512 /* buffered EEPROM words rw */
|
||||
|
||||
/* Offset to data in NVM read/write registers */
|
||||
#define IGC_NVM_RW_REG_DATA 16
|
||||
#define IGC_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */
|
||||
#define IGC_NVM_RW_REG_START 1 /* Start operation */
|
||||
#define IGC_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */
|
||||
#define IGC_NVM_POLL_READ 0 /* Flag for polling for read complete */
|
||||
#define IGC_NVM_DEV_STARTER 5 /* Dev_starter Version */
|
||||
|
||||
/* NVM Word Offsets */
|
||||
#define NVM_CHECKSUM_REG 0x003F
|
||||
|
||||
/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
|
||||
#define NVM_SUM 0xBABA
|
||||
#define NVM_WORD_SIZE_BASE_SHIFT 6
|
||||
|
||||
/* Collision related configuration parameters */
|
||||
#define IGC_COLLISION_THRESHOLD 15
|
||||
#define IGC_CT_SHIFT 4
|
||||
#define IGC_COLLISION_DISTANCE 63
|
||||
#define IGC_COLD_SHIFT 12
|
||||
|
||||
/* Device Status */
|
||||
#define IGC_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
|
||||
#define IGC_STATUS_LU 0x00000002 /* Link up.0=no,1=link */
|
||||
#define IGC_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */
|
||||
#define IGC_STATUS_FUNC_SHIFT 2
|
||||
#define IGC_STATUS_TXOFF 0x00000010 /* transmission paused */
|
||||
#define IGC_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
|
||||
#define IGC_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
|
||||
#define IGC_STATUS_SPEED_2500 0x00400000 /* Speed 2.5Gb/s */
|
||||
|
||||
#define SPEED_10 10
|
||||
#define SPEED_100 100
|
||||
#define SPEED_1000 1000
|
||||
#define SPEED_2500 2500
|
||||
#define HALF_DUPLEX 1
|
||||
#define FULL_DUPLEX 2
|
||||
|
||||
/* 1Gbps and 2.5Gbps half duplex is not supported, nor spec-compliant. */
|
||||
#define ADVERTISE_10_HALF 0x0001
|
||||
#define ADVERTISE_10_FULL 0x0002
|
||||
#define ADVERTISE_100_HALF 0x0004
|
||||
#define ADVERTISE_100_FULL 0x0008
|
||||
#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */
|
||||
#define ADVERTISE_1000_FULL 0x0020
|
||||
#define ADVERTISE_2500_HALF 0x0040 /* Not used, just FYI */
|
||||
#define ADVERTISE_2500_FULL 0x0080
|
||||
|
||||
#define IGC_ALL_SPEED_DUPLEX_2500 ( \
|
||||
ADVERTISE_10_HALF | ADVERTISE_10_FULL | ADVERTISE_100_HALF | \
|
||||
ADVERTISE_100_FULL | ADVERTISE_1000_FULL | ADVERTISE_2500_FULL)
|
||||
|
||||
#define AUTONEG_ADVERTISE_SPEED_DEFAULT_2500 IGC_ALL_SPEED_DUPLEX_2500
|
||||
|
||||
/* Interrupt Cause Read */
|
||||
#define IGC_ICR_TXDW BIT(0) /* Transmit desc written back */
|
||||
#define IGC_ICR_TXQE BIT(1) /* Transmit Queue empty */
|
||||
#define IGC_ICR_LSC BIT(2) /* Link Status Change */
|
||||
#define IGC_ICR_RXSEQ BIT(3) /* Rx sequence error */
|
||||
#define IGC_ICR_RXDMT0 BIT(4) /* Rx desc min. threshold (0) */
|
||||
#define IGC_ICR_RXO BIT(6) /* Rx overrun */
|
||||
#define IGC_ICR_RXT0 BIT(7) /* Rx timer intr (ring 0) */
|
||||
#define IGC_ICR_TS BIT(19) /* Time Sync Interrupt */
|
||||
#define IGC_ICR_DRSTA BIT(30) /* Device Reset Asserted */
|
||||
|
||||
/* If this bit asserted, the driver should claim the interrupt */
|
||||
#define IGC_ICR_INT_ASSERTED BIT(31)
|
||||
|
||||
#define IGC_ICS_RXT0 IGC_ICR_RXT0 /* Rx timer intr */
|
||||
|
||||
#define IMS_ENABLE_MASK ( \
|
||||
IGC_IMS_RXT0 | \
|
||||
IGC_IMS_TXDW | \
|
||||
IGC_IMS_RXDMT0 | \
|
||||
IGC_IMS_RXSEQ | \
|
||||
IGC_IMS_LSC)
|
||||
|
||||
/* Interrupt Mask Set */
|
||||
#define IGC_IMS_TXDW IGC_ICR_TXDW /* Tx desc written back */
|
||||
#define IGC_IMS_RXSEQ IGC_ICR_RXSEQ /* Rx sequence error */
|
||||
#define IGC_IMS_LSC IGC_ICR_LSC /* Link Status Change */
|
||||
#define IGC_IMS_DOUTSYNC IGC_ICR_DOUTSYNC /* NIC DMA out of sync */
|
||||
#define IGC_IMS_DRSTA IGC_ICR_DRSTA /* Device Reset Asserted */
|
||||
#define IGC_IMS_RXT0 IGC_ICR_RXT0 /* Rx timer intr */
|
||||
#define IGC_IMS_RXDMT0 IGC_ICR_RXDMT0 /* Rx desc min. threshold */
|
||||
#define IGC_IMS_TS IGC_ICR_TS /* Time Sync Interrupt */
|
||||
|
||||
#define IGC_QVECTOR_MASK 0x7FFC /* Q-vector mask */
|
||||
#define IGC_ITR_VAL_MASK 0x04 /* ITR value mask */
|
||||
|
||||
/* Interrupt Cause Set */
|
||||
#define IGC_ICS_LSC IGC_ICR_LSC /* Link Status Change */
|
||||
#define IGC_ICS_RXDMT0 IGC_ICR_RXDMT0 /* rx desc min. threshold */
|
||||
|
||||
#define IGC_ICR_DOUTSYNC 0x10000000 /* NIC DMA out of sync */
|
||||
#define IGC_EITR_CNT_IGNR 0x80000000 /* Don't reset counters on write */
|
||||
#define IGC_IVAR_VALID 0x80
|
||||
#define IGC_GPIE_NSICR 0x00000001
|
||||
#define IGC_GPIE_MSIX_MODE 0x00000010
|
||||
#define IGC_GPIE_EIAME 0x40000000
|
||||
#define IGC_GPIE_PBA 0x80000000
|
||||
|
||||
/* Receive Descriptor bit definitions */
|
||||
#define IGC_RXD_STAT_DD 0x01 /* Descriptor Done */
|
||||
|
||||
/* Transmit Descriptor bit definitions */
|
||||
#define IGC_TXD_DTYP_D 0x00100000 /* Data Descriptor */
|
||||
#define IGC_TXD_DTYP_C 0x00000000 /* Context Descriptor */
|
||||
#define IGC_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
|
||||
#define IGC_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
|
||||
#define IGC_TXD_CMD_EOP 0x01000000 /* End of Packet */
|
||||
#define IGC_TXD_CMD_IC 0x04000000 /* Insert Checksum */
|
||||
#define IGC_TXD_CMD_DEXT 0x20000000 /* Desc extension (0 = legacy) */
|
||||
#define IGC_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
|
||||
#define IGC_TXD_STAT_DD 0x00000001 /* Descriptor Done */
|
||||
#define IGC_TXD_CMD_TCP 0x01000000 /* TCP packet */
|
||||
#define IGC_TXD_CMD_IP 0x02000000 /* IP packet */
|
||||
#define IGC_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
|
||||
#define IGC_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */
|
||||
|
||||
/* IPSec Encrypt Enable */
|
||||
#define IGC_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
|
||||
#define IGC_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
|
||||
|
||||
#define IGC_ADVTXD_TSN_CNTX_FIRST 0x00000080
|
||||
|
||||
/* Transmit Control */
|
||||
#define IGC_TCTL_EN 0x00000002 /* enable Tx */
|
||||
#define IGC_TCTL_PSP 0x00000008 /* pad short packets */
|
||||
#define IGC_TCTL_CT 0x00000ff0 /* collision threshold */
|
||||
#define IGC_TCTL_COLD 0x003ff000 /* collision distance */
|
||||
#define IGC_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
|
||||
|
||||
/* Flow Control Constants */
|
||||
#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001
|
||||
#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
|
||||
#define FLOW_CONTROL_TYPE 0x8808
|
||||
/* Enable XON frame transmission */
|
||||
#define IGC_FCRTL_XONE 0x80000000
|
||||
|
||||
/* Management Control */
|
||||
#define IGC_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */
|
||||
#define IGC_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */
|
||||
|
||||
/* Receive Control */
|
||||
#define IGC_RCTL_RST 0x00000001 /* Software reset */
|
||||
#define IGC_RCTL_EN 0x00000002 /* enable */
|
||||
#define IGC_RCTL_SBP 0x00000004 /* store bad packet */
|
||||
#define IGC_RCTL_UPE 0x00000008 /* unicast promisc enable */
|
||||
#define IGC_RCTL_MPE 0x00000010 /* multicast promisc enable */
|
||||
#define IGC_RCTL_LPE 0x00000020 /* long packet enable */
|
||||
#define IGC_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */
|
||||
#define IGC_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */
|
||||
|
||||
#define IGC_RCTL_RDMTS_HALF 0x00000000 /* Rx desc min thresh size */
|
||||
#define IGC_RCTL_BAM 0x00008000 /* broadcast enable */
|
||||
|
||||
/* Split Replication Receive Control */
|
||||
#define IGC_SRRCTL_TIMESTAMP 0x40000000
|
||||
#define IGC_SRRCTL_TIMER1SEL(timer) (((timer) & 0x3) << 14)
|
||||
#define IGC_SRRCTL_TIMER0SEL(timer) (((timer) & 0x3) << 17)
|
||||
|
||||
/* Receive Descriptor bit definitions */
|
||||
#define IGC_RXD_STAT_EOP 0x02 /* End of Packet */
|
||||
#define IGC_RXD_STAT_IXSM 0x04 /* Ignore checksum */
|
||||
#define IGC_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */
|
||||
#define IGC_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */
|
||||
#define IGC_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
|
||||
|
||||
#define IGC_RXDEXT_STATERR_LB 0x00040000
|
||||
|
||||
/* Advanced Receive Descriptor bit definitions */
|
||||
#define IGC_RXDADV_STAT_TSIP 0x08000 /* timestamp in packet */
|
||||
|
||||
#define IGC_RXDEXT_STATERR_L4E 0x20000000
|
||||
#define IGC_RXDEXT_STATERR_IPE 0x40000000
|
||||
#define IGC_RXDEXT_STATERR_RXE 0x80000000
|
||||
|
||||
#define IGC_MRQC_RSS_FIELD_IPV4_TCP 0x00010000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV4 0x00020000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6 0x00100000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6_TCP 0x00200000
|
||||
|
||||
/* Header split receive */
|
||||
#define IGC_RFCTL_IPV6_EX_DIS 0x00010000
|
||||
#define IGC_RFCTL_LEF 0x00040000
|
||||
|
||||
#define IGC_RCTL_SZ_256 0x00030000 /* Rx buffer size 256 */
|
||||
|
||||
#define IGC_RCTL_MO_SHIFT 12 /* multicast offset shift */
|
||||
#define IGC_RCTL_CFIEN 0x00080000 /* canonical form enable */
|
||||
#define IGC_RCTL_DPF 0x00400000 /* discard pause frames */
|
||||
#define IGC_RCTL_PMCF 0x00800000 /* pass MAC control frames */
|
||||
#define IGC_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
|
||||
|
||||
#define I225_RXPBSIZE_DEFAULT 0x000000A2 /* RXPBSIZE default */
|
||||
#define I225_TXPBSIZE_DEFAULT 0x04000014 /* TXPBSIZE default */
|
||||
#define IGC_RXPBS_CFG_TS_EN 0x80000000 /* Timestamp in Rx buffer */
|
||||
|
||||
#define IGC_TXPBSIZE_TSN 0x04145145 /* 5k bytes buffer for each queue */
|
||||
|
||||
#define IGC_DTXMXPKTSZ_TSN 0x19 /* 1600 bytes of max TX DMA packet size */
|
||||
#define IGC_DTXMXPKTSZ_DEFAULT 0x98 /* 9728-byte Jumbo frames */
|
||||
|
||||
/* Transmit Scheduling Latency */
|
||||
/* Latency between transmission scheduling (LaunchTime) and the time
|
||||
* the packet is transmitted to the network in nanosecond.
|
||||
*/
|
||||
#define IGC_TXOFFSET_SPEED_10 0x000034BC
|
||||
#define IGC_TXOFFSET_SPEED_100 0x00000578
|
||||
#define IGC_TXOFFSET_SPEED_1000 0x0000012C
|
||||
#define IGC_TXOFFSET_SPEED_2500 0x00000578
|
||||
|
||||
/* Time Sync Interrupt Causes */
|
||||
#define IGC_TSICR_SYS_WRAP BIT(0) /* SYSTIM Wrap around. */
|
||||
#define IGC_TSICR_TXTS BIT(1) /* Transmit Timestamp. */
|
||||
#define IGC_TSICR_TT0 BIT(3) /* Target Time 0 Trigger. */
|
||||
#define IGC_TSICR_TT1 BIT(4) /* Target Time 1 Trigger. */
|
||||
#define IGC_TSICR_AUTT0 BIT(5) /* Auxiliary Timestamp 0 Taken. */
|
||||
#define IGC_TSICR_AUTT1 BIT(6) /* Auxiliary Timestamp 1 Taken. */
|
||||
|
||||
#define IGC_TSICR_INTERRUPTS IGC_TSICR_TXTS
|
||||
|
||||
#define IGC_FTQF_VF_BP 0x00008000
|
||||
#define IGC_FTQF_1588_TIME_STAMP 0x08000000
|
||||
#define IGC_FTQF_MASK 0xF0000000
|
||||
#define IGC_FTQF_MASK_PROTO_BP 0x10000000
|
||||
|
||||
/* Time Sync Receive Control bit definitions */
|
||||
#define IGC_TSYNCRXCTL_TYPE_MASK 0x0000000E /* Rx type mask */
|
||||
#define IGC_TSYNCRXCTL_TYPE_L2_V2 0x00
|
||||
#define IGC_TSYNCRXCTL_TYPE_L4_V1 0x02
|
||||
#define IGC_TSYNCRXCTL_TYPE_L2_L4_V2 0x04
|
||||
#define IGC_TSYNCRXCTL_TYPE_ALL 0x08
|
||||
#define IGC_TSYNCRXCTL_TYPE_EVENT_V2 0x0A
|
||||
#define IGC_TSYNCRXCTL_ENABLED 0x00000010 /* enable Rx timestamping */
|
||||
#define IGC_TSYNCRXCTL_SYSCFI 0x00000020 /* Sys clock frequency */
|
||||
#define IGC_TSYNCRXCTL_RXSYNSIG 0x00000400 /* Sample RX tstamp in PHY sop */
|
||||
|
||||
/* Time Sync Receive Configuration */
|
||||
#define IGC_TSYNCRXCFG_PTP_V1_CTRLT_MASK 0x000000FF
|
||||
#define IGC_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE 0x00
|
||||
#define IGC_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE 0x01
|
||||
|
||||
/* Immediate Interrupt Receive */
|
||||
#define IGC_IMIR_CLEAR_MASK 0xF001FFFF /* IMIR Reg Clear Mask */
|
||||
#define IGC_IMIR_PORT_BYPASS 0x20000 /* IMIR Port Bypass Bit */
|
||||
#define IGC_IMIR_PRIORITY_SHIFT 29 /* IMIR Priority Shift */
|
||||
#define IGC_IMIREXT_CLEAR_MASK 0x7FFFF /* IMIREXT Reg Clear Mask */
|
||||
|
||||
/* Immediate Interrupt Receive Extended */
|
||||
#define IGC_IMIREXT_CTRL_BP 0x00080000 /* Bypass check of ctrl bits */
|
||||
#define IGC_IMIREXT_SIZE_BP 0x00001000 /* Packet size bypass */
|
||||
|
||||
/* Time Sync Transmit Control bit definitions */
|
||||
#define IGC_TSYNCTXCTL_TXTT_0 0x00000001 /* Tx timestamp reg 0 valid */
|
||||
#define IGC_TSYNCTXCTL_ENABLED 0x00000010 /* enable Tx timestamping */
|
||||
#define IGC_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK 0x0000F000 /* max delay */
|
||||
#define IGC_TSYNCTXCTL_SYNC_COMP_ERR 0x20000000 /* sync err */
|
||||
#define IGC_TSYNCTXCTL_SYNC_COMP 0x40000000 /* sync complete */
|
||||
#define IGC_TSYNCTXCTL_START_SYNC 0x80000000 /* initiate sync */
|
||||
#define IGC_TSYNCTXCTL_TXSYNSIG 0x00000020 /* Sample TX tstamp in PHY sop */
|
||||
|
||||
/* Timer selection bits */
|
||||
#define IGC_AUX_IO_TIMER_SEL_SYSTIM0 (0u << 30) /* Select SYSTIM0 for auxiliary time stamp */
|
||||
#define IGC_AUX_IO_TIMER_SEL_SYSTIM1 (1u << 30) /* Select SYSTIM1 for auxiliary time stamp */
|
||||
#define IGC_AUX_IO_TIMER_SEL_SYSTIM2 (2u << 30) /* Select SYSTIM2 for auxiliary time stamp */
|
||||
#define IGC_AUX_IO_TIMER_SEL_SYSTIM3 (3u << 30) /* Select SYSTIM3 for auxiliary time stamp */
|
||||
#define IGC_TT_IO_TIMER_SEL_SYSTIM0 (0u << 30) /* Select SYSTIM0 for target time stamp */
|
||||
#define IGC_TT_IO_TIMER_SEL_SYSTIM1 (1u << 30) /* Select SYSTIM1 for target time stamp */
|
||||
#define IGC_TT_IO_TIMER_SEL_SYSTIM2 (2u << 30) /* Select SYSTIM2 for target time stamp */
|
||||
#define IGC_TT_IO_TIMER_SEL_SYSTIM3 (3u << 30) /* Select SYSTIM3 for target time stamp */
|
||||
|
||||
/* TSAUXC Configuration Bits */
|
||||
#define IGC_TSAUXC_EN_TT0 BIT(0) /* Enable target time 0. */
|
||||
#define IGC_TSAUXC_EN_TT1 BIT(1) /* Enable target time 1. */
|
||||
#define IGC_TSAUXC_EN_CLK0 BIT(2) /* Enable Configurable Frequency Clock 0. */
|
||||
#define IGC_TSAUXC_ST0 BIT(4) /* Start Clock 0 Toggle on Target Time 0. */
|
||||
#define IGC_TSAUXC_EN_CLK1 BIT(5) /* Enable Configurable Frequency Clock 1. */
|
||||
#define IGC_TSAUXC_ST1 BIT(7) /* Start Clock 1 Toggle on Target Time 1. */
|
||||
#define IGC_TSAUXC_EN_TS0 BIT(8) /* Enable hardware timestamp 0. */
|
||||
#define IGC_TSAUXC_AUTT0 BIT(9) /* Auxiliary Timestamp Taken. */
|
||||
#define IGC_TSAUXC_EN_TS1 BIT(10) /* Enable hardware timestamp 0. */
|
||||
#define IGC_TSAUXC_AUTT1 BIT(11) /* Auxiliary Timestamp Taken. */
|
||||
#define IGC_TSAUXC_PLSG BIT(17) /* Generate a pulse. */
|
||||
#define IGC_TSAUXC_DISABLE1 BIT(27) /* Disable SYSTIM0 Count Operation. */
|
||||
#define IGC_TSAUXC_DISABLE2 BIT(28) /* Disable SYSTIM1 Count Operation. */
|
||||
#define IGC_TSAUXC_DISABLE3 BIT(29) /* Disable SYSTIM2 Count Operation. */
|
||||
#define IGC_TSAUXC_DIS_TS_CLEAR BIT(30) /* Disable EN_TT0/1 auto clear. */
|
||||
#define IGC_TSAUXC_DISABLE0 BIT(31) /* Disable SYSTIM0 Count Operation. */
|
||||
|
||||
/* SDP Configuration Bits */
|
||||
#define IGC_AUX0_SEL_SDP0 (0u << 0) /* Assign SDP0 to auxiliary time stamp 0. */
|
||||
#define IGC_AUX0_SEL_SDP1 (1u << 0) /* Assign SDP1 to auxiliary time stamp 0. */
|
||||
#define IGC_AUX0_SEL_SDP2 (2u << 0) /* Assign SDP2 to auxiliary time stamp 0. */
|
||||
#define IGC_AUX0_SEL_SDP3 (3u << 0) /* Assign SDP3 to auxiliary time stamp 0. */
|
||||
#define IGC_AUX0_TS_SDP_EN (1u << 2) /* Enable auxiliary time stamp trigger 0. */
|
||||
#define IGC_AUX1_SEL_SDP0 (0u << 3) /* Assign SDP0 to auxiliary time stamp 1. */
|
||||
#define IGC_AUX1_SEL_SDP1 (1u << 3) /* Assign SDP1 to auxiliary time stamp 1. */
|
||||
#define IGC_AUX1_SEL_SDP2 (2u << 3) /* Assign SDP2 to auxiliary time stamp 1. */
|
||||
#define IGC_AUX1_SEL_SDP3 (3u << 3) /* Assign SDP3 to auxiliary time stamp 1. */
|
||||
#define IGC_AUX1_TS_SDP_EN (1u << 5) /* Enable auxiliary time stamp trigger 1. */
|
||||
#define IGC_TS_SDP0_SEL_TT0 (0u << 6) /* Target time 0 is output on SDP0. */
|
||||
#define IGC_TS_SDP0_SEL_TT1 (1u << 6) /* Target time 1 is output on SDP0. */
|
||||
#define IGC_TS_SDP0_SEL_FC0 (2u << 6) /* Freq clock 0 is output on SDP0. */
|
||||
#define IGC_TS_SDP0_SEL_FC1 (3u << 6) /* Freq clock 1 is output on SDP0. */
|
||||
#define IGC_TS_SDP0_EN (1u << 8) /* SDP0 is assigned to Tsync. */
|
||||
#define IGC_TS_SDP1_SEL_TT0 (0u << 9) /* Target time 0 is output on SDP1. */
|
||||
#define IGC_TS_SDP1_SEL_TT1 (1u << 9) /* Target time 1 is output on SDP1. */
|
||||
#define IGC_TS_SDP1_SEL_FC0 (2u << 9) /* Freq clock 0 is output on SDP1. */
|
||||
#define IGC_TS_SDP1_SEL_FC1 (3u << 9) /* Freq clock 1 is output on SDP1. */
|
||||
#define IGC_TS_SDP1_EN (1u << 11) /* SDP1 is assigned to Tsync. */
|
||||
#define IGC_TS_SDP2_SEL_TT0 (0u << 12) /* Target time 0 is output on SDP2. */
|
||||
#define IGC_TS_SDP2_SEL_TT1 (1u << 12) /* Target time 1 is output on SDP2. */
|
||||
#define IGC_TS_SDP2_SEL_FC0 (2u << 12) /* Freq clock 0 is output on SDP2. */
|
||||
#define IGC_TS_SDP2_SEL_FC1 (3u << 12) /* Freq clock 1 is output on SDP2. */
|
||||
#define IGC_TS_SDP2_EN (1u << 14) /* SDP2 is assigned to Tsync. */
|
||||
#define IGC_TS_SDP3_SEL_TT0 (0u << 15) /* Target time 0 is output on SDP3. */
|
||||
#define IGC_TS_SDP3_SEL_TT1 (1u << 15) /* Target time 1 is output on SDP3. */
|
||||
#define IGC_TS_SDP3_SEL_FC0 (2u << 15) /* Freq clock 0 is output on SDP3. */
|
||||
#define IGC_TS_SDP3_SEL_FC1 (3u << 15) /* Freq clock 1 is output on SDP3. */
|
||||
#define IGC_TS_SDP3_EN (1u << 17) /* SDP3 is assigned to Tsync. */
|
||||
|
||||
/* Transmit Scheduling */
|
||||
#define IGC_TQAVCTRL_TRANSMIT_MODE_TSN 0x00000001
|
||||
#define IGC_TQAVCTRL_ENHANCED_QAV 0x00000008
|
||||
#define IGC_TQAVCTRL_FUTSCDDIS 0x00000080
|
||||
|
||||
#define IGC_TXQCTL_QUEUE_MODE_LAUNCHT 0x00000001
|
||||
#define IGC_TXQCTL_STRICT_CYCLE 0x00000002
|
||||
#define IGC_TXQCTL_STRICT_END 0x00000004
|
||||
#define IGC_TXQCTL_QAV_SEL_MASK 0x000000C0
|
||||
#define IGC_TXQCTL_QAV_SEL_CBS0 0x00000080
|
||||
#define IGC_TXQCTL_QAV_SEL_CBS1 0x000000C0
|
||||
|
||||
#define IGC_TQAVCC_IDLESLOPE_MASK 0xFFFF
|
||||
#define IGC_TQAVCC_KEEP_CREDITS BIT(30)
|
||||
|
||||
#define IGC_MAX_SR_QUEUES 2
|
||||
|
||||
/* Receive Checksum Control */
|
||||
#define IGC_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */
|
||||
#define IGC_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */
|
||||
|
||||
/* PCIe PTM Control */
|
||||
#define IGC_PTM_CTRL_START_NOW BIT(29) /* Start PTM Now */
|
||||
#define IGC_PTM_CTRL_EN BIT(30) /* Enable PTM */
|
||||
#define IGC_PTM_CTRL_TRIG BIT(31) /* PTM Cycle trigger */
|
||||
#define IGC_PTM_CTRL_SHRT_CYC(usec) (((usec) & 0x2f) << 2)
|
||||
#define IGC_PTM_CTRL_PTM_TO(usec) (((usec) & 0xff) << 8)
|
||||
|
||||
#define IGC_PTM_SHORT_CYC_DEFAULT 10 /* Default Short/interrupted cycle interval */
|
||||
#define IGC_PTM_CYC_TIME_DEFAULT 5 /* Default PTM cycle time */
|
||||
#define IGC_PTM_TIMEOUT_DEFAULT 255 /* Default timeout for PTM errors */
|
||||
|
||||
/* PCIe Digital Delay */
|
||||
#define IGC_PCIE_DIG_DELAY_DEFAULT 0x01440000
|
||||
|
||||
/* PCIe PHY Delay */
|
||||
#define IGC_PCIE_PHY_DELAY_DEFAULT 0x40900000
|
||||
|
||||
#define IGC_TIMADJ_ADJUST_METH 0x40000000
|
||||
|
||||
/* PCIe PTM Status */
|
||||
#define IGC_PTM_STAT_VALID BIT(0) /* PTM Status */
|
||||
#define IGC_PTM_STAT_RET_ERR BIT(1) /* Root port timeout */
|
||||
#define IGC_PTM_STAT_BAD_PTM_RES BIT(2) /* PTM Response msg instead of PTM Response Data */
|
||||
#define IGC_PTM_STAT_T4M1_OVFL BIT(3) /* T4 minus T1 overflow */
|
||||
#define IGC_PTM_STAT_ADJUST_1ST BIT(4) /* 1588 timer adjusted during 1st PTM cycle */
|
||||
#define IGC_PTM_STAT_ADJUST_CYC BIT(5) /* 1588 timer adjusted during non-1st PTM cycle */
|
||||
|
||||
/* PCIe PTM Cycle Control */
|
||||
#define IGC_PTM_CYCLE_CTRL_CYC_TIME(msec) ((msec) & 0x3ff) /* PTM Cycle Time (msec) */
|
||||
#define IGC_PTM_CYCLE_CTRL_AUTO_CYC_EN BIT(31) /* PTM Cycle Control */
|
||||
|
||||
/* GPY211 - I225 defines */
|
||||
#define GPY_MMD_MASK 0xFFFF0000
|
||||
#define GPY_MMD_SHIFT 16
|
||||
#define GPY_REG_MASK 0x0000FFFF
|
||||
|
||||
#define IGC_MMDAC_FUNC_DATA 0x4000 /* Data, no post increment */
|
||||
|
||||
/* MAC definitions */
|
||||
#define IGC_FACTPS_MNGCG 0x20000000
|
||||
#define IGC_FWSM_MODE_MASK 0xE
|
||||
#define IGC_FWSM_MODE_SHIFT 1
|
||||
|
||||
/* Management Control */
|
||||
#define IGC_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */
|
||||
#define IGC_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */
|
||||
|
||||
/* PHY */
|
||||
#define PHY_REVISION_MASK 0xFFFFFFF0
|
||||
#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
|
||||
#define IGC_GEN_POLL_TIMEOUT 1920
|
||||
|
||||
/* PHY Control Register */
|
||||
#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
|
||||
#define MII_CR_POWER_DOWN 0x0800 /* Power down */
|
||||
#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
|
||||
|
||||
/* PHY Status Register */
|
||||
#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
|
||||
#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
|
||||
#define IGC_PHY_RST_COMP 0x0100 /* Internal PHY reset completion */
|
||||
|
||||
/* PHY 1000 MII Register/Bit Definitions */
|
||||
/* PHY Registers defined by IEEE */
|
||||
#define PHY_CONTROL 0x00 /* Control Register */
|
||||
#define PHY_STATUS 0x01 /* Status Register */
|
||||
#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
|
||||
#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
|
||||
#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
|
||||
#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
|
||||
#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
|
||||
#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
|
||||
|
||||
/* MDI Control */
|
||||
#define IGC_MDIC_DATA_MASK 0x0000FFFF
|
||||
#define IGC_MDIC_REG_MASK 0x001F0000
|
||||
#define IGC_MDIC_REG_SHIFT 16
|
||||
#define IGC_MDIC_PHY_MASK 0x03E00000
|
||||
#define IGC_MDIC_PHY_SHIFT 21
|
||||
#define IGC_MDIC_OP_WRITE 0x04000000
|
||||
#define IGC_MDIC_OP_READ 0x08000000
|
||||
#define IGC_MDIC_READY 0x10000000
|
||||
#define IGC_MDIC_ERROR 0x40000000
|
||||
|
||||
#define IGC_N0_QUEUE -1
|
||||
|
||||
#define IGC_MAX_MAC_HDR_LEN 127
|
||||
#define IGC_MAX_NETWORK_HDR_LEN 511
|
||||
|
||||
#define IGC_VLANPQF_QSEL(_n, q_idx) ((q_idx) << ((_n) * 4))
|
||||
#define IGC_VLANPQF_VALID(_n) (0x1 << (3 + (_n) * 4))
|
||||
#define IGC_VLANPQF_QUEUE_MASK 0x03
|
||||
|
||||
#define IGC_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
|
||||
#define IGC_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type:1=IPv4 */
|
||||
#define IGC_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet Type of TCP */
|
||||
#define IGC_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 packet TYPE of SCTP */
|
||||
|
||||
/* Maximum size of the MTA register table in all supported adapters */
|
||||
#define MAX_MTA_REG 128
|
||||
|
||||
/* EEE defines */
|
||||
#define IGC_IPCNFG_EEE_2_5G_AN 0x00000010 /* IPCNFG EEE Ena 2.5G AN */
|
||||
#define IGC_IPCNFG_EEE_1G_AN 0x00000008 /* IPCNFG EEE Ena 1G AN */
|
||||
#define IGC_IPCNFG_EEE_100M_AN 0x00000004 /* IPCNFG EEE Ena 100M AN */
|
||||
#define IGC_EEER_EEE_NEG 0x20000000 /* EEE capability nego */
|
||||
#define IGC_EEER_TX_LPI_EN 0x00010000 /* EEER Tx LPI Enable */
|
||||
#define IGC_EEER_RX_LPI_EN 0x00020000 /* EEER Rx LPI Enable */
|
||||
#define IGC_EEER_LPI_FC 0x00040000 /* EEER Ena on Flow Cntrl */
|
||||
#define IGC_EEE_SU_LPI_CLK_STP 0x00800000 /* EEE LPI Clock Stop */
|
||||
|
||||
/* LTR defines */
|
||||
#define IGC_LTRC_EEEMS_EN 0x00000020 /* Enable EEE LTR max send */
|
||||
#define IGC_RXPBS_SIZE_I225_MASK 0x0000003F /* Rx packet buffer size */
|
||||
#define IGC_TW_SYSTEM_1000_MASK 0x000000FF
|
||||
/* Minimum time for 100BASE-T where no data will be transmit following move out
|
||||
* of EEE LPI Tx state
|
||||
*/
|
||||
#define IGC_TW_SYSTEM_100_MASK 0x0000FF00
|
||||
#define IGC_TW_SYSTEM_100_SHIFT 8
|
||||
/* Reg val to set scale to 1024 nsec */
|
||||
#define IGC_LTRMINV_SCALE_1024 2
|
||||
/* Reg val to set scale to 32768 nsec */
|
||||
#define IGC_LTRMINV_SCALE_32768 3
|
||||
/* Reg val to set scale to 1024 nsec */
|
||||
#define IGC_LTRMAXV_SCALE_1024 2
|
||||
/* Reg val to set scale to 32768 nsec */
|
||||
#define IGC_LTRMAXV_SCALE_32768 3
|
||||
#define IGC_LTRMINV_LTRV_MASK 0x000003FF /* LTR minimum value */
|
||||
#define IGC_LTRMAXV_LTRV_MASK 0x000003FF /* LTR maximum value */
|
||||
#define IGC_LTRMINV_LSNP_REQ 0x00008000 /* LTR Snoop Requirement */
|
||||
#define IGC_LTRMINV_SCALE_SHIFT 10
|
||||
#define IGC_LTRMAXV_LSNP_REQ 0x00008000 /* LTR Snoop Requirement */
|
||||
#define IGC_LTRMAXV_SCALE_SHIFT 10
|
||||
|
||||
#endif /* _IGC_DEFINES_H_ */
|
||||
|
|
@ -0,0 +1,680 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_DEFINES_H_
|
||||
#define _IGC_DEFINES_H_
|
||||
|
||||
/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
|
||||
#define REQ_TX_DESCRIPTOR_MULTIPLE 8
|
||||
#define REQ_RX_DESCRIPTOR_MULTIPLE 8
|
||||
|
||||
#define IGC_CTRL_EXT_SDP2_DIR 0x00000400 /* SDP2 Data direction */
|
||||
#define IGC_CTRL_EXT_SDP3_DIR 0x00000800 /* SDP3 Data direction */
|
||||
#define IGC_CTRL_EXT_DRV_LOAD 0x10000000 /* Drv loaded bit for FW */
|
||||
|
||||
/* Definitions for power management and wakeup registers */
|
||||
/* Wake Up Control */
|
||||
#define IGC_WUC_PME_EN 0x00000002 /* PME Enable */
|
||||
|
||||
/* Wake Up Filter Control */
|
||||
#define IGC_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
|
||||
#define IGC_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */
|
||||
#define IGC_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */
|
||||
#define IGC_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */
|
||||
#define IGC_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
|
||||
#define IGC_WUFC_FLEX_HQ BIT(14) /* Flex Filters Host Queuing */
|
||||
#define IGC_WUFC_FLX0 BIT(16) /* Flexible Filter 0 Enable */
|
||||
#define IGC_WUFC_FLX1 BIT(17) /* Flexible Filter 1 Enable */
|
||||
#define IGC_WUFC_FLX2 BIT(18) /* Flexible Filter 2 Enable */
|
||||
#define IGC_WUFC_FLX3 BIT(19) /* Flexible Filter 3 Enable */
|
||||
#define IGC_WUFC_FLX4 BIT(20) /* Flexible Filter 4 Enable */
|
||||
#define IGC_WUFC_FLX5 BIT(21) /* Flexible Filter 5 Enable */
|
||||
#define IGC_WUFC_FLX6 BIT(22) /* Flexible Filter 6 Enable */
|
||||
#define IGC_WUFC_FLX7 BIT(23) /* Flexible Filter 7 Enable */
|
||||
|
||||
#define IGC_WUFC_FILTER_MASK GENMASK(23, 14)
|
||||
|
||||
#define IGC_CTRL_ADVD3WUC 0x00100000 /* D3 WUC */
|
||||
|
||||
/* Wake Up Status */
|
||||
#define IGC_WUS_EX 0x00000004 /* Directed Exact */
|
||||
#define IGC_WUS_ARPD 0x00000020 /* Directed ARP Request */
|
||||
#define IGC_WUS_IPV4 0x00000040 /* Directed IPv4 */
|
||||
#define IGC_WUS_IPV6 0x00000080 /* Directed IPv6 */
|
||||
#define IGC_WUS_NSD 0x00000400 /* Directed IPv6 Neighbor Solicitation */
|
||||
|
||||
/* Packet types that are enabled for wake packet delivery */
|
||||
#define WAKE_PKT_WUS ( \
|
||||
IGC_WUS_EX | \
|
||||
IGC_WUS_ARPD | \
|
||||
IGC_WUS_IPV4 | \
|
||||
IGC_WUS_IPV6 | \
|
||||
IGC_WUS_NSD)
|
||||
|
||||
/* Wake Up Packet Length */
|
||||
#define IGC_WUPL_MASK 0x00000FFF
|
||||
|
||||
/* Wake Up Packet Memory stores the first 128 bytes of the wake up packet */
|
||||
#define IGC_WUPM_BYTES 128
|
||||
|
||||
/* Wakeup Filter Control Extended */
|
||||
#define IGC_WUFC_EXT_FLX8 BIT(8) /* Flexible Filter 8 Enable */
|
||||
#define IGC_WUFC_EXT_FLX9 BIT(9) /* Flexible Filter 9 Enable */
|
||||
#define IGC_WUFC_EXT_FLX10 BIT(10) /* Flexible Filter 10 Enable */
|
||||
#define IGC_WUFC_EXT_FLX11 BIT(11) /* Flexible Filter 11 Enable */
|
||||
#define IGC_WUFC_EXT_FLX12 BIT(12) /* Flexible Filter 12 Enable */
|
||||
#define IGC_WUFC_EXT_FLX13 BIT(13) /* Flexible Filter 13 Enable */
|
||||
#define IGC_WUFC_EXT_FLX14 BIT(14) /* Flexible Filter 14 Enable */
|
||||
#define IGC_WUFC_EXT_FLX15 BIT(15) /* Flexible Filter 15 Enable */
|
||||
#define IGC_WUFC_EXT_FLX16 BIT(16) /* Flexible Filter 16 Enable */
|
||||
#define IGC_WUFC_EXT_FLX17 BIT(17) /* Flexible Filter 17 Enable */
|
||||
#define IGC_WUFC_EXT_FLX18 BIT(18) /* Flexible Filter 18 Enable */
|
||||
#define IGC_WUFC_EXT_FLX19 BIT(19) /* Flexible Filter 19 Enable */
|
||||
#define IGC_WUFC_EXT_FLX20 BIT(20) /* Flexible Filter 20 Enable */
|
||||
#define IGC_WUFC_EXT_FLX21 BIT(21) /* Flexible Filter 21 Enable */
|
||||
#define IGC_WUFC_EXT_FLX22 BIT(22) /* Flexible Filter 22 Enable */
|
||||
#define IGC_WUFC_EXT_FLX23 BIT(23) /* Flexible Filter 23 Enable */
|
||||
#define IGC_WUFC_EXT_FLX24 BIT(24) /* Flexible Filter 24 Enable */
|
||||
#define IGC_WUFC_EXT_FLX25 BIT(25) /* Flexible Filter 25 Enable */
|
||||
#define IGC_WUFC_EXT_FLX26 BIT(26) /* Flexible Filter 26 Enable */
|
||||
#define IGC_WUFC_EXT_FLX27 BIT(27) /* Flexible Filter 27 Enable */
|
||||
#define IGC_WUFC_EXT_FLX28 BIT(28) /* Flexible Filter 28 Enable */
|
||||
#define IGC_WUFC_EXT_FLX29 BIT(29) /* Flexible Filter 29 Enable */
|
||||
#define IGC_WUFC_EXT_FLX30 BIT(30) /* Flexible Filter 30 Enable */
|
||||
#define IGC_WUFC_EXT_FLX31 BIT(31) /* Flexible Filter 31 Enable */
|
||||
|
||||
#define IGC_WUFC_EXT_FILTER_MASK GENMASK(31, 8)
|
||||
|
||||
/* Loop limit on how long we wait for auto-negotiation to complete */
|
||||
#define COPPER_LINK_UP_LIMIT 10
|
||||
#define PHY_AUTO_NEG_LIMIT 45
|
||||
|
||||
/* Number of 100 microseconds we wait for PCI Express master disable */
|
||||
#define MASTER_DISABLE_TIMEOUT 800
|
||||
/*Blocks new Master requests */
|
||||
#define IGC_CTRL_GIO_MASTER_DISABLE 0x00000004
|
||||
/* Status of Master requests. */
|
||||
#define IGC_STATUS_GIO_MASTER_ENABLE 0x00080000
|
||||
|
||||
/* Receive Address
|
||||
* Number of high/low register pairs in the RAR. The RAR (Receive Address
|
||||
* Registers) holds the directed and multicast addresses that we monitor.
|
||||
* Technically, we have 16 spots. However, we reserve one of these spots
|
||||
* (RAR[15]) for our directed address used by controllers with
|
||||
* manageability enabled, allowing us room for 15 multicast addresses.
|
||||
*/
|
||||
#define IGC_RAH_RAH_MASK 0x0000FFFF
|
||||
#define IGC_RAH_ASEL_MASK 0x00030000
|
||||
#define IGC_RAH_ASEL_SRC_ADDR BIT(16)
|
||||
#define IGC_RAH_QSEL_MASK 0x000C0000
|
||||
#define IGC_RAH_QSEL_SHIFT 18
|
||||
#define IGC_RAH_QSEL_ENABLE BIT(28)
|
||||
#define IGC_RAH_AV 0x80000000 /* Receive descriptor valid */
|
||||
|
||||
#define IGC_RAL_MAC_ADDR_LEN 4
|
||||
#define IGC_RAH_MAC_ADDR_LEN 2
|
||||
|
||||
/* Error Codes */
|
||||
#define IGC_SUCCESS 0
|
||||
#define IGC_ERR_NVM 1
|
||||
#define IGC_ERR_PHY 2
|
||||
#define IGC_ERR_CONFIG 3
|
||||
#define IGC_ERR_PARAM 4
|
||||
#define IGC_ERR_MAC_INIT 5
|
||||
#define IGC_ERR_RESET 9
|
||||
#define IGC_ERR_MASTER_REQUESTS_PENDING 10
|
||||
#define IGC_ERR_BLK_PHY_RESET 12
|
||||
#define IGC_ERR_SWFW_SYNC 13
|
||||
|
||||
/* Device Control */
|
||||
#define IGC_CTRL_RST 0x04000000 /* Global reset */
|
||||
|
||||
#define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */
|
||||
#define IGC_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
|
||||
#define IGC_CTRL_FRCSPD 0x00000800 /* Force Speed */
|
||||
#define IGC_CTRL_FRCDPX 0x00001000 /* Force Duplex */
|
||||
#define IGC_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
|
||||
|
||||
#define IGC_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
|
||||
#define IGC_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
|
||||
|
||||
#define IGC_CTRL_SDP0_DIR 0x00400000 /* SDP0 Data direction */
|
||||
#define IGC_CTRL_SDP1_DIR 0x00800000 /* SDP1 Data direction */
|
||||
|
||||
/* As per the EAS the maximum supported size is 9.5KB (9728 bytes) */
|
||||
#define MAX_JUMBO_FRAME_SIZE 0x2600
|
||||
|
||||
/* PBA constants */
|
||||
#define IGC_PBA_34K 0x0022
|
||||
|
||||
/* SW Semaphore Register */
|
||||
#define IGC_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
|
||||
#define IGC_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
|
||||
|
||||
/* SWFW_SYNC Definitions */
|
||||
#define IGC_SWFW_EEP_SM 0x1
|
||||
#define IGC_SWFW_PHY0_SM 0x2
|
||||
|
||||
/* Autoneg Advertisement Register */
|
||||
#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
|
||||
#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
|
||||
#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
|
||||
#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
|
||||
#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
|
||||
#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
|
||||
|
||||
/* Link Partner Ability Register (Base Page) */
|
||||
#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
|
||||
#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
|
||||
|
||||
/* 1000BASE-T Control Register */
|
||||
#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
|
||||
#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
|
||||
|
||||
/* 1000BASE-T Status Register */
|
||||
#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
|
||||
|
||||
/* PHY GPY 211 registers */
|
||||
#define STANDARD_AN_REG_MASK 0x0007 /* MMD */
|
||||
#define ANEG_MULTIGBT_AN_CTRL 0x0020 /* MULTI GBT AN Control Register */
|
||||
#define MMD_DEVADDR_SHIFT 16 /* Shift MMD to higher bits */
|
||||
#define CR_2500T_FD_CAPS 0x0080 /* Advertise 2500T FD capability */
|
||||
|
||||
/* NVM Control */
|
||||
/* Number of milliseconds for NVM auto read done after MAC reset. */
|
||||
#define AUTO_READ_DONE_TIMEOUT 10
|
||||
#define IGC_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */
|
||||
#define IGC_EECD_REQ 0x00000040 /* NVM Access Request */
|
||||
#define IGC_EECD_GNT 0x00000080 /* NVM Access Grant */
|
||||
/* NVM Addressing bits based on type 0=small, 1=large */
|
||||
#define IGC_EECD_ADDR_BITS 0x00000400
|
||||
#define IGC_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */
|
||||
#define IGC_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */
|
||||
#define IGC_EECD_SIZE_EX_SHIFT 11
|
||||
#define IGC_EECD_FLUPD_I225 0x00800000 /* Update FLASH */
|
||||
#define IGC_EECD_FLUDONE_I225 0x04000000 /* Update FLASH done*/
|
||||
#define IGC_EECD_FLASH_DETECTED_I225 0x00080000 /* FLASH detected */
|
||||
#define IGC_FLUDONE_ATTEMPTS 20000
|
||||
#define IGC_EERD_EEWR_MAX_COUNT 512 /* buffered EEPROM words rw */
|
||||
|
||||
/* Offset to data in NVM read/write registers */
|
||||
#define IGC_NVM_RW_REG_DATA 16
|
||||
#define IGC_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */
|
||||
#define IGC_NVM_RW_REG_START 1 /* Start operation */
|
||||
#define IGC_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */
|
||||
#define IGC_NVM_POLL_READ 0 /* Flag for polling for read complete */
|
||||
#define IGC_NVM_DEV_STARTER 5 /* Dev_starter Version */
|
||||
|
||||
/* NVM Word Offsets */
|
||||
#define NVM_CHECKSUM_REG 0x003F
|
||||
|
||||
/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
|
||||
#define NVM_SUM 0xBABA
|
||||
#define NVM_WORD_SIZE_BASE_SHIFT 6
|
||||
|
||||
/* Collision related configuration parameters */
|
||||
#define IGC_COLLISION_THRESHOLD 15
|
||||
#define IGC_CT_SHIFT 4
|
||||
#define IGC_COLLISION_DISTANCE 63
|
||||
#define IGC_COLD_SHIFT 12
|
||||
|
||||
/* Device Status */
|
||||
#define IGC_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
|
||||
#define IGC_STATUS_LU 0x00000002 /* Link up.0=no,1=link */
|
||||
#define IGC_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */
|
||||
#define IGC_STATUS_FUNC_SHIFT 2
|
||||
#define IGC_STATUS_TXOFF 0x00000010 /* transmission paused */
|
||||
#define IGC_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
|
||||
#define IGC_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
|
||||
#define IGC_STATUS_SPEED_2500 0x00400000 /* Speed 2.5Gb/s */
|
||||
|
||||
#define SPEED_10 10
|
||||
#define SPEED_100 100
|
||||
#define SPEED_1000 1000
|
||||
#define SPEED_2500 2500
|
||||
#define HALF_DUPLEX 1
|
||||
#define FULL_DUPLEX 2
|
||||
|
||||
/* 1Gbps and 2.5Gbps half duplex is not supported, nor spec-compliant. */
|
||||
#define ADVERTISE_10_HALF 0x0001
|
||||
#define ADVERTISE_10_FULL 0x0002
|
||||
#define ADVERTISE_100_HALF 0x0004
|
||||
#define ADVERTISE_100_FULL 0x0008
|
||||
#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */
|
||||
#define ADVERTISE_1000_FULL 0x0020
|
||||
#define ADVERTISE_2500_HALF 0x0040 /* Not used, just FYI */
|
||||
#define ADVERTISE_2500_FULL 0x0080
|
||||
|
||||
#define IGC_ALL_SPEED_DUPLEX_2500 ( \
|
||||
ADVERTISE_10_HALF | ADVERTISE_10_FULL | ADVERTISE_100_HALF | \
|
||||
ADVERTISE_100_FULL | ADVERTISE_1000_FULL | ADVERTISE_2500_FULL)
|
||||
|
||||
#define AUTONEG_ADVERTISE_SPEED_DEFAULT_2500 IGC_ALL_SPEED_DUPLEX_2500
|
||||
|
||||
/* Interrupt Cause Read */
|
||||
#define IGC_ICR_TXDW BIT(0) /* Transmit desc written back */
|
||||
#define IGC_ICR_TXQE BIT(1) /* Transmit Queue empty */
|
||||
#define IGC_ICR_LSC BIT(2) /* Link Status Change */
|
||||
#define IGC_ICR_RXSEQ BIT(3) /* Rx sequence error */
|
||||
#define IGC_ICR_RXDMT0 BIT(4) /* Rx desc min. threshold (0) */
|
||||
#define IGC_ICR_RXO BIT(6) /* Rx overrun */
|
||||
#define IGC_ICR_RXT0 BIT(7) /* Rx timer intr (ring 0) */
|
||||
#define IGC_ICR_TS BIT(19) /* Time Sync Interrupt */
|
||||
#define IGC_ICR_DRSTA BIT(30) /* Device Reset Asserted */
|
||||
|
||||
/* If this bit asserted, the driver should claim the interrupt */
|
||||
#define IGC_ICR_INT_ASSERTED BIT(31)
|
||||
|
||||
#define IGC_ICS_RXT0 IGC_ICR_RXT0 /* Rx timer intr */
|
||||
|
||||
#define IMS_ENABLE_MASK ( \
|
||||
IGC_IMS_RXT0 | \
|
||||
IGC_IMS_TXDW | \
|
||||
IGC_IMS_RXDMT0 | \
|
||||
IGC_IMS_RXSEQ | \
|
||||
IGC_IMS_LSC)
|
||||
|
||||
/* Interrupt Mask Set */
|
||||
#define IGC_IMS_TXDW IGC_ICR_TXDW /* Tx desc written back */
|
||||
#define IGC_IMS_RXSEQ IGC_ICR_RXSEQ /* Rx sequence error */
|
||||
#define IGC_IMS_LSC IGC_ICR_LSC /* Link Status Change */
|
||||
#define IGC_IMS_DOUTSYNC IGC_ICR_DOUTSYNC /* NIC DMA out of sync */
|
||||
#define IGC_IMS_DRSTA IGC_ICR_DRSTA /* Device Reset Asserted */
|
||||
#define IGC_IMS_RXT0 IGC_ICR_RXT0 /* Rx timer intr */
|
||||
#define IGC_IMS_RXDMT0 IGC_ICR_RXDMT0 /* Rx desc min. threshold */
|
||||
#define IGC_IMS_TS IGC_ICR_TS /* Time Sync Interrupt */
|
||||
|
||||
#define IGC_QVECTOR_MASK 0x7FFC /* Q-vector mask */
|
||||
#define IGC_ITR_VAL_MASK 0x04 /* ITR value mask */
|
||||
|
||||
/* Interrupt Cause Set */
|
||||
#define IGC_ICS_LSC IGC_ICR_LSC /* Link Status Change */
|
||||
#define IGC_ICS_RXDMT0 IGC_ICR_RXDMT0 /* rx desc min. threshold */
|
||||
|
||||
#define IGC_ICR_DOUTSYNC 0x10000000 /* NIC DMA out of sync */
|
||||
#define IGC_EITR_CNT_IGNR 0x80000000 /* Don't reset counters on write */
|
||||
#define IGC_IVAR_VALID 0x80
|
||||
#define IGC_GPIE_NSICR 0x00000001
|
||||
#define IGC_GPIE_MSIX_MODE 0x00000010
|
||||
#define IGC_GPIE_EIAME 0x40000000
|
||||
#define IGC_GPIE_PBA 0x80000000
|
||||
|
||||
/* Receive Descriptor bit definitions */
|
||||
#define IGC_RXD_STAT_DD 0x01 /* Descriptor Done */
|
||||
|
||||
/* Transmit Descriptor bit definitions */
|
||||
#define IGC_TXD_DTYP_D 0x00100000 /* Data Descriptor */
|
||||
#define IGC_TXD_DTYP_C 0x00000000 /* Context Descriptor */
|
||||
#define IGC_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
|
||||
#define IGC_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
|
||||
#define IGC_TXD_CMD_EOP 0x01000000 /* End of Packet */
|
||||
#define IGC_TXD_CMD_IC 0x04000000 /* Insert Checksum */
|
||||
#define IGC_TXD_CMD_DEXT 0x20000000 /* Desc extension (0 = legacy) */
|
||||
#define IGC_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
|
||||
#define IGC_TXD_STAT_DD 0x00000001 /* Descriptor Done */
|
||||
#define IGC_TXD_CMD_TCP 0x01000000 /* TCP packet */
|
||||
#define IGC_TXD_CMD_IP 0x02000000 /* IP packet */
|
||||
#define IGC_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
|
||||
#define IGC_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */
|
||||
|
||||
/* IPSec Encrypt Enable */
|
||||
#define IGC_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
|
||||
#define IGC_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
|
||||
|
||||
#define IGC_ADVTXD_TSN_CNTX_FIRST 0x00000080
|
||||
|
||||
/* Transmit Control */
|
||||
#define IGC_TCTL_EN 0x00000002 /* enable Tx */
|
||||
#define IGC_TCTL_PSP 0x00000008 /* pad short packets */
|
||||
#define IGC_TCTL_CT 0x00000ff0 /* collision threshold */
|
||||
#define IGC_TCTL_COLD 0x003ff000 /* collision distance */
|
||||
#define IGC_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
|
||||
|
||||
/* Flow Control Constants */
|
||||
#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001
|
||||
#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
|
||||
#define FLOW_CONTROL_TYPE 0x8808
|
||||
/* Enable XON frame transmission */
|
||||
#define IGC_FCRTL_XONE 0x80000000
|
||||
|
||||
/* Management Control */
|
||||
#define IGC_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */
|
||||
#define IGC_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */
|
||||
|
||||
/* Receive Control */
|
||||
#define IGC_RCTL_RST 0x00000001 /* Software reset */
|
||||
#define IGC_RCTL_EN 0x00000002 /* enable */
|
||||
#define IGC_RCTL_SBP 0x00000004 /* store bad packet */
|
||||
#define IGC_RCTL_UPE 0x00000008 /* unicast promisc enable */
|
||||
#define IGC_RCTL_MPE 0x00000010 /* multicast promisc enable */
|
||||
#define IGC_RCTL_LPE 0x00000020 /* long packet enable */
|
||||
#define IGC_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */
|
||||
#define IGC_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */
|
||||
|
||||
#define IGC_RCTL_RDMTS_HALF 0x00000000 /* Rx desc min thresh size */
|
||||
#define IGC_RCTL_BAM 0x00008000 /* broadcast enable */
|
||||
|
||||
/* Split Replication Receive Control */
|
||||
#define IGC_SRRCTL_TIMESTAMP 0x40000000
|
||||
#define IGC_SRRCTL_TIMER1SEL(timer) (((timer) & 0x3) << 14)
|
||||
#define IGC_SRRCTL_TIMER0SEL(timer) (((timer) & 0x3) << 17)
|
||||
|
||||
/* Receive Descriptor bit definitions */
|
||||
#define IGC_RXD_STAT_EOP 0x02 /* End of Packet */
|
||||
#define IGC_RXD_STAT_IXSM 0x04 /* Ignore checksum */
|
||||
#define IGC_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */
|
||||
#define IGC_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */
|
||||
#define IGC_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
|
||||
|
||||
#define IGC_RXDEXT_STATERR_LB 0x00040000
|
||||
|
||||
/* Advanced Receive Descriptor bit definitions */
|
||||
#define IGC_RXDADV_STAT_TSIP 0x08000 /* timestamp in packet */
|
||||
|
||||
#define IGC_RXDEXT_STATERR_L4E 0x20000000
|
||||
#define IGC_RXDEXT_STATERR_IPE 0x40000000
|
||||
#define IGC_RXDEXT_STATERR_RXE 0x80000000
|
||||
|
||||
#define IGC_MRQC_RSS_FIELD_IPV4_TCP 0x00010000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV4 0x00020000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6 0x00100000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6_TCP 0x00200000
|
||||
|
||||
/* Header split receive */
|
||||
#define IGC_RFCTL_IPV6_EX_DIS 0x00010000
|
||||
#define IGC_RFCTL_LEF 0x00040000
|
||||
|
||||
#define IGC_RCTL_SZ_256 0x00030000 /* Rx buffer size 256 */
|
||||
|
||||
#define IGC_RCTL_MO_SHIFT 12 /* multicast offset shift */
|
||||
#define IGC_RCTL_CFIEN 0x00080000 /* canonical form enable */
|
||||
#define IGC_RCTL_DPF 0x00400000 /* discard pause frames */
|
||||
#define IGC_RCTL_PMCF 0x00800000 /* pass MAC control frames */
|
||||
#define IGC_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
|
||||
|
||||
#define I225_RXPBSIZE_DEFAULT 0x000000A2 /* RXPBSIZE default */
|
||||
#define I225_TXPBSIZE_DEFAULT 0x04000014 /* TXPBSIZE default */
|
||||
#define IGC_RXPBS_CFG_TS_EN 0x80000000 /* Timestamp in Rx buffer */
|
||||
|
||||
#define IGC_TXPBSIZE_TSN 0x04145145 /* 5k bytes buffer for each queue */
|
||||
|
||||
#define IGC_DTXMXPKTSZ_TSN 0x19 /* 1600 bytes of max TX DMA packet size */
|
||||
#define IGC_DTXMXPKTSZ_DEFAULT 0x98 /* 9728-byte Jumbo frames */
|
||||
|
||||
/* Transmit Scheduling Latency */
|
||||
/* Latency between transmission scheduling (LaunchTime) and the time
|
||||
* the packet is transmitted to the network in nanosecond.
|
||||
*/
|
||||
#define IGC_TXOFFSET_SPEED_10 0x000034BC
|
||||
#define IGC_TXOFFSET_SPEED_100 0x00000578
|
||||
#define IGC_TXOFFSET_SPEED_1000 0x0000012C
|
||||
#define IGC_TXOFFSET_SPEED_2500 0x00000578
|
||||
|
||||
/* Time Sync Interrupt Causes */
|
||||
#define IGC_TSICR_SYS_WRAP BIT(0) /* SYSTIM Wrap around. */
|
||||
#define IGC_TSICR_TXTS BIT(1) /* Transmit Timestamp. */
|
||||
#define IGC_TSICR_TT0 BIT(3) /* Target Time 0 Trigger. */
|
||||
#define IGC_TSICR_TT1 BIT(4) /* Target Time 1 Trigger. */
|
||||
#define IGC_TSICR_AUTT0 BIT(5) /* Auxiliary Timestamp 0 Taken. */
|
||||
#define IGC_TSICR_AUTT1 BIT(6) /* Auxiliary Timestamp 1 Taken. */
|
||||
|
||||
#define IGC_TSICR_INTERRUPTS IGC_TSICR_TXTS
|
||||
|
||||
#define IGC_FTQF_VF_BP 0x00008000
|
||||
#define IGC_FTQF_1588_TIME_STAMP 0x08000000
|
||||
#define IGC_FTQF_MASK 0xF0000000
|
||||
#define IGC_FTQF_MASK_PROTO_BP 0x10000000
|
||||
|
||||
/* Time Sync Receive Control bit definitions */
|
||||
#define IGC_TSYNCRXCTL_TYPE_MASK 0x0000000E /* Rx type mask */
|
||||
#define IGC_TSYNCRXCTL_TYPE_L2_V2 0x00
|
||||
#define IGC_TSYNCRXCTL_TYPE_L4_V1 0x02
|
||||
#define IGC_TSYNCRXCTL_TYPE_L2_L4_V2 0x04
|
||||
#define IGC_TSYNCRXCTL_TYPE_ALL 0x08
|
||||
#define IGC_TSYNCRXCTL_TYPE_EVENT_V2 0x0A
|
||||
#define IGC_TSYNCRXCTL_ENABLED 0x00000010 /* enable Rx timestamping */
|
||||
#define IGC_TSYNCRXCTL_SYSCFI 0x00000020 /* Sys clock frequency */
|
||||
#define IGC_TSYNCRXCTL_RXSYNSIG 0x00000400 /* Sample RX tstamp in PHY sop */
|
||||
|
||||
/* Time Sync Receive Configuration */
|
||||
#define IGC_TSYNCRXCFG_PTP_V1_CTRLT_MASK 0x000000FF
|
||||
#define IGC_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE 0x00
|
||||
#define IGC_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE 0x01
|
||||
|
||||
/* Immediate Interrupt Receive */
|
||||
#define IGC_IMIR_CLEAR_MASK 0xF001FFFF /* IMIR Reg Clear Mask */
|
||||
#define IGC_IMIR_PORT_BYPASS 0x20000 /* IMIR Port Bypass Bit */
|
||||
#define IGC_IMIR_PRIORITY_SHIFT 29 /* IMIR Priority Shift */
|
||||
#define IGC_IMIREXT_CLEAR_MASK 0x7FFFF /* IMIREXT Reg Clear Mask */
|
||||
|
||||
/* Immediate Interrupt Receive Extended */
|
||||
#define IGC_IMIREXT_CTRL_BP 0x00080000 /* Bypass check of ctrl bits */
|
||||
#define IGC_IMIREXT_SIZE_BP 0x00001000 /* Packet size bypass */
|
||||
|
||||
/* Time Sync Transmit Control bit definitions */
|
||||
#define IGC_TSYNCTXCTL_TXTT_0 0x00000001 /* Tx timestamp reg 0 valid */
|
||||
#define IGC_TSYNCTXCTL_ENABLED 0x00000010 /* enable Tx timestamping */
|
||||
#define IGC_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK 0x0000F000 /* max delay */
|
||||
#define IGC_TSYNCTXCTL_SYNC_COMP_ERR 0x20000000 /* sync err */
|
||||
#define IGC_TSYNCTXCTL_SYNC_COMP 0x40000000 /* sync complete */
|
||||
#define IGC_TSYNCTXCTL_START_SYNC 0x80000000 /* initiate sync */
|
||||
#define IGC_TSYNCTXCTL_TXSYNSIG 0x00000020 /* Sample TX tstamp in PHY sop */
|
||||
|
||||
/* Timer selection bits */
|
||||
#define IGC_AUX_IO_TIMER_SEL_SYSTIM0 (0u << 30) /* Select SYSTIM0 for auxiliary time stamp */
|
||||
#define IGC_AUX_IO_TIMER_SEL_SYSTIM1 (1u << 30) /* Select SYSTIM1 for auxiliary time stamp */
|
||||
#define IGC_AUX_IO_TIMER_SEL_SYSTIM2 (2u << 30) /* Select SYSTIM2 for auxiliary time stamp */
|
||||
#define IGC_AUX_IO_TIMER_SEL_SYSTIM3 (3u << 30) /* Select SYSTIM3 for auxiliary time stamp */
|
||||
#define IGC_TT_IO_TIMER_SEL_SYSTIM0 (0u << 30) /* Select SYSTIM0 for target time stamp */
|
||||
#define IGC_TT_IO_TIMER_SEL_SYSTIM1 (1u << 30) /* Select SYSTIM1 for target time stamp */
|
||||
#define IGC_TT_IO_TIMER_SEL_SYSTIM2 (2u << 30) /* Select SYSTIM2 for target time stamp */
|
||||
#define IGC_TT_IO_TIMER_SEL_SYSTIM3 (3u << 30) /* Select SYSTIM3 for target time stamp */
|
||||
|
||||
/* TSAUXC Configuration Bits */
|
||||
#define IGC_TSAUXC_EN_TT0 BIT(0) /* Enable target time 0. */
|
||||
#define IGC_TSAUXC_EN_TT1 BIT(1) /* Enable target time 1. */
|
||||
#define IGC_TSAUXC_EN_CLK0 BIT(2) /* Enable Configurable Frequency Clock 0. */
|
||||
#define IGC_TSAUXC_ST0 BIT(4) /* Start Clock 0 Toggle on Target Time 0. */
|
||||
#define IGC_TSAUXC_EN_CLK1 BIT(5) /* Enable Configurable Frequency Clock 1. */
|
||||
#define IGC_TSAUXC_ST1 BIT(7) /* Start Clock 1 Toggle on Target Time 1. */
|
||||
#define IGC_TSAUXC_EN_TS0 BIT(8) /* Enable hardware timestamp 0. */
|
||||
#define IGC_TSAUXC_AUTT0 BIT(9) /* Auxiliary Timestamp Taken. */
|
||||
#define IGC_TSAUXC_EN_TS1 BIT(10) /* Enable hardware timestamp 0. */
|
||||
#define IGC_TSAUXC_AUTT1 BIT(11) /* Auxiliary Timestamp Taken. */
|
||||
#define IGC_TSAUXC_PLSG BIT(17) /* Generate a pulse. */
|
||||
#define IGC_TSAUXC_DISABLE1 BIT(27) /* Disable SYSTIM0 Count Operation. */
|
||||
#define IGC_TSAUXC_DISABLE2 BIT(28) /* Disable SYSTIM1 Count Operation. */
|
||||
#define IGC_TSAUXC_DISABLE3 BIT(29) /* Disable SYSTIM2 Count Operation. */
|
||||
#define IGC_TSAUXC_DIS_TS_CLEAR BIT(30) /* Disable EN_TT0/1 auto clear. */
|
||||
#define IGC_TSAUXC_DISABLE0 BIT(31) /* Disable SYSTIM0 Count Operation. */
|
||||
|
||||
/* SDP Configuration Bits */
|
||||
#define IGC_AUX0_SEL_SDP0 (0u << 0) /* Assign SDP0 to auxiliary time stamp 0. */
|
||||
#define IGC_AUX0_SEL_SDP1 (1u << 0) /* Assign SDP1 to auxiliary time stamp 0. */
|
||||
#define IGC_AUX0_SEL_SDP2 (2u << 0) /* Assign SDP2 to auxiliary time stamp 0. */
|
||||
#define IGC_AUX0_SEL_SDP3 (3u << 0) /* Assign SDP3 to auxiliary time stamp 0. */
|
||||
#define IGC_AUX0_TS_SDP_EN (1u << 2) /* Enable auxiliary time stamp trigger 0. */
|
||||
#define IGC_AUX1_SEL_SDP0 (0u << 3) /* Assign SDP0 to auxiliary time stamp 1. */
|
||||
#define IGC_AUX1_SEL_SDP1 (1u << 3) /* Assign SDP1 to auxiliary time stamp 1. */
|
||||
#define IGC_AUX1_SEL_SDP2 (2u << 3) /* Assign SDP2 to auxiliary time stamp 1. */
|
||||
#define IGC_AUX1_SEL_SDP3 (3u << 3) /* Assign SDP3 to auxiliary time stamp 1. */
|
||||
#define IGC_AUX1_TS_SDP_EN (1u << 5) /* Enable auxiliary time stamp trigger 1. */
|
||||
#define IGC_TS_SDP0_SEL_TT0 (0u << 6) /* Target time 0 is output on SDP0. */
|
||||
#define IGC_TS_SDP0_SEL_TT1 (1u << 6) /* Target time 1 is output on SDP0. */
|
||||
#define IGC_TS_SDP0_SEL_FC0 (2u << 6) /* Freq clock 0 is output on SDP0. */
|
||||
#define IGC_TS_SDP0_SEL_FC1 (3u << 6) /* Freq clock 1 is output on SDP0. */
|
||||
#define IGC_TS_SDP0_EN (1u << 8) /* SDP0 is assigned to Tsync. */
|
||||
#define IGC_TS_SDP1_SEL_TT0 (0u << 9) /* Target time 0 is output on SDP1. */
|
||||
#define IGC_TS_SDP1_SEL_TT1 (1u << 9) /* Target time 1 is output on SDP1. */
|
||||
#define IGC_TS_SDP1_SEL_FC0 (2u << 9) /* Freq clock 0 is output on SDP1. */
|
||||
#define IGC_TS_SDP1_SEL_FC1 (3u << 9) /* Freq clock 1 is output on SDP1. */
|
||||
#define IGC_TS_SDP1_EN (1u << 11) /* SDP1 is assigned to Tsync. */
|
||||
#define IGC_TS_SDP2_SEL_TT0 (0u << 12) /* Target time 0 is output on SDP2. */
|
||||
#define IGC_TS_SDP2_SEL_TT1 (1u << 12) /* Target time 1 is output on SDP2. */
|
||||
#define IGC_TS_SDP2_SEL_FC0 (2u << 12) /* Freq clock 0 is output on SDP2. */
|
||||
#define IGC_TS_SDP2_SEL_FC1 (3u << 12) /* Freq clock 1 is output on SDP2. */
|
||||
#define IGC_TS_SDP2_EN (1u << 14) /* SDP2 is assigned to Tsync. */
|
||||
#define IGC_TS_SDP3_SEL_TT0 (0u << 15) /* Target time 0 is output on SDP3. */
|
||||
#define IGC_TS_SDP3_SEL_TT1 (1u << 15) /* Target time 1 is output on SDP3. */
|
||||
#define IGC_TS_SDP3_SEL_FC0 (2u << 15) /* Freq clock 0 is output on SDP3. */
|
||||
#define IGC_TS_SDP3_SEL_FC1 (3u << 15) /* Freq clock 1 is output on SDP3. */
|
||||
#define IGC_TS_SDP3_EN (1u << 17) /* SDP3 is assigned to Tsync. */
|
||||
|
||||
/* Transmit Scheduling */
|
||||
#define IGC_TQAVCTRL_TRANSMIT_MODE_TSN 0x00000001
|
||||
#define IGC_TQAVCTRL_ENHANCED_QAV 0x00000008
|
||||
#define IGC_TQAVCTRL_FUTSCDDIS 0x00000080
|
||||
|
||||
#define IGC_TXQCTL_QUEUE_MODE_LAUNCHT 0x00000001
|
||||
#define IGC_TXQCTL_STRICT_CYCLE 0x00000002
|
||||
#define IGC_TXQCTL_STRICT_END 0x00000004
|
||||
#define IGC_TXQCTL_QAV_SEL_MASK 0x000000C0
|
||||
#define IGC_TXQCTL_QAV_SEL_CBS0 0x00000080
|
||||
#define IGC_TXQCTL_QAV_SEL_CBS1 0x000000C0
|
||||
|
||||
#define IGC_TQAVCC_IDLESLOPE_MASK 0xFFFF
|
||||
#define IGC_TQAVCC_KEEP_CREDITS BIT(30)
|
||||
|
||||
#define IGC_MAX_SR_QUEUES 2
|
||||
|
||||
/* Receive Checksum Control */
|
||||
#define IGC_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */
|
||||
#define IGC_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */
|
||||
|
||||
/* PCIe PTM Control */
|
||||
#define IGC_PTM_CTRL_START_NOW BIT(29) /* Start PTM Now */
|
||||
#define IGC_PTM_CTRL_EN BIT(30) /* Enable PTM */
|
||||
#define IGC_PTM_CTRL_TRIG BIT(31) /* PTM Cycle trigger */
|
||||
#define IGC_PTM_CTRL_SHRT_CYC(usec) (((usec) & 0x2f) << 2)
|
||||
#define IGC_PTM_CTRL_PTM_TO(usec) (((usec) & 0xff) << 8)
|
||||
|
||||
#define IGC_PTM_SHORT_CYC_DEFAULT 10 /* Default Short/interrupted cycle interval */
|
||||
#define IGC_PTM_CYC_TIME_DEFAULT 5 /* Default PTM cycle time */
|
||||
#define IGC_PTM_TIMEOUT_DEFAULT 255 /* Default timeout for PTM errors */
|
||||
|
||||
/* PCIe Digital Delay */
|
||||
#define IGC_PCIE_DIG_DELAY_DEFAULT 0x01440000
|
||||
|
||||
/* PCIe PHY Delay */
|
||||
#define IGC_PCIE_PHY_DELAY_DEFAULT 0x40900000
|
||||
|
||||
#define IGC_TIMADJ_ADJUST_METH 0x40000000
|
||||
|
||||
/* PCIe PTM Status */
|
||||
#define IGC_PTM_STAT_VALID BIT(0) /* PTM Status */
|
||||
#define IGC_PTM_STAT_RET_ERR BIT(1) /* Root port timeout */
|
||||
#define IGC_PTM_STAT_BAD_PTM_RES BIT(2) /* PTM Response msg instead of PTM Response Data */
|
||||
#define IGC_PTM_STAT_T4M1_OVFL BIT(3) /* T4 minus T1 overflow */
|
||||
#define IGC_PTM_STAT_ADJUST_1ST BIT(4) /* 1588 timer adjusted during 1st PTM cycle */
|
||||
#define IGC_PTM_STAT_ADJUST_CYC BIT(5) /* 1588 timer adjusted during non-1st PTM cycle */
|
||||
|
||||
/* PCIe PTM Cycle Control */
|
||||
#define IGC_PTM_CYCLE_CTRL_CYC_TIME(msec) ((msec) & 0x3ff) /* PTM Cycle Time (msec) */
|
||||
#define IGC_PTM_CYCLE_CTRL_AUTO_CYC_EN BIT(31) /* PTM Cycle Control */
|
||||
|
||||
/* GPY211 - I225 defines */
|
||||
#define GPY_MMD_MASK 0xFFFF0000
|
||||
#define GPY_MMD_SHIFT 16
|
||||
#define GPY_REG_MASK 0x0000FFFF
|
||||
|
||||
#define IGC_MMDAC_FUNC_DATA 0x4000 /* Data, no post increment */
|
||||
|
||||
/* MAC definitions */
|
||||
#define IGC_FACTPS_MNGCG 0x20000000
|
||||
#define IGC_FWSM_MODE_MASK 0xE
|
||||
#define IGC_FWSM_MODE_SHIFT 1
|
||||
|
||||
/* Management Control */
|
||||
#define IGC_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */
|
||||
#define IGC_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */
|
||||
|
||||
/* PHY */
|
||||
#define PHY_REVISION_MASK 0xFFFFFFF0
|
||||
#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
|
||||
#define IGC_GEN_POLL_TIMEOUT 1920
|
||||
|
||||
/* PHY Control Register */
|
||||
#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
|
||||
#define MII_CR_POWER_DOWN 0x0800 /* Power down */
|
||||
#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
|
||||
|
||||
/* PHY Status Register */
|
||||
#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
|
||||
#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
|
||||
#define IGC_PHY_RST_COMP 0x0100 /* Internal PHY reset completion */
|
||||
|
||||
/* PHY 1000 MII Register/Bit Definitions */
|
||||
/* PHY Registers defined by IEEE */
|
||||
#define PHY_CONTROL 0x00 /* Control Register */
|
||||
#define PHY_STATUS 0x01 /* Status Register */
|
||||
#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
|
||||
#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
|
||||
#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
|
||||
#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
|
||||
#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
|
||||
#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
|
||||
|
||||
/* MDI Control */
|
||||
#define IGC_MDIC_DATA_MASK 0x0000FFFF
|
||||
#define IGC_MDIC_REG_MASK 0x001F0000
|
||||
#define IGC_MDIC_REG_SHIFT 16
|
||||
#define IGC_MDIC_PHY_MASK 0x03E00000
|
||||
#define IGC_MDIC_PHY_SHIFT 21
|
||||
#define IGC_MDIC_OP_WRITE 0x04000000
|
||||
#define IGC_MDIC_OP_READ 0x08000000
|
||||
#define IGC_MDIC_READY 0x10000000
|
||||
#define IGC_MDIC_ERROR 0x40000000
|
||||
|
||||
#define IGC_N0_QUEUE -1
|
||||
|
||||
#define IGC_MAX_MAC_HDR_LEN 127
|
||||
#define IGC_MAX_NETWORK_HDR_LEN 511
|
||||
|
||||
#define IGC_VLANPQF_QSEL(_n, q_idx) ((q_idx) << ((_n) * 4))
|
||||
#define IGC_VLANPQF_VALID(_n) (0x1 << (3 + (_n) * 4))
|
||||
#define IGC_VLANPQF_QUEUE_MASK 0x03
|
||||
|
||||
#define IGC_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
|
||||
#define IGC_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type:1=IPv4 */
|
||||
#define IGC_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet Type of TCP */
|
||||
#define IGC_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 packet TYPE of SCTP */
|
||||
|
||||
/* Maximum size of the MTA register table in all supported adapters */
|
||||
#define MAX_MTA_REG 128
|
||||
|
||||
/* EEE defines */
|
||||
#define IGC_IPCNFG_EEE_2_5G_AN 0x00000010 /* IPCNFG EEE Ena 2.5G AN */
|
||||
#define IGC_IPCNFG_EEE_1G_AN 0x00000008 /* IPCNFG EEE Ena 1G AN */
|
||||
#define IGC_IPCNFG_EEE_100M_AN 0x00000004 /* IPCNFG EEE Ena 100M AN */
|
||||
#define IGC_EEER_EEE_NEG 0x20000000 /* EEE capability nego */
|
||||
#define IGC_EEER_TX_LPI_EN 0x00010000 /* EEER Tx LPI Enable */
|
||||
#define IGC_EEER_RX_LPI_EN 0x00020000 /* EEER Rx LPI Enable */
|
||||
#define IGC_EEER_LPI_FC 0x00040000 /* EEER Ena on Flow Cntrl */
|
||||
#define IGC_EEE_SU_LPI_CLK_STP 0x00800000 /* EEE LPI Clock Stop */
|
||||
|
||||
/* LTR defines */
|
||||
#define IGC_LTRC_EEEMS_EN 0x00000020 /* Enable EEE LTR max send */
|
||||
#define IGC_RXPBS_SIZE_I225_MASK 0x0000003F /* Rx packet buffer size */
|
||||
#define IGC_TW_SYSTEM_1000_MASK 0x000000FF
|
||||
/* Minimum time for 100BASE-T where no data will be transmit following move out
|
||||
* of EEE LPI Tx state
|
||||
*/
|
||||
#define IGC_TW_SYSTEM_100_MASK 0x0000FF00
|
||||
#define IGC_TW_SYSTEM_100_SHIFT 8
|
||||
/* Reg val to set scale to 1024 nsec */
|
||||
#define IGC_LTRMINV_SCALE_1024 2
|
||||
/* Reg val to set scale to 32768 nsec */
|
||||
#define IGC_LTRMINV_SCALE_32768 3
|
||||
/* Reg val to set scale to 1024 nsec */
|
||||
#define IGC_LTRMAXV_SCALE_1024 2
|
||||
/* Reg val to set scale to 32768 nsec */
|
||||
#define IGC_LTRMAXV_SCALE_32768 3
|
||||
#define IGC_LTRMINV_LTRV_MASK 0x000003FF /* LTR minimum value */
|
||||
#define IGC_LTRMAXV_LTRV_MASK 0x000003FF /* LTR maximum value */
|
||||
#define IGC_LTRMINV_LSNP_REQ 0x00008000 /* LTR Snoop Requirement */
|
||||
#define IGC_LTRMINV_SCALE_SHIFT 10
|
||||
#define IGC_LTRMAXV_LSNP_REQ 0x00008000 /* LTR Snoop Requirement */
|
||||
#define IGC_LTRMAXV_SCALE_SHIFT 10
|
||||
|
||||
#endif /* _IGC_DEFINES_H_ */
|
||||
|
|
@ -0,0 +1,687 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_DEFINES_H_
|
||||
#define _IGC_DEFINES_H_
|
||||
|
||||
/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
|
||||
#define REQ_TX_DESCRIPTOR_MULTIPLE 8
|
||||
#define REQ_RX_DESCRIPTOR_MULTIPLE 8
|
||||
|
||||
#define IGC_CTRL_EXT_SDP2_DIR 0x00000400 /* SDP2 Data direction */
|
||||
#define IGC_CTRL_EXT_SDP3_DIR 0x00000800 /* SDP3 Data direction */
|
||||
#define IGC_CTRL_EXT_DRV_LOAD 0x10000000 /* Drv loaded bit for FW */
|
||||
|
||||
/* Definitions for power management and wakeup registers */
|
||||
/* Wake Up Control */
|
||||
#define IGC_WUC_PME_EN 0x00000002 /* PME Enable */
|
||||
|
||||
/* Wake Up Filter Control */
|
||||
#define IGC_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
|
||||
#define IGC_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */
|
||||
#define IGC_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */
|
||||
#define IGC_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */
|
||||
#define IGC_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
|
||||
#define IGC_WUFC_FLEX_HQ BIT(14) /* Flex Filters Host Queuing */
|
||||
#define IGC_WUFC_FLX0 BIT(16) /* Flexible Filter 0 Enable */
|
||||
#define IGC_WUFC_FLX1 BIT(17) /* Flexible Filter 1 Enable */
|
||||
#define IGC_WUFC_FLX2 BIT(18) /* Flexible Filter 2 Enable */
|
||||
#define IGC_WUFC_FLX3 BIT(19) /* Flexible Filter 3 Enable */
|
||||
#define IGC_WUFC_FLX4 BIT(20) /* Flexible Filter 4 Enable */
|
||||
#define IGC_WUFC_FLX5 BIT(21) /* Flexible Filter 5 Enable */
|
||||
#define IGC_WUFC_FLX6 BIT(22) /* Flexible Filter 6 Enable */
|
||||
#define IGC_WUFC_FLX7 BIT(23) /* Flexible Filter 7 Enable */
|
||||
|
||||
#define IGC_WUFC_FILTER_MASK GENMASK(23, 14)
|
||||
|
||||
#define IGC_CTRL_ADVD3WUC 0x00100000 /* D3 WUC */
|
||||
|
||||
/* Wake Up Status */
|
||||
#define IGC_WUS_EX 0x00000004 /* Directed Exact */
|
||||
#define IGC_WUS_ARPD 0x00000020 /* Directed ARP Request */
|
||||
#define IGC_WUS_IPV4 0x00000040 /* Directed IPv4 */
|
||||
#define IGC_WUS_IPV6 0x00000080 /* Directed IPv6 */
|
||||
#define IGC_WUS_NSD 0x00000400 /* Directed IPv6 Neighbor Solicitation */
|
||||
|
||||
/* Packet types that are enabled for wake packet delivery */
|
||||
#define WAKE_PKT_WUS ( \
|
||||
IGC_WUS_EX | \
|
||||
IGC_WUS_ARPD | \
|
||||
IGC_WUS_IPV4 | \
|
||||
IGC_WUS_IPV6 | \
|
||||
IGC_WUS_NSD)
|
||||
|
||||
/* Wake Up Packet Length */
|
||||
#define IGC_WUPL_MASK 0x00000FFF
|
||||
|
||||
/* Wake Up Packet Memory stores the first 128 bytes of the wake up packet */
|
||||
#define IGC_WUPM_BYTES 128
|
||||
|
||||
/* Wakeup Filter Control Extended */
|
||||
#define IGC_WUFC_EXT_FLX8 BIT(8) /* Flexible Filter 8 Enable */
|
||||
#define IGC_WUFC_EXT_FLX9 BIT(9) /* Flexible Filter 9 Enable */
|
||||
#define IGC_WUFC_EXT_FLX10 BIT(10) /* Flexible Filter 10 Enable */
|
||||
#define IGC_WUFC_EXT_FLX11 BIT(11) /* Flexible Filter 11 Enable */
|
||||
#define IGC_WUFC_EXT_FLX12 BIT(12) /* Flexible Filter 12 Enable */
|
||||
#define IGC_WUFC_EXT_FLX13 BIT(13) /* Flexible Filter 13 Enable */
|
||||
#define IGC_WUFC_EXT_FLX14 BIT(14) /* Flexible Filter 14 Enable */
|
||||
#define IGC_WUFC_EXT_FLX15 BIT(15) /* Flexible Filter 15 Enable */
|
||||
#define IGC_WUFC_EXT_FLX16 BIT(16) /* Flexible Filter 16 Enable */
|
||||
#define IGC_WUFC_EXT_FLX17 BIT(17) /* Flexible Filter 17 Enable */
|
||||
#define IGC_WUFC_EXT_FLX18 BIT(18) /* Flexible Filter 18 Enable */
|
||||
#define IGC_WUFC_EXT_FLX19 BIT(19) /* Flexible Filter 19 Enable */
|
||||
#define IGC_WUFC_EXT_FLX20 BIT(20) /* Flexible Filter 20 Enable */
|
||||
#define IGC_WUFC_EXT_FLX21 BIT(21) /* Flexible Filter 21 Enable */
|
||||
#define IGC_WUFC_EXT_FLX22 BIT(22) /* Flexible Filter 22 Enable */
|
||||
#define IGC_WUFC_EXT_FLX23 BIT(23) /* Flexible Filter 23 Enable */
|
||||
#define IGC_WUFC_EXT_FLX24 BIT(24) /* Flexible Filter 24 Enable */
|
||||
#define IGC_WUFC_EXT_FLX25 BIT(25) /* Flexible Filter 25 Enable */
|
||||
#define IGC_WUFC_EXT_FLX26 BIT(26) /* Flexible Filter 26 Enable */
|
||||
#define IGC_WUFC_EXT_FLX27 BIT(27) /* Flexible Filter 27 Enable */
|
||||
#define IGC_WUFC_EXT_FLX28 BIT(28) /* Flexible Filter 28 Enable */
|
||||
#define IGC_WUFC_EXT_FLX29 BIT(29) /* Flexible Filter 29 Enable */
|
||||
#define IGC_WUFC_EXT_FLX30 BIT(30) /* Flexible Filter 30 Enable */
|
||||
#define IGC_WUFC_EXT_FLX31 BIT(31) /* Flexible Filter 31 Enable */
|
||||
|
||||
#define IGC_WUFC_EXT_FILTER_MASK GENMASK(31, 8)
|
||||
|
||||
/* Loop limit on how long we wait for auto-negotiation to complete */
|
||||
#define COPPER_LINK_UP_LIMIT 10
|
||||
#define PHY_AUTO_NEG_LIMIT 45
|
||||
|
||||
/* Number of 100 microseconds we wait for PCI Express master disable */
|
||||
#define MASTER_DISABLE_TIMEOUT 800
|
||||
/*Blocks new Master requests */
|
||||
#define IGC_CTRL_GIO_MASTER_DISABLE 0x00000004
|
||||
/* Status of Master requests. */
|
||||
#define IGC_STATUS_GIO_MASTER_ENABLE 0x00080000
|
||||
|
||||
/* Receive Address
|
||||
* Number of high/low register pairs in the RAR. The RAR (Receive Address
|
||||
* Registers) holds the directed and multicast addresses that we monitor.
|
||||
* Technically, we have 16 spots. However, we reserve one of these spots
|
||||
* (RAR[15]) for our directed address used by controllers with
|
||||
* manageability enabled, allowing us room for 15 multicast addresses.
|
||||
*/
|
||||
#define IGC_RAH_RAH_MASK 0x0000FFFF
|
||||
#define IGC_RAH_ASEL_MASK 0x00030000
|
||||
#define IGC_RAH_ASEL_SRC_ADDR BIT(16)
|
||||
#define IGC_RAH_QSEL_MASK 0x000C0000
|
||||
#define IGC_RAH_QSEL_SHIFT 18
|
||||
#define IGC_RAH_QSEL_ENABLE BIT(28)
|
||||
#define IGC_RAH_AV 0x80000000 /* Receive descriptor valid */
|
||||
|
||||
#define IGC_RAL_MAC_ADDR_LEN 4
|
||||
#define IGC_RAH_MAC_ADDR_LEN 2
|
||||
|
||||
/* Error Codes */
|
||||
#define IGC_SUCCESS 0
|
||||
#define IGC_ERR_NVM 1
|
||||
#define IGC_ERR_PHY 2
|
||||
#define IGC_ERR_CONFIG 3
|
||||
#define IGC_ERR_PARAM 4
|
||||
#define IGC_ERR_MAC_INIT 5
|
||||
#define IGC_ERR_RESET 9
|
||||
#define IGC_ERR_MASTER_REQUESTS_PENDING 10
|
||||
#define IGC_ERR_BLK_PHY_RESET 12
|
||||
#define IGC_ERR_SWFW_SYNC 13
|
||||
|
||||
/* Device Control */
|
||||
#define IGC_CTRL_RST 0x04000000 /* Global reset */
|
||||
|
||||
#define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */
|
||||
#define IGC_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
|
||||
#define IGC_CTRL_FRCSPD 0x00000800 /* Force Speed */
|
||||
#define IGC_CTRL_FRCDPX 0x00001000 /* Force Duplex */
|
||||
#define IGC_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
|
||||
|
||||
#define IGC_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
|
||||
#define IGC_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
|
||||
|
||||
#define IGC_CTRL_SDP0_DIR 0x00400000 /* SDP0 Data direction */
|
||||
#define IGC_CTRL_SDP1_DIR 0x00800000 /* SDP1 Data direction */
|
||||
|
||||
/* As per the EAS the maximum supported size is 9.5KB (9728 bytes) */
|
||||
#define MAX_JUMBO_FRAME_SIZE 0x2600
|
||||
|
||||
/* PBA constants */
|
||||
#define IGC_PBA_34K 0x0022
|
||||
|
||||
/* SW Semaphore Register */
|
||||
#define IGC_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
|
||||
#define IGC_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
|
||||
|
||||
/* SWFW_SYNC Definitions */
|
||||
#define IGC_SWFW_EEP_SM 0x1
|
||||
#define IGC_SWFW_PHY0_SM 0x2
|
||||
|
||||
/* Autoneg Advertisement Register */
|
||||
#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
|
||||
#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
|
||||
#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
|
||||
#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
|
||||
#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
|
||||
#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
|
||||
|
||||
/* Link Partner Ability Register (Base Page) */
|
||||
#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
|
||||
#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
|
||||
|
||||
/* 1000BASE-T Control Register */
|
||||
#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
|
||||
#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
|
||||
|
||||
/* 1000BASE-T Status Register */
|
||||
#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
|
||||
|
||||
/* PHY GPY 211 registers */
|
||||
#define STANDARD_AN_REG_MASK 0x0007 /* MMD */
|
||||
#define ANEG_MULTIGBT_AN_CTRL 0x0020 /* MULTI GBT AN Control Register */
|
||||
#define MMD_DEVADDR_SHIFT 16 /* Shift MMD to higher bits */
|
||||
#define CR_2500T_FD_CAPS 0x0080 /* Advertise 2500T FD capability */
|
||||
|
||||
/* NVM Control */
|
||||
/* Number of milliseconds for NVM auto read done after MAC reset. */
|
||||
#define AUTO_READ_DONE_TIMEOUT 10
|
||||
#define IGC_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */
|
||||
#define IGC_EECD_REQ 0x00000040 /* NVM Access Request */
|
||||
#define IGC_EECD_GNT 0x00000080 /* NVM Access Grant */
|
||||
/* NVM Addressing bits based on type 0=small, 1=large */
|
||||
#define IGC_EECD_ADDR_BITS 0x00000400
|
||||
#define IGC_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */
|
||||
#define IGC_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */
|
||||
#define IGC_EECD_SIZE_EX_SHIFT 11
|
||||
#define IGC_EECD_FLUPD_I225 0x00800000 /* Update FLASH */
|
||||
#define IGC_EECD_FLUDONE_I225 0x04000000 /* Update FLASH done*/
|
||||
#define IGC_EECD_FLASH_DETECTED_I225 0x00080000 /* FLASH detected */
|
||||
#define IGC_FLUDONE_ATTEMPTS 20000
|
||||
#define IGC_EERD_EEWR_MAX_COUNT 512 /* buffered EEPROM words rw */
|
||||
|
||||
/* Offset to data in NVM read/write registers */
|
||||
#define IGC_NVM_RW_REG_DATA 16
|
||||
#define IGC_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */
|
||||
#define IGC_NVM_RW_REG_START 1 /* Start operation */
|
||||
#define IGC_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */
|
||||
#define IGC_NVM_POLL_READ 0 /* Flag for polling for read complete */
|
||||
#define IGC_NVM_DEV_STARTER 5 /* Dev_starter Version */
|
||||
|
||||
/* NVM Word Offsets */
|
||||
#define NVM_CHECKSUM_REG 0x003F
|
||||
|
||||
/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
|
||||
#define NVM_SUM 0xBABA
|
||||
#define NVM_WORD_SIZE_BASE_SHIFT 6
|
||||
|
||||
/* Collision related configuration parameters */
|
||||
#define IGC_COLLISION_THRESHOLD 15
|
||||
#define IGC_CT_SHIFT 4
|
||||
#define IGC_COLLISION_DISTANCE 63
|
||||
#define IGC_COLD_SHIFT 12
|
||||
|
||||
/* Device Status */
|
||||
#define IGC_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
|
||||
#define IGC_STATUS_LU 0x00000002 /* Link up.0=no,1=link */
|
||||
#define IGC_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */
|
||||
#define IGC_STATUS_FUNC_SHIFT 2
|
||||
#define IGC_STATUS_TXOFF 0x00000010 /* transmission paused */
|
||||
#define IGC_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
|
||||
#define IGC_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
|
||||
#define IGC_STATUS_SPEED_2500 0x00400000 /* Speed 2.5Gb/s */
|
||||
|
||||
#define SPEED_10 10
|
||||
#define SPEED_100 100
|
||||
#define SPEED_1000 1000
|
||||
#define SPEED_2500 2500
|
||||
#define HALF_DUPLEX 1
|
||||
#define FULL_DUPLEX 2
|
||||
|
||||
/* 1Gbps and 2.5Gbps half duplex is not supported, nor spec-compliant. */
|
||||
#define ADVERTISE_10_HALF 0x0001
|
||||
#define ADVERTISE_10_FULL 0x0002
|
||||
#define ADVERTISE_100_HALF 0x0004
|
||||
#define ADVERTISE_100_FULL 0x0008
|
||||
#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */
|
||||
#define ADVERTISE_1000_FULL 0x0020
|
||||
#define ADVERTISE_2500_HALF 0x0040 /* Not used, just FYI */
|
||||
#define ADVERTISE_2500_FULL 0x0080
|
||||
|
||||
#define IGC_ALL_SPEED_DUPLEX_2500 ( \
|
||||
ADVERTISE_10_HALF | ADVERTISE_10_FULL | ADVERTISE_100_HALF | \
|
||||
ADVERTISE_100_FULL | ADVERTISE_1000_FULL | ADVERTISE_2500_FULL)
|
||||
|
||||
#define AUTONEG_ADVERTISE_SPEED_DEFAULT_2500 IGC_ALL_SPEED_DUPLEX_2500
|
||||
|
||||
/* Interrupt Cause Read */
|
||||
#define IGC_ICR_TXDW BIT(0) /* Transmit desc written back */
|
||||
#define IGC_ICR_TXQE BIT(1) /* Transmit Queue empty */
|
||||
#define IGC_ICR_LSC BIT(2) /* Link Status Change */
|
||||
#define IGC_ICR_RXSEQ BIT(3) /* Rx sequence error */
|
||||
#define IGC_ICR_RXDMT0 BIT(4) /* Rx desc min. threshold (0) */
|
||||
#define IGC_ICR_RXO BIT(6) /* Rx overrun */
|
||||
#define IGC_ICR_RXT0 BIT(7) /* Rx timer intr (ring 0) */
|
||||
#define IGC_ICR_TS BIT(19) /* Time Sync Interrupt */
|
||||
#define IGC_ICR_DRSTA BIT(30) /* Device Reset Asserted */
|
||||
|
||||
/* If this bit asserted, the driver should claim the interrupt */
|
||||
#define IGC_ICR_INT_ASSERTED BIT(31)
|
||||
|
||||
#define IGC_ICS_RXT0 IGC_ICR_RXT0 /* Rx timer intr */
|
||||
|
||||
#define IMS_ENABLE_MASK ( \
|
||||
IGC_IMS_RXT0 | \
|
||||
IGC_IMS_TXDW | \
|
||||
IGC_IMS_RXDMT0 | \
|
||||
IGC_IMS_RXSEQ | \
|
||||
IGC_IMS_LSC)
|
||||
|
||||
/* Interrupt Mask Set */
|
||||
#define IGC_IMS_TXDW IGC_ICR_TXDW /* Tx desc written back */
|
||||
#define IGC_IMS_RXSEQ IGC_ICR_RXSEQ /* Rx sequence error */
|
||||
#define IGC_IMS_LSC IGC_ICR_LSC /* Link Status Change */
|
||||
#define IGC_IMS_DOUTSYNC IGC_ICR_DOUTSYNC /* NIC DMA out of sync */
|
||||
#define IGC_IMS_DRSTA IGC_ICR_DRSTA /* Device Reset Asserted */
|
||||
#define IGC_IMS_RXT0 IGC_ICR_RXT0 /* Rx timer intr */
|
||||
#define IGC_IMS_RXDMT0 IGC_ICR_RXDMT0 /* Rx desc min. threshold */
|
||||
#define IGC_IMS_TS IGC_ICR_TS /* Time Sync Interrupt */
|
||||
|
||||
#define IGC_QVECTOR_MASK 0x7FFC /* Q-vector mask */
|
||||
#define IGC_ITR_VAL_MASK 0x04 /* ITR value mask */
|
||||
|
||||
/* Interrupt Cause Set */
|
||||
#define IGC_ICS_LSC IGC_ICR_LSC /* Link Status Change */
|
||||
#define IGC_ICS_RXDMT0 IGC_ICR_RXDMT0 /* rx desc min. threshold */
|
||||
|
||||
#define IGC_ICR_DOUTSYNC 0x10000000 /* NIC DMA out of sync */
|
||||
#define IGC_EITR_CNT_IGNR 0x80000000 /* Don't reset counters on write */
|
||||
#define IGC_IVAR_VALID 0x80
|
||||
#define IGC_GPIE_NSICR 0x00000001
|
||||
#define IGC_GPIE_MSIX_MODE 0x00000010
|
||||
#define IGC_GPIE_EIAME 0x40000000
|
||||
#define IGC_GPIE_PBA 0x80000000
|
||||
|
||||
/* Receive Descriptor bit definitions */
|
||||
#define IGC_RXD_STAT_DD 0x01 /* Descriptor Done */
|
||||
|
||||
/* Transmit Descriptor bit definitions */
|
||||
#define IGC_TXD_DTYP_D 0x00100000 /* Data Descriptor */
|
||||
#define IGC_TXD_DTYP_C 0x00000000 /* Context Descriptor */
|
||||
#define IGC_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
|
||||
#define IGC_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
|
||||
#define IGC_TXD_CMD_EOP 0x01000000 /* End of Packet */
|
||||
#define IGC_TXD_CMD_IC 0x04000000 /* Insert Checksum */
|
||||
#define IGC_TXD_CMD_DEXT 0x20000000 /* Desc extension (0 = legacy) */
|
||||
#define IGC_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
|
||||
#define IGC_TXD_STAT_DD 0x00000001 /* Descriptor Done */
|
||||
#define IGC_TXD_CMD_TCP 0x01000000 /* TCP packet */
|
||||
#define IGC_TXD_CMD_IP 0x02000000 /* IP packet */
|
||||
#define IGC_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
|
||||
#define IGC_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */
|
||||
|
||||
/* IPSec Encrypt Enable */
|
||||
#define IGC_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
|
||||
#define IGC_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
|
||||
|
||||
#define IGC_ADVTXD_TSN_CNTX_FIRST 0x00000080
|
||||
|
||||
/* Transmit Control */
|
||||
#define IGC_TCTL_EN 0x00000002 /* enable Tx */
|
||||
#define IGC_TCTL_PSP 0x00000008 /* pad short packets */
|
||||
#define IGC_TCTL_CT 0x00000ff0 /* collision threshold */
|
||||
#define IGC_TCTL_COLD 0x003ff000 /* collision distance */
|
||||
#define IGC_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
|
||||
|
||||
/* Flow Control Constants */
|
||||
#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001
|
||||
#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
|
||||
#define FLOW_CONTROL_TYPE 0x8808
|
||||
/* Enable XON frame transmission */
|
||||
#define IGC_FCRTL_XONE 0x80000000
|
||||
|
||||
/* Management Control */
|
||||
#define IGC_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */
|
||||
#define IGC_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */
|
||||
|
||||
/* Receive Control */
|
||||
#define IGC_RCTL_RST 0x00000001 /* Software reset */
|
||||
#define IGC_RCTL_EN 0x00000002 /* enable */
|
||||
#define IGC_RCTL_SBP 0x00000004 /* store bad packet */
|
||||
#define IGC_RCTL_UPE 0x00000008 /* unicast promisc enable */
|
||||
#define IGC_RCTL_MPE 0x00000010 /* multicast promisc enable */
|
||||
#define IGC_RCTL_LPE 0x00000020 /* long packet enable */
|
||||
#define IGC_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */
|
||||
#define IGC_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */
|
||||
|
||||
#define IGC_RCTL_RDMTS_HALF 0x00000000 /* Rx desc min thresh size */
|
||||
#define IGC_RCTL_BAM 0x00008000 /* broadcast enable */
|
||||
|
||||
/* Split Replication Receive Control */
|
||||
#define IGC_SRRCTL_TIMESTAMP 0x40000000
|
||||
#define IGC_SRRCTL_TIMER1SEL(timer) (((timer) & 0x3) << 14)
|
||||
#define IGC_SRRCTL_TIMER0SEL(timer) (((timer) & 0x3) << 17)
|
||||
|
||||
/* Receive Descriptor bit definitions */
|
||||
#define IGC_RXD_STAT_EOP 0x02 /* End of Packet */
|
||||
#define IGC_RXD_STAT_IXSM 0x04 /* Ignore checksum */
|
||||
#define IGC_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */
|
||||
#define IGC_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */
|
||||
#define IGC_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
|
||||
|
||||
#define IGC_RXDEXT_STATERR_LB 0x00040000
|
||||
|
||||
/* Advanced Receive Descriptor bit definitions */
|
||||
#define IGC_RXDADV_STAT_TSIP 0x08000 /* timestamp in packet */
|
||||
|
||||
#define IGC_RXDEXT_STATERR_L4E 0x20000000
|
||||
#define IGC_RXDEXT_STATERR_IPE 0x40000000
|
||||
#define IGC_RXDEXT_STATERR_RXE 0x80000000
|
||||
|
||||
#define IGC_MRQC_RSS_FIELD_IPV4_TCP 0x00010000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV4 0x00020000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6 0x00100000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6_TCP 0x00200000
|
||||
|
||||
/* Header split receive */
|
||||
#define IGC_RFCTL_IPV6_EX_DIS 0x00010000
|
||||
#define IGC_RFCTL_LEF 0x00040000
|
||||
|
||||
#define IGC_RCTL_SZ_256 0x00030000 /* Rx buffer size 256 */
|
||||
|
||||
#define IGC_RCTL_MO_SHIFT 12 /* multicast offset shift */
|
||||
#define IGC_RCTL_CFIEN 0x00080000 /* canonical form enable */
|
||||
#define IGC_RCTL_DPF 0x00400000 /* discard pause frames */
|
||||
#define IGC_RCTL_PMCF 0x00800000 /* pass MAC control frames */
|
||||
#define IGC_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
|
||||
|
||||
#define I225_RXPBSIZE_DEFAULT 0x000000A2 /* RXPBSIZE default */
|
||||
#define I225_TXPBSIZE_DEFAULT 0x04000014 /* TXPBSIZE default */
|
||||
#define IGC_RXPBS_CFG_TS_EN 0x80000000 /* Timestamp in Rx buffer */
|
||||
|
||||
#define IGC_TXPBSIZE_TSN 0x04145145 /* 5k bytes buffer for each queue */
|
||||
|
||||
#define IGC_DTXMXPKTSZ_TSN 0x19 /* 1600 bytes of max TX DMA packet size */
|
||||
#define IGC_DTXMXPKTSZ_DEFAULT 0x98 /* 9728-byte Jumbo frames */
|
||||
|
||||
/* Transmit Scheduling Latency */
|
||||
/* Latency between transmission scheduling (LaunchTime) and the time
|
||||
* the packet is transmitted to the network in nanosecond.
|
||||
*/
|
||||
#define IGC_TXOFFSET_SPEED_10 0x000034BC
|
||||
#define IGC_TXOFFSET_SPEED_100 0x00000578
|
||||
#define IGC_TXOFFSET_SPEED_1000 0x0000012C
|
||||
#define IGC_TXOFFSET_SPEED_2500 0x00000578
|
||||
|
||||
/* Time Sync Interrupt Causes */
|
||||
#define IGC_TSICR_SYS_WRAP BIT(0) /* SYSTIM Wrap around. */
|
||||
#define IGC_TSICR_TXTS BIT(1) /* Transmit Timestamp. */
|
||||
#define IGC_TSICR_TT0 BIT(3) /* Target Time 0 Trigger. */
|
||||
#define IGC_TSICR_TT1 BIT(4) /* Target Time 1 Trigger. */
|
||||
#define IGC_TSICR_AUTT0 BIT(5) /* Auxiliary Timestamp 0 Taken. */
|
||||
#define IGC_TSICR_AUTT1 BIT(6) /* Auxiliary Timestamp 1 Taken. */
|
||||
|
||||
#define IGC_TSICR_INTERRUPTS IGC_TSICR_TXTS
|
||||
|
||||
#define IGC_FTQF_VF_BP 0x00008000
|
||||
#define IGC_FTQF_1588_TIME_STAMP 0x08000000
|
||||
#define IGC_FTQF_MASK 0xF0000000
|
||||
#define IGC_FTQF_MASK_PROTO_BP 0x10000000
|
||||
|
||||
/* Time Sync Receive Control bit definitions */
|
||||
#define IGC_TSYNCRXCTL_TYPE_MASK 0x0000000E /* Rx type mask */
|
||||
#define IGC_TSYNCRXCTL_TYPE_L2_V2 0x00
|
||||
#define IGC_TSYNCRXCTL_TYPE_L4_V1 0x02
|
||||
#define IGC_TSYNCRXCTL_TYPE_L2_L4_V2 0x04
|
||||
#define IGC_TSYNCRXCTL_TYPE_ALL 0x08
|
||||
#define IGC_TSYNCRXCTL_TYPE_EVENT_V2 0x0A
|
||||
#define IGC_TSYNCRXCTL_ENABLED 0x00000010 /* enable Rx timestamping */
|
||||
#define IGC_TSYNCRXCTL_SYSCFI 0x00000020 /* Sys clock frequency */
|
||||
#define IGC_TSYNCRXCTL_RXSYNSIG 0x00000400 /* Sample RX tstamp in PHY sop */
|
||||
|
||||
/* Time Sync Receive Configuration */
|
||||
#define IGC_TSYNCRXCFG_PTP_V1_CTRLT_MASK 0x000000FF
|
||||
#define IGC_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE 0x00
|
||||
#define IGC_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE 0x01
|
||||
|
||||
/* Immediate Interrupt Receive */
|
||||
#define IGC_IMIR_CLEAR_MASK 0xF001FFFF /* IMIR Reg Clear Mask */
|
||||
#define IGC_IMIR_PORT_BYPASS 0x20000 /* IMIR Port Bypass Bit */
|
||||
#define IGC_IMIR_PRIORITY_SHIFT 29 /* IMIR Priority Shift */
|
||||
#define IGC_IMIREXT_CLEAR_MASK 0x7FFFF /* IMIREXT Reg Clear Mask */
|
||||
|
||||
/* Immediate Interrupt Receive Extended */
|
||||
#define IGC_IMIREXT_CTRL_BP 0x00080000 /* Bypass check of ctrl bits */
|
||||
#define IGC_IMIREXT_SIZE_BP 0x00001000 /* Packet size bypass */
|
||||
|
||||
/* Time Sync Transmit Control bit definitions */
|
||||
#define IGC_TSYNCTXCTL_TXTT_0 0x00000001 /* Tx timestamp reg 0 valid */
|
||||
#define IGC_TSYNCTXCTL_TXTT_1 0x00000002 /* Tx timestamp reg 1 valid */
|
||||
#define IGC_TSYNCTXCTL_TXTT_2 0x00000004 /* Tx timestamp reg 2 valid */
|
||||
#define IGC_TSYNCTXCTL_TXTT_3 0x00000008 /* Tx timestamp reg 3 valid */
|
||||
#define IGC_TSYNCTXCTL_ENABLED 0x00000010 /* enable Tx timestamping */
|
||||
#define IGC_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK 0x0000F000 /* max delay */
|
||||
#define IGC_TSYNCTXCTL_SYNC_COMP_ERR 0x20000000 /* sync err */
|
||||
#define IGC_TSYNCTXCTL_SYNC_COMP 0x40000000 /* sync complete */
|
||||
#define IGC_TSYNCTXCTL_START_SYNC 0x80000000 /* initiate sync */
|
||||
#define IGC_TSYNCTXCTL_TXSYNSIG 0x00000020 /* Sample TX tstamp in PHY sop */
|
||||
|
||||
#define IGC_TSYNCTXCTL_TXTT_ANY ( \
|
||||
IGC_TSYNCTXCTL_TXTT_0 | IGC_TSYNCTXCTL_TXTT_1 | \
|
||||
IGC_TSYNCTXCTL_TXTT_2 | IGC_TSYNCTXCTL_TXTT_3)
|
||||
|
||||
/* Timer selection bits */
|
||||
#define IGC_AUX_IO_TIMER_SEL_SYSTIM0 (0u << 30) /* Select SYSTIM0 for auxiliary time stamp */
|
||||
#define IGC_AUX_IO_TIMER_SEL_SYSTIM1 (1u << 30) /* Select SYSTIM1 for auxiliary time stamp */
|
||||
#define IGC_AUX_IO_TIMER_SEL_SYSTIM2 (2u << 30) /* Select SYSTIM2 for auxiliary time stamp */
|
||||
#define IGC_AUX_IO_TIMER_SEL_SYSTIM3 (3u << 30) /* Select SYSTIM3 for auxiliary time stamp */
|
||||
#define IGC_TT_IO_TIMER_SEL_SYSTIM0 (0u << 30) /* Select SYSTIM0 for target time stamp */
|
||||
#define IGC_TT_IO_TIMER_SEL_SYSTIM1 (1u << 30) /* Select SYSTIM1 for target time stamp */
|
||||
#define IGC_TT_IO_TIMER_SEL_SYSTIM2 (2u << 30) /* Select SYSTIM2 for target time stamp */
|
||||
#define IGC_TT_IO_TIMER_SEL_SYSTIM3 (3u << 30) /* Select SYSTIM3 for target time stamp */
|
||||
|
||||
/* TSAUXC Configuration Bits */
|
||||
#define IGC_TSAUXC_EN_TT0 BIT(0) /* Enable target time 0. */
|
||||
#define IGC_TSAUXC_EN_TT1 BIT(1) /* Enable target time 1. */
|
||||
#define IGC_TSAUXC_EN_CLK0 BIT(2) /* Enable Configurable Frequency Clock 0. */
|
||||
#define IGC_TSAUXC_ST0 BIT(4) /* Start Clock 0 Toggle on Target Time 0. */
|
||||
#define IGC_TSAUXC_EN_CLK1 BIT(5) /* Enable Configurable Frequency Clock 1. */
|
||||
#define IGC_TSAUXC_ST1 BIT(7) /* Start Clock 1 Toggle on Target Time 1. */
|
||||
#define IGC_TSAUXC_EN_TS0 BIT(8) /* Enable hardware timestamp 0. */
|
||||
#define IGC_TSAUXC_AUTT0 BIT(9) /* Auxiliary Timestamp Taken. */
|
||||
#define IGC_TSAUXC_EN_TS1 BIT(10) /* Enable hardware timestamp 0. */
|
||||
#define IGC_TSAUXC_AUTT1 BIT(11) /* Auxiliary Timestamp Taken. */
|
||||
#define IGC_TSAUXC_PLSG BIT(17) /* Generate a pulse. */
|
||||
#define IGC_TSAUXC_DISABLE1 BIT(27) /* Disable SYSTIM0 Count Operation. */
|
||||
#define IGC_TSAUXC_DISABLE2 BIT(28) /* Disable SYSTIM1 Count Operation. */
|
||||
#define IGC_TSAUXC_DISABLE3 BIT(29) /* Disable SYSTIM2 Count Operation. */
|
||||
#define IGC_TSAUXC_DIS_TS_CLEAR BIT(30) /* Disable EN_TT0/1 auto clear. */
|
||||
#define IGC_TSAUXC_DISABLE0 BIT(31) /* Disable SYSTIM0 Count Operation. */
|
||||
|
||||
/* SDP Configuration Bits */
|
||||
#define IGC_AUX0_SEL_SDP0 (0u << 0) /* Assign SDP0 to auxiliary time stamp 0. */
|
||||
#define IGC_AUX0_SEL_SDP1 (1u << 0) /* Assign SDP1 to auxiliary time stamp 0. */
|
||||
#define IGC_AUX0_SEL_SDP2 (2u << 0) /* Assign SDP2 to auxiliary time stamp 0. */
|
||||
#define IGC_AUX0_SEL_SDP3 (3u << 0) /* Assign SDP3 to auxiliary time stamp 0. */
|
||||
#define IGC_AUX0_TS_SDP_EN (1u << 2) /* Enable auxiliary time stamp trigger 0. */
|
||||
#define IGC_AUX1_SEL_SDP0 (0u << 3) /* Assign SDP0 to auxiliary time stamp 1. */
|
||||
#define IGC_AUX1_SEL_SDP1 (1u << 3) /* Assign SDP1 to auxiliary time stamp 1. */
|
||||
#define IGC_AUX1_SEL_SDP2 (2u << 3) /* Assign SDP2 to auxiliary time stamp 1. */
|
||||
#define IGC_AUX1_SEL_SDP3 (3u << 3) /* Assign SDP3 to auxiliary time stamp 1. */
|
||||
#define IGC_AUX1_TS_SDP_EN (1u << 5) /* Enable auxiliary time stamp trigger 1. */
|
||||
#define IGC_TS_SDP0_SEL_TT0 (0u << 6) /* Target time 0 is output on SDP0. */
|
||||
#define IGC_TS_SDP0_SEL_TT1 (1u << 6) /* Target time 1 is output on SDP0. */
|
||||
#define IGC_TS_SDP0_SEL_FC0 (2u << 6) /* Freq clock 0 is output on SDP0. */
|
||||
#define IGC_TS_SDP0_SEL_FC1 (3u << 6) /* Freq clock 1 is output on SDP0. */
|
||||
#define IGC_TS_SDP0_EN (1u << 8) /* SDP0 is assigned to Tsync. */
|
||||
#define IGC_TS_SDP1_SEL_TT0 (0u << 9) /* Target time 0 is output on SDP1. */
|
||||
#define IGC_TS_SDP1_SEL_TT1 (1u << 9) /* Target time 1 is output on SDP1. */
|
||||
#define IGC_TS_SDP1_SEL_FC0 (2u << 9) /* Freq clock 0 is output on SDP1. */
|
||||
#define IGC_TS_SDP1_SEL_FC1 (3u << 9) /* Freq clock 1 is output on SDP1. */
|
||||
#define IGC_TS_SDP1_EN (1u << 11) /* SDP1 is assigned to Tsync. */
|
||||
#define IGC_TS_SDP2_SEL_TT0 (0u << 12) /* Target time 0 is output on SDP2. */
|
||||
#define IGC_TS_SDP2_SEL_TT1 (1u << 12) /* Target time 1 is output on SDP2. */
|
||||
#define IGC_TS_SDP2_SEL_FC0 (2u << 12) /* Freq clock 0 is output on SDP2. */
|
||||
#define IGC_TS_SDP2_SEL_FC1 (3u << 12) /* Freq clock 1 is output on SDP2. */
|
||||
#define IGC_TS_SDP2_EN (1u << 14) /* SDP2 is assigned to Tsync. */
|
||||
#define IGC_TS_SDP3_SEL_TT0 (0u << 15) /* Target time 0 is output on SDP3. */
|
||||
#define IGC_TS_SDP3_SEL_TT1 (1u << 15) /* Target time 1 is output on SDP3. */
|
||||
#define IGC_TS_SDP3_SEL_FC0 (2u << 15) /* Freq clock 0 is output on SDP3. */
|
||||
#define IGC_TS_SDP3_SEL_FC1 (3u << 15) /* Freq clock 1 is output on SDP3. */
|
||||
#define IGC_TS_SDP3_EN (1u << 17) /* SDP3 is assigned to Tsync. */
|
||||
|
||||
/* Transmit Scheduling */
|
||||
#define IGC_TQAVCTRL_TRANSMIT_MODE_TSN 0x00000001
|
||||
#define IGC_TQAVCTRL_ENHANCED_QAV 0x00000008
|
||||
#define IGC_TQAVCTRL_FUTSCDDIS 0x00000080
|
||||
|
||||
#define IGC_TXQCTL_QUEUE_MODE_LAUNCHT 0x00000001
|
||||
#define IGC_TXQCTL_STRICT_CYCLE 0x00000002
|
||||
#define IGC_TXQCTL_STRICT_END 0x00000004
|
||||
#define IGC_TXQCTL_QAV_SEL_MASK 0x000000C0
|
||||
#define IGC_TXQCTL_QAV_SEL_CBS0 0x00000080
|
||||
#define IGC_TXQCTL_QAV_SEL_CBS1 0x000000C0
|
||||
|
||||
#define IGC_TQAVCC_IDLESLOPE_MASK 0xFFFF
|
||||
#define IGC_TQAVCC_KEEP_CREDITS BIT(30)
|
||||
|
||||
#define IGC_MAX_SR_QUEUES 2
|
||||
|
||||
/* Receive Checksum Control */
|
||||
#define IGC_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */
|
||||
#define IGC_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */
|
||||
|
||||
/* PCIe PTM Control */
|
||||
#define IGC_PTM_CTRL_START_NOW BIT(29) /* Start PTM Now */
|
||||
#define IGC_PTM_CTRL_EN BIT(30) /* Enable PTM */
|
||||
#define IGC_PTM_CTRL_TRIG BIT(31) /* PTM Cycle trigger */
|
||||
#define IGC_PTM_CTRL_SHRT_CYC(usec) (((usec) & 0x3f) << 2)
|
||||
#define IGC_PTM_CTRL_PTM_TO(usec) (((usec) & 0xff) << 8)
|
||||
|
||||
#define IGC_PTM_SHORT_CYC_DEFAULT 1 /* Default short cycle interval */
|
||||
#define IGC_PTM_CYC_TIME_DEFAULT 5 /* Default PTM cycle time */
|
||||
#define IGC_PTM_TIMEOUT_DEFAULT 255 /* Default timeout for PTM errors */
|
||||
|
||||
/* PCIe Digital Delay */
|
||||
#define IGC_PCIE_DIG_DELAY_DEFAULT 0x01440000
|
||||
|
||||
/* PCIe PHY Delay */
|
||||
#define IGC_PCIE_PHY_DELAY_DEFAULT 0x40900000
|
||||
|
||||
#define IGC_TIMADJ_ADJUST_METH 0x40000000
|
||||
|
||||
/* PCIe PTM Status */
|
||||
#define IGC_PTM_STAT_VALID BIT(0) /* PTM Status */
|
||||
#define IGC_PTM_STAT_RET_ERR BIT(1) /* Root port timeout */
|
||||
#define IGC_PTM_STAT_BAD_PTM_RES BIT(2) /* PTM Response msg instead of PTM Response Data */
|
||||
#define IGC_PTM_STAT_T4M1_OVFL BIT(3) /* T4 minus T1 overflow */
|
||||
#define IGC_PTM_STAT_ADJUST_1ST BIT(4) /* 1588 timer adjusted during 1st PTM cycle */
|
||||
#define IGC_PTM_STAT_ADJUST_CYC BIT(5) /* 1588 timer adjusted during non-1st PTM cycle */
|
||||
|
||||
/* PCIe PTM Cycle Control */
|
||||
#define IGC_PTM_CYCLE_CTRL_CYC_TIME(msec) ((msec) & 0x3ff) /* PTM Cycle Time (msec) */
|
||||
#define IGC_PTM_CYCLE_CTRL_AUTO_CYC_EN BIT(31) /* PTM Cycle Control */
|
||||
|
||||
/* GPY211 - I225 defines */
|
||||
#define GPY_MMD_MASK 0xFFFF0000
|
||||
#define GPY_MMD_SHIFT 16
|
||||
#define GPY_REG_MASK 0x0000FFFF
|
||||
|
||||
#define IGC_MMDAC_FUNC_DATA 0x4000 /* Data, no post increment */
|
||||
|
||||
/* MAC definitions */
|
||||
#define IGC_FACTPS_MNGCG 0x20000000
|
||||
#define IGC_FWSM_MODE_MASK 0xE
|
||||
#define IGC_FWSM_MODE_SHIFT 1
|
||||
|
||||
/* Management Control */
|
||||
#define IGC_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */
|
||||
#define IGC_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */
|
||||
|
||||
/* PHY */
|
||||
#define PHY_REVISION_MASK 0xFFFFFFF0
|
||||
#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
|
||||
#define IGC_GEN_POLL_TIMEOUT 1920
|
||||
|
||||
/* PHY Control Register */
|
||||
#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
|
||||
#define MII_CR_POWER_DOWN 0x0800 /* Power down */
|
||||
#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
|
||||
|
||||
/* PHY Status Register */
|
||||
#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
|
||||
#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
|
||||
#define IGC_PHY_RST_COMP 0x0100 /* Internal PHY reset completion */
|
||||
|
||||
/* PHY 1000 MII Register/Bit Definitions */
|
||||
/* PHY Registers defined by IEEE */
|
||||
#define PHY_CONTROL 0x00 /* Control Register */
|
||||
#define PHY_STATUS 0x01 /* Status Register */
|
||||
#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
|
||||
#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
|
||||
#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
|
||||
#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
|
||||
#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
|
||||
#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
|
||||
|
||||
/* MDI Control */
|
||||
#define IGC_MDIC_DATA_MASK 0x0000FFFF
|
||||
#define IGC_MDIC_REG_MASK 0x001F0000
|
||||
#define IGC_MDIC_REG_SHIFT 16
|
||||
#define IGC_MDIC_PHY_MASK 0x03E00000
|
||||
#define IGC_MDIC_PHY_SHIFT 21
|
||||
#define IGC_MDIC_OP_WRITE 0x04000000
|
||||
#define IGC_MDIC_OP_READ 0x08000000
|
||||
#define IGC_MDIC_READY 0x10000000
|
||||
#define IGC_MDIC_ERROR 0x40000000
|
||||
|
||||
#define IGC_N0_QUEUE -1
|
||||
|
||||
#define IGC_MAX_MAC_HDR_LEN 127
|
||||
#define IGC_MAX_NETWORK_HDR_LEN 511
|
||||
|
||||
#define IGC_VLANPQF_QSEL(_n, q_idx) ((q_idx) << ((_n) * 4))
|
||||
#define IGC_VLANPQF_VALID(_n) (0x1 << (3 + (_n) * 4))
|
||||
#define IGC_VLANPQF_QUEUE_MASK 0x03
|
||||
|
||||
#define IGC_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
|
||||
#define IGC_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type:1=IPv4 */
|
||||
#define IGC_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet Type of TCP */
|
||||
#define IGC_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 packet TYPE of SCTP */
|
||||
|
||||
/* Maximum size of the MTA register table in all supported adapters */
|
||||
#define MAX_MTA_REG 128
|
||||
|
||||
/* EEE defines */
|
||||
#define IGC_IPCNFG_EEE_2_5G_AN 0x00000010 /* IPCNFG EEE Ena 2.5G AN */
|
||||
#define IGC_IPCNFG_EEE_1G_AN 0x00000008 /* IPCNFG EEE Ena 1G AN */
|
||||
#define IGC_IPCNFG_EEE_100M_AN 0x00000004 /* IPCNFG EEE Ena 100M AN */
|
||||
#define IGC_EEER_EEE_NEG 0x20000000 /* EEE capability nego */
|
||||
#define IGC_EEER_TX_LPI_EN 0x00010000 /* EEER Tx LPI Enable */
|
||||
#define IGC_EEER_RX_LPI_EN 0x00020000 /* EEER Rx LPI Enable */
|
||||
#define IGC_EEER_LPI_FC 0x00040000 /* EEER Ena on Flow Cntrl */
|
||||
#define IGC_EEE_SU_LPI_CLK_STP 0x00800000 /* EEE LPI Clock Stop */
|
||||
|
||||
/* LTR defines */
|
||||
#define IGC_LTRC_EEEMS_EN 0x00000020 /* Enable EEE LTR max send */
|
||||
#define IGC_RXPBS_SIZE_I225_MASK 0x0000003F /* Rx packet buffer size */
|
||||
#define IGC_TW_SYSTEM_1000_MASK 0x000000FF
|
||||
/* Minimum time for 100BASE-T where no data will be transmit following move out
|
||||
* of EEE LPI Tx state
|
||||
*/
|
||||
#define IGC_TW_SYSTEM_100_MASK 0x0000FF00
|
||||
#define IGC_TW_SYSTEM_100_SHIFT 8
|
||||
/* Reg val to set scale to 1024 nsec */
|
||||
#define IGC_LTRMINV_SCALE_1024 2
|
||||
/* Reg val to set scale to 32768 nsec */
|
||||
#define IGC_LTRMINV_SCALE_32768 3
|
||||
/* Reg val to set scale to 1024 nsec */
|
||||
#define IGC_LTRMAXV_SCALE_1024 2
|
||||
/* Reg val to set scale to 32768 nsec */
|
||||
#define IGC_LTRMAXV_SCALE_32768 3
|
||||
#define IGC_LTRMINV_LTRV_MASK 0x000003FF /* LTR minimum value */
|
||||
#define IGC_LTRMAXV_LTRV_MASK 0x000003FF /* LTR maximum value */
|
||||
#define IGC_LTRMINV_LSNP_REQ 0x00008000 /* LTR Snoop Requirement */
|
||||
#define IGC_LTRMINV_SCALE_SHIFT 10
|
||||
#define IGC_LTRMAXV_LSNP_REQ 0x00008000 /* LTR Snoop Requirement */
|
||||
#define IGC_LTRMAXV_SCALE_SHIFT 10
|
||||
|
||||
#endif /* _IGC_DEFINES_H_ */
|
||||
|
|
@ -0,0 +1,687 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_DEFINES_H_
|
||||
#define _IGC_DEFINES_H_
|
||||
|
||||
/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
|
||||
#define REQ_TX_DESCRIPTOR_MULTIPLE 8
|
||||
#define REQ_RX_DESCRIPTOR_MULTIPLE 8
|
||||
|
||||
#define IGC_CTRL_EXT_SDP2_DIR 0x00000400 /* SDP2 Data direction */
|
||||
#define IGC_CTRL_EXT_SDP3_DIR 0x00000800 /* SDP3 Data direction */
|
||||
#define IGC_CTRL_EXT_DRV_LOAD 0x10000000 /* Drv loaded bit for FW */
|
||||
|
||||
/* Definitions for power management and wakeup registers */
|
||||
/* Wake Up Control */
|
||||
#define IGC_WUC_PME_EN 0x00000002 /* PME Enable */
|
||||
|
||||
/* Wake Up Filter Control */
|
||||
#define IGC_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
|
||||
#define IGC_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */
|
||||
#define IGC_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */
|
||||
#define IGC_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */
|
||||
#define IGC_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
|
||||
#define IGC_WUFC_FLEX_HQ BIT(14) /* Flex Filters Host Queuing */
|
||||
#define IGC_WUFC_FLX0 BIT(16) /* Flexible Filter 0 Enable */
|
||||
#define IGC_WUFC_FLX1 BIT(17) /* Flexible Filter 1 Enable */
|
||||
#define IGC_WUFC_FLX2 BIT(18) /* Flexible Filter 2 Enable */
|
||||
#define IGC_WUFC_FLX3 BIT(19) /* Flexible Filter 3 Enable */
|
||||
#define IGC_WUFC_FLX4 BIT(20) /* Flexible Filter 4 Enable */
|
||||
#define IGC_WUFC_FLX5 BIT(21) /* Flexible Filter 5 Enable */
|
||||
#define IGC_WUFC_FLX6 BIT(22) /* Flexible Filter 6 Enable */
|
||||
#define IGC_WUFC_FLX7 BIT(23) /* Flexible Filter 7 Enable */
|
||||
|
||||
#define IGC_WUFC_FILTER_MASK GENMASK(23, 14)
|
||||
|
||||
#define IGC_CTRL_ADVD3WUC 0x00100000 /* D3 WUC */
|
||||
|
||||
/* Wake Up Status */
|
||||
#define IGC_WUS_EX 0x00000004 /* Directed Exact */
|
||||
#define IGC_WUS_ARPD 0x00000020 /* Directed ARP Request */
|
||||
#define IGC_WUS_IPV4 0x00000040 /* Directed IPv4 */
|
||||
#define IGC_WUS_IPV6 0x00000080 /* Directed IPv6 */
|
||||
#define IGC_WUS_NSD 0x00000400 /* Directed IPv6 Neighbor Solicitation */
|
||||
|
||||
/* Packet types that are enabled for wake packet delivery */
|
||||
#define WAKE_PKT_WUS ( \
|
||||
IGC_WUS_EX | \
|
||||
IGC_WUS_ARPD | \
|
||||
IGC_WUS_IPV4 | \
|
||||
IGC_WUS_IPV6 | \
|
||||
IGC_WUS_NSD)
|
||||
|
||||
/* Wake Up Packet Length */
|
||||
#define IGC_WUPL_MASK 0x00000FFF
|
||||
|
||||
/* Wake Up Packet Memory stores the first 128 bytes of the wake up packet */
|
||||
#define IGC_WUPM_BYTES 128
|
||||
|
||||
/* Wakeup Filter Control Extended */
|
||||
#define IGC_WUFC_EXT_FLX8 BIT(8) /* Flexible Filter 8 Enable */
|
||||
#define IGC_WUFC_EXT_FLX9 BIT(9) /* Flexible Filter 9 Enable */
|
||||
#define IGC_WUFC_EXT_FLX10 BIT(10) /* Flexible Filter 10 Enable */
|
||||
#define IGC_WUFC_EXT_FLX11 BIT(11) /* Flexible Filter 11 Enable */
|
||||
#define IGC_WUFC_EXT_FLX12 BIT(12) /* Flexible Filter 12 Enable */
|
||||
#define IGC_WUFC_EXT_FLX13 BIT(13) /* Flexible Filter 13 Enable */
|
||||
#define IGC_WUFC_EXT_FLX14 BIT(14) /* Flexible Filter 14 Enable */
|
||||
#define IGC_WUFC_EXT_FLX15 BIT(15) /* Flexible Filter 15 Enable */
|
||||
#define IGC_WUFC_EXT_FLX16 BIT(16) /* Flexible Filter 16 Enable */
|
||||
#define IGC_WUFC_EXT_FLX17 BIT(17) /* Flexible Filter 17 Enable */
|
||||
#define IGC_WUFC_EXT_FLX18 BIT(18) /* Flexible Filter 18 Enable */
|
||||
#define IGC_WUFC_EXT_FLX19 BIT(19) /* Flexible Filter 19 Enable */
|
||||
#define IGC_WUFC_EXT_FLX20 BIT(20) /* Flexible Filter 20 Enable */
|
||||
#define IGC_WUFC_EXT_FLX21 BIT(21) /* Flexible Filter 21 Enable */
|
||||
#define IGC_WUFC_EXT_FLX22 BIT(22) /* Flexible Filter 22 Enable */
|
||||
#define IGC_WUFC_EXT_FLX23 BIT(23) /* Flexible Filter 23 Enable */
|
||||
#define IGC_WUFC_EXT_FLX24 BIT(24) /* Flexible Filter 24 Enable */
|
||||
#define IGC_WUFC_EXT_FLX25 BIT(25) /* Flexible Filter 25 Enable */
|
||||
#define IGC_WUFC_EXT_FLX26 BIT(26) /* Flexible Filter 26 Enable */
|
||||
#define IGC_WUFC_EXT_FLX27 BIT(27) /* Flexible Filter 27 Enable */
|
||||
#define IGC_WUFC_EXT_FLX28 BIT(28) /* Flexible Filter 28 Enable */
|
||||
#define IGC_WUFC_EXT_FLX29 BIT(29) /* Flexible Filter 29 Enable */
|
||||
#define IGC_WUFC_EXT_FLX30 BIT(30) /* Flexible Filter 30 Enable */
|
||||
#define IGC_WUFC_EXT_FLX31 BIT(31) /* Flexible Filter 31 Enable */
|
||||
|
||||
#define IGC_WUFC_EXT_FILTER_MASK GENMASK(31, 8)
|
||||
|
||||
/* Loop limit on how long we wait for auto-negotiation to complete */
|
||||
#define COPPER_LINK_UP_LIMIT 10
|
||||
#define PHY_AUTO_NEG_LIMIT 45
|
||||
|
||||
/* Number of 100 microseconds we wait for PCI Express master disable */
|
||||
#define MASTER_DISABLE_TIMEOUT 800
|
||||
/*Blocks new Master requests */
|
||||
#define IGC_CTRL_GIO_MASTER_DISABLE 0x00000004
|
||||
/* Status of Master requests. */
|
||||
#define IGC_STATUS_GIO_MASTER_ENABLE 0x00080000
|
||||
|
||||
/* Receive Address
|
||||
* Number of high/low register pairs in the RAR. The RAR (Receive Address
|
||||
* Registers) holds the directed and multicast addresses that we monitor.
|
||||
* Technically, we have 16 spots. However, we reserve one of these spots
|
||||
* (RAR[15]) for our directed address used by controllers with
|
||||
* manageability enabled, allowing us room for 15 multicast addresses.
|
||||
*/
|
||||
#define IGC_RAH_RAH_MASK 0x0000FFFF
|
||||
#define IGC_RAH_ASEL_MASK 0x00030000
|
||||
#define IGC_RAH_ASEL_SRC_ADDR BIT(16)
|
||||
#define IGC_RAH_QSEL_MASK 0x000C0000
|
||||
#define IGC_RAH_QSEL_SHIFT 18
|
||||
#define IGC_RAH_QSEL_ENABLE BIT(28)
|
||||
#define IGC_RAH_AV 0x80000000 /* Receive descriptor valid */
|
||||
|
||||
#define IGC_RAL_MAC_ADDR_LEN 4
|
||||
#define IGC_RAH_MAC_ADDR_LEN 2
|
||||
|
||||
/* Error Codes */
|
||||
#define IGC_SUCCESS 0
|
||||
#define IGC_ERR_NVM 1
|
||||
#define IGC_ERR_PHY 2
|
||||
#define IGC_ERR_CONFIG 3
|
||||
#define IGC_ERR_PARAM 4
|
||||
#define IGC_ERR_MAC_INIT 5
|
||||
#define IGC_ERR_RESET 9
|
||||
#define IGC_ERR_MASTER_REQUESTS_PENDING 10
|
||||
#define IGC_ERR_BLK_PHY_RESET 12
|
||||
#define IGC_ERR_SWFW_SYNC 13
|
||||
|
||||
/* Device Control */
|
||||
#define IGC_CTRL_RST 0x04000000 /* Global reset */
|
||||
|
||||
#define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */
|
||||
#define IGC_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
|
||||
#define IGC_CTRL_FRCSPD 0x00000800 /* Force Speed */
|
||||
#define IGC_CTRL_FRCDPX 0x00001000 /* Force Duplex */
|
||||
#define IGC_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
|
||||
|
||||
#define IGC_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
|
||||
#define IGC_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
|
||||
|
||||
#define IGC_CTRL_SDP0_DIR 0x00400000 /* SDP0 Data direction */
|
||||
#define IGC_CTRL_SDP1_DIR 0x00800000 /* SDP1 Data direction */
|
||||
|
||||
/* As per the EAS the maximum supported size is 9.5KB (9728 bytes) */
|
||||
#define MAX_JUMBO_FRAME_SIZE 0x2600
|
||||
|
||||
/* PBA constants */
|
||||
#define IGC_PBA_34K 0x0022
|
||||
|
||||
/* SW Semaphore Register */
|
||||
#define IGC_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
|
||||
#define IGC_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
|
||||
|
||||
/* SWFW_SYNC Definitions */
|
||||
#define IGC_SWFW_EEP_SM 0x1
|
||||
#define IGC_SWFW_PHY0_SM 0x2
|
||||
|
||||
/* Autoneg Advertisement Register */
|
||||
#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
|
||||
#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
|
||||
#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
|
||||
#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
|
||||
#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
|
||||
#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
|
||||
|
||||
/* Link Partner Ability Register (Base Page) */
|
||||
#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
|
||||
#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
|
||||
|
||||
/* 1000BASE-T Control Register */
|
||||
#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
|
||||
#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
|
||||
|
||||
/* 1000BASE-T Status Register */
|
||||
#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
|
||||
|
||||
/* PHY GPY 211 registers */
|
||||
#define STANDARD_AN_REG_MASK 0x0007 /* MMD */
|
||||
#define ANEG_MULTIGBT_AN_CTRL 0x0020 /* MULTI GBT AN Control Register */
|
||||
#define MMD_DEVADDR_SHIFT 16 /* Shift MMD to higher bits */
|
||||
#define CR_2500T_FD_CAPS 0x0080 /* Advertise 2500T FD capability */
|
||||
|
||||
/* NVM Control */
|
||||
/* Number of milliseconds for NVM auto read done after MAC reset. */
|
||||
#define AUTO_READ_DONE_TIMEOUT 10
|
||||
#define IGC_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */
|
||||
#define IGC_EECD_REQ 0x00000040 /* NVM Access Request */
|
||||
#define IGC_EECD_GNT 0x00000080 /* NVM Access Grant */
|
||||
/* NVM Addressing bits based on type 0=small, 1=large */
|
||||
#define IGC_EECD_ADDR_BITS 0x00000400
|
||||
#define IGC_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */
|
||||
#define IGC_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */
|
||||
#define IGC_EECD_SIZE_EX_SHIFT 11
|
||||
#define IGC_EECD_FLUPD_I225 0x00800000 /* Update FLASH */
|
||||
#define IGC_EECD_FLUDONE_I225 0x04000000 /* Update FLASH done*/
|
||||
#define IGC_EECD_FLASH_DETECTED_I225 0x00080000 /* FLASH detected */
|
||||
#define IGC_FLUDONE_ATTEMPTS 20000
|
||||
#define IGC_EERD_EEWR_MAX_COUNT 512 /* buffered EEPROM words rw */
|
||||
|
||||
/* Offset to data in NVM read/write registers */
|
||||
#define IGC_NVM_RW_REG_DATA 16
|
||||
#define IGC_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */
|
||||
#define IGC_NVM_RW_REG_START 1 /* Start operation */
|
||||
#define IGC_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */
|
||||
#define IGC_NVM_POLL_READ 0 /* Flag for polling for read complete */
|
||||
#define IGC_NVM_DEV_STARTER 5 /* Dev_starter Version */
|
||||
|
||||
/* NVM Word Offsets */
|
||||
#define NVM_CHECKSUM_REG 0x003F
|
||||
|
||||
/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
|
||||
#define NVM_SUM 0xBABA
|
||||
#define NVM_WORD_SIZE_BASE_SHIFT 6
|
||||
|
||||
/* Collision related configuration parameters */
|
||||
#define IGC_COLLISION_THRESHOLD 15
|
||||
#define IGC_CT_SHIFT 4
|
||||
#define IGC_COLLISION_DISTANCE 63
|
||||
#define IGC_COLD_SHIFT 12
|
||||
|
||||
/* Device Status */
|
||||
#define IGC_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
|
||||
#define IGC_STATUS_LU 0x00000002 /* Link up.0=no,1=link */
|
||||
#define IGC_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */
|
||||
#define IGC_STATUS_FUNC_SHIFT 2
|
||||
#define IGC_STATUS_TXOFF 0x00000010 /* transmission paused */
|
||||
#define IGC_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
|
||||
#define IGC_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
|
||||
#define IGC_STATUS_SPEED_2500 0x00400000 /* Speed 2.5Gb/s */
|
||||
|
||||
#define SPEED_10 10
|
||||
#define SPEED_100 100
|
||||
#define SPEED_1000 1000
|
||||
#define SPEED_2500 2500
|
||||
#define HALF_DUPLEX 1
|
||||
#define FULL_DUPLEX 2
|
||||
|
||||
/* 1Gbps and 2.5Gbps half duplex is not supported, nor spec-compliant. */
|
||||
#define ADVERTISE_10_HALF 0x0001
|
||||
#define ADVERTISE_10_FULL 0x0002
|
||||
#define ADVERTISE_100_HALF 0x0004
|
||||
#define ADVERTISE_100_FULL 0x0008
|
||||
#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */
|
||||
#define ADVERTISE_1000_FULL 0x0020
|
||||
#define ADVERTISE_2500_HALF 0x0040 /* Not used, just FYI */
|
||||
#define ADVERTISE_2500_FULL 0x0080
|
||||
|
||||
#define IGC_ALL_SPEED_DUPLEX_2500 ( \
|
||||
ADVERTISE_10_HALF | ADVERTISE_10_FULL | ADVERTISE_100_HALF | \
|
||||
ADVERTISE_100_FULL | ADVERTISE_1000_FULL | ADVERTISE_2500_FULL)
|
||||
|
||||
#define AUTONEG_ADVERTISE_SPEED_DEFAULT_2500 IGC_ALL_SPEED_DUPLEX_2500
|
||||
|
||||
/* Interrupt Cause Read */
|
||||
#define IGC_ICR_TXDW BIT(0) /* Transmit desc written back */
|
||||
#define IGC_ICR_TXQE BIT(1) /* Transmit Queue empty */
|
||||
#define IGC_ICR_LSC BIT(2) /* Link Status Change */
|
||||
#define IGC_ICR_RXSEQ BIT(3) /* Rx sequence error */
|
||||
#define IGC_ICR_RXDMT0 BIT(4) /* Rx desc min. threshold (0) */
|
||||
#define IGC_ICR_RXO BIT(6) /* Rx overrun */
|
||||
#define IGC_ICR_RXT0 BIT(7) /* Rx timer intr (ring 0) */
|
||||
#define IGC_ICR_TS BIT(19) /* Time Sync Interrupt */
|
||||
#define IGC_ICR_DRSTA BIT(30) /* Device Reset Asserted */
|
||||
|
||||
/* If this bit asserted, the driver should claim the interrupt */
|
||||
#define IGC_ICR_INT_ASSERTED BIT(31)
|
||||
|
||||
#define IGC_ICS_RXT0 IGC_ICR_RXT0 /* Rx timer intr */
|
||||
|
||||
#define IMS_ENABLE_MASK ( \
|
||||
IGC_IMS_RXT0 | \
|
||||
IGC_IMS_TXDW | \
|
||||
IGC_IMS_RXDMT0 | \
|
||||
IGC_IMS_RXSEQ | \
|
||||
IGC_IMS_LSC)
|
||||
|
||||
/* Interrupt Mask Set */
|
||||
#define IGC_IMS_TXDW IGC_ICR_TXDW /* Tx desc written back */
|
||||
#define IGC_IMS_RXSEQ IGC_ICR_RXSEQ /* Rx sequence error */
|
||||
#define IGC_IMS_LSC IGC_ICR_LSC /* Link Status Change */
|
||||
#define IGC_IMS_DOUTSYNC IGC_ICR_DOUTSYNC /* NIC DMA out of sync */
|
||||
#define IGC_IMS_DRSTA IGC_ICR_DRSTA /* Device Reset Asserted */
|
||||
#define IGC_IMS_RXT0 IGC_ICR_RXT0 /* Rx timer intr */
|
||||
#define IGC_IMS_RXDMT0 IGC_ICR_RXDMT0 /* Rx desc min. threshold */
|
||||
#define IGC_IMS_TS IGC_ICR_TS /* Time Sync Interrupt */
|
||||
|
||||
#define IGC_QVECTOR_MASK 0x7FFC /* Q-vector mask */
|
||||
#define IGC_ITR_VAL_MASK 0x04 /* ITR value mask */
|
||||
|
||||
/* Interrupt Cause Set */
|
||||
#define IGC_ICS_LSC IGC_ICR_LSC /* Link Status Change */
|
||||
#define IGC_ICS_RXDMT0 IGC_ICR_RXDMT0 /* rx desc min. threshold */
|
||||
|
||||
#define IGC_ICR_DOUTSYNC 0x10000000 /* NIC DMA out of sync */
|
||||
#define IGC_EITR_CNT_IGNR 0x80000000 /* Don't reset counters on write */
|
||||
#define IGC_IVAR_VALID 0x80
|
||||
#define IGC_GPIE_NSICR 0x00000001
|
||||
#define IGC_GPIE_MSIX_MODE 0x00000010
|
||||
#define IGC_GPIE_EIAME 0x40000000
|
||||
#define IGC_GPIE_PBA 0x80000000
|
||||
|
||||
/* Receive Descriptor bit definitions */
|
||||
#define IGC_RXD_STAT_DD 0x01 /* Descriptor Done */
|
||||
|
||||
/* Transmit Descriptor bit definitions */
|
||||
#define IGC_TXD_DTYP_D 0x00100000 /* Data Descriptor */
|
||||
#define IGC_TXD_DTYP_C 0x00000000 /* Context Descriptor */
|
||||
#define IGC_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
|
||||
#define IGC_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
|
||||
#define IGC_TXD_CMD_EOP 0x01000000 /* End of Packet */
|
||||
#define IGC_TXD_CMD_IC 0x04000000 /* Insert Checksum */
|
||||
#define IGC_TXD_CMD_DEXT 0x20000000 /* Desc extension (0 = legacy) */
|
||||
#define IGC_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
|
||||
#define IGC_TXD_STAT_DD 0x00000001 /* Descriptor Done */
|
||||
#define IGC_TXD_CMD_TCP 0x01000000 /* TCP packet */
|
||||
#define IGC_TXD_CMD_IP 0x02000000 /* IP packet */
|
||||
#define IGC_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
|
||||
#define IGC_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */
|
||||
|
||||
/* IPSec Encrypt Enable */
|
||||
#define IGC_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
|
||||
#define IGC_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
|
||||
|
||||
#define IGC_ADVTXD_TSN_CNTX_FIRST 0x00000080
|
||||
|
||||
/* Transmit Control */
|
||||
#define IGC_TCTL_EN 0x00000002 /* enable Tx */
|
||||
#define IGC_TCTL_PSP 0x00000008 /* pad short packets */
|
||||
#define IGC_TCTL_CT 0x00000ff0 /* collision threshold */
|
||||
#define IGC_TCTL_COLD 0x003ff000 /* collision distance */
|
||||
#define IGC_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
|
||||
|
||||
/* Flow Control Constants */
|
||||
#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001
|
||||
#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
|
||||
#define FLOW_CONTROL_TYPE 0x8808
|
||||
/* Enable XON frame transmission */
|
||||
#define IGC_FCRTL_XONE 0x80000000
|
||||
|
||||
/* Management Control */
|
||||
#define IGC_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */
|
||||
#define IGC_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */
|
||||
|
||||
/* Receive Control */
|
||||
#define IGC_RCTL_RST 0x00000001 /* Software reset */
|
||||
#define IGC_RCTL_EN 0x00000002 /* enable */
|
||||
#define IGC_RCTL_SBP 0x00000004 /* store bad packet */
|
||||
#define IGC_RCTL_UPE 0x00000008 /* unicast promisc enable */
|
||||
#define IGC_RCTL_MPE 0x00000010 /* multicast promisc enable */
|
||||
#define IGC_RCTL_LPE 0x00000020 /* long packet enable */
|
||||
#define IGC_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */
|
||||
#define IGC_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */
|
||||
|
||||
#define IGC_RCTL_RDMTS_HALF 0x00000000 /* Rx desc min thresh size */
|
||||
#define IGC_RCTL_BAM 0x00008000 /* broadcast enable */
|
||||
|
||||
/* Split Replication Receive Control */
|
||||
#define IGC_SRRCTL_TIMESTAMP 0x40000000
|
||||
#define IGC_SRRCTL_TIMER1SEL(timer) (((timer) & 0x3) << 14)
|
||||
#define IGC_SRRCTL_TIMER0SEL(timer) (((timer) & 0x3) << 17)
|
||||
|
||||
/* Receive Descriptor bit definitions */
|
||||
#define IGC_RXD_STAT_EOP 0x02 /* End of Packet */
|
||||
#define IGC_RXD_STAT_IXSM 0x04 /* Ignore checksum */
|
||||
#define IGC_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */
|
||||
#define IGC_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */
|
||||
#define IGC_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
|
||||
|
||||
#define IGC_RXDEXT_STATERR_LB 0x00040000
|
||||
|
||||
/* Advanced Receive Descriptor bit definitions */
|
||||
#define IGC_RXDADV_STAT_TSIP 0x08000 /* timestamp in packet */
|
||||
|
||||
#define IGC_RXDEXT_STATERR_L4E 0x20000000
|
||||
#define IGC_RXDEXT_STATERR_IPE 0x40000000
|
||||
#define IGC_RXDEXT_STATERR_RXE 0x80000000
|
||||
|
||||
#define IGC_MRQC_RSS_FIELD_IPV4_TCP 0x00010000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV4 0x00020000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6 0x00100000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6_TCP 0x00200000
|
||||
|
||||
/* Header split receive */
|
||||
#define IGC_RFCTL_IPV6_EX_DIS 0x00010000
|
||||
#define IGC_RFCTL_LEF 0x00040000
|
||||
|
||||
#define IGC_RCTL_SZ_256 0x00030000 /* Rx buffer size 256 */
|
||||
|
||||
#define IGC_RCTL_MO_SHIFT 12 /* multicast offset shift */
|
||||
#define IGC_RCTL_CFIEN 0x00080000 /* canonical form enable */
|
||||
#define IGC_RCTL_DPF 0x00400000 /* discard pause frames */
|
||||
#define IGC_RCTL_PMCF 0x00800000 /* pass MAC control frames */
|
||||
#define IGC_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
|
||||
|
||||
#define I225_RXPBSIZE_DEFAULT 0x000000A2 /* RXPBSIZE default */
|
||||
#define I225_TXPBSIZE_DEFAULT 0x04000014 /* TXPBSIZE default */
|
||||
#define IGC_RXPBS_CFG_TS_EN 0x80000000 /* Timestamp in Rx buffer */
|
||||
|
||||
#define IGC_TXPBSIZE_TSN 0x04145145 /* 5k bytes buffer for each queue */
|
||||
|
||||
#define IGC_DTXMXPKTSZ_TSN 0x19 /* 1600 bytes of max TX DMA packet size */
|
||||
#define IGC_DTXMXPKTSZ_DEFAULT 0x98 /* 9728-byte Jumbo frames */
|
||||
|
||||
/* Transmit Scheduling Latency */
|
||||
/* Latency between transmission scheduling (LaunchTime) and the time
|
||||
* the packet is transmitted to the network in nanosecond.
|
||||
*/
|
||||
#define IGC_TXOFFSET_SPEED_10 0x000034BC
|
||||
#define IGC_TXOFFSET_SPEED_100 0x00000578
|
||||
#define IGC_TXOFFSET_SPEED_1000 0x0000012C
|
||||
#define IGC_TXOFFSET_SPEED_2500 0x00000578
|
||||
|
||||
/* Time Sync Interrupt Causes */
|
||||
#define IGC_TSICR_SYS_WRAP BIT(0) /* SYSTIM Wrap around. */
|
||||
#define IGC_TSICR_TXTS BIT(1) /* Transmit Timestamp. */
|
||||
#define IGC_TSICR_TT0 BIT(3) /* Target Time 0 Trigger. */
|
||||
#define IGC_TSICR_TT1 BIT(4) /* Target Time 1 Trigger. */
|
||||
#define IGC_TSICR_AUTT0 BIT(5) /* Auxiliary Timestamp 0 Taken. */
|
||||
#define IGC_TSICR_AUTT1 BIT(6) /* Auxiliary Timestamp 1 Taken. */
|
||||
|
||||
#define IGC_TSICR_INTERRUPTS IGC_TSICR_TXTS
|
||||
|
||||
#define IGC_FTQF_VF_BP 0x00008000
|
||||
#define IGC_FTQF_1588_TIME_STAMP 0x08000000
|
||||
#define IGC_FTQF_MASK 0xF0000000
|
||||
#define IGC_FTQF_MASK_PROTO_BP 0x10000000
|
||||
|
||||
/* Time Sync Receive Control bit definitions */
|
||||
#define IGC_TSYNCRXCTL_TYPE_MASK 0x0000000E /* Rx type mask */
|
||||
#define IGC_TSYNCRXCTL_TYPE_L2_V2 0x00
|
||||
#define IGC_TSYNCRXCTL_TYPE_L4_V1 0x02
|
||||
#define IGC_TSYNCRXCTL_TYPE_L2_L4_V2 0x04
|
||||
#define IGC_TSYNCRXCTL_TYPE_ALL 0x08
|
||||
#define IGC_TSYNCRXCTL_TYPE_EVENT_V2 0x0A
|
||||
#define IGC_TSYNCRXCTL_ENABLED 0x00000010 /* enable Rx timestamping */
|
||||
#define IGC_TSYNCRXCTL_SYSCFI 0x00000020 /* Sys clock frequency */
|
||||
#define IGC_TSYNCRXCTL_RXSYNSIG 0x00000400 /* Sample RX tstamp in PHY sop */
|
||||
|
||||
/* Time Sync Receive Configuration */
|
||||
#define IGC_TSYNCRXCFG_PTP_V1_CTRLT_MASK 0x000000FF
|
||||
#define IGC_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE 0x00
|
||||
#define IGC_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE 0x01
|
||||
|
||||
/* Immediate Interrupt Receive */
|
||||
#define IGC_IMIR_CLEAR_MASK 0xF001FFFF /* IMIR Reg Clear Mask */
|
||||
#define IGC_IMIR_PORT_BYPASS 0x20000 /* IMIR Port Bypass Bit */
|
||||
#define IGC_IMIR_PRIORITY_SHIFT 29 /* IMIR Priority Shift */
|
||||
#define IGC_IMIREXT_CLEAR_MASK 0x7FFFF /* IMIREXT Reg Clear Mask */
|
||||
|
||||
/* Immediate Interrupt Receive Extended */
|
||||
#define IGC_IMIREXT_CTRL_BP 0x00080000 /* Bypass check of ctrl bits */
|
||||
#define IGC_IMIREXT_SIZE_BP 0x00001000 /* Packet size bypass */
|
||||
|
||||
/* Time Sync Transmit Control bit definitions */
|
||||
#define IGC_TSYNCTXCTL_TXTT_0 0x00000001 /* Tx timestamp reg 0 valid */
|
||||
#define IGC_TSYNCTXCTL_TXTT_1 0x00000002 /* Tx timestamp reg 1 valid */
|
||||
#define IGC_TSYNCTXCTL_TXTT_2 0x00000004 /* Tx timestamp reg 2 valid */
|
||||
#define IGC_TSYNCTXCTL_TXTT_3 0x00000008 /* Tx timestamp reg 3 valid */
|
||||
#define IGC_TSYNCTXCTL_ENABLED 0x00000010 /* enable Tx timestamping */
|
||||
#define IGC_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK 0x0000F000 /* max delay */
|
||||
#define IGC_TSYNCTXCTL_SYNC_COMP_ERR 0x20000000 /* sync err */
|
||||
#define IGC_TSYNCTXCTL_SYNC_COMP 0x40000000 /* sync complete */
|
||||
#define IGC_TSYNCTXCTL_START_SYNC 0x80000000 /* initiate sync */
|
||||
#define IGC_TSYNCTXCTL_TXSYNSIG 0x00000020 /* Sample TX tstamp in PHY sop */
|
||||
|
||||
#define IGC_TSYNCTXCTL_TXTT_ANY ( \
|
||||
IGC_TSYNCTXCTL_TXTT_0 | IGC_TSYNCTXCTL_TXTT_1 | \
|
||||
IGC_TSYNCTXCTL_TXTT_2 | IGC_TSYNCTXCTL_TXTT_3)
|
||||
|
||||
/* Timer selection bits */
|
||||
#define IGC_AUX_IO_TIMER_SEL_SYSTIM0 (0u << 30) /* Select SYSTIM0 for auxiliary time stamp */
|
||||
#define IGC_AUX_IO_TIMER_SEL_SYSTIM1 (1u << 30) /* Select SYSTIM1 for auxiliary time stamp */
|
||||
#define IGC_AUX_IO_TIMER_SEL_SYSTIM2 (2u << 30) /* Select SYSTIM2 for auxiliary time stamp */
|
||||
#define IGC_AUX_IO_TIMER_SEL_SYSTIM3 (3u << 30) /* Select SYSTIM3 for auxiliary time stamp */
|
||||
#define IGC_TT_IO_TIMER_SEL_SYSTIM0 (0u << 30) /* Select SYSTIM0 for target time stamp */
|
||||
#define IGC_TT_IO_TIMER_SEL_SYSTIM1 (1u << 30) /* Select SYSTIM1 for target time stamp */
|
||||
#define IGC_TT_IO_TIMER_SEL_SYSTIM2 (2u << 30) /* Select SYSTIM2 for target time stamp */
|
||||
#define IGC_TT_IO_TIMER_SEL_SYSTIM3 (3u << 30) /* Select SYSTIM3 for target time stamp */
|
||||
|
||||
/* TSAUXC Configuration Bits */
|
||||
#define IGC_TSAUXC_EN_TT0 BIT(0) /* Enable target time 0. */
|
||||
#define IGC_TSAUXC_EN_TT1 BIT(1) /* Enable target time 1. */
|
||||
#define IGC_TSAUXC_EN_CLK0 BIT(2) /* Enable Configurable Frequency Clock 0. */
|
||||
#define IGC_TSAUXC_ST0 BIT(4) /* Start Clock 0 Toggle on Target Time 0. */
|
||||
#define IGC_TSAUXC_EN_CLK1 BIT(5) /* Enable Configurable Frequency Clock 1. */
|
||||
#define IGC_TSAUXC_ST1 BIT(7) /* Start Clock 1 Toggle on Target Time 1. */
|
||||
#define IGC_TSAUXC_EN_TS0 BIT(8) /* Enable hardware timestamp 0. */
|
||||
#define IGC_TSAUXC_AUTT0 BIT(9) /* Auxiliary Timestamp Taken. */
|
||||
#define IGC_TSAUXC_EN_TS1 BIT(10) /* Enable hardware timestamp 0. */
|
||||
#define IGC_TSAUXC_AUTT1 BIT(11) /* Auxiliary Timestamp Taken. */
|
||||
#define IGC_TSAUXC_PLSG BIT(17) /* Generate a pulse. */
|
||||
#define IGC_TSAUXC_DISABLE1 BIT(27) /* Disable SYSTIM0 Count Operation. */
|
||||
#define IGC_TSAUXC_DISABLE2 BIT(28) /* Disable SYSTIM1 Count Operation. */
|
||||
#define IGC_TSAUXC_DISABLE3 BIT(29) /* Disable SYSTIM2 Count Operation. */
|
||||
#define IGC_TSAUXC_DIS_TS_CLEAR BIT(30) /* Disable EN_TT0/1 auto clear. */
|
||||
#define IGC_TSAUXC_DISABLE0 BIT(31) /* Disable SYSTIM0 Count Operation. */
|
||||
|
||||
/* SDP Configuration Bits */
|
||||
#define IGC_AUX0_SEL_SDP0 (0u << 0) /* Assign SDP0 to auxiliary time stamp 0. */
|
||||
#define IGC_AUX0_SEL_SDP1 (1u << 0) /* Assign SDP1 to auxiliary time stamp 0. */
|
||||
#define IGC_AUX0_SEL_SDP2 (2u << 0) /* Assign SDP2 to auxiliary time stamp 0. */
|
||||
#define IGC_AUX0_SEL_SDP3 (3u << 0) /* Assign SDP3 to auxiliary time stamp 0. */
|
||||
#define IGC_AUX0_TS_SDP_EN (1u << 2) /* Enable auxiliary time stamp trigger 0. */
|
||||
#define IGC_AUX1_SEL_SDP0 (0u << 3) /* Assign SDP0 to auxiliary time stamp 1. */
|
||||
#define IGC_AUX1_SEL_SDP1 (1u << 3) /* Assign SDP1 to auxiliary time stamp 1. */
|
||||
#define IGC_AUX1_SEL_SDP2 (2u << 3) /* Assign SDP2 to auxiliary time stamp 1. */
|
||||
#define IGC_AUX1_SEL_SDP3 (3u << 3) /* Assign SDP3 to auxiliary time stamp 1. */
|
||||
#define IGC_AUX1_TS_SDP_EN (1u << 5) /* Enable auxiliary time stamp trigger 1. */
|
||||
#define IGC_TS_SDP0_SEL_TT0 (0u << 6) /* Target time 0 is output on SDP0. */
|
||||
#define IGC_TS_SDP0_SEL_TT1 (1u << 6) /* Target time 1 is output on SDP0. */
|
||||
#define IGC_TS_SDP0_SEL_FC0 (2u << 6) /* Freq clock 0 is output on SDP0. */
|
||||
#define IGC_TS_SDP0_SEL_FC1 (3u << 6) /* Freq clock 1 is output on SDP0. */
|
||||
#define IGC_TS_SDP0_EN (1u << 8) /* SDP0 is assigned to Tsync. */
|
||||
#define IGC_TS_SDP1_SEL_TT0 (0u << 9) /* Target time 0 is output on SDP1. */
|
||||
#define IGC_TS_SDP1_SEL_TT1 (1u << 9) /* Target time 1 is output on SDP1. */
|
||||
#define IGC_TS_SDP1_SEL_FC0 (2u << 9) /* Freq clock 0 is output on SDP1. */
|
||||
#define IGC_TS_SDP1_SEL_FC1 (3u << 9) /* Freq clock 1 is output on SDP1. */
|
||||
#define IGC_TS_SDP1_EN (1u << 11) /* SDP1 is assigned to Tsync. */
|
||||
#define IGC_TS_SDP2_SEL_TT0 (0u << 12) /* Target time 0 is output on SDP2. */
|
||||
#define IGC_TS_SDP2_SEL_TT1 (1u << 12) /* Target time 1 is output on SDP2. */
|
||||
#define IGC_TS_SDP2_SEL_FC0 (2u << 12) /* Freq clock 0 is output on SDP2. */
|
||||
#define IGC_TS_SDP2_SEL_FC1 (3u << 12) /* Freq clock 1 is output on SDP2. */
|
||||
#define IGC_TS_SDP2_EN (1u << 14) /* SDP2 is assigned to Tsync. */
|
||||
#define IGC_TS_SDP3_SEL_TT0 (0u << 15) /* Target time 0 is output on SDP3. */
|
||||
#define IGC_TS_SDP3_SEL_TT1 (1u << 15) /* Target time 1 is output on SDP3. */
|
||||
#define IGC_TS_SDP3_SEL_FC0 (2u << 15) /* Freq clock 0 is output on SDP3. */
|
||||
#define IGC_TS_SDP3_SEL_FC1 (3u << 15) /* Freq clock 1 is output on SDP3. */
|
||||
#define IGC_TS_SDP3_EN (1u << 17) /* SDP3 is assigned to Tsync. */
|
||||
|
||||
/* Transmit Scheduling */
|
||||
#define IGC_TQAVCTRL_TRANSMIT_MODE_TSN 0x00000001
|
||||
#define IGC_TQAVCTRL_ENHANCED_QAV 0x00000008
|
||||
#define IGC_TQAVCTRL_FUTSCDDIS 0x00000080
|
||||
|
||||
#define IGC_TXQCTL_QUEUE_MODE_LAUNCHT 0x00000001
|
||||
#define IGC_TXQCTL_STRICT_CYCLE 0x00000002
|
||||
#define IGC_TXQCTL_STRICT_END 0x00000004
|
||||
#define IGC_TXQCTL_QAV_SEL_MASK 0x000000C0
|
||||
#define IGC_TXQCTL_QAV_SEL_CBS0 0x00000080
|
||||
#define IGC_TXQCTL_QAV_SEL_CBS1 0x000000C0
|
||||
|
||||
#define IGC_TQAVCC_IDLESLOPE_MASK 0xFFFF
|
||||
#define IGC_TQAVCC_KEEP_CREDITS BIT(30)
|
||||
|
||||
#define IGC_MAX_SR_QUEUES 2
|
||||
|
||||
/* Receive Checksum Control */
|
||||
#define IGC_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */
|
||||
#define IGC_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */
|
||||
|
||||
/* PCIe PTM Control */
|
||||
#define IGC_PTM_CTRL_START_NOW BIT(29) /* Start PTM Now */
|
||||
#define IGC_PTM_CTRL_EN BIT(30) /* Enable PTM */
|
||||
#define IGC_PTM_CTRL_TRIG BIT(31) /* PTM Cycle trigger */
|
||||
#define IGC_PTM_CTRL_SHRT_CYC(usec) (((usec) & 0x3f) << 2)
|
||||
#define IGC_PTM_CTRL_PTM_TO(usec) (((usec) & 0xff) << 8)
|
||||
|
||||
#define IGC_PTM_SHORT_CYC_DEFAULT 1 /* Default short cycle interval */
|
||||
#define IGC_PTM_CYC_TIME_DEFAULT 5 /* Default PTM cycle time */
|
||||
#define IGC_PTM_TIMEOUT_DEFAULT 255 /* Default timeout for PTM errors */
|
||||
|
||||
/* PCIe Digital Delay */
|
||||
#define IGC_PCIE_DIG_DELAY_DEFAULT 0x01440000
|
||||
|
||||
/* PCIe PHY Delay */
|
||||
#define IGC_PCIE_PHY_DELAY_DEFAULT 0x40900000
|
||||
|
||||
#define IGC_TIMADJ_ADJUST_METH 0x40000000
|
||||
|
||||
/* PCIe PTM Status */
|
||||
#define IGC_PTM_STAT_VALID BIT(0) /* PTM Status */
|
||||
#define IGC_PTM_STAT_RET_ERR BIT(1) /* Root port timeout */
|
||||
#define IGC_PTM_STAT_BAD_PTM_RES BIT(2) /* PTM Response msg instead of PTM Response Data */
|
||||
#define IGC_PTM_STAT_T4M1_OVFL BIT(3) /* T4 minus T1 overflow */
|
||||
#define IGC_PTM_STAT_ADJUST_1ST BIT(4) /* 1588 timer adjusted during 1st PTM cycle */
|
||||
#define IGC_PTM_STAT_ADJUST_CYC BIT(5) /* 1588 timer adjusted during non-1st PTM cycle */
|
||||
|
||||
/* PCIe PTM Cycle Control */
|
||||
#define IGC_PTM_CYCLE_CTRL_CYC_TIME(msec) ((msec) & 0x3ff) /* PTM Cycle Time (msec) */
|
||||
#define IGC_PTM_CYCLE_CTRL_AUTO_CYC_EN BIT(31) /* PTM Cycle Control */
|
||||
|
||||
/* GPY211 - I225 defines */
|
||||
#define GPY_MMD_MASK 0xFFFF0000
|
||||
#define GPY_MMD_SHIFT 16
|
||||
#define GPY_REG_MASK 0x0000FFFF
|
||||
|
||||
#define IGC_MMDAC_FUNC_DATA 0x4000 /* Data, no post increment */
|
||||
|
||||
/* MAC definitions */
|
||||
#define IGC_FACTPS_MNGCG 0x20000000
|
||||
#define IGC_FWSM_MODE_MASK 0xE
|
||||
#define IGC_FWSM_MODE_SHIFT 1
|
||||
|
||||
/* Management Control */
|
||||
#define IGC_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */
|
||||
#define IGC_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */
|
||||
|
||||
/* PHY */
|
||||
#define PHY_REVISION_MASK 0xFFFFFFF0
|
||||
#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
|
||||
#define IGC_GEN_POLL_TIMEOUT 1920
|
||||
|
||||
/* PHY Control Register */
|
||||
#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
|
||||
#define MII_CR_POWER_DOWN 0x0800 /* Power down */
|
||||
#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
|
||||
|
||||
/* PHY Status Register */
|
||||
#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
|
||||
#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
|
||||
#define IGC_PHY_RST_COMP 0x0100 /* Internal PHY reset completion */
|
||||
|
||||
/* PHY 1000 MII Register/Bit Definitions */
|
||||
/* PHY Registers defined by IEEE */
|
||||
#define PHY_CONTROL 0x00 /* Control Register */
|
||||
#define PHY_STATUS 0x01 /* Status Register */
|
||||
#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
|
||||
#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
|
||||
#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
|
||||
#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
|
||||
#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
|
||||
#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
|
||||
|
||||
/* MDI Control */
|
||||
#define IGC_MDIC_DATA_MASK 0x0000FFFF
|
||||
#define IGC_MDIC_REG_MASK 0x001F0000
|
||||
#define IGC_MDIC_REG_SHIFT 16
|
||||
#define IGC_MDIC_PHY_MASK 0x03E00000
|
||||
#define IGC_MDIC_PHY_SHIFT 21
|
||||
#define IGC_MDIC_OP_WRITE 0x04000000
|
||||
#define IGC_MDIC_OP_READ 0x08000000
|
||||
#define IGC_MDIC_READY 0x10000000
|
||||
#define IGC_MDIC_ERROR 0x40000000
|
||||
|
||||
#define IGC_N0_QUEUE -1
|
||||
|
||||
#define IGC_MAX_MAC_HDR_LEN 127
|
||||
#define IGC_MAX_NETWORK_HDR_LEN 511
|
||||
|
||||
#define IGC_VLANPQF_QSEL(_n, q_idx) ((q_idx) << ((_n) * 4))
|
||||
#define IGC_VLANPQF_VALID(_n) (0x1 << (3 + (_n) * 4))
|
||||
#define IGC_VLANPQF_QUEUE_MASK 0x03
|
||||
|
||||
#define IGC_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
|
||||
#define IGC_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type:1=IPv4 */
|
||||
#define IGC_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet Type of TCP */
|
||||
#define IGC_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 packet TYPE of SCTP */
|
||||
|
||||
/* Maximum size of the MTA register table in all supported adapters */
|
||||
#define MAX_MTA_REG 128
|
||||
|
||||
/* EEE defines */
|
||||
#define IGC_IPCNFG_EEE_2_5G_AN 0x00000010 /* IPCNFG EEE Ena 2.5G AN */
|
||||
#define IGC_IPCNFG_EEE_1G_AN 0x00000008 /* IPCNFG EEE Ena 1G AN */
|
||||
#define IGC_IPCNFG_EEE_100M_AN 0x00000004 /* IPCNFG EEE Ena 100M AN */
|
||||
#define IGC_EEER_EEE_NEG 0x20000000 /* EEE capability nego */
|
||||
#define IGC_EEER_TX_LPI_EN 0x00010000 /* EEER Tx LPI Enable */
|
||||
#define IGC_EEER_RX_LPI_EN 0x00020000 /* EEER Rx LPI Enable */
|
||||
#define IGC_EEER_LPI_FC 0x00040000 /* EEER Ena on Flow Cntrl */
|
||||
#define IGC_EEE_SU_LPI_CLK_STP 0x00800000 /* EEE LPI Clock Stop */
|
||||
|
||||
/* LTR defines */
|
||||
#define IGC_LTRC_EEEMS_EN 0x00000020 /* Enable EEE LTR max send */
|
||||
#define IGC_RXPBS_SIZE_I225_MASK 0x0000003F /* Rx packet buffer size */
|
||||
#define IGC_TW_SYSTEM_1000_MASK 0x000000FF
|
||||
/* Minimum time for 100BASE-T where no data will be transmit following move out
|
||||
* of EEE LPI Tx state
|
||||
*/
|
||||
#define IGC_TW_SYSTEM_100_MASK 0x0000FF00
|
||||
#define IGC_TW_SYSTEM_100_SHIFT 8
|
||||
/* Reg val to set scale to 1024 nsec */
|
||||
#define IGC_LTRMINV_SCALE_1024 2
|
||||
/* Reg val to set scale to 32768 nsec */
|
||||
#define IGC_LTRMINV_SCALE_32768 3
|
||||
/* Reg val to set scale to 1024 nsec */
|
||||
#define IGC_LTRMAXV_SCALE_1024 2
|
||||
/* Reg val to set scale to 32768 nsec */
|
||||
#define IGC_LTRMAXV_SCALE_32768 3
|
||||
#define IGC_LTRMINV_LTRV_MASK 0x000003FF /* LTR minimum value */
|
||||
#define IGC_LTRMAXV_LTRV_MASK 0x000003FF /* LTR maximum value */
|
||||
#define IGC_LTRMINV_LSNP_REQ 0x00008000 /* LTR Snoop Requirement */
|
||||
#define IGC_LTRMINV_SCALE_SHIFT 10
|
||||
#define IGC_LTRMAXV_LSNP_REQ 0x00008000 /* LTR Snoop Requirement */
|
||||
#define IGC_LTRMAXV_SCALE_SHIFT 10
|
||||
|
||||
#endif /* _IGC_DEFINES_H_ */
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2020 Intel Corporation */
|
||||
|
||||
#include "igc-6.4-ethercat.h"
|
||||
#include "igc_diag-6.4-ethercat.h"
|
||||
|
||||
static struct igc_reg_test reg_test[] = {
|
||||
{ IGC_FCAL, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ IGC_FCAH, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
|
||||
{ IGC_FCT, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
|
||||
{ IGC_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ IGC_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 },
|
||||
{ IGC_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
|
||||
{ IGC_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
|
||||
{ IGC_FCRTH, 1, PATTERN_TEST, 0x0003FFF0, 0x0003FFF0 },
|
||||
{ IGC_FCTTV, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
|
||||
{ IGC_TIPG, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF },
|
||||
{ IGC_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ IGC_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 },
|
||||
{ IGC_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
|
||||
{ IGC_TDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
|
||||
{ IGC_RCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
|
||||
{ IGC_RCTL, 1, SET_READ_TEST, 0x04CFB2FE, 0x003FFFFB },
|
||||
{ IGC_RCTL, 1, SET_READ_TEST, 0x04CFB2FE, 0xFFFFFFFF },
|
||||
{ IGC_TCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
|
||||
{ IGC_RA, 16, TABLE64_TEST_LO,
|
||||
0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ IGC_RA, 16, TABLE64_TEST_HI,
|
||||
0x900FFFFF, 0xFFFFFFFF },
|
||||
{ IGC_MTA, 128, TABLE32_TEST,
|
||||
0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static bool reg_pattern_test(struct igc_adapter *adapter, u64 *data, int reg,
|
||||
u32 mask, u32 write)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 pat, val, before;
|
||||
static const u32 test_pattern[] = {
|
||||
0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
|
||||
};
|
||||
|
||||
for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) {
|
||||
before = rd32(reg);
|
||||
wr32(reg, test_pattern[pat] & write);
|
||||
val = rd32(reg);
|
||||
if (val != (test_pattern[pat] & write & mask)) {
|
||||
netdev_err(adapter->netdev,
|
||||
"pattern test reg %04X failed: got 0x%08X expected 0x%08X",
|
||||
reg, val, test_pattern[pat] & write & mask);
|
||||
*data = reg;
|
||||
wr32(reg, before);
|
||||
return false;
|
||||
}
|
||||
wr32(reg, before);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool reg_set_and_check(struct igc_adapter *adapter, u64 *data, int reg,
|
||||
u32 mask, u32 write)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 val, before;
|
||||
|
||||
before = rd32(reg);
|
||||
wr32(reg, write & mask);
|
||||
val = rd32(reg);
|
||||
if ((write & mask) != (val & mask)) {
|
||||
netdev_err(adapter->netdev,
|
||||
"set/check reg %04X test failed: got 0x%08X expected 0x%08X",
|
||||
reg, (val & mask), (write & mask));
|
||||
*data = reg;
|
||||
wr32(reg, before);
|
||||
return false;
|
||||
}
|
||||
wr32(reg, before);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool igc_reg_test(struct igc_adapter *adapter, u64 *data)
|
||||
{
|
||||
struct igc_reg_test *test = reg_test;
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 value, before, after;
|
||||
u32 i, toggle, b = false;
|
||||
|
||||
/* Because the status register is such a special case,
|
||||
* we handle it separately from the rest of the register
|
||||
* tests. Some bits are read-only, some toggle, and some
|
||||
* are writeable.
|
||||
*/
|
||||
toggle = 0x6800D3;
|
||||
before = rd32(IGC_STATUS);
|
||||
value = before & toggle;
|
||||
wr32(IGC_STATUS, toggle);
|
||||
after = rd32(IGC_STATUS) & toggle;
|
||||
if (value != after) {
|
||||
netdev_err(adapter->netdev,
|
||||
"failed STATUS register test got: 0x%08X expected: 0x%08X",
|
||||
after, value);
|
||||
*data = 1;
|
||||
return false;
|
||||
}
|
||||
/* restore previous status */
|
||||
wr32(IGC_STATUS, before);
|
||||
|
||||
/* Perform the remainder of the register test, looping through
|
||||
* the test table until we either fail or reach the null entry.
|
||||
*/
|
||||
while (test->reg) {
|
||||
for (i = 0; i < test->array_len; i++) {
|
||||
switch (test->test_type) {
|
||||
case PATTERN_TEST:
|
||||
b = reg_pattern_test(adapter, data,
|
||||
test->reg + (i * 0x40),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
case SET_READ_TEST:
|
||||
b = reg_set_and_check(adapter, data,
|
||||
test->reg + (i * 0x40),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
case TABLE64_TEST_LO:
|
||||
b = reg_pattern_test(adapter, data,
|
||||
test->reg + (i * 8),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
case TABLE64_TEST_HI:
|
||||
b = reg_pattern_test(adapter, data,
|
||||
test->reg + 4 + (i * 8),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
case TABLE32_TEST:
|
||||
b = reg_pattern_test(adapter, data,
|
||||
test->reg + (i * 4),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
}
|
||||
if (!b)
|
||||
return false;
|
||||
}
|
||||
test++;
|
||||
}
|
||||
*data = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool igc_eeprom_test(struct igc_adapter *adapter, u64 *data)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
|
||||
*data = 0;
|
||||
|
||||
if (hw->nvm.ops.validate(hw) != IGC_SUCCESS) {
|
||||
*data = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool igc_link_test(struct igc_adapter *adapter, u64 *data)
|
||||
{
|
||||
bool link_up;
|
||||
|
||||
*data = 0;
|
||||
|
||||
/* add delay to give enough time for autonegotioation to finish */
|
||||
if (adapter->hw.mac.autoneg)
|
||||
ssleep(5);
|
||||
|
||||
link_up = igc_has_link(adapter);
|
||||
if (!link_up) {
|
||||
*data = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2020 Intel Corporation */
|
||||
|
||||
bool igc_reg_test(struct igc_adapter *adapter, u64 *data);
|
||||
bool igc_eeprom_test(struct igc_adapter *adapter, u64 *data);
|
||||
bool igc_link_test(struct igc_adapter *adapter, u64 *data);
|
||||
|
||||
struct igc_reg_test {
|
||||
u16 reg;
|
||||
u8 array_len;
|
||||
u8 test_type;
|
||||
u32 mask;
|
||||
u32 write;
|
||||
};
|
||||
|
||||
/* In the hardware, registers are laid out either singly, in arrays
|
||||
* spaced 0x40 bytes apart, or in contiguous tables. We assume
|
||||
* most tests take place on arrays or single registers (handled
|
||||
* as a single-element array) and special-case the tables.
|
||||
* Table tests are always pattern tests.
|
||||
*
|
||||
* We also make provision for some required setup steps by specifying
|
||||
* registers to be written without any read-back testing.
|
||||
*/
|
||||
|
||||
#define PATTERN_TEST 1
|
||||
#define SET_READ_TEST 2
|
||||
#define TABLE32_TEST 3
|
||||
#define TABLE64_TEST_LO 4
|
||||
#define TABLE64_TEST_HI 5
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2020 Intel Corporation */
|
||||
|
||||
#include "igc.h"
|
||||
#include "igc_diag.h"
|
||||
|
||||
static struct igc_reg_test reg_test[] = {
|
||||
{ IGC_FCAL, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ IGC_FCAH, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
|
||||
{ IGC_FCT, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
|
||||
{ IGC_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ IGC_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 },
|
||||
{ IGC_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
|
||||
{ IGC_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
|
||||
{ IGC_FCRTH, 1, PATTERN_TEST, 0x0003FFF0, 0x0003FFF0 },
|
||||
{ IGC_FCTTV, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
|
||||
{ IGC_TIPG, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF },
|
||||
{ IGC_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ IGC_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 },
|
||||
{ IGC_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
|
||||
{ IGC_TDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
|
||||
{ IGC_RCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
|
||||
{ IGC_RCTL, 1, SET_READ_TEST, 0x04CFB2FE, 0x003FFFFB },
|
||||
{ IGC_RCTL, 1, SET_READ_TEST, 0x04CFB2FE, 0xFFFFFFFF },
|
||||
{ IGC_TCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
|
||||
{ IGC_RA, 16, TABLE64_TEST_LO,
|
||||
0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ IGC_RA, 16, TABLE64_TEST_HI,
|
||||
0x900FFFFF, 0xFFFFFFFF },
|
||||
{ IGC_MTA, 128, TABLE32_TEST,
|
||||
0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static bool reg_pattern_test(struct igc_adapter *adapter, u64 *data, int reg,
|
||||
u32 mask, u32 write)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 pat, val, before;
|
||||
static const u32 test_pattern[] = {
|
||||
0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
|
||||
};
|
||||
|
||||
for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) {
|
||||
before = rd32(reg);
|
||||
wr32(reg, test_pattern[pat] & write);
|
||||
val = rd32(reg);
|
||||
if (val != (test_pattern[pat] & write & mask)) {
|
||||
netdev_err(adapter->netdev,
|
||||
"pattern test reg %04X failed: got 0x%08X expected 0x%08X",
|
||||
reg, val, test_pattern[pat] & write & mask);
|
||||
*data = reg;
|
||||
wr32(reg, before);
|
||||
return false;
|
||||
}
|
||||
wr32(reg, before);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool reg_set_and_check(struct igc_adapter *adapter, u64 *data, int reg,
|
||||
u32 mask, u32 write)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 val, before;
|
||||
|
||||
before = rd32(reg);
|
||||
wr32(reg, write & mask);
|
||||
val = rd32(reg);
|
||||
if ((write & mask) != (val & mask)) {
|
||||
netdev_err(adapter->netdev,
|
||||
"set/check reg %04X test failed: got 0x%08X expected 0x%08X",
|
||||
reg, (val & mask), (write & mask));
|
||||
*data = reg;
|
||||
wr32(reg, before);
|
||||
return false;
|
||||
}
|
||||
wr32(reg, before);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool igc_reg_test(struct igc_adapter *adapter, u64 *data)
|
||||
{
|
||||
struct igc_reg_test *test = reg_test;
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 value, before, after;
|
||||
u32 i, toggle, b = false;
|
||||
|
||||
/* Because the status register is such a special case,
|
||||
* we handle it separately from the rest of the register
|
||||
* tests. Some bits are read-only, some toggle, and some
|
||||
* are writeable.
|
||||
*/
|
||||
toggle = 0x6800D3;
|
||||
before = rd32(IGC_STATUS);
|
||||
value = before & toggle;
|
||||
wr32(IGC_STATUS, toggle);
|
||||
after = rd32(IGC_STATUS) & toggle;
|
||||
if (value != after) {
|
||||
netdev_err(adapter->netdev,
|
||||
"failed STATUS register test got: 0x%08X expected: 0x%08X",
|
||||
after, value);
|
||||
*data = 1;
|
||||
return false;
|
||||
}
|
||||
/* restore previous status */
|
||||
wr32(IGC_STATUS, before);
|
||||
|
||||
/* Perform the remainder of the register test, looping through
|
||||
* the test table until we either fail or reach the null entry.
|
||||
*/
|
||||
while (test->reg) {
|
||||
for (i = 0; i < test->array_len; i++) {
|
||||
switch (test->test_type) {
|
||||
case PATTERN_TEST:
|
||||
b = reg_pattern_test(adapter, data,
|
||||
test->reg + (i * 0x40),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
case SET_READ_TEST:
|
||||
b = reg_set_and_check(adapter, data,
|
||||
test->reg + (i * 0x40),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
case TABLE64_TEST_LO:
|
||||
b = reg_pattern_test(adapter, data,
|
||||
test->reg + (i * 8),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
case TABLE64_TEST_HI:
|
||||
b = reg_pattern_test(adapter, data,
|
||||
test->reg + 4 + (i * 8),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
case TABLE32_TEST:
|
||||
b = reg_pattern_test(adapter, data,
|
||||
test->reg + (i * 4),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
}
|
||||
if (!b)
|
||||
return false;
|
||||
}
|
||||
test++;
|
||||
}
|
||||
*data = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool igc_eeprom_test(struct igc_adapter *adapter, u64 *data)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
|
||||
*data = 0;
|
||||
|
||||
if (hw->nvm.ops.validate(hw) != IGC_SUCCESS) {
|
||||
*data = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool igc_link_test(struct igc_adapter *adapter, u64 *data)
|
||||
{
|
||||
bool link_up;
|
||||
|
||||
*data = 0;
|
||||
|
||||
/* add delay to give enough time for autonegotioation to finish */
|
||||
if (adapter->hw.mac.autoneg)
|
||||
ssleep(5);
|
||||
|
||||
link_up = igc_has_link(adapter);
|
||||
if (!link_up) {
|
||||
*data = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2020 Intel Corporation */
|
||||
|
||||
bool igc_reg_test(struct igc_adapter *adapter, u64 *data);
|
||||
bool igc_eeprom_test(struct igc_adapter *adapter, u64 *data);
|
||||
bool igc_link_test(struct igc_adapter *adapter, u64 *data);
|
||||
|
||||
struct igc_reg_test {
|
||||
u16 reg;
|
||||
u8 array_len;
|
||||
u8 test_type;
|
||||
u32 mask;
|
||||
u32 write;
|
||||
};
|
||||
|
||||
/* In the hardware, registers are laid out either singly, in arrays
|
||||
* spaced 0x40 bytes apart, or in contiguous tables. We assume
|
||||
* most tests take place on arrays or single registers (handled
|
||||
* as a single-element array) and special-case the tables.
|
||||
* Table tests are always pattern tests.
|
||||
*
|
||||
* We also make provision for some required setup steps by specifying
|
||||
* registers to be written without any read-back testing.
|
||||
*/
|
||||
|
||||
#define PATTERN_TEST 1
|
||||
#define SET_READ_TEST 2
|
||||
#define TABLE32_TEST 3
|
||||
#define TABLE64_TEST_LO 4
|
||||
#define TABLE64_TEST_HI 5
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2020 Intel Corporation */
|
||||
|
||||
#include "igc-6.6-ethercat.h"
|
||||
#include "igc_diag-6.6-ethercat.h"
|
||||
|
||||
static struct igc_reg_test reg_test[] = {
|
||||
{ IGC_FCAL, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ IGC_FCAH, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
|
||||
{ IGC_FCT, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
|
||||
{ IGC_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ IGC_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 },
|
||||
{ IGC_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
|
||||
{ IGC_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
|
||||
{ IGC_FCRTH, 1, PATTERN_TEST, 0x0003FFF0, 0x0003FFF0 },
|
||||
{ IGC_FCTTV, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
|
||||
{ IGC_TIPG, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF },
|
||||
{ IGC_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ IGC_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 },
|
||||
{ IGC_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
|
||||
{ IGC_TDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
|
||||
{ IGC_RCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
|
||||
{ IGC_RCTL, 1, SET_READ_TEST, 0x04CFB2FE, 0x003FFFFB },
|
||||
{ IGC_RCTL, 1, SET_READ_TEST, 0x04CFB2FE, 0xFFFFFFFF },
|
||||
{ IGC_TCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
|
||||
{ IGC_RA, 16, TABLE64_TEST_LO,
|
||||
0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ IGC_RA, 16, TABLE64_TEST_HI,
|
||||
0x900FFFFF, 0xFFFFFFFF },
|
||||
{ IGC_MTA, 128, TABLE32_TEST,
|
||||
0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static bool reg_pattern_test(struct igc_adapter *adapter, u64 *data, int reg,
|
||||
u32 mask, u32 write)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 pat, val, before;
|
||||
static const u32 test_pattern[] = {
|
||||
0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
|
||||
};
|
||||
|
||||
for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) {
|
||||
before = rd32(reg);
|
||||
wr32(reg, test_pattern[pat] & write);
|
||||
val = rd32(reg);
|
||||
if (val != (test_pattern[pat] & write & mask)) {
|
||||
netdev_err(adapter->netdev,
|
||||
"pattern test reg %04X failed: got 0x%08X expected 0x%08X",
|
||||
reg, val, test_pattern[pat] & write & mask);
|
||||
*data = reg;
|
||||
wr32(reg, before);
|
||||
return false;
|
||||
}
|
||||
wr32(reg, before);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool reg_set_and_check(struct igc_adapter *adapter, u64 *data, int reg,
|
||||
u32 mask, u32 write)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 val, before;
|
||||
|
||||
before = rd32(reg);
|
||||
wr32(reg, write & mask);
|
||||
val = rd32(reg);
|
||||
if ((write & mask) != (val & mask)) {
|
||||
netdev_err(adapter->netdev,
|
||||
"set/check reg %04X test failed: got 0x%08X expected 0x%08X",
|
||||
reg, (val & mask), (write & mask));
|
||||
*data = reg;
|
||||
wr32(reg, before);
|
||||
return false;
|
||||
}
|
||||
wr32(reg, before);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool igc_reg_test(struct igc_adapter *adapter, u64 *data)
|
||||
{
|
||||
struct igc_reg_test *test = reg_test;
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 value, before, after;
|
||||
u32 i, toggle, b = false;
|
||||
|
||||
/* Because the status register is such a special case,
|
||||
* we handle it separately from the rest of the register
|
||||
* tests. Some bits are read-only, some toggle, and some
|
||||
* are writeable.
|
||||
*/
|
||||
toggle = 0x6800D3;
|
||||
before = rd32(IGC_STATUS);
|
||||
value = before & toggle;
|
||||
wr32(IGC_STATUS, toggle);
|
||||
after = rd32(IGC_STATUS) & toggle;
|
||||
if (value != after) {
|
||||
netdev_err(adapter->netdev,
|
||||
"failed STATUS register test got: 0x%08X expected: 0x%08X",
|
||||
after, value);
|
||||
*data = 1;
|
||||
return false;
|
||||
}
|
||||
/* restore previous status */
|
||||
wr32(IGC_STATUS, before);
|
||||
|
||||
/* Perform the remainder of the register test, looping through
|
||||
* the test table until we either fail or reach the null entry.
|
||||
*/
|
||||
while (test->reg) {
|
||||
for (i = 0; i < test->array_len; i++) {
|
||||
switch (test->test_type) {
|
||||
case PATTERN_TEST:
|
||||
b = reg_pattern_test(adapter, data,
|
||||
test->reg + (i * 0x40),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
case SET_READ_TEST:
|
||||
b = reg_set_and_check(adapter, data,
|
||||
test->reg + (i * 0x40),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
case TABLE64_TEST_LO:
|
||||
b = reg_pattern_test(adapter, data,
|
||||
test->reg + (i * 8),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
case TABLE64_TEST_HI:
|
||||
b = reg_pattern_test(adapter, data,
|
||||
test->reg + 4 + (i * 8),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
case TABLE32_TEST:
|
||||
b = reg_pattern_test(adapter, data,
|
||||
test->reg + (i * 4),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
}
|
||||
if (!b)
|
||||
return false;
|
||||
}
|
||||
test++;
|
||||
}
|
||||
*data = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool igc_eeprom_test(struct igc_adapter *adapter, u64 *data)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
|
||||
*data = 0;
|
||||
|
||||
if (hw->nvm.ops.validate(hw) != IGC_SUCCESS) {
|
||||
*data = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool igc_link_test(struct igc_adapter *adapter, u64 *data)
|
||||
{
|
||||
bool link_up;
|
||||
|
||||
*data = 0;
|
||||
|
||||
/* add delay to give enough time for autonegotioation to finish */
|
||||
if (adapter->hw.mac.autoneg)
|
||||
ssleep(5);
|
||||
|
||||
link_up = igc_has_link(adapter);
|
||||
if (!link_up) {
|
||||
*data = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2020 Intel Corporation */
|
||||
|
||||
bool igc_reg_test(struct igc_adapter *adapter, u64 *data);
|
||||
bool igc_eeprom_test(struct igc_adapter *adapter, u64 *data);
|
||||
bool igc_link_test(struct igc_adapter *adapter, u64 *data);
|
||||
|
||||
struct igc_reg_test {
|
||||
u16 reg;
|
||||
u8 array_len;
|
||||
u8 test_type;
|
||||
u32 mask;
|
||||
u32 write;
|
||||
};
|
||||
|
||||
/* In the hardware, registers are laid out either singly, in arrays
|
||||
* spaced 0x40 bytes apart, or in contiguous tables. We assume
|
||||
* most tests take place on arrays or single registers (handled
|
||||
* as a single-element array) and special-case the tables.
|
||||
* Table tests are always pattern tests.
|
||||
*
|
||||
* We also make provision for some required setup steps by specifying
|
||||
* registers to be written without any read-back testing.
|
||||
*/
|
||||
|
||||
#define PATTERN_TEST 1
|
||||
#define SET_READ_TEST 2
|
||||
#define TABLE32_TEST 3
|
||||
#define TABLE64_TEST_LO 4
|
||||
#define TABLE64_TEST_HI 5
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2020 Intel Corporation */
|
||||
|
||||
#include "igc.h"
|
||||
#include "igc_diag.h"
|
||||
|
||||
static struct igc_reg_test reg_test[] = {
|
||||
{ IGC_FCAL, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ IGC_FCAH, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
|
||||
{ IGC_FCT, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
|
||||
{ IGC_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ IGC_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 },
|
||||
{ IGC_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
|
||||
{ IGC_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
|
||||
{ IGC_FCRTH, 1, PATTERN_TEST, 0x0003FFF0, 0x0003FFF0 },
|
||||
{ IGC_FCTTV, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
|
||||
{ IGC_TIPG, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF },
|
||||
{ IGC_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ IGC_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 },
|
||||
{ IGC_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
|
||||
{ IGC_TDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
|
||||
{ IGC_RCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
|
||||
{ IGC_RCTL, 1, SET_READ_TEST, 0x04CFB2FE, 0x003FFFFB },
|
||||
{ IGC_RCTL, 1, SET_READ_TEST, 0x04CFB2FE, 0xFFFFFFFF },
|
||||
{ IGC_TCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
|
||||
{ IGC_RA, 16, TABLE64_TEST_LO,
|
||||
0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ IGC_RA, 16, TABLE64_TEST_HI,
|
||||
0x900FFFFF, 0xFFFFFFFF },
|
||||
{ IGC_MTA, 128, TABLE32_TEST,
|
||||
0xFFFFFFFF, 0xFFFFFFFF },
|
||||
{ 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static bool reg_pattern_test(struct igc_adapter *adapter, u64 *data, int reg,
|
||||
u32 mask, u32 write)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 pat, val, before;
|
||||
static const u32 test_pattern[] = {
|
||||
0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
|
||||
};
|
||||
|
||||
for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) {
|
||||
before = rd32(reg);
|
||||
wr32(reg, test_pattern[pat] & write);
|
||||
val = rd32(reg);
|
||||
if (val != (test_pattern[pat] & write & mask)) {
|
||||
netdev_err(adapter->netdev,
|
||||
"pattern test reg %04X failed: got 0x%08X expected 0x%08X",
|
||||
reg, val, test_pattern[pat] & write & mask);
|
||||
*data = reg;
|
||||
wr32(reg, before);
|
||||
return false;
|
||||
}
|
||||
wr32(reg, before);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool reg_set_and_check(struct igc_adapter *adapter, u64 *data, int reg,
|
||||
u32 mask, u32 write)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 val, before;
|
||||
|
||||
before = rd32(reg);
|
||||
wr32(reg, write & mask);
|
||||
val = rd32(reg);
|
||||
if ((write & mask) != (val & mask)) {
|
||||
netdev_err(adapter->netdev,
|
||||
"set/check reg %04X test failed: got 0x%08X expected 0x%08X",
|
||||
reg, (val & mask), (write & mask));
|
||||
*data = reg;
|
||||
wr32(reg, before);
|
||||
return false;
|
||||
}
|
||||
wr32(reg, before);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool igc_reg_test(struct igc_adapter *adapter, u64 *data)
|
||||
{
|
||||
struct igc_reg_test *test = reg_test;
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 value, before, after;
|
||||
u32 i, toggle, b = false;
|
||||
|
||||
/* Because the status register is such a special case,
|
||||
* we handle it separately from the rest of the register
|
||||
* tests. Some bits are read-only, some toggle, and some
|
||||
* are writeable.
|
||||
*/
|
||||
toggle = 0x6800D3;
|
||||
before = rd32(IGC_STATUS);
|
||||
value = before & toggle;
|
||||
wr32(IGC_STATUS, toggle);
|
||||
after = rd32(IGC_STATUS) & toggle;
|
||||
if (value != after) {
|
||||
netdev_err(adapter->netdev,
|
||||
"failed STATUS register test got: 0x%08X expected: 0x%08X",
|
||||
after, value);
|
||||
*data = 1;
|
||||
return false;
|
||||
}
|
||||
/* restore previous status */
|
||||
wr32(IGC_STATUS, before);
|
||||
|
||||
/* Perform the remainder of the register test, looping through
|
||||
* the test table until we either fail or reach the null entry.
|
||||
*/
|
||||
while (test->reg) {
|
||||
for (i = 0; i < test->array_len; i++) {
|
||||
switch (test->test_type) {
|
||||
case PATTERN_TEST:
|
||||
b = reg_pattern_test(adapter, data,
|
||||
test->reg + (i * 0x40),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
case SET_READ_TEST:
|
||||
b = reg_set_and_check(adapter, data,
|
||||
test->reg + (i * 0x40),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
case TABLE64_TEST_LO:
|
||||
b = reg_pattern_test(adapter, data,
|
||||
test->reg + (i * 8),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
case TABLE64_TEST_HI:
|
||||
b = reg_pattern_test(adapter, data,
|
||||
test->reg + 4 + (i * 8),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
case TABLE32_TEST:
|
||||
b = reg_pattern_test(adapter, data,
|
||||
test->reg + (i * 4),
|
||||
test->mask,
|
||||
test->write);
|
||||
break;
|
||||
}
|
||||
if (!b)
|
||||
return false;
|
||||
}
|
||||
test++;
|
||||
}
|
||||
*data = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool igc_eeprom_test(struct igc_adapter *adapter, u64 *data)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
|
||||
*data = 0;
|
||||
|
||||
if (hw->nvm.ops.validate(hw) != IGC_SUCCESS) {
|
||||
*data = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool igc_link_test(struct igc_adapter *adapter, u64 *data)
|
||||
{
|
||||
bool link_up;
|
||||
|
||||
*data = 0;
|
||||
|
||||
/* add delay to give enough time for autonegotioation to finish */
|
||||
if (adapter->hw.mac.autoneg)
|
||||
ssleep(5);
|
||||
|
||||
link_up = igc_has_link(adapter);
|
||||
if (!link_up) {
|
||||
*data = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2020 Intel Corporation */
|
||||
|
||||
bool igc_reg_test(struct igc_adapter *adapter, u64 *data);
|
||||
bool igc_eeprom_test(struct igc_adapter *adapter, u64 *data);
|
||||
bool igc_link_test(struct igc_adapter *adapter, u64 *data);
|
||||
|
||||
struct igc_reg_test {
|
||||
u16 reg;
|
||||
u8 array_len;
|
||||
u8 test_type;
|
||||
u32 mask;
|
||||
u32 write;
|
||||
};
|
||||
|
||||
/* In the hardware, registers are laid out either singly, in arrays
|
||||
* spaced 0x40 bytes apart, or in contiguous tables. We assume
|
||||
* most tests take place on arrays or single registers (handled
|
||||
* as a single-element array) and special-case the tables.
|
||||
* Table tests are always pattern tests.
|
||||
*
|
||||
* We also make provision for some required setup steps by specifying
|
||||
* registers to be written without any read-back testing.
|
||||
*/
|
||||
|
||||
#define PATTERN_TEST 1
|
||||
#define SET_READ_TEST 2
|
||||
#define TABLE32_TEST 3
|
||||
#define TABLE64_TEST_LO 4
|
||||
#define TABLE64_TEST_HI 5
|
||||
|
|
@ -0,0 +1,318 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include "igc-6.4-ethercat.h"
|
||||
|
||||
struct igc_reg_info {
|
||||
u32 ofs;
|
||||
char *name;
|
||||
};
|
||||
|
||||
static const struct igc_reg_info igc_reg_info_tbl[] = {
|
||||
/* General Registers */
|
||||
{IGC_CTRL, "CTRL"},
|
||||
{IGC_STATUS, "STATUS"},
|
||||
{IGC_CTRL_EXT, "CTRL_EXT"},
|
||||
{IGC_MDIC, "MDIC"},
|
||||
|
||||
/* Interrupt Registers */
|
||||
{IGC_ICR, "ICR"},
|
||||
|
||||
/* RX Registers */
|
||||
{IGC_RCTL, "RCTL"},
|
||||
{IGC_RDLEN(0), "RDLEN"},
|
||||
{IGC_RDH(0), "RDH"},
|
||||
{IGC_RDT(0), "RDT"},
|
||||
{IGC_RXDCTL(0), "RXDCTL"},
|
||||
{IGC_RDBAL(0), "RDBAL"},
|
||||
{IGC_RDBAH(0), "RDBAH"},
|
||||
|
||||
/* TX Registers */
|
||||
{IGC_TCTL, "TCTL"},
|
||||
{IGC_TDBAL(0), "TDBAL"},
|
||||
{IGC_TDBAH(0), "TDBAH"},
|
||||
{IGC_TDLEN(0), "TDLEN"},
|
||||
{IGC_TDH(0), "TDH"},
|
||||
{IGC_TDT(0), "TDT"},
|
||||
{IGC_TXDCTL(0), "TXDCTL"},
|
||||
|
||||
/* List Terminator */
|
||||
{}
|
||||
};
|
||||
|
||||
/* igc_regdump - register printout routine */
|
||||
static void igc_regdump(struct igc_hw *hw, struct igc_reg_info *reginfo)
|
||||
{
|
||||
struct net_device *dev = igc_get_hw_dev(hw);
|
||||
int n = 0;
|
||||
char rname[16];
|
||||
u32 regs[8];
|
||||
|
||||
switch (reginfo->ofs) {
|
||||
case IGC_RDLEN(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDLEN(n));
|
||||
break;
|
||||
case IGC_RDH(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDH(n));
|
||||
break;
|
||||
case IGC_RDT(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDT(n));
|
||||
break;
|
||||
case IGC_RXDCTL(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RXDCTL(n));
|
||||
break;
|
||||
case IGC_RDBAL(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDBAL(n));
|
||||
break;
|
||||
case IGC_RDBAH(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDBAH(n));
|
||||
break;
|
||||
case IGC_TDBAL(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDBAL(n));
|
||||
break;
|
||||
case IGC_TDBAH(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDBAH(n));
|
||||
break;
|
||||
case IGC_TDLEN(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDLEN(n));
|
||||
break;
|
||||
case IGC_TDH(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDH(n));
|
||||
break;
|
||||
case IGC_TDT(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDT(n));
|
||||
break;
|
||||
case IGC_TXDCTL(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TXDCTL(n));
|
||||
break;
|
||||
default:
|
||||
netdev_info(dev, "%-15s %08x\n", reginfo->name,
|
||||
rd32(reginfo->ofs));
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(rname, 16, "%s%s", reginfo->name, "[0-3]");
|
||||
netdev_info(dev, "%-15s %08x %08x %08x %08x\n", rname, regs[0], regs[1],
|
||||
regs[2], regs[3]);
|
||||
}
|
||||
|
||||
/* igc_rings_dump - Tx-rings and Rx-rings */
|
||||
void igc_rings_dump(struct igc_adapter *adapter)
|
||||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
struct my_u0 { __le64 a; __le64 b; } *u0;
|
||||
union igc_adv_tx_desc *tx_desc;
|
||||
union igc_adv_rx_desc *rx_desc;
|
||||
struct igc_ring *tx_ring;
|
||||
struct igc_ring *rx_ring;
|
||||
u32 staterr;
|
||||
u16 i, n;
|
||||
|
||||
if (!netif_msg_hw(adapter))
|
||||
return;
|
||||
|
||||
netdev_info(netdev, "Device info: state %016lX trans_start %016lX\n",
|
||||
netdev->state, dev_trans_start(netdev));
|
||||
|
||||
/* Print TX Ring Summary */
|
||||
if (!netif_running(netdev))
|
||||
goto exit;
|
||||
|
||||
netdev_info(netdev, "TX Rings Summary\n");
|
||||
netdev_info(netdev, "Queue [NTU] [NTC] [bi(ntc)->dma ] leng ntw timestamp\n");
|
||||
for (n = 0; n < adapter->num_tx_queues; n++) {
|
||||
struct igc_tx_buffer *buffer_info;
|
||||
|
||||
tx_ring = adapter->tx_ring[n];
|
||||
buffer_info = &tx_ring->tx_buffer_info[tx_ring->next_to_clean];
|
||||
|
||||
netdev_info(netdev, "%5d %5X %5X %016llX %04X %p %016llX\n",
|
||||
n, tx_ring->next_to_use, tx_ring->next_to_clean,
|
||||
(u64)dma_unmap_addr(buffer_info, dma),
|
||||
dma_unmap_len(buffer_info, len),
|
||||
buffer_info->next_to_watch,
|
||||
(u64)buffer_info->time_stamp);
|
||||
}
|
||||
|
||||
/* Print TX Rings */
|
||||
if (!netif_msg_tx_done(adapter))
|
||||
goto rx_ring_summary;
|
||||
|
||||
netdev_info(netdev, "TX Rings Dump\n");
|
||||
|
||||
/* Transmit Descriptor Formats
|
||||
*
|
||||
* Advanced Transmit Descriptor
|
||||
* +--------------------------------------------------------------+
|
||||
* 0 | Buffer Address [63:0] |
|
||||
* +--------------------------------------------------------------+
|
||||
* 8 | PAYLEN | PORTS |CC|IDX | STA | DCMD |DTYP|MAC|RSV| DTALEN |
|
||||
* +--------------------------------------------------------------+
|
||||
* 63 46 45 40 39 38 36 35 32 31 24 15 0
|
||||
*/
|
||||
|
||||
for (n = 0; n < adapter->num_tx_queues; n++) {
|
||||
tx_ring = adapter->tx_ring[n];
|
||||
netdev_info(netdev, "------------------------------------\n");
|
||||
netdev_info(netdev, "TX QUEUE INDEX = %d\n",
|
||||
tx_ring->queue_index);
|
||||
netdev_info(netdev, "------------------------------------\n");
|
||||
netdev_info(netdev, "T [desc] [address 63:0 ] [PlPOCIStDDM Ln] [bi->dma ] leng ntw timestamp bi->skb\n");
|
||||
|
||||
for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
|
||||
const char *next_desc;
|
||||
struct igc_tx_buffer *buffer_info;
|
||||
|
||||
tx_desc = IGC_TX_DESC(tx_ring, i);
|
||||
buffer_info = &tx_ring->tx_buffer_info[i];
|
||||
u0 = (struct my_u0 *)tx_desc;
|
||||
if (i == tx_ring->next_to_use &&
|
||||
i == tx_ring->next_to_clean)
|
||||
next_desc = " NTC/U";
|
||||
else if (i == tx_ring->next_to_use)
|
||||
next_desc = " NTU";
|
||||
else if (i == tx_ring->next_to_clean)
|
||||
next_desc = " NTC";
|
||||
else
|
||||
next_desc = "";
|
||||
|
||||
netdev_info(netdev, "T [0x%03X] %016llX %016llX %016llX %04X %p %016llX %p%s\n",
|
||||
i, le64_to_cpu(u0->a),
|
||||
le64_to_cpu(u0->b),
|
||||
(u64)dma_unmap_addr(buffer_info, dma),
|
||||
dma_unmap_len(buffer_info, len),
|
||||
buffer_info->next_to_watch,
|
||||
(u64)buffer_info->time_stamp,
|
||||
buffer_info->skb, next_desc);
|
||||
|
||||
if (netif_msg_pktdata(adapter) && buffer_info->skb)
|
||||
print_hex_dump(KERN_INFO, "",
|
||||
DUMP_PREFIX_ADDRESS,
|
||||
16, 1, buffer_info->skb->data,
|
||||
dma_unmap_len(buffer_info, len),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print RX Rings Summary */
|
||||
rx_ring_summary:
|
||||
netdev_info(netdev, "RX Rings Summary\n");
|
||||
netdev_info(netdev, "Queue [NTU] [NTC]\n");
|
||||
for (n = 0; n < adapter->num_rx_queues; n++) {
|
||||
rx_ring = adapter->rx_ring[n];
|
||||
netdev_info(netdev, "%5d %5X %5X\n", n, rx_ring->next_to_use,
|
||||
rx_ring->next_to_clean);
|
||||
}
|
||||
|
||||
/* Print RX Rings */
|
||||
if (!netif_msg_rx_status(adapter))
|
||||
goto exit;
|
||||
|
||||
netdev_info(netdev, "RX Rings Dump\n");
|
||||
|
||||
/* Advanced Receive Descriptor (Read) Format
|
||||
* 63 1 0
|
||||
* +-----------------------------------------------------+
|
||||
* 0 | Packet Buffer Address [63:1] |A0/NSE|
|
||||
* +----------------------------------------------+------+
|
||||
* 8 | Header Buffer Address [63:1] | DD |
|
||||
* +-----------------------------------------------------+
|
||||
*
|
||||
*
|
||||
* Advanced Receive Descriptor (Write-Back) Format
|
||||
*
|
||||
* 63 48 47 32 31 30 21 20 17 16 4 3 0
|
||||
* +------------------------------------------------------+
|
||||
* 0 | Packet IP |SPH| HDR_LEN | RSV|Packet| RSS |
|
||||
* | Checksum Ident | | | | Type | Type |
|
||||
* +------------------------------------------------------+
|
||||
* 8 | VLAN Tag | Length | Extended Error | Extended Status |
|
||||
* +------------------------------------------------------+
|
||||
* 63 48 47 32 31 20 19 0
|
||||
*/
|
||||
|
||||
for (n = 0; n < adapter->num_rx_queues; n++) {
|
||||
rx_ring = adapter->rx_ring[n];
|
||||
netdev_info(netdev, "------------------------------------\n");
|
||||
netdev_info(netdev, "RX QUEUE INDEX = %d\n",
|
||||
rx_ring->queue_index);
|
||||
netdev_info(netdev, "------------------------------------\n");
|
||||
netdev_info(netdev, "R [desc] [ PktBuf A0] [ HeadBuf DD] [bi->dma ] [bi->skb] <-- Adv Rx Read format\n");
|
||||
netdev_info(netdev, "RWB[desc] [PcsmIpSHl PtRs] [vl er S cks ln] ---------------- [bi->skb] <-- Adv Rx Write-Back format\n");
|
||||
|
||||
for (i = 0; i < rx_ring->count; i++) {
|
||||
const char *next_desc;
|
||||
struct igc_rx_buffer *buffer_info;
|
||||
|
||||
buffer_info = &rx_ring->rx_buffer_info[i];
|
||||
rx_desc = IGC_RX_DESC(rx_ring, i);
|
||||
u0 = (struct my_u0 *)rx_desc;
|
||||
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
|
||||
|
||||
if (i == rx_ring->next_to_use)
|
||||
next_desc = " NTU";
|
||||
else if (i == rx_ring->next_to_clean)
|
||||
next_desc = " NTC";
|
||||
else
|
||||
next_desc = "";
|
||||
|
||||
if (staterr & IGC_RXD_STAT_DD) {
|
||||
/* Descriptor Done */
|
||||
netdev_info(netdev, "%s[0x%03X] %016llX %016llX ---------------- %s\n",
|
||||
"RWB", i,
|
||||
le64_to_cpu(u0->a),
|
||||
le64_to_cpu(u0->b),
|
||||
next_desc);
|
||||
} else {
|
||||
netdev_info(netdev, "%s[0x%03X] %016llX %016llX %016llX %s\n",
|
||||
"R ", i,
|
||||
le64_to_cpu(u0->a),
|
||||
le64_to_cpu(u0->b),
|
||||
(u64)buffer_info->dma,
|
||||
next_desc);
|
||||
|
||||
if (netif_msg_pktdata(adapter) &&
|
||||
buffer_info->dma && buffer_info->page) {
|
||||
print_hex_dump(KERN_INFO, "",
|
||||
DUMP_PREFIX_ADDRESS,
|
||||
16, 1,
|
||||
page_address
|
||||
(buffer_info->page) +
|
||||
buffer_info->page_offset,
|
||||
igc_rx_bufsz(rx_ring),
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
/* igc_regs_dump - registers dump */
|
||||
void igc_regs_dump(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
struct igc_reg_info *reginfo;
|
||||
|
||||
/* Print Registers */
|
||||
netdev_info(adapter->netdev, "Register Dump\n");
|
||||
netdev_info(adapter->netdev, "Register Name Value\n");
|
||||
for (reginfo = (struct igc_reg_info *)igc_reg_info_tbl;
|
||||
reginfo->name; reginfo++) {
|
||||
igc_regdump(hw, reginfo);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,318 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include "igc.h"
|
||||
|
||||
struct igc_reg_info {
|
||||
u32 ofs;
|
||||
char *name;
|
||||
};
|
||||
|
||||
static const struct igc_reg_info igc_reg_info_tbl[] = {
|
||||
/* General Registers */
|
||||
{IGC_CTRL, "CTRL"},
|
||||
{IGC_STATUS, "STATUS"},
|
||||
{IGC_CTRL_EXT, "CTRL_EXT"},
|
||||
{IGC_MDIC, "MDIC"},
|
||||
|
||||
/* Interrupt Registers */
|
||||
{IGC_ICR, "ICR"},
|
||||
|
||||
/* RX Registers */
|
||||
{IGC_RCTL, "RCTL"},
|
||||
{IGC_RDLEN(0), "RDLEN"},
|
||||
{IGC_RDH(0), "RDH"},
|
||||
{IGC_RDT(0), "RDT"},
|
||||
{IGC_RXDCTL(0), "RXDCTL"},
|
||||
{IGC_RDBAL(0), "RDBAL"},
|
||||
{IGC_RDBAH(0), "RDBAH"},
|
||||
|
||||
/* TX Registers */
|
||||
{IGC_TCTL, "TCTL"},
|
||||
{IGC_TDBAL(0), "TDBAL"},
|
||||
{IGC_TDBAH(0), "TDBAH"},
|
||||
{IGC_TDLEN(0), "TDLEN"},
|
||||
{IGC_TDH(0), "TDH"},
|
||||
{IGC_TDT(0), "TDT"},
|
||||
{IGC_TXDCTL(0), "TXDCTL"},
|
||||
|
||||
/* List Terminator */
|
||||
{}
|
||||
};
|
||||
|
||||
/* igc_regdump - register printout routine */
|
||||
static void igc_regdump(struct igc_hw *hw, struct igc_reg_info *reginfo)
|
||||
{
|
||||
struct net_device *dev = igc_get_hw_dev(hw);
|
||||
int n = 0;
|
||||
char rname[16];
|
||||
u32 regs[8];
|
||||
|
||||
switch (reginfo->ofs) {
|
||||
case IGC_RDLEN(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDLEN(n));
|
||||
break;
|
||||
case IGC_RDH(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDH(n));
|
||||
break;
|
||||
case IGC_RDT(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDT(n));
|
||||
break;
|
||||
case IGC_RXDCTL(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RXDCTL(n));
|
||||
break;
|
||||
case IGC_RDBAL(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDBAL(n));
|
||||
break;
|
||||
case IGC_RDBAH(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDBAH(n));
|
||||
break;
|
||||
case IGC_TDBAL(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDBAL(n));
|
||||
break;
|
||||
case IGC_TDBAH(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDBAH(n));
|
||||
break;
|
||||
case IGC_TDLEN(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDLEN(n));
|
||||
break;
|
||||
case IGC_TDH(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDH(n));
|
||||
break;
|
||||
case IGC_TDT(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDT(n));
|
||||
break;
|
||||
case IGC_TXDCTL(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TXDCTL(n));
|
||||
break;
|
||||
default:
|
||||
netdev_info(dev, "%-15s %08x\n", reginfo->name,
|
||||
rd32(reginfo->ofs));
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(rname, 16, "%s%s", reginfo->name, "[0-3]");
|
||||
netdev_info(dev, "%-15s %08x %08x %08x %08x\n", rname, regs[0], regs[1],
|
||||
regs[2], regs[3]);
|
||||
}
|
||||
|
||||
/* igc_rings_dump - Tx-rings and Rx-rings */
|
||||
void igc_rings_dump(struct igc_adapter *adapter)
|
||||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
struct my_u0 { __le64 a; __le64 b; } *u0;
|
||||
union igc_adv_tx_desc *tx_desc;
|
||||
union igc_adv_rx_desc *rx_desc;
|
||||
struct igc_ring *tx_ring;
|
||||
struct igc_ring *rx_ring;
|
||||
u32 staterr;
|
||||
u16 i, n;
|
||||
|
||||
if (!netif_msg_hw(adapter))
|
||||
return;
|
||||
|
||||
netdev_info(netdev, "Device info: state %016lX trans_start %016lX\n",
|
||||
netdev->state, dev_trans_start(netdev));
|
||||
|
||||
/* Print TX Ring Summary */
|
||||
if (!netif_running(netdev))
|
||||
goto exit;
|
||||
|
||||
netdev_info(netdev, "TX Rings Summary\n");
|
||||
netdev_info(netdev, "Queue [NTU] [NTC] [bi(ntc)->dma ] leng ntw timestamp\n");
|
||||
for (n = 0; n < adapter->num_tx_queues; n++) {
|
||||
struct igc_tx_buffer *buffer_info;
|
||||
|
||||
tx_ring = adapter->tx_ring[n];
|
||||
buffer_info = &tx_ring->tx_buffer_info[tx_ring->next_to_clean];
|
||||
|
||||
netdev_info(netdev, "%5d %5X %5X %016llX %04X %p %016llX\n",
|
||||
n, tx_ring->next_to_use, tx_ring->next_to_clean,
|
||||
(u64)dma_unmap_addr(buffer_info, dma),
|
||||
dma_unmap_len(buffer_info, len),
|
||||
buffer_info->next_to_watch,
|
||||
(u64)buffer_info->time_stamp);
|
||||
}
|
||||
|
||||
/* Print TX Rings */
|
||||
if (!netif_msg_tx_done(adapter))
|
||||
goto rx_ring_summary;
|
||||
|
||||
netdev_info(netdev, "TX Rings Dump\n");
|
||||
|
||||
/* Transmit Descriptor Formats
|
||||
*
|
||||
* Advanced Transmit Descriptor
|
||||
* +--------------------------------------------------------------+
|
||||
* 0 | Buffer Address [63:0] |
|
||||
* +--------------------------------------------------------------+
|
||||
* 8 | PAYLEN | PORTS |CC|IDX | STA | DCMD |DTYP|MAC|RSV| DTALEN |
|
||||
* +--------------------------------------------------------------+
|
||||
* 63 46 45 40 39 38 36 35 32 31 24 15 0
|
||||
*/
|
||||
|
||||
for (n = 0; n < adapter->num_tx_queues; n++) {
|
||||
tx_ring = adapter->tx_ring[n];
|
||||
netdev_info(netdev, "------------------------------------\n");
|
||||
netdev_info(netdev, "TX QUEUE INDEX = %d\n",
|
||||
tx_ring->queue_index);
|
||||
netdev_info(netdev, "------------------------------------\n");
|
||||
netdev_info(netdev, "T [desc] [address 63:0 ] [PlPOCIStDDM Ln] [bi->dma ] leng ntw timestamp bi->skb\n");
|
||||
|
||||
for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
|
||||
const char *next_desc;
|
||||
struct igc_tx_buffer *buffer_info;
|
||||
|
||||
tx_desc = IGC_TX_DESC(tx_ring, i);
|
||||
buffer_info = &tx_ring->tx_buffer_info[i];
|
||||
u0 = (struct my_u0 *)tx_desc;
|
||||
if (i == tx_ring->next_to_use &&
|
||||
i == tx_ring->next_to_clean)
|
||||
next_desc = " NTC/U";
|
||||
else if (i == tx_ring->next_to_use)
|
||||
next_desc = " NTU";
|
||||
else if (i == tx_ring->next_to_clean)
|
||||
next_desc = " NTC";
|
||||
else
|
||||
next_desc = "";
|
||||
|
||||
netdev_info(netdev, "T [0x%03X] %016llX %016llX %016llX %04X %p %016llX %p%s\n",
|
||||
i, le64_to_cpu(u0->a),
|
||||
le64_to_cpu(u0->b),
|
||||
(u64)dma_unmap_addr(buffer_info, dma),
|
||||
dma_unmap_len(buffer_info, len),
|
||||
buffer_info->next_to_watch,
|
||||
(u64)buffer_info->time_stamp,
|
||||
buffer_info->skb, next_desc);
|
||||
|
||||
if (netif_msg_pktdata(adapter) && buffer_info->skb)
|
||||
print_hex_dump(KERN_INFO, "",
|
||||
DUMP_PREFIX_ADDRESS,
|
||||
16, 1, buffer_info->skb->data,
|
||||
dma_unmap_len(buffer_info, len),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print RX Rings Summary */
|
||||
rx_ring_summary:
|
||||
netdev_info(netdev, "RX Rings Summary\n");
|
||||
netdev_info(netdev, "Queue [NTU] [NTC]\n");
|
||||
for (n = 0; n < adapter->num_rx_queues; n++) {
|
||||
rx_ring = adapter->rx_ring[n];
|
||||
netdev_info(netdev, "%5d %5X %5X\n", n, rx_ring->next_to_use,
|
||||
rx_ring->next_to_clean);
|
||||
}
|
||||
|
||||
/* Print RX Rings */
|
||||
if (!netif_msg_rx_status(adapter))
|
||||
goto exit;
|
||||
|
||||
netdev_info(netdev, "RX Rings Dump\n");
|
||||
|
||||
/* Advanced Receive Descriptor (Read) Format
|
||||
* 63 1 0
|
||||
* +-----------------------------------------------------+
|
||||
* 0 | Packet Buffer Address [63:1] |A0/NSE|
|
||||
* +----------------------------------------------+------+
|
||||
* 8 | Header Buffer Address [63:1] | DD |
|
||||
* +-----------------------------------------------------+
|
||||
*
|
||||
*
|
||||
* Advanced Receive Descriptor (Write-Back) Format
|
||||
*
|
||||
* 63 48 47 32 31 30 21 20 17 16 4 3 0
|
||||
* +------------------------------------------------------+
|
||||
* 0 | Packet IP |SPH| HDR_LEN | RSV|Packet| RSS |
|
||||
* | Checksum Ident | | | | Type | Type |
|
||||
* +------------------------------------------------------+
|
||||
* 8 | VLAN Tag | Length | Extended Error | Extended Status |
|
||||
* +------------------------------------------------------+
|
||||
* 63 48 47 32 31 20 19 0
|
||||
*/
|
||||
|
||||
for (n = 0; n < adapter->num_rx_queues; n++) {
|
||||
rx_ring = adapter->rx_ring[n];
|
||||
netdev_info(netdev, "------------------------------------\n");
|
||||
netdev_info(netdev, "RX QUEUE INDEX = %d\n",
|
||||
rx_ring->queue_index);
|
||||
netdev_info(netdev, "------------------------------------\n");
|
||||
netdev_info(netdev, "R [desc] [ PktBuf A0] [ HeadBuf DD] [bi->dma ] [bi->skb] <-- Adv Rx Read format\n");
|
||||
netdev_info(netdev, "RWB[desc] [PcsmIpSHl PtRs] [vl er S cks ln] ---------------- [bi->skb] <-- Adv Rx Write-Back format\n");
|
||||
|
||||
for (i = 0; i < rx_ring->count; i++) {
|
||||
const char *next_desc;
|
||||
struct igc_rx_buffer *buffer_info;
|
||||
|
||||
buffer_info = &rx_ring->rx_buffer_info[i];
|
||||
rx_desc = IGC_RX_DESC(rx_ring, i);
|
||||
u0 = (struct my_u0 *)rx_desc;
|
||||
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
|
||||
|
||||
if (i == rx_ring->next_to_use)
|
||||
next_desc = " NTU";
|
||||
else if (i == rx_ring->next_to_clean)
|
||||
next_desc = " NTC";
|
||||
else
|
||||
next_desc = "";
|
||||
|
||||
if (staterr & IGC_RXD_STAT_DD) {
|
||||
/* Descriptor Done */
|
||||
netdev_info(netdev, "%s[0x%03X] %016llX %016llX ---------------- %s\n",
|
||||
"RWB", i,
|
||||
le64_to_cpu(u0->a),
|
||||
le64_to_cpu(u0->b),
|
||||
next_desc);
|
||||
} else {
|
||||
netdev_info(netdev, "%s[0x%03X] %016llX %016llX %016llX %s\n",
|
||||
"R ", i,
|
||||
le64_to_cpu(u0->a),
|
||||
le64_to_cpu(u0->b),
|
||||
(u64)buffer_info->dma,
|
||||
next_desc);
|
||||
|
||||
if (netif_msg_pktdata(adapter) &&
|
||||
buffer_info->dma && buffer_info->page) {
|
||||
print_hex_dump(KERN_INFO, "",
|
||||
DUMP_PREFIX_ADDRESS,
|
||||
16, 1,
|
||||
page_address
|
||||
(buffer_info->page) +
|
||||
buffer_info->page_offset,
|
||||
igc_rx_bufsz(rx_ring),
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
/* igc_regs_dump - registers dump */
|
||||
void igc_regs_dump(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
struct igc_reg_info *reginfo;
|
||||
|
||||
/* Print Registers */
|
||||
netdev_info(adapter->netdev, "Register Dump\n");
|
||||
netdev_info(adapter->netdev, "Register Name Value\n");
|
||||
for (reginfo = (struct igc_reg_info *)igc_reg_info_tbl;
|
||||
reginfo->name; reginfo++) {
|
||||
igc_regdump(hw, reginfo);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,318 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include "igc-6.6-ethercat.h"
|
||||
|
||||
struct igc_reg_info {
|
||||
u32 ofs;
|
||||
char *name;
|
||||
};
|
||||
|
||||
static const struct igc_reg_info igc_reg_info_tbl[] = {
|
||||
/* General Registers */
|
||||
{IGC_CTRL, "CTRL"},
|
||||
{IGC_STATUS, "STATUS"},
|
||||
{IGC_CTRL_EXT, "CTRL_EXT"},
|
||||
{IGC_MDIC, "MDIC"},
|
||||
|
||||
/* Interrupt Registers */
|
||||
{IGC_ICR, "ICR"},
|
||||
|
||||
/* RX Registers */
|
||||
{IGC_RCTL, "RCTL"},
|
||||
{IGC_RDLEN(0), "RDLEN"},
|
||||
{IGC_RDH(0), "RDH"},
|
||||
{IGC_RDT(0), "RDT"},
|
||||
{IGC_RXDCTL(0), "RXDCTL"},
|
||||
{IGC_RDBAL(0), "RDBAL"},
|
||||
{IGC_RDBAH(0), "RDBAH"},
|
||||
|
||||
/* TX Registers */
|
||||
{IGC_TCTL, "TCTL"},
|
||||
{IGC_TDBAL(0), "TDBAL"},
|
||||
{IGC_TDBAH(0), "TDBAH"},
|
||||
{IGC_TDLEN(0), "TDLEN"},
|
||||
{IGC_TDH(0), "TDH"},
|
||||
{IGC_TDT(0), "TDT"},
|
||||
{IGC_TXDCTL(0), "TXDCTL"},
|
||||
|
||||
/* List Terminator */
|
||||
{}
|
||||
};
|
||||
|
||||
/* igc_regdump - register printout routine */
|
||||
static void igc_regdump(struct igc_hw *hw, struct igc_reg_info *reginfo)
|
||||
{
|
||||
struct net_device *dev = igc_get_hw_dev(hw);
|
||||
int n = 0;
|
||||
char rname[16];
|
||||
u32 regs[8];
|
||||
|
||||
switch (reginfo->ofs) {
|
||||
case IGC_RDLEN(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDLEN(n));
|
||||
break;
|
||||
case IGC_RDH(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDH(n));
|
||||
break;
|
||||
case IGC_RDT(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDT(n));
|
||||
break;
|
||||
case IGC_RXDCTL(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RXDCTL(n));
|
||||
break;
|
||||
case IGC_RDBAL(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDBAL(n));
|
||||
break;
|
||||
case IGC_RDBAH(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDBAH(n));
|
||||
break;
|
||||
case IGC_TDBAL(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDBAL(n));
|
||||
break;
|
||||
case IGC_TDBAH(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDBAH(n));
|
||||
break;
|
||||
case IGC_TDLEN(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDLEN(n));
|
||||
break;
|
||||
case IGC_TDH(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDH(n));
|
||||
break;
|
||||
case IGC_TDT(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDT(n));
|
||||
break;
|
||||
case IGC_TXDCTL(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TXDCTL(n));
|
||||
break;
|
||||
default:
|
||||
netdev_info(dev, "%-15s %08x\n", reginfo->name,
|
||||
rd32(reginfo->ofs));
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(rname, 16, "%s%s", reginfo->name, "[0-3]");
|
||||
netdev_info(dev, "%-15s %08x %08x %08x %08x\n", rname, regs[0], regs[1],
|
||||
regs[2], regs[3]);
|
||||
}
|
||||
|
||||
/* igc_rings_dump - Tx-rings and Rx-rings */
|
||||
void igc_rings_dump(struct igc_adapter *adapter)
|
||||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
struct my_u0 { __le64 a; __le64 b; } *u0;
|
||||
union igc_adv_tx_desc *tx_desc;
|
||||
union igc_adv_rx_desc *rx_desc;
|
||||
struct igc_ring *tx_ring;
|
||||
struct igc_ring *rx_ring;
|
||||
u32 staterr;
|
||||
u16 i, n;
|
||||
|
||||
if (!netif_msg_hw(adapter))
|
||||
return;
|
||||
|
||||
netdev_info(netdev, "Device info: state %016lX trans_start %016lX\n",
|
||||
netdev->state, dev_trans_start(netdev));
|
||||
|
||||
/* Print TX Ring Summary */
|
||||
if (!netif_running(netdev))
|
||||
goto exit;
|
||||
|
||||
netdev_info(netdev, "TX Rings Summary\n");
|
||||
netdev_info(netdev, "Queue [NTU] [NTC] [bi(ntc)->dma ] leng ntw timestamp\n");
|
||||
for (n = 0; n < adapter->num_tx_queues; n++) {
|
||||
struct igc_tx_buffer *buffer_info;
|
||||
|
||||
tx_ring = adapter->tx_ring[n];
|
||||
buffer_info = &tx_ring->tx_buffer_info[tx_ring->next_to_clean];
|
||||
|
||||
netdev_info(netdev, "%5d %5X %5X %016llX %04X %p %016llX\n",
|
||||
n, tx_ring->next_to_use, tx_ring->next_to_clean,
|
||||
(u64)dma_unmap_addr(buffer_info, dma),
|
||||
dma_unmap_len(buffer_info, len),
|
||||
buffer_info->next_to_watch,
|
||||
(u64)buffer_info->time_stamp);
|
||||
}
|
||||
|
||||
/* Print TX Rings */
|
||||
if (!netif_msg_tx_done(adapter))
|
||||
goto rx_ring_summary;
|
||||
|
||||
netdev_info(netdev, "TX Rings Dump\n");
|
||||
|
||||
/* Transmit Descriptor Formats
|
||||
*
|
||||
* Advanced Transmit Descriptor
|
||||
* +--------------------------------------------------------------+
|
||||
* 0 | Buffer Address [63:0] |
|
||||
* +--------------------------------------------------------------+
|
||||
* 8 | PAYLEN | PORTS |CC|IDX | STA | DCMD |DTYP|MAC|RSV| DTALEN |
|
||||
* +--------------------------------------------------------------+
|
||||
* 63 46 45 40 39 38 36 35 32 31 24 15 0
|
||||
*/
|
||||
|
||||
for (n = 0; n < adapter->num_tx_queues; n++) {
|
||||
tx_ring = adapter->tx_ring[n];
|
||||
netdev_info(netdev, "------------------------------------\n");
|
||||
netdev_info(netdev, "TX QUEUE INDEX = %d\n",
|
||||
tx_ring->queue_index);
|
||||
netdev_info(netdev, "------------------------------------\n");
|
||||
netdev_info(netdev, "T [desc] [address 63:0 ] [PlPOCIStDDM Ln] [bi->dma ] leng ntw timestamp bi->skb\n");
|
||||
|
||||
for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
|
||||
const char *next_desc;
|
||||
struct igc_tx_buffer *buffer_info;
|
||||
|
||||
tx_desc = IGC_TX_DESC(tx_ring, i);
|
||||
buffer_info = &tx_ring->tx_buffer_info[i];
|
||||
u0 = (struct my_u0 *)tx_desc;
|
||||
if (i == tx_ring->next_to_use &&
|
||||
i == tx_ring->next_to_clean)
|
||||
next_desc = " NTC/U";
|
||||
else if (i == tx_ring->next_to_use)
|
||||
next_desc = " NTU";
|
||||
else if (i == tx_ring->next_to_clean)
|
||||
next_desc = " NTC";
|
||||
else
|
||||
next_desc = "";
|
||||
|
||||
netdev_info(netdev, "T [0x%03X] %016llX %016llX %016llX %04X %p %016llX %p%s\n",
|
||||
i, le64_to_cpu(u0->a),
|
||||
le64_to_cpu(u0->b),
|
||||
(u64)dma_unmap_addr(buffer_info, dma),
|
||||
dma_unmap_len(buffer_info, len),
|
||||
buffer_info->next_to_watch,
|
||||
(u64)buffer_info->time_stamp,
|
||||
buffer_info->skb, next_desc);
|
||||
|
||||
if (netif_msg_pktdata(adapter) && buffer_info->skb)
|
||||
print_hex_dump(KERN_INFO, "",
|
||||
DUMP_PREFIX_ADDRESS,
|
||||
16, 1, buffer_info->skb->data,
|
||||
dma_unmap_len(buffer_info, len),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print RX Rings Summary */
|
||||
rx_ring_summary:
|
||||
netdev_info(netdev, "RX Rings Summary\n");
|
||||
netdev_info(netdev, "Queue [NTU] [NTC]\n");
|
||||
for (n = 0; n < adapter->num_rx_queues; n++) {
|
||||
rx_ring = adapter->rx_ring[n];
|
||||
netdev_info(netdev, "%5d %5X %5X\n", n, rx_ring->next_to_use,
|
||||
rx_ring->next_to_clean);
|
||||
}
|
||||
|
||||
/* Print RX Rings */
|
||||
if (!netif_msg_rx_status(adapter))
|
||||
goto exit;
|
||||
|
||||
netdev_info(netdev, "RX Rings Dump\n");
|
||||
|
||||
/* Advanced Receive Descriptor (Read) Format
|
||||
* 63 1 0
|
||||
* +-----------------------------------------------------+
|
||||
* 0 | Packet Buffer Address [63:1] |A0/NSE|
|
||||
* +----------------------------------------------+------+
|
||||
* 8 | Header Buffer Address [63:1] | DD |
|
||||
* +-----------------------------------------------------+
|
||||
*
|
||||
*
|
||||
* Advanced Receive Descriptor (Write-Back) Format
|
||||
*
|
||||
* 63 48 47 32 31 30 21 20 17 16 4 3 0
|
||||
* +------------------------------------------------------+
|
||||
* 0 | Packet IP |SPH| HDR_LEN | RSV|Packet| RSS |
|
||||
* | Checksum Ident | | | | Type | Type |
|
||||
* +------------------------------------------------------+
|
||||
* 8 | VLAN Tag | Length | Extended Error | Extended Status |
|
||||
* +------------------------------------------------------+
|
||||
* 63 48 47 32 31 20 19 0
|
||||
*/
|
||||
|
||||
for (n = 0; n < adapter->num_rx_queues; n++) {
|
||||
rx_ring = adapter->rx_ring[n];
|
||||
netdev_info(netdev, "------------------------------------\n");
|
||||
netdev_info(netdev, "RX QUEUE INDEX = %d\n",
|
||||
rx_ring->queue_index);
|
||||
netdev_info(netdev, "------------------------------------\n");
|
||||
netdev_info(netdev, "R [desc] [ PktBuf A0] [ HeadBuf DD] [bi->dma ] [bi->skb] <-- Adv Rx Read format\n");
|
||||
netdev_info(netdev, "RWB[desc] [PcsmIpSHl PtRs] [vl er S cks ln] ---------------- [bi->skb] <-- Adv Rx Write-Back format\n");
|
||||
|
||||
for (i = 0; i < rx_ring->count; i++) {
|
||||
const char *next_desc;
|
||||
struct igc_rx_buffer *buffer_info;
|
||||
|
||||
buffer_info = &rx_ring->rx_buffer_info[i];
|
||||
rx_desc = IGC_RX_DESC(rx_ring, i);
|
||||
u0 = (struct my_u0 *)rx_desc;
|
||||
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
|
||||
|
||||
if (i == rx_ring->next_to_use)
|
||||
next_desc = " NTU";
|
||||
else if (i == rx_ring->next_to_clean)
|
||||
next_desc = " NTC";
|
||||
else
|
||||
next_desc = "";
|
||||
|
||||
if (staterr & IGC_RXD_STAT_DD) {
|
||||
/* Descriptor Done */
|
||||
netdev_info(netdev, "%s[0x%03X] %016llX %016llX ---------------- %s\n",
|
||||
"RWB", i,
|
||||
le64_to_cpu(u0->a),
|
||||
le64_to_cpu(u0->b),
|
||||
next_desc);
|
||||
} else {
|
||||
netdev_info(netdev, "%s[0x%03X] %016llX %016llX %016llX %s\n",
|
||||
"R ", i,
|
||||
le64_to_cpu(u0->a),
|
||||
le64_to_cpu(u0->b),
|
||||
(u64)buffer_info->dma,
|
||||
next_desc);
|
||||
|
||||
if (netif_msg_pktdata(adapter) &&
|
||||
buffer_info->dma && buffer_info->page) {
|
||||
print_hex_dump(KERN_INFO, "",
|
||||
DUMP_PREFIX_ADDRESS,
|
||||
16, 1,
|
||||
page_address
|
||||
(buffer_info->page) +
|
||||
buffer_info->page_offset,
|
||||
igc_rx_bufsz(rx_ring),
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
/* igc_regs_dump - registers dump */
|
||||
void igc_regs_dump(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
struct igc_reg_info *reginfo;
|
||||
|
||||
/* Print Registers */
|
||||
netdev_info(adapter->netdev, "Register Dump\n");
|
||||
netdev_info(adapter->netdev, "Register Name Value\n");
|
||||
for (reginfo = (struct igc_reg_info *)igc_reg_info_tbl;
|
||||
reginfo->name; reginfo++) {
|
||||
igc_regdump(hw, reginfo);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,318 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include "igc.h"
|
||||
|
||||
struct igc_reg_info {
|
||||
u32 ofs;
|
||||
char *name;
|
||||
};
|
||||
|
||||
static const struct igc_reg_info igc_reg_info_tbl[] = {
|
||||
/* General Registers */
|
||||
{IGC_CTRL, "CTRL"},
|
||||
{IGC_STATUS, "STATUS"},
|
||||
{IGC_CTRL_EXT, "CTRL_EXT"},
|
||||
{IGC_MDIC, "MDIC"},
|
||||
|
||||
/* Interrupt Registers */
|
||||
{IGC_ICR, "ICR"},
|
||||
|
||||
/* RX Registers */
|
||||
{IGC_RCTL, "RCTL"},
|
||||
{IGC_RDLEN(0), "RDLEN"},
|
||||
{IGC_RDH(0), "RDH"},
|
||||
{IGC_RDT(0), "RDT"},
|
||||
{IGC_RXDCTL(0), "RXDCTL"},
|
||||
{IGC_RDBAL(0), "RDBAL"},
|
||||
{IGC_RDBAH(0), "RDBAH"},
|
||||
|
||||
/* TX Registers */
|
||||
{IGC_TCTL, "TCTL"},
|
||||
{IGC_TDBAL(0), "TDBAL"},
|
||||
{IGC_TDBAH(0), "TDBAH"},
|
||||
{IGC_TDLEN(0), "TDLEN"},
|
||||
{IGC_TDH(0), "TDH"},
|
||||
{IGC_TDT(0), "TDT"},
|
||||
{IGC_TXDCTL(0), "TXDCTL"},
|
||||
|
||||
/* List Terminator */
|
||||
{}
|
||||
};
|
||||
|
||||
/* igc_regdump - register printout routine */
|
||||
static void igc_regdump(struct igc_hw *hw, struct igc_reg_info *reginfo)
|
||||
{
|
||||
struct net_device *dev = igc_get_hw_dev(hw);
|
||||
int n = 0;
|
||||
char rname[16];
|
||||
u32 regs[8];
|
||||
|
||||
switch (reginfo->ofs) {
|
||||
case IGC_RDLEN(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDLEN(n));
|
||||
break;
|
||||
case IGC_RDH(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDH(n));
|
||||
break;
|
||||
case IGC_RDT(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDT(n));
|
||||
break;
|
||||
case IGC_RXDCTL(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RXDCTL(n));
|
||||
break;
|
||||
case IGC_RDBAL(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDBAL(n));
|
||||
break;
|
||||
case IGC_RDBAH(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_RDBAH(n));
|
||||
break;
|
||||
case IGC_TDBAL(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDBAL(n));
|
||||
break;
|
||||
case IGC_TDBAH(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDBAH(n));
|
||||
break;
|
||||
case IGC_TDLEN(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDLEN(n));
|
||||
break;
|
||||
case IGC_TDH(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDH(n));
|
||||
break;
|
||||
case IGC_TDT(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TDT(n));
|
||||
break;
|
||||
case IGC_TXDCTL(0):
|
||||
for (n = 0; n < 4; n++)
|
||||
regs[n] = rd32(IGC_TXDCTL(n));
|
||||
break;
|
||||
default:
|
||||
netdev_info(dev, "%-15s %08x\n", reginfo->name,
|
||||
rd32(reginfo->ofs));
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(rname, 16, "%s%s", reginfo->name, "[0-3]");
|
||||
netdev_info(dev, "%-15s %08x %08x %08x %08x\n", rname, regs[0], regs[1],
|
||||
regs[2], regs[3]);
|
||||
}
|
||||
|
||||
/* igc_rings_dump - Tx-rings and Rx-rings */
|
||||
void igc_rings_dump(struct igc_adapter *adapter)
|
||||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
struct my_u0 { __le64 a; __le64 b; } *u0;
|
||||
union igc_adv_tx_desc *tx_desc;
|
||||
union igc_adv_rx_desc *rx_desc;
|
||||
struct igc_ring *tx_ring;
|
||||
struct igc_ring *rx_ring;
|
||||
u32 staterr;
|
||||
u16 i, n;
|
||||
|
||||
if (!netif_msg_hw(adapter))
|
||||
return;
|
||||
|
||||
netdev_info(netdev, "Device info: state %016lX trans_start %016lX\n",
|
||||
netdev->state, dev_trans_start(netdev));
|
||||
|
||||
/* Print TX Ring Summary */
|
||||
if (!netif_running(netdev))
|
||||
goto exit;
|
||||
|
||||
netdev_info(netdev, "TX Rings Summary\n");
|
||||
netdev_info(netdev, "Queue [NTU] [NTC] [bi(ntc)->dma ] leng ntw timestamp\n");
|
||||
for (n = 0; n < adapter->num_tx_queues; n++) {
|
||||
struct igc_tx_buffer *buffer_info;
|
||||
|
||||
tx_ring = adapter->tx_ring[n];
|
||||
buffer_info = &tx_ring->tx_buffer_info[tx_ring->next_to_clean];
|
||||
|
||||
netdev_info(netdev, "%5d %5X %5X %016llX %04X %p %016llX\n",
|
||||
n, tx_ring->next_to_use, tx_ring->next_to_clean,
|
||||
(u64)dma_unmap_addr(buffer_info, dma),
|
||||
dma_unmap_len(buffer_info, len),
|
||||
buffer_info->next_to_watch,
|
||||
(u64)buffer_info->time_stamp);
|
||||
}
|
||||
|
||||
/* Print TX Rings */
|
||||
if (!netif_msg_tx_done(adapter))
|
||||
goto rx_ring_summary;
|
||||
|
||||
netdev_info(netdev, "TX Rings Dump\n");
|
||||
|
||||
/* Transmit Descriptor Formats
|
||||
*
|
||||
* Advanced Transmit Descriptor
|
||||
* +--------------------------------------------------------------+
|
||||
* 0 | Buffer Address [63:0] |
|
||||
* +--------------------------------------------------------------+
|
||||
* 8 | PAYLEN | PORTS |CC|IDX | STA | DCMD |DTYP|MAC|RSV| DTALEN |
|
||||
* +--------------------------------------------------------------+
|
||||
* 63 46 45 40 39 38 36 35 32 31 24 15 0
|
||||
*/
|
||||
|
||||
for (n = 0; n < adapter->num_tx_queues; n++) {
|
||||
tx_ring = adapter->tx_ring[n];
|
||||
netdev_info(netdev, "------------------------------------\n");
|
||||
netdev_info(netdev, "TX QUEUE INDEX = %d\n",
|
||||
tx_ring->queue_index);
|
||||
netdev_info(netdev, "------------------------------------\n");
|
||||
netdev_info(netdev, "T [desc] [address 63:0 ] [PlPOCIStDDM Ln] [bi->dma ] leng ntw timestamp bi->skb\n");
|
||||
|
||||
for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
|
||||
const char *next_desc;
|
||||
struct igc_tx_buffer *buffer_info;
|
||||
|
||||
tx_desc = IGC_TX_DESC(tx_ring, i);
|
||||
buffer_info = &tx_ring->tx_buffer_info[i];
|
||||
u0 = (struct my_u0 *)tx_desc;
|
||||
if (i == tx_ring->next_to_use &&
|
||||
i == tx_ring->next_to_clean)
|
||||
next_desc = " NTC/U";
|
||||
else if (i == tx_ring->next_to_use)
|
||||
next_desc = " NTU";
|
||||
else if (i == tx_ring->next_to_clean)
|
||||
next_desc = " NTC";
|
||||
else
|
||||
next_desc = "";
|
||||
|
||||
netdev_info(netdev, "T [0x%03X] %016llX %016llX %016llX %04X %p %016llX %p%s\n",
|
||||
i, le64_to_cpu(u0->a),
|
||||
le64_to_cpu(u0->b),
|
||||
(u64)dma_unmap_addr(buffer_info, dma),
|
||||
dma_unmap_len(buffer_info, len),
|
||||
buffer_info->next_to_watch,
|
||||
(u64)buffer_info->time_stamp,
|
||||
buffer_info->skb, next_desc);
|
||||
|
||||
if (netif_msg_pktdata(adapter) && buffer_info->skb)
|
||||
print_hex_dump(KERN_INFO, "",
|
||||
DUMP_PREFIX_ADDRESS,
|
||||
16, 1, buffer_info->skb->data,
|
||||
dma_unmap_len(buffer_info, len),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print RX Rings Summary */
|
||||
rx_ring_summary:
|
||||
netdev_info(netdev, "RX Rings Summary\n");
|
||||
netdev_info(netdev, "Queue [NTU] [NTC]\n");
|
||||
for (n = 0; n < adapter->num_rx_queues; n++) {
|
||||
rx_ring = adapter->rx_ring[n];
|
||||
netdev_info(netdev, "%5d %5X %5X\n", n, rx_ring->next_to_use,
|
||||
rx_ring->next_to_clean);
|
||||
}
|
||||
|
||||
/* Print RX Rings */
|
||||
if (!netif_msg_rx_status(adapter))
|
||||
goto exit;
|
||||
|
||||
netdev_info(netdev, "RX Rings Dump\n");
|
||||
|
||||
/* Advanced Receive Descriptor (Read) Format
|
||||
* 63 1 0
|
||||
* +-----------------------------------------------------+
|
||||
* 0 | Packet Buffer Address [63:1] |A0/NSE|
|
||||
* +----------------------------------------------+------+
|
||||
* 8 | Header Buffer Address [63:1] | DD |
|
||||
* +-----------------------------------------------------+
|
||||
*
|
||||
*
|
||||
* Advanced Receive Descriptor (Write-Back) Format
|
||||
*
|
||||
* 63 48 47 32 31 30 21 20 17 16 4 3 0
|
||||
* +------------------------------------------------------+
|
||||
* 0 | Packet IP |SPH| HDR_LEN | RSV|Packet| RSS |
|
||||
* | Checksum Ident | | | | Type | Type |
|
||||
* +------------------------------------------------------+
|
||||
* 8 | VLAN Tag | Length | Extended Error | Extended Status |
|
||||
* +------------------------------------------------------+
|
||||
* 63 48 47 32 31 20 19 0
|
||||
*/
|
||||
|
||||
for (n = 0; n < adapter->num_rx_queues; n++) {
|
||||
rx_ring = adapter->rx_ring[n];
|
||||
netdev_info(netdev, "------------------------------------\n");
|
||||
netdev_info(netdev, "RX QUEUE INDEX = %d\n",
|
||||
rx_ring->queue_index);
|
||||
netdev_info(netdev, "------------------------------------\n");
|
||||
netdev_info(netdev, "R [desc] [ PktBuf A0] [ HeadBuf DD] [bi->dma ] [bi->skb] <-- Adv Rx Read format\n");
|
||||
netdev_info(netdev, "RWB[desc] [PcsmIpSHl PtRs] [vl er S cks ln] ---------------- [bi->skb] <-- Adv Rx Write-Back format\n");
|
||||
|
||||
for (i = 0; i < rx_ring->count; i++) {
|
||||
const char *next_desc;
|
||||
struct igc_rx_buffer *buffer_info;
|
||||
|
||||
buffer_info = &rx_ring->rx_buffer_info[i];
|
||||
rx_desc = IGC_RX_DESC(rx_ring, i);
|
||||
u0 = (struct my_u0 *)rx_desc;
|
||||
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
|
||||
|
||||
if (i == rx_ring->next_to_use)
|
||||
next_desc = " NTU";
|
||||
else if (i == rx_ring->next_to_clean)
|
||||
next_desc = " NTC";
|
||||
else
|
||||
next_desc = "";
|
||||
|
||||
if (staterr & IGC_RXD_STAT_DD) {
|
||||
/* Descriptor Done */
|
||||
netdev_info(netdev, "%s[0x%03X] %016llX %016llX ---------------- %s\n",
|
||||
"RWB", i,
|
||||
le64_to_cpu(u0->a),
|
||||
le64_to_cpu(u0->b),
|
||||
next_desc);
|
||||
} else {
|
||||
netdev_info(netdev, "%s[0x%03X] %016llX %016llX %016llX %s\n",
|
||||
"R ", i,
|
||||
le64_to_cpu(u0->a),
|
||||
le64_to_cpu(u0->b),
|
||||
(u64)buffer_info->dma,
|
||||
next_desc);
|
||||
|
||||
if (netif_msg_pktdata(adapter) &&
|
||||
buffer_info->dma && buffer_info->page) {
|
||||
print_hex_dump(KERN_INFO, "",
|
||||
DUMP_PREFIX_ADDRESS,
|
||||
16, 1,
|
||||
page_address
|
||||
(buffer_info->page) +
|
||||
buffer_info->page_offset,
|
||||
igc_rx_bufsz(rx_ring),
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
/* igc_regs_dump - registers dump */
|
||||
void igc_regs_dump(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
struct igc_reg_info *reginfo;
|
||||
|
||||
/* Print Registers */
|
||||
netdev_info(adapter->netdev, "Register Dump\n");
|
||||
netdev_info(adapter->netdev, "Register Name Value\n");
|
||||
for (reginfo = (struct igc_reg_info *)igc_reg_info_tbl;
|
||||
reginfo->name; reginfo++) {
|
||||
igc_regdump(hw, reginfo);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,288 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_HW_H_
|
||||
#define _IGC_HW_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include "igc_regs-6.4-ethercat.h"
|
||||
#include "igc_defines-6.4-ethercat.h"
|
||||
#include "igc_mac-6.4-ethercat.h"
|
||||
#include "igc_phy-6.4-ethercat.h"
|
||||
#include "igc_nvm-6.4-ethercat.h"
|
||||
#include "igc_i225-6.4-ethercat.h"
|
||||
#include "igc_base-6.4-ethercat.h"
|
||||
|
||||
#define IGC_DEV_ID_I225_LM 0x15F2
|
||||
#define IGC_DEV_ID_I225_V 0x15F3
|
||||
#define IGC_DEV_ID_I225_I 0x15F8
|
||||
#define IGC_DEV_ID_I220_V 0x15F7
|
||||
#define IGC_DEV_ID_I225_K 0x3100
|
||||
#define IGC_DEV_ID_I225_K2 0x3101
|
||||
#define IGC_DEV_ID_I226_K 0x3102
|
||||
#define IGC_DEV_ID_I225_LMVP 0x5502
|
||||
#define IGC_DEV_ID_I226_LMVP 0x5503
|
||||
#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
|
||||
|
||||
/* Function pointers for the MAC. */
|
||||
struct igc_mac_operations {
|
||||
s32 (*check_for_link)(struct igc_hw *hw);
|
||||
s32 (*reset_hw)(struct igc_hw *hw);
|
||||
s32 (*init_hw)(struct igc_hw *hw);
|
||||
s32 (*setup_physical_interface)(struct igc_hw *hw);
|
||||
void (*rar_set)(struct igc_hw *hw, u8 *address, u32 index);
|
||||
s32 (*read_mac_addr)(struct igc_hw *hw);
|
||||
s32 (*get_speed_and_duplex)(struct igc_hw *hw, u16 *speed,
|
||||
u16 *duplex);
|
||||
s32 (*acquire_swfw_sync)(struct igc_hw *hw, u16 mask);
|
||||
void (*release_swfw_sync)(struct igc_hw *hw, u16 mask);
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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_base_info;
|
||||
|
||||
struct igc_mac_info {
|
||||
struct igc_mac_operations ops;
|
||||
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 perm_addr[ETH_ALEN];
|
||||
|
||||
enum igc_mac_type type;
|
||||
|
||||
u32 mc_filter_type;
|
||||
|
||||
u16 mta_reg_count;
|
||||
u16 uta_reg_count;
|
||||
|
||||
u32 mta_shadow[MAX_MTA_REG];
|
||||
u16 rar_entry_count;
|
||||
|
||||
bool asf_firmware_present;
|
||||
bool arc_subsystem_valid;
|
||||
|
||||
bool autoneg;
|
||||
bool autoneg_failed;
|
||||
bool get_link_status;
|
||||
};
|
||||
|
||||
struct igc_nvm_operations {
|
||||
s32 (*acquire)(struct igc_hw *hw);
|
||||
s32 (*read)(struct igc_hw *hw, u16 offset, u16 i, u16 *data);
|
||||
void (*release)(struct igc_hw *hw);
|
||||
s32 (*write)(struct igc_hw *hw, u16 offset, u16 i, u16 *data);
|
||||
s32 (*update)(struct igc_hw *hw);
|
||||
s32 (*validate)(struct igc_hw *hw);
|
||||
};
|
||||
|
||||
struct igc_phy_operations {
|
||||
s32 (*acquire)(struct igc_hw *hw);
|
||||
s32 (*check_reset_block)(struct igc_hw *hw);
|
||||
s32 (*force_speed_duplex)(struct igc_hw *hw);
|
||||
s32 (*get_phy_info)(struct igc_hw *hw);
|
||||
s32 (*read_reg)(struct igc_hw *hw, u32 address, u16 *data);
|
||||
void (*release)(struct igc_hw *hw);
|
||||
s32 (*reset)(struct igc_hw *hw);
|
||||
s32 (*write_reg)(struct igc_hw *hw, u32 address, u16 data);
|
||||
};
|
||||
|
||||
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_phy_info {
|
||||
struct igc_phy_operations ops;
|
||||
|
||||
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 is_mdix;
|
||||
bool speed_downgraded;
|
||||
bool autoneg_wait_to_complete;
|
||||
};
|
||||
|
||||
struct igc_bus_info {
|
||||
u16 func;
|
||||
u16 pci_cmd_word;
|
||||
};
|
||||
|
||||
enum igc_fc_mode {
|
||||
igc_fc_none = 0,
|
||||
igc_fc_rx_pause,
|
||||
igc_fc_tx_pause,
|
||||
igc_fc_full,
|
||||
igc_fc_default = 0xFF
|
||||
};
|
||||
|
||||
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 */
|
||||
bool send_xon; /* Flow control send XON */
|
||||
bool strict_ieee; /* Strict IEEE mode */
|
||||
enum igc_fc_mode current_mode; /* Type of flow control */
|
||||
enum igc_fc_mode requested_mode;
|
||||
};
|
||||
|
||||
struct igc_dev_spec_base {
|
||||
bool clear_semaphore_once;
|
||||
bool eee_enable;
|
||||
};
|
||||
|
||||
struct igc_hw {
|
||||
void *back;
|
||||
|
||||
u8 __iomem *hw_addr;
|
||||
unsigned long io_base;
|
||||
|
||||
struct igc_mac_info mac;
|
||||
struct igc_fc_info fc;
|
||||
struct igc_nvm_info nvm;
|
||||
struct igc_phy_info phy;
|
||||
|
||||
struct igc_bus_info bus;
|
||||
|
||||
union {
|
||||
struct igc_dev_spec_base _base;
|
||||
} dev_spec;
|
||||
|
||||
u16 device_id;
|
||||
u16 subsystem_vendor_id;
|
||||
u16 subsystem_device_id;
|
||||
u16 vendor_id;
|
||||
|
||||
u8 revision_id;
|
||||
};
|
||||
|
||||
/* 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 cexterr;
|
||||
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 tsctfc;
|
||||
u64 iac;
|
||||
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;
|
||||
u64 txdrop;
|
||||
};
|
||||
|
||||
struct net_device *igc_get_hw_dev(struct igc_hw *hw);
|
||||
#define hw_dbg(format, arg...) \
|
||||
netdev_dbg(igc_get_hw_dev(hw), format, ##arg)
|
||||
|
||||
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 /* _IGC_HW_H_ */
|
||||
|
|
@ -0,0 +1,288 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_HW_H_
|
||||
#define _IGC_HW_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include "igc_regs.h"
|
||||
#include "igc_defines.h"
|
||||
#include "igc_mac.h"
|
||||
#include "igc_phy.h"
|
||||
#include "igc_nvm.h"
|
||||
#include "igc_i225.h"
|
||||
#include "igc_base.h"
|
||||
|
||||
#define IGC_DEV_ID_I225_LM 0x15F2
|
||||
#define IGC_DEV_ID_I225_V 0x15F3
|
||||
#define IGC_DEV_ID_I225_I 0x15F8
|
||||
#define IGC_DEV_ID_I220_V 0x15F7
|
||||
#define IGC_DEV_ID_I225_K 0x3100
|
||||
#define IGC_DEV_ID_I225_K2 0x3101
|
||||
#define IGC_DEV_ID_I226_K 0x3102
|
||||
#define IGC_DEV_ID_I225_LMVP 0x5502
|
||||
#define IGC_DEV_ID_I226_LMVP 0x5503
|
||||
#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
|
||||
|
||||
/* Function pointers for the MAC. */
|
||||
struct igc_mac_operations {
|
||||
s32 (*check_for_link)(struct igc_hw *hw);
|
||||
s32 (*reset_hw)(struct igc_hw *hw);
|
||||
s32 (*init_hw)(struct igc_hw *hw);
|
||||
s32 (*setup_physical_interface)(struct igc_hw *hw);
|
||||
void (*rar_set)(struct igc_hw *hw, u8 *address, u32 index);
|
||||
s32 (*read_mac_addr)(struct igc_hw *hw);
|
||||
s32 (*get_speed_and_duplex)(struct igc_hw *hw, u16 *speed,
|
||||
u16 *duplex);
|
||||
s32 (*acquire_swfw_sync)(struct igc_hw *hw, u16 mask);
|
||||
void (*release_swfw_sync)(struct igc_hw *hw, u16 mask);
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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_base_info;
|
||||
|
||||
struct igc_mac_info {
|
||||
struct igc_mac_operations ops;
|
||||
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 perm_addr[ETH_ALEN];
|
||||
|
||||
enum igc_mac_type type;
|
||||
|
||||
u32 mc_filter_type;
|
||||
|
||||
u16 mta_reg_count;
|
||||
u16 uta_reg_count;
|
||||
|
||||
u32 mta_shadow[MAX_MTA_REG];
|
||||
u16 rar_entry_count;
|
||||
|
||||
bool asf_firmware_present;
|
||||
bool arc_subsystem_valid;
|
||||
|
||||
bool autoneg;
|
||||
bool autoneg_failed;
|
||||
bool get_link_status;
|
||||
};
|
||||
|
||||
struct igc_nvm_operations {
|
||||
s32 (*acquire)(struct igc_hw *hw);
|
||||
s32 (*read)(struct igc_hw *hw, u16 offset, u16 i, u16 *data);
|
||||
void (*release)(struct igc_hw *hw);
|
||||
s32 (*write)(struct igc_hw *hw, u16 offset, u16 i, u16 *data);
|
||||
s32 (*update)(struct igc_hw *hw);
|
||||
s32 (*validate)(struct igc_hw *hw);
|
||||
};
|
||||
|
||||
struct igc_phy_operations {
|
||||
s32 (*acquire)(struct igc_hw *hw);
|
||||
s32 (*check_reset_block)(struct igc_hw *hw);
|
||||
s32 (*force_speed_duplex)(struct igc_hw *hw);
|
||||
s32 (*get_phy_info)(struct igc_hw *hw);
|
||||
s32 (*read_reg)(struct igc_hw *hw, u32 address, u16 *data);
|
||||
void (*release)(struct igc_hw *hw);
|
||||
s32 (*reset)(struct igc_hw *hw);
|
||||
s32 (*write_reg)(struct igc_hw *hw, u32 address, u16 data);
|
||||
};
|
||||
|
||||
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_phy_info {
|
||||
struct igc_phy_operations ops;
|
||||
|
||||
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 is_mdix;
|
||||
bool speed_downgraded;
|
||||
bool autoneg_wait_to_complete;
|
||||
};
|
||||
|
||||
struct igc_bus_info {
|
||||
u16 func;
|
||||
u16 pci_cmd_word;
|
||||
};
|
||||
|
||||
enum igc_fc_mode {
|
||||
igc_fc_none = 0,
|
||||
igc_fc_rx_pause,
|
||||
igc_fc_tx_pause,
|
||||
igc_fc_full,
|
||||
igc_fc_default = 0xFF
|
||||
};
|
||||
|
||||
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 */
|
||||
bool send_xon; /* Flow control send XON */
|
||||
bool strict_ieee; /* Strict IEEE mode */
|
||||
enum igc_fc_mode current_mode; /* Type of flow control */
|
||||
enum igc_fc_mode requested_mode;
|
||||
};
|
||||
|
||||
struct igc_dev_spec_base {
|
||||
bool clear_semaphore_once;
|
||||
bool eee_enable;
|
||||
};
|
||||
|
||||
struct igc_hw {
|
||||
void *back;
|
||||
|
||||
u8 __iomem *hw_addr;
|
||||
unsigned long io_base;
|
||||
|
||||
struct igc_mac_info mac;
|
||||
struct igc_fc_info fc;
|
||||
struct igc_nvm_info nvm;
|
||||
struct igc_phy_info phy;
|
||||
|
||||
struct igc_bus_info bus;
|
||||
|
||||
union {
|
||||
struct igc_dev_spec_base _base;
|
||||
} dev_spec;
|
||||
|
||||
u16 device_id;
|
||||
u16 subsystem_vendor_id;
|
||||
u16 subsystem_device_id;
|
||||
u16 vendor_id;
|
||||
|
||||
u8 revision_id;
|
||||
};
|
||||
|
||||
/* 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 cexterr;
|
||||
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 tsctfc;
|
||||
u64 iac;
|
||||
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;
|
||||
u64 txdrop;
|
||||
};
|
||||
|
||||
struct net_device *igc_get_hw_dev(struct igc_hw *hw);
|
||||
#define hw_dbg(format, arg...) \
|
||||
netdev_dbg(igc_get_hw_dev(hw), format, ##arg)
|
||||
|
||||
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 /* _IGC_HW_H_ */
|
||||
|
|
@ -0,0 +1,288 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_HW_H_
|
||||
#define _IGC_HW_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include "igc_regs-6.6-ethercat.h"
|
||||
#include "igc_defines-6.6-ethercat.h"
|
||||
#include "igc_mac-6.6-ethercat.h"
|
||||
#include "igc_phy-6.6-ethercat.h"
|
||||
#include "igc_nvm-6.6-ethercat.h"
|
||||
#include "igc_i225-6.6-ethercat.h"
|
||||
#include "igc_base-6.6-ethercat.h"
|
||||
|
||||
#define IGC_DEV_ID_I225_LM 0x15F2
|
||||
#define IGC_DEV_ID_I225_V 0x15F3
|
||||
#define IGC_DEV_ID_I225_I 0x15F8
|
||||
#define IGC_DEV_ID_I220_V 0x15F7
|
||||
#define IGC_DEV_ID_I225_K 0x3100
|
||||
#define IGC_DEV_ID_I225_K2 0x3101
|
||||
#define IGC_DEV_ID_I226_K 0x3102
|
||||
#define IGC_DEV_ID_I225_LMVP 0x5502
|
||||
#define IGC_DEV_ID_I226_LMVP 0x5503
|
||||
#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
|
||||
|
||||
/* Function pointers for the MAC. */
|
||||
struct igc_mac_operations {
|
||||
s32 (*check_for_link)(struct igc_hw *hw);
|
||||
s32 (*reset_hw)(struct igc_hw *hw);
|
||||
s32 (*init_hw)(struct igc_hw *hw);
|
||||
s32 (*setup_physical_interface)(struct igc_hw *hw);
|
||||
void (*rar_set)(struct igc_hw *hw, u8 *address, u32 index);
|
||||
s32 (*read_mac_addr)(struct igc_hw *hw);
|
||||
s32 (*get_speed_and_duplex)(struct igc_hw *hw, u16 *speed,
|
||||
u16 *duplex);
|
||||
s32 (*acquire_swfw_sync)(struct igc_hw *hw, u16 mask);
|
||||
void (*release_swfw_sync)(struct igc_hw *hw, u16 mask);
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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_base_info;
|
||||
|
||||
struct igc_mac_info {
|
||||
struct igc_mac_operations ops;
|
||||
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 perm_addr[ETH_ALEN];
|
||||
|
||||
enum igc_mac_type type;
|
||||
|
||||
u32 mc_filter_type;
|
||||
|
||||
u16 mta_reg_count;
|
||||
u16 uta_reg_count;
|
||||
|
||||
u32 mta_shadow[MAX_MTA_REG];
|
||||
u16 rar_entry_count;
|
||||
|
||||
bool asf_firmware_present;
|
||||
bool arc_subsystem_valid;
|
||||
|
||||
bool autoneg;
|
||||
bool autoneg_failed;
|
||||
bool get_link_status;
|
||||
};
|
||||
|
||||
struct igc_nvm_operations {
|
||||
s32 (*acquire)(struct igc_hw *hw);
|
||||
s32 (*read)(struct igc_hw *hw, u16 offset, u16 i, u16 *data);
|
||||
void (*release)(struct igc_hw *hw);
|
||||
s32 (*write)(struct igc_hw *hw, u16 offset, u16 i, u16 *data);
|
||||
s32 (*update)(struct igc_hw *hw);
|
||||
s32 (*validate)(struct igc_hw *hw);
|
||||
};
|
||||
|
||||
struct igc_phy_operations {
|
||||
s32 (*acquire)(struct igc_hw *hw);
|
||||
s32 (*check_reset_block)(struct igc_hw *hw);
|
||||
s32 (*force_speed_duplex)(struct igc_hw *hw);
|
||||
s32 (*get_phy_info)(struct igc_hw *hw);
|
||||
s32 (*read_reg)(struct igc_hw *hw, u32 address, u16 *data);
|
||||
void (*release)(struct igc_hw *hw);
|
||||
s32 (*reset)(struct igc_hw *hw);
|
||||
s32 (*write_reg)(struct igc_hw *hw, u32 address, u16 data);
|
||||
};
|
||||
|
||||
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_phy_info {
|
||||
struct igc_phy_operations ops;
|
||||
|
||||
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 is_mdix;
|
||||
bool speed_downgraded;
|
||||
bool autoneg_wait_to_complete;
|
||||
};
|
||||
|
||||
struct igc_bus_info {
|
||||
u16 func;
|
||||
u16 pci_cmd_word;
|
||||
};
|
||||
|
||||
enum igc_fc_mode {
|
||||
igc_fc_none = 0,
|
||||
igc_fc_rx_pause,
|
||||
igc_fc_tx_pause,
|
||||
igc_fc_full,
|
||||
igc_fc_default = 0xFF
|
||||
};
|
||||
|
||||
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 */
|
||||
bool send_xon; /* Flow control send XON */
|
||||
bool strict_ieee; /* Strict IEEE mode */
|
||||
enum igc_fc_mode current_mode; /* Type of flow control */
|
||||
enum igc_fc_mode requested_mode;
|
||||
};
|
||||
|
||||
struct igc_dev_spec_base {
|
||||
bool clear_semaphore_once;
|
||||
bool eee_enable;
|
||||
};
|
||||
|
||||
struct igc_hw {
|
||||
void *back;
|
||||
|
||||
u8 __iomem *hw_addr;
|
||||
unsigned long io_base;
|
||||
|
||||
struct igc_mac_info mac;
|
||||
struct igc_fc_info fc;
|
||||
struct igc_nvm_info nvm;
|
||||
struct igc_phy_info phy;
|
||||
|
||||
struct igc_bus_info bus;
|
||||
|
||||
union {
|
||||
struct igc_dev_spec_base _base;
|
||||
} dev_spec;
|
||||
|
||||
u16 device_id;
|
||||
u16 subsystem_vendor_id;
|
||||
u16 subsystem_device_id;
|
||||
u16 vendor_id;
|
||||
|
||||
u8 revision_id;
|
||||
};
|
||||
|
||||
/* 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 cexterr;
|
||||
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 tsctfc;
|
||||
u64 iac;
|
||||
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;
|
||||
u64 txdrop;
|
||||
};
|
||||
|
||||
struct net_device *igc_get_hw_dev(struct igc_hw *hw);
|
||||
#define hw_dbg(format, arg...) \
|
||||
netdev_dbg(igc_get_hw_dev(hw), format, ##arg)
|
||||
|
||||
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 /* _IGC_HW_H_ */
|
||||
|
|
@ -0,0 +1,288 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_HW_H_
|
||||
#define _IGC_HW_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include "igc_regs.h"
|
||||
#include "igc_defines.h"
|
||||
#include "igc_mac.h"
|
||||
#include "igc_phy.h"
|
||||
#include "igc_nvm.h"
|
||||
#include "igc_i225.h"
|
||||
#include "igc_base.h"
|
||||
|
||||
#define IGC_DEV_ID_I225_LM 0x15F2
|
||||
#define IGC_DEV_ID_I225_V 0x15F3
|
||||
#define IGC_DEV_ID_I225_I 0x15F8
|
||||
#define IGC_DEV_ID_I220_V 0x15F7
|
||||
#define IGC_DEV_ID_I225_K 0x3100
|
||||
#define IGC_DEV_ID_I225_K2 0x3101
|
||||
#define IGC_DEV_ID_I226_K 0x3102
|
||||
#define IGC_DEV_ID_I225_LMVP 0x5502
|
||||
#define IGC_DEV_ID_I226_LMVP 0x5503
|
||||
#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
|
||||
|
||||
/* Function pointers for the MAC. */
|
||||
struct igc_mac_operations {
|
||||
s32 (*check_for_link)(struct igc_hw *hw);
|
||||
s32 (*reset_hw)(struct igc_hw *hw);
|
||||
s32 (*init_hw)(struct igc_hw *hw);
|
||||
s32 (*setup_physical_interface)(struct igc_hw *hw);
|
||||
void (*rar_set)(struct igc_hw *hw, u8 *address, u32 index);
|
||||
s32 (*read_mac_addr)(struct igc_hw *hw);
|
||||
s32 (*get_speed_and_duplex)(struct igc_hw *hw, u16 *speed,
|
||||
u16 *duplex);
|
||||
s32 (*acquire_swfw_sync)(struct igc_hw *hw, u16 mask);
|
||||
void (*release_swfw_sync)(struct igc_hw *hw, u16 mask);
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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_base_info;
|
||||
|
||||
struct igc_mac_info {
|
||||
struct igc_mac_operations ops;
|
||||
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 perm_addr[ETH_ALEN];
|
||||
|
||||
enum igc_mac_type type;
|
||||
|
||||
u32 mc_filter_type;
|
||||
|
||||
u16 mta_reg_count;
|
||||
u16 uta_reg_count;
|
||||
|
||||
u32 mta_shadow[MAX_MTA_REG];
|
||||
u16 rar_entry_count;
|
||||
|
||||
bool asf_firmware_present;
|
||||
bool arc_subsystem_valid;
|
||||
|
||||
bool autoneg;
|
||||
bool autoneg_failed;
|
||||
bool get_link_status;
|
||||
};
|
||||
|
||||
struct igc_nvm_operations {
|
||||
s32 (*acquire)(struct igc_hw *hw);
|
||||
s32 (*read)(struct igc_hw *hw, u16 offset, u16 i, u16 *data);
|
||||
void (*release)(struct igc_hw *hw);
|
||||
s32 (*write)(struct igc_hw *hw, u16 offset, u16 i, u16 *data);
|
||||
s32 (*update)(struct igc_hw *hw);
|
||||
s32 (*validate)(struct igc_hw *hw);
|
||||
};
|
||||
|
||||
struct igc_phy_operations {
|
||||
s32 (*acquire)(struct igc_hw *hw);
|
||||
s32 (*check_reset_block)(struct igc_hw *hw);
|
||||
s32 (*force_speed_duplex)(struct igc_hw *hw);
|
||||
s32 (*get_phy_info)(struct igc_hw *hw);
|
||||
s32 (*read_reg)(struct igc_hw *hw, u32 address, u16 *data);
|
||||
void (*release)(struct igc_hw *hw);
|
||||
s32 (*reset)(struct igc_hw *hw);
|
||||
s32 (*write_reg)(struct igc_hw *hw, u32 address, u16 data);
|
||||
};
|
||||
|
||||
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_phy_info {
|
||||
struct igc_phy_operations ops;
|
||||
|
||||
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 is_mdix;
|
||||
bool speed_downgraded;
|
||||
bool autoneg_wait_to_complete;
|
||||
};
|
||||
|
||||
struct igc_bus_info {
|
||||
u16 func;
|
||||
u16 pci_cmd_word;
|
||||
};
|
||||
|
||||
enum igc_fc_mode {
|
||||
igc_fc_none = 0,
|
||||
igc_fc_rx_pause,
|
||||
igc_fc_tx_pause,
|
||||
igc_fc_full,
|
||||
igc_fc_default = 0xFF
|
||||
};
|
||||
|
||||
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 */
|
||||
bool send_xon; /* Flow control send XON */
|
||||
bool strict_ieee; /* Strict IEEE mode */
|
||||
enum igc_fc_mode current_mode; /* Type of flow control */
|
||||
enum igc_fc_mode requested_mode;
|
||||
};
|
||||
|
||||
struct igc_dev_spec_base {
|
||||
bool clear_semaphore_once;
|
||||
bool eee_enable;
|
||||
};
|
||||
|
||||
struct igc_hw {
|
||||
void *back;
|
||||
|
||||
u8 __iomem *hw_addr;
|
||||
unsigned long io_base;
|
||||
|
||||
struct igc_mac_info mac;
|
||||
struct igc_fc_info fc;
|
||||
struct igc_nvm_info nvm;
|
||||
struct igc_phy_info phy;
|
||||
|
||||
struct igc_bus_info bus;
|
||||
|
||||
union {
|
||||
struct igc_dev_spec_base _base;
|
||||
} dev_spec;
|
||||
|
||||
u16 device_id;
|
||||
u16 subsystem_vendor_id;
|
||||
u16 subsystem_device_id;
|
||||
u16 vendor_id;
|
||||
|
||||
u8 revision_id;
|
||||
};
|
||||
|
||||
/* 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 cexterr;
|
||||
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 tsctfc;
|
||||
u64 iac;
|
||||
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;
|
||||
u64 txdrop;
|
||||
};
|
||||
|
||||
struct net_device *igc_get_hw_dev(struct igc_hw *hw);
|
||||
#define hw_dbg(format, arg...) \
|
||||
netdev_dbg(igc_get_hw_dev(hw), format, ##arg)
|
||||
|
||||
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 /* _IGC_HW_H_ */
|
||||
|
|
@ -0,0 +1,641 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "igc_hw-6.4-ethercat.h"
|
||||
|
||||
/**
|
||||
* igc_acquire_nvm_i225 - Acquire exclusive access to EEPROM
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Acquire the necessary semaphores for exclusive access to the EEPROM.
|
||||
* 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).
|
||||
*/
|
||||
static s32 igc_acquire_nvm_i225(struct igc_hw *hw)
|
||||
{
|
||||
return igc_acquire_swfw_sync_i225(hw, IGC_SWFW_EEP_SM);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_release_nvm_i225 - Release exclusive access to EEPROM
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Stop any current commands to the EEPROM and clear the EEPROM request bit,
|
||||
* then release the semaphores acquired.
|
||||
*/
|
||||
static void igc_release_nvm_i225(struct igc_hw *hw)
|
||||
{
|
||||
igc_release_swfw_sync_i225(hw, IGC_SWFW_EEP_SM);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_hw_semaphore_i225 - Acquire hardware semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Acquire the HW semaphore to access the PHY or NVM
|
||||
*/
|
||||
static s32 igc_get_hw_semaphore_i225(struct igc_hw *hw)
|
||||
{
|
||||
s32 timeout = hw->nvm.word_size + 1;
|
||||
s32 i = 0;
|
||||
u32 swsm;
|
||||
|
||||
/* Get the SW semaphore */
|
||||
while (i < timeout) {
|
||||
swsm = rd32(IGC_SWSM);
|
||||
if (!(swsm & IGC_SWSM_SMBI))
|
||||
break;
|
||||
|
||||
usleep_range(500, 600);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == timeout) {
|
||||
/* In rare circumstances, the SW semaphore may already be held
|
||||
* unintentionally. Clear the semaphore once before giving up.
|
||||
*/
|
||||
if (hw->dev_spec._base.clear_semaphore_once) {
|
||||
hw->dev_spec._base.clear_semaphore_once = false;
|
||||
igc_put_hw_semaphore(hw);
|
||||
for (i = 0; i < timeout; i++) {
|
||||
swsm = rd32(IGC_SWSM);
|
||||
if (!(swsm & IGC_SWSM_SMBI))
|
||||
break;
|
||||
|
||||
usleep_range(500, 600);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we do not have the semaphore here, we have to give up. */
|
||||
if (i == timeout) {
|
||||
hw_dbg("Driver can't access device - SMBI bit is set.\n");
|
||||
return -IGC_ERR_NVM;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the FW semaphore. */
|
||||
for (i = 0; i < timeout; i++) {
|
||||
swsm = rd32(IGC_SWSM);
|
||||
wr32(IGC_SWSM, swsm | IGC_SWSM_SWESMBI);
|
||||
|
||||
/* Semaphore acquired if bit latched */
|
||||
if (rd32(IGC_SWSM) & IGC_SWSM_SWESMBI)
|
||||
break;
|
||||
|
||||
usleep_range(500, 600);
|
||||
}
|
||||
|
||||
if (i == timeout) {
|
||||
/* Release semaphores */
|
||||
igc_put_hw_semaphore(hw);
|
||||
hw_dbg("Driver can't access the NVM\n");
|
||||
return -IGC_ERR_NVM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_acquire_swfw_sync_i225 - Acquire SW/FW semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
* @mask: specifies which semaphore to acquire
|
||||
*
|
||||
* Acquire the SW/FW semaphore to access the PHY or NVM. The mask
|
||||
* will also specify which port we're acquiring the lock for.
|
||||
*/
|
||||
s32 igc_acquire_swfw_sync_i225(struct igc_hw *hw, u16 mask)
|
||||
{
|
||||
s32 i = 0, timeout = 200;
|
||||
u32 fwmask = mask << 16;
|
||||
u32 swmask = mask;
|
||||
s32 ret_val = 0;
|
||||
u32 swfw_sync;
|
||||
|
||||
while (i < timeout) {
|
||||
if (igc_get_hw_semaphore_i225(hw)) {
|
||||
ret_val = -IGC_ERR_SWFW_SYNC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
swfw_sync = rd32(IGC_SW_FW_SYNC);
|
||||
if (!(swfw_sync & (fwmask | swmask)))
|
||||
break;
|
||||
|
||||
/* Firmware currently using resource (fwmask) */
|
||||
igc_put_hw_semaphore(hw);
|
||||
mdelay(5);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == timeout) {
|
||||
hw_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n");
|
||||
ret_val = -IGC_ERR_SWFW_SYNC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
swfw_sync |= swmask;
|
||||
wr32(IGC_SW_FW_SYNC, swfw_sync);
|
||||
|
||||
igc_put_hw_semaphore(hw);
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_release_swfw_sync_i225 - Release SW/FW semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
* @mask: specifies which semaphore to acquire
|
||||
*
|
||||
* Release the SW/FW semaphore used to access the PHY or NVM. The mask
|
||||
* will also specify which port we're releasing the lock for.
|
||||
*/
|
||||
void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask)
|
||||
{
|
||||
u32 swfw_sync;
|
||||
|
||||
/* Releasing the resource requires first getting the HW semaphore.
|
||||
* If we fail to get the semaphore, there is nothing we can do,
|
||||
* except log an error and quit. We are not allowed to hang here
|
||||
* indefinitely, as it may cause denial of service or system crash.
|
||||
*/
|
||||
if (igc_get_hw_semaphore_i225(hw)) {
|
||||
hw_dbg("Failed to release SW_FW_SYNC.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
swfw_sync = rd32(IGC_SW_FW_SYNC);
|
||||
swfw_sync &= ~mask;
|
||||
wr32(IGC_SW_FW_SYNC, swfw_sync);
|
||||
|
||||
igc_put_hw_semaphore(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_nvm_srrd_i225 - Reads Shadow Ram using EERD register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset of word in the Shadow Ram to read
|
||||
* @words: number of words to read
|
||||
* @data: word read from the Shadow Ram
|
||||
*
|
||||
* Reads a 16 bit word from the Shadow Ram using the EERD register.
|
||||
* Uses necessary synchronization semaphores.
|
||||
*/
|
||||
static s32 igc_read_nvm_srrd_i225(struct igc_hw *hw, u16 offset, u16 words,
|
||||
u16 *data)
|
||||
{
|
||||
s32 status = 0;
|
||||
u16 i, count;
|
||||
|
||||
/* We cannot hold synchronization semaphores for too long,
|
||||
* because of forceful takeover procedure. However it is more efficient
|
||||
* to read in bursts than synchronizing access for each word.
|
||||
*/
|
||||
for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) {
|
||||
count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ?
|
||||
IGC_EERD_EEWR_MAX_COUNT : (words - i);
|
||||
|
||||
status = hw->nvm.ops.acquire(hw);
|
||||
if (status)
|
||||
break;
|
||||
|
||||
status = igc_read_nvm_eerd(hw, offset, count, data + i);
|
||||
hw->nvm.ops.release(hw);
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_nvm_srwr - Write to Shadow Ram using EEWR
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset within the Shadow Ram to be written to
|
||||
* @words: number of words to write
|
||||
* @data: 16 bit word(s) to be written to the Shadow Ram
|
||||
*
|
||||
* Writes data to Shadow Ram at offset using EEWR register.
|
||||
*
|
||||
* If igc_update_nvm_checksum is not called after this function , the
|
||||
* Shadow Ram will most likely contain an invalid checksum.
|
||||
*/
|
||||
static s32 igc_write_nvm_srwr(struct igc_hw *hw, u16 offset, u16 words,
|
||||
u16 *data)
|
||||
{
|
||||
struct igc_nvm_info *nvm = &hw->nvm;
|
||||
s32 ret_val = -IGC_ERR_NVM;
|
||||
u32 attempts = 100000;
|
||||
u32 i, k, eewr = 0;
|
||||
|
||||
/* 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) {
|
||||
hw_dbg("nvm parameter(s) out of bounds\n");
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
for (i = 0; i < words; i++) {
|
||||
ret_val = -IGC_ERR_NVM;
|
||||
eewr = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) |
|
||||
(data[i] << IGC_NVM_RW_REG_DATA) |
|
||||
IGC_NVM_RW_REG_START;
|
||||
|
||||
wr32(IGC_SRWR, eewr);
|
||||
|
||||
for (k = 0; k < attempts; k++) {
|
||||
if (IGC_NVM_RW_REG_DONE &
|
||||
rd32(IGC_SRWR)) {
|
||||
ret_val = 0;
|
||||
break;
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
if (ret_val) {
|
||||
hw_dbg("Shadow RAM write EEWR timed out\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_nvm_srwr_i225 - Write to Shadow RAM using EEWR
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset within the Shadow RAM to be written to
|
||||
* @words: number of words to write
|
||||
* @data: 16 bit word(s) to be written to the Shadow RAM
|
||||
*
|
||||
* Writes data to Shadow RAM at offset using EEWR register.
|
||||
*
|
||||
* If igc_update_nvm_checksum is not called after this function , the
|
||||
* data will not be committed to FLASH and also Shadow RAM will most likely
|
||||
* contain an invalid checksum.
|
||||
*
|
||||
* If error code is returned, data and Shadow RAM may be inconsistent - buffer
|
||||
* partially written.
|
||||
*/
|
||||
static s32 igc_write_nvm_srwr_i225(struct igc_hw *hw, u16 offset, u16 words,
|
||||
u16 *data)
|
||||
{
|
||||
s32 status = 0;
|
||||
u16 i, count;
|
||||
|
||||
/* We cannot hold synchronization semaphores for too long,
|
||||
* because of forceful takeover procedure. However it is more efficient
|
||||
* to write in bursts than synchronizing access for each word.
|
||||
*/
|
||||
for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) {
|
||||
count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ?
|
||||
IGC_EERD_EEWR_MAX_COUNT : (words - i);
|
||||
|
||||
status = hw->nvm.ops.acquire(hw);
|
||||
if (status)
|
||||
break;
|
||||
|
||||
status = igc_write_nvm_srwr(hw, offset, count, data + i);
|
||||
hw->nvm.ops.release(hw);
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_validate_nvm_checksum_i225 - 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.
|
||||
*/
|
||||
static s32 igc_validate_nvm_checksum_i225(struct igc_hw *hw)
|
||||
{
|
||||
s32 (*read_op_ptr)(struct igc_hw *hw, u16 offset, u16 count,
|
||||
u16 *data);
|
||||
s32 status = 0;
|
||||
|
||||
status = hw->nvm.ops.acquire(hw);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
/* Replace the read function with semaphore grabbing with
|
||||
* the one that skips this for a while.
|
||||
* We have semaphore taken already here.
|
||||
*/
|
||||
read_op_ptr = hw->nvm.ops.read;
|
||||
hw->nvm.ops.read = igc_read_nvm_eerd;
|
||||
|
||||
status = igc_validate_nvm_checksum(hw);
|
||||
|
||||
/* Revert original read operation. */
|
||||
hw->nvm.ops.read = read_op_ptr;
|
||||
|
||||
hw->nvm.ops.release(hw);
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_pool_flash_update_done_i225 - Pool FLUDONE status
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_pool_flash_update_done_i225(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = -IGC_ERR_NVM;
|
||||
u32 i, reg;
|
||||
|
||||
for (i = 0; i < IGC_FLUDONE_ATTEMPTS; i++) {
|
||||
reg = rd32(IGC_EECD);
|
||||
if (reg & IGC_EECD_FLUDONE_I225) {
|
||||
ret_val = 0;
|
||||
break;
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_update_flash_i225 - Commit EEPROM to the flash
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_update_flash_i225(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
u32 flup;
|
||||
|
||||
ret_val = igc_pool_flash_update_done_i225(hw);
|
||||
if (ret_val == -IGC_ERR_NVM) {
|
||||
hw_dbg("Flash update time out\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
flup = rd32(IGC_EECD) | IGC_EECD_FLUPD_I225;
|
||||
wr32(IGC_EECD, flup);
|
||||
|
||||
ret_val = igc_pool_flash_update_done_i225(hw);
|
||||
if (ret_val)
|
||||
hw_dbg("Flash update time out\n");
|
||||
else
|
||||
hw_dbg("Flash update complete\n");
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_update_nvm_checksum_i225 - 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. Next commit EEPROM data onto the Flash.
|
||||
*/
|
||||
static s32 igc_update_nvm_checksum_i225(struct igc_hw *hw)
|
||||
{
|
||||
u16 checksum = 0;
|
||||
s32 ret_val = 0;
|
||||
u16 i, nvm_data;
|
||||
|
||||
/* Read the first word from the EEPROM. If this times out or fails, do
|
||||
* not continue or we could be in for a very long wait while every
|
||||
* EEPROM read fails
|
||||
*/
|
||||
ret_val = igc_read_nvm_eerd(hw, 0, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("EEPROM read failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_val = hw->nvm.ops.acquire(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* Do not use hw->nvm.ops.write, hw->nvm.ops.read
|
||||
* because we do not want to take the synchronization
|
||||
* semaphores twice here.
|
||||
*/
|
||||
|
||||
for (i = 0; i < NVM_CHECKSUM_REG; i++) {
|
||||
ret_val = igc_read_nvm_eerd(hw, i, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw->nvm.ops.release(hw);
|
||||
hw_dbg("NVM Read Error while updating checksum.\n");
|
||||
goto out;
|
||||
}
|
||||
checksum += nvm_data;
|
||||
}
|
||||
checksum = (u16)NVM_SUM - checksum;
|
||||
ret_val = igc_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1,
|
||||
&checksum);
|
||||
if (ret_val) {
|
||||
hw->nvm.ops.release(hw);
|
||||
hw_dbg("NVM Write Error while updating checksum.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
hw->nvm.ops.release(hw);
|
||||
|
||||
ret_val = igc_update_flash_i225(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_flash_presence_i225 - Check if flash device is detected
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
bool igc_get_flash_presence_i225(struct igc_hw *hw)
|
||||
{
|
||||
bool ret_val = false;
|
||||
u32 eec = 0;
|
||||
|
||||
eec = rd32(IGC_EECD);
|
||||
if (eec & IGC_EECD_FLASH_DETECTED_I225)
|
||||
ret_val = true;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_nvm_params_i225 - Init NVM func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
s32 igc_init_nvm_params_i225(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_nvm_info *nvm = &hw->nvm;
|
||||
|
||||
nvm->ops.acquire = igc_acquire_nvm_i225;
|
||||
nvm->ops.release = igc_release_nvm_i225;
|
||||
|
||||
/* NVM Function Pointers */
|
||||
if (igc_get_flash_presence_i225(hw)) {
|
||||
nvm->ops.read = igc_read_nvm_srrd_i225;
|
||||
nvm->ops.write = igc_write_nvm_srwr_i225;
|
||||
nvm->ops.validate = igc_validate_nvm_checksum_i225;
|
||||
nvm->ops.update = igc_update_nvm_checksum_i225;
|
||||
} else {
|
||||
nvm->ops.read = igc_read_nvm_eerd;
|
||||
nvm->ops.write = NULL;
|
||||
nvm->ops.validate = NULL;
|
||||
nvm->ops.update = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_set_eee_i225 - Enable/disable EEE support
|
||||
* @hw: pointer to the HW structure
|
||||
* @adv2p5G: boolean flag enabling 2.5G EEE advertisement
|
||||
* @adv1G: boolean flag enabling 1G EEE advertisement
|
||||
* @adv100M: boolean flag enabling 100M EEE advertisement
|
||||
*
|
||||
* Enable/disable EEE based on setting in dev_spec structure.
|
||||
**/
|
||||
s32 igc_set_eee_i225(struct igc_hw *hw, bool adv2p5G, bool adv1G,
|
||||
bool adv100M)
|
||||
{
|
||||
u32 ipcnfg, eeer;
|
||||
|
||||
ipcnfg = rd32(IGC_IPCNFG);
|
||||
eeer = rd32(IGC_EEER);
|
||||
|
||||
/* enable or disable per user setting */
|
||||
if (hw->dev_spec._base.eee_enable) {
|
||||
u32 eee_su = rd32(IGC_EEE_SU);
|
||||
|
||||
if (adv100M)
|
||||
ipcnfg |= IGC_IPCNFG_EEE_100M_AN;
|
||||
else
|
||||
ipcnfg &= ~IGC_IPCNFG_EEE_100M_AN;
|
||||
|
||||
if (adv1G)
|
||||
ipcnfg |= IGC_IPCNFG_EEE_1G_AN;
|
||||
else
|
||||
ipcnfg &= ~IGC_IPCNFG_EEE_1G_AN;
|
||||
|
||||
if (adv2p5G)
|
||||
ipcnfg |= IGC_IPCNFG_EEE_2_5G_AN;
|
||||
else
|
||||
ipcnfg &= ~IGC_IPCNFG_EEE_2_5G_AN;
|
||||
|
||||
eeer |= (IGC_EEER_TX_LPI_EN | IGC_EEER_RX_LPI_EN |
|
||||
IGC_EEER_LPI_FC);
|
||||
|
||||
/* This bit should not be set in normal operation. */
|
||||
if (eee_su & IGC_EEE_SU_LPI_CLK_STP)
|
||||
hw_dbg("LPI Clock Stop Bit should not be set!\n");
|
||||
} else {
|
||||
ipcnfg &= ~(IGC_IPCNFG_EEE_2_5G_AN | IGC_IPCNFG_EEE_1G_AN |
|
||||
IGC_IPCNFG_EEE_100M_AN);
|
||||
eeer &= ~(IGC_EEER_TX_LPI_EN | IGC_EEER_RX_LPI_EN |
|
||||
IGC_EEER_LPI_FC);
|
||||
}
|
||||
wr32(IGC_IPCNFG, ipcnfg);
|
||||
wr32(IGC_EEER, eeer);
|
||||
rd32(IGC_IPCNFG);
|
||||
rd32(IGC_EEER);
|
||||
|
||||
return IGC_SUCCESS;
|
||||
}
|
||||
|
||||
/* igc_set_ltr_i225 - Set Latency Tolerance Reporting thresholds
|
||||
* @hw: pointer to the HW structure
|
||||
* @link: bool indicating link status
|
||||
*
|
||||
* Set the LTR thresholds based on the link speed (Mbps), EEE, and DMAC
|
||||
* settings, otherwise specify that there is no LTR requirement.
|
||||
*/
|
||||
s32 igc_set_ltr_i225(struct igc_hw *hw, bool link)
|
||||
{
|
||||
u32 tw_system, ltrc, ltrv, ltr_min, ltr_max, scale_min, scale_max;
|
||||
u16 speed, duplex;
|
||||
s32 size;
|
||||
|
||||
/* If we do not have link, LTR thresholds are zero. */
|
||||
if (link) {
|
||||
hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
|
||||
|
||||
/* Check if using copper interface with EEE enabled or if the
|
||||
* link speed is 10 Mbps.
|
||||
*/
|
||||
if (hw->dev_spec._base.eee_enable &&
|
||||
speed != SPEED_10) {
|
||||
/* EEE enabled, so send LTRMAX threshold. */
|
||||
ltrc = rd32(IGC_LTRC) |
|
||||
IGC_LTRC_EEEMS_EN;
|
||||
wr32(IGC_LTRC, ltrc);
|
||||
|
||||
/* Calculate tw_system (nsec). */
|
||||
if (speed == SPEED_100) {
|
||||
tw_system = ((rd32(IGC_EEE_SU) &
|
||||
IGC_TW_SYSTEM_100_MASK) >>
|
||||
IGC_TW_SYSTEM_100_SHIFT) * 500;
|
||||
} else {
|
||||
tw_system = (rd32(IGC_EEE_SU) &
|
||||
IGC_TW_SYSTEM_1000_MASK) * 500;
|
||||
}
|
||||
} else {
|
||||
tw_system = 0;
|
||||
}
|
||||
|
||||
/* Get the Rx packet buffer size. */
|
||||
size = rd32(IGC_RXPBS) &
|
||||
IGC_RXPBS_SIZE_I225_MASK;
|
||||
|
||||
/* Convert size to bytes, subtract the MTU, and then
|
||||
* convert the size to bits.
|
||||
*/
|
||||
size *= 1024;
|
||||
size *= 8;
|
||||
|
||||
if (size < 0) {
|
||||
hw_dbg("Invalid effective Rx buffer size %d\n",
|
||||
size);
|
||||
return -IGC_ERR_CONFIG;
|
||||
}
|
||||
|
||||
/* Calculate the thresholds. Since speed is in Mbps, simplify
|
||||
* the calculation by multiplying size/speed by 1000 for result
|
||||
* to be in nsec before dividing by the scale in nsec. Set the
|
||||
* scale such that the LTR threshold fits in the register.
|
||||
*/
|
||||
ltr_min = (1000 * size) / speed;
|
||||
ltr_max = ltr_min + tw_system;
|
||||
scale_min = (ltr_min / 1024) < 1024 ? IGC_LTRMINV_SCALE_1024 :
|
||||
IGC_LTRMINV_SCALE_32768;
|
||||
scale_max = (ltr_max / 1024) < 1024 ? IGC_LTRMAXV_SCALE_1024 :
|
||||
IGC_LTRMAXV_SCALE_32768;
|
||||
ltr_min /= scale_min == IGC_LTRMINV_SCALE_1024 ? 1024 : 32768;
|
||||
ltr_min -= 1;
|
||||
ltr_max /= scale_max == IGC_LTRMAXV_SCALE_1024 ? 1024 : 32768;
|
||||
ltr_max -= 1;
|
||||
|
||||
/* Only write the LTR thresholds if they differ from before. */
|
||||
ltrv = rd32(IGC_LTRMINV);
|
||||
if (ltr_min != (ltrv & IGC_LTRMINV_LTRV_MASK)) {
|
||||
ltrv = IGC_LTRMINV_LSNP_REQ | ltr_min |
|
||||
(scale_min << IGC_LTRMINV_SCALE_SHIFT);
|
||||
wr32(IGC_LTRMINV, ltrv);
|
||||
}
|
||||
|
||||
ltrv = rd32(IGC_LTRMAXV);
|
||||
if (ltr_max != (ltrv & IGC_LTRMAXV_LTRV_MASK)) {
|
||||
ltrv = IGC_LTRMAXV_LSNP_REQ | ltr_max |
|
||||
(scale_max << IGC_LTRMAXV_SCALE_SHIFT);
|
||||
wr32(IGC_LTRMAXV, ltrv);
|
||||
}
|
||||
}
|
||||
|
||||
return IGC_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_I225_H_
|
||||
#define _IGC_I225_H_
|
||||
|
||||
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_nvm_params_i225(struct igc_hw *hw);
|
||||
bool igc_get_flash_presence_i225(struct igc_hw *hw);
|
||||
s32 igc_set_eee_i225(struct igc_hw *hw, bool adv2p5G, bool adv1G,
|
||||
bool adv100M);
|
||||
s32 igc_set_ltr_i225(struct igc_hw *hw, bool link);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,641 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "igc_hw.h"
|
||||
|
||||
/**
|
||||
* igc_acquire_nvm_i225 - Acquire exclusive access to EEPROM
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Acquire the necessary semaphores for exclusive access to the EEPROM.
|
||||
* 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).
|
||||
*/
|
||||
static s32 igc_acquire_nvm_i225(struct igc_hw *hw)
|
||||
{
|
||||
return igc_acquire_swfw_sync_i225(hw, IGC_SWFW_EEP_SM);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_release_nvm_i225 - Release exclusive access to EEPROM
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Stop any current commands to the EEPROM and clear the EEPROM request bit,
|
||||
* then release the semaphores acquired.
|
||||
*/
|
||||
static void igc_release_nvm_i225(struct igc_hw *hw)
|
||||
{
|
||||
igc_release_swfw_sync_i225(hw, IGC_SWFW_EEP_SM);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_hw_semaphore_i225 - Acquire hardware semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Acquire the HW semaphore to access the PHY or NVM
|
||||
*/
|
||||
static s32 igc_get_hw_semaphore_i225(struct igc_hw *hw)
|
||||
{
|
||||
s32 timeout = hw->nvm.word_size + 1;
|
||||
s32 i = 0;
|
||||
u32 swsm;
|
||||
|
||||
/* Get the SW semaphore */
|
||||
while (i < timeout) {
|
||||
swsm = rd32(IGC_SWSM);
|
||||
if (!(swsm & IGC_SWSM_SMBI))
|
||||
break;
|
||||
|
||||
usleep_range(500, 600);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == timeout) {
|
||||
/* In rare circumstances, the SW semaphore may already be held
|
||||
* unintentionally. Clear the semaphore once before giving up.
|
||||
*/
|
||||
if (hw->dev_spec._base.clear_semaphore_once) {
|
||||
hw->dev_spec._base.clear_semaphore_once = false;
|
||||
igc_put_hw_semaphore(hw);
|
||||
for (i = 0; i < timeout; i++) {
|
||||
swsm = rd32(IGC_SWSM);
|
||||
if (!(swsm & IGC_SWSM_SMBI))
|
||||
break;
|
||||
|
||||
usleep_range(500, 600);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we do not have the semaphore here, we have to give up. */
|
||||
if (i == timeout) {
|
||||
hw_dbg("Driver can't access device - SMBI bit is set.\n");
|
||||
return -IGC_ERR_NVM;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the FW semaphore. */
|
||||
for (i = 0; i < timeout; i++) {
|
||||
swsm = rd32(IGC_SWSM);
|
||||
wr32(IGC_SWSM, swsm | IGC_SWSM_SWESMBI);
|
||||
|
||||
/* Semaphore acquired if bit latched */
|
||||
if (rd32(IGC_SWSM) & IGC_SWSM_SWESMBI)
|
||||
break;
|
||||
|
||||
usleep_range(500, 600);
|
||||
}
|
||||
|
||||
if (i == timeout) {
|
||||
/* Release semaphores */
|
||||
igc_put_hw_semaphore(hw);
|
||||
hw_dbg("Driver can't access the NVM\n");
|
||||
return -IGC_ERR_NVM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_acquire_swfw_sync_i225 - Acquire SW/FW semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
* @mask: specifies which semaphore to acquire
|
||||
*
|
||||
* Acquire the SW/FW semaphore to access the PHY or NVM. The mask
|
||||
* will also specify which port we're acquiring the lock for.
|
||||
*/
|
||||
s32 igc_acquire_swfw_sync_i225(struct igc_hw *hw, u16 mask)
|
||||
{
|
||||
s32 i = 0, timeout = 200;
|
||||
u32 fwmask = mask << 16;
|
||||
u32 swmask = mask;
|
||||
s32 ret_val = 0;
|
||||
u32 swfw_sync;
|
||||
|
||||
while (i < timeout) {
|
||||
if (igc_get_hw_semaphore_i225(hw)) {
|
||||
ret_val = -IGC_ERR_SWFW_SYNC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
swfw_sync = rd32(IGC_SW_FW_SYNC);
|
||||
if (!(swfw_sync & (fwmask | swmask)))
|
||||
break;
|
||||
|
||||
/* Firmware currently using resource (fwmask) */
|
||||
igc_put_hw_semaphore(hw);
|
||||
mdelay(5);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == timeout) {
|
||||
hw_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n");
|
||||
ret_val = -IGC_ERR_SWFW_SYNC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
swfw_sync |= swmask;
|
||||
wr32(IGC_SW_FW_SYNC, swfw_sync);
|
||||
|
||||
igc_put_hw_semaphore(hw);
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_release_swfw_sync_i225 - Release SW/FW semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
* @mask: specifies which semaphore to acquire
|
||||
*
|
||||
* Release the SW/FW semaphore used to access the PHY or NVM. The mask
|
||||
* will also specify which port we're releasing the lock for.
|
||||
*/
|
||||
void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask)
|
||||
{
|
||||
u32 swfw_sync;
|
||||
|
||||
/* Releasing the resource requires first getting the HW semaphore.
|
||||
* If we fail to get the semaphore, there is nothing we can do,
|
||||
* except log an error and quit. We are not allowed to hang here
|
||||
* indefinitely, as it may cause denial of service or system crash.
|
||||
*/
|
||||
if (igc_get_hw_semaphore_i225(hw)) {
|
||||
hw_dbg("Failed to release SW_FW_SYNC.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
swfw_sync = rd32(IGC_SW_FW_SYNC);
|
||||
swfw_sync &= ~mask;
|
||||
wr32(IGC_SW_FW_SYNC, swfw_sync);
|
||||
|
||||
igc_put_hw_semaphore(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_nvm_srrd_i225 - Reads Shadow Ram using EERD register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset of word in the Shadow Ram to read
|
||||
* @words: number of words to read
|
||||
* @data: word read from the Shadow Ram
|
||||
*
|
||||
* Reads a 16 bit word from the Shadow Ram using the EERD register.
|
||||
* Uses necessary synchronization semaphores.
|
||||
*/
|
||||
static s32 igc_read_nvm_srrd_i225(struct igc_hw *hw, u16 offset, u16 words,
|
||||
u16 *data)
|
||||
{
|
||||
s32 status = 0;
|
||||
u16 i, count;
|
||||
|
||||
/* We cannot hold synchronization semaphores for too long,
|
||||
* because of forceful takeover procedure. However it is more efficient
|
||||
* to read in bursts than synchronizing access for each word.
|
||||
*/
|
||||
for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) {
|
||||
count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ?
|
||||
IGC_EERD_EEWR_MAX_COUNT : (words - i);
|
||||
|
||||
status = hw->nvm.ops.acquire(hw);
|
||||
if (status)
|
||||
break;
|
||||
|
||||
status = igc_read_nvm_eerd(hw, offset, count, data + i);
|
||||
hw->nvm.ops.release(hw);
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_nvm_srwr - Write to Shadow Ram using EEWR
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset within the Shadow Ram to be written to
|
||||
* @words: number of words to write
|
||||
* @data: 16 bit word(s) to be written to the Shadow Ram
|
||||
*
|
||||
* Writes data to Shadow Ram at offset using EEWR register.
|
||||
*
|
||||
* If igc_update_nvm_checksum is not called after this function , the
|
||||
* Shadow Ram will most likely contain an invalid checksum.
|
||||
*/
|
||||
static s32 igc_write_nvm_srwr(struct igc_hw *hw, u16 offset, u16 words,
|
||||
u16 *data)
|
||||
{
|
||||
struct igc_nvm_info *nvm = &hw->nvm;
|
||||
s32 ret_val = -IGC_ERR_NVM;
|
||||
u32 attempts = 100000;
|
||||
u32 i, k, eewr = 0;
|
||||
|
||||
/* 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) {
|
||||
hw_dbg("nvm parameter(s) out of bounds\n");
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
for (i = 0; i < words; i++) {
|
||||
ret_val = -IGC_ERR_NVM;
|
||||
eewr = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) |
|
||||
(data[i] << IGC_NVM_RW_REG_DATA) |
|
||||
IGC_NVM_RW_REG_START;
|
||||
|
||||
wr32(IGC_SRWR, eewr);
|
||||
|
||||
for (k = 0; k < attempts; k++) {
|
||||
if (IGC_NVM_RW_REG_DONE &
|
||||
rd32(IGC_SRWR)) {
|
||||
ret_val = 0;
|
||||
break;
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
if (ret_val) {
|
||||
hw_dbg("Shadow RAM write EEWR timed out\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_nvm_srwr_i225 - Write to Shadow RAM using EEWR
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset within the Shadow RAM to be written to
|
||||
* @words: number of words to write
|
||||
* @data: 16 bit word(s) to be written to the Shadow RAM
|
||||
*
|
||||
* Writes data to Shadow RAM at offset using EEWR register.
|
||||
*
|
||||
* If igc_update_nvm_checksum is not called after this function , the
|
||||
* data will not be committed to FLASH and also Shadow RAM will most likely
|
||||
* contain an invalid checksum.
|
||||
*
|
||||
* If error code is returned, data and Shadow RAM may be inconsistent - buffer
|
||||
* partially written.
|
||||
*/
|
||||
static s32 igc_write_nvm_srwr_i225(struct igc_hw *hw, u16 offset, u16 words,
|
||||
u16 *data)
|
||||
{
|
||||
s32 status = 0;
|
||||
u16 i, count;
|
||||
|
||||
/* We cannot hold synchronization semaphores for too long,
|
||||
* because of forceful takeover procedure. However it is more efficient
|
||||
* to write in bursts than synchronizing access for each word.
|
||||
*/
|
||||
for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) {
|
||||
count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ?
|
||||
IGC_EERD_EEWR_MAX_COUNT : (words - i);
|
||||
|
||||
status = hw->nvm.ops.acquire(hw);
|
||||
if (status)
|
||||
break;
|
||||
|
||||
status = igc_write_nvm_srwr(hw, offset, count, data + i);
|
||||
hw->nvm.ops.release(hw);
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_validate_nvm_checksum_i225 - 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.
|
||||
*/
|
||||
static s32 igc_validate_nvm_checksum_i225(struct igc_hw *hw)
|
||||
{
|
||||
s32 (*read_op_ptr)(struct igc_hw *hw, u16 offset, u16 count,
|
||||
u16 *data);
|
||||
s32 status = 0;
|
||||
|
||||
status = hw->nvm.ops.acquire(hw);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
/* Replace the read function with semaphore grabbing with
|
||||
* the one that skips this for a while.
|
||||
* We have semaphore taken already here.
|
||||
*/
|
||||
read_op_ptr = hw->nvm.ops.read;
|
||||
hw->nvm.ops.read = igc_read_nvm_eerd;
|
||||
|
||||
status = igc_validate_nvm_checksum(hw);
|
||||
|
||||
/* Revert original read operation. */
|
||||
hw->nvm.ops.read = read_op_ptr;
|
||||
|
||||
hw->nvm.ops.release(hw);
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_pool_flash_update_done_i225 - Pool FLUDONE status
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_pool_flash_update_done_i225(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = -IGC_ERR_NVM;
|
||||
u32 i, reg;
|
||||
|
||||
for (i = 0; i < IGC_FLUDONE_ATTEMPTS; i++) {
|
||||
reg = rd32(IGC_EECD);
|
||||
if (reg & IGC_EECD_FLUDONE_I225) {
|
||||
ret_val = 0;
|
||||
break;
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_update_flash_i225 - Commit EEPROM to the flash
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_update_flash_i225(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
u32 flup;
|
||||
|
||||
ret_val = igc_pool_flash_update_done_i225(hw);
|
||||
if (ret_val == -IGC_ERR_NVM) {
|
||||
hw_dbg("Flash update time out\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
flup = rd32(IGC_EECD) | IGC_EECD_FLUPD_I225;
|
||||
wr32(IGC_EECD, flup);
|
||||
|
||||
ret_val = igc_pool_flash_update_done_i225(hw);
|
||||
if (ret_val)
|
||||
hw_dbg("Flash update time out\n");
|
||||
else
|
||||
hw_dbg("Flash update complete\n");
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_update_nvm_checksum_i225 - 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. Next commit EEPROM data onto the Flash.
|
||||
*/
|
||||
static s32 igc_update_nvm_checksum_i225(struct igc_hw *hw)
|
||||
{
|
||||
u16 checksum = 0;
|
||||
s32 ret_val = 0;
|
||||
u16 i, nvm_data;
|
||||
|
||||
/* Read the first word from the EEPROM. If this times out or fails, do
|
||||
* not continue or we could be in for a very long wait while every
|
||||
* EEPROM read fails
|
||||
*/
|
||||
ret_val = igc_read_nvm_eerd(hw, 0, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("EEPROM read failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_val = hw->nvm.ops.acquire(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* Do not use hw->nvm.ops.write, hw->nvm.ops.read
|
||||
* because we do not want to take the synchronization
|
||||
* semaphores twice here.
|
||||
*/
|
||||
|
||||
for (i = 0; i < NVM_CHECKSUM_REG; i++) {
|
||||
ret_val = igc_read_nvm_eerd(hw, i, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw->nvm.ops.release(hw);
|
||||
hw_dbg("NVM Read Error while updating checksum.\n");
|
||||
goto out;
|
||||
}
|
||||
checksum += nvm_data;
|
||||
}
|
||||
checksum = (u16)NVM_SUM - checksum;
|
||||
ret_val = igc_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1,
|
||||
&checksum);
|
||||
if (ret_val) {
|
||||
hw->nvm.ops.release(hw);
|
||||
hw_dbg("NVM Write Error while updating checksum.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
hw->nvm.ops.release(hw);
|
||||
|
||||
ret_val = igc_update_flash_i225(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_flash_presence_i225 - Check if flash device is detected
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
bool igc_get_flash_presence_i225(struct igc_hw *hw)
|
||||
{
|
||||
bool ret_val = false;
|
||||
u32 eec = 0;
|
||||
|
||||
eec = rd32(IGC_EECD);
|
||||
if (eec & IGC_EECD_FLASH_DETECTED_I225)
|
||||
ret_val = true;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_nvm_params_i225 - Init NVM func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
s32 igc_init_nvm_params_i225(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_nvm_info *nvm = &hw->nvm;
|
||||
|
||||
nvm->ops.acquire = igc_acquire_nvm_i225;
|
||||
nvm->ops.release = igc_release_nvm_i225;
|
||||
|
||||
/* NVM Function Pointers */
|
||||
if (igc_get_flash_presence_i225(hw)) {
|
||||
nvm->ops.read = igc_read_nvm_srrd_i225;
|
||||
nvm->ops.write = igc_write_nvm_srwr_i225;
|
||||
nvm->ops.validate = igc_validate_nvm_checksum_i225;
|
||||
nvm->ops.update = igc_update_nvm_checksum_i225;
|
||||
} else {
|
||||
nvm->ops.read = igc_read_nvm_eerd;
|
||||
nvm->ops.write = NULL;
|
||||
nvm->ops.validate = NULL;
|
||||
nvm->ops.update = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_set_eee_i225 - Enable/disable EEE support
|
||||
* @hw: pointer to the HW structure
|
||||
* @adv2p5G: boolean flag enabling 2.5G EEE advertisement
|
||||
* @adv1G: boolean flag enabling 1G EEE advertisement
|
||||
* @adv100M: boolean flag enabling 100M EEE advertisement
|
||||
*
|
||||
* Enable/disable EEE based on setting in dev_spec structure.
|
||||
**/
|
||||
s32 igc_set_eee_i225(struct igc_hw *hw, bool adv2p5G, bool adv1G,
|
||||
bool adv100M)
|
||||
{
|
||||
u32 ipcnfg, eeer;
|
||||
|
||||
ipcnfg = rd32(IGC_IPCNFG);
|
||||
eeer = rd32(IGC_EEER);
|
||||
|
||||
/* enable or disable per user setting */
|
||||
if (hw->dev_spec._base.eee_enable) {
|
||||
u32 eee_su = rd32(IGC_EEE_SU);
|
||||
|
||||
if (adv100M)
|
||||
ipcnfg |= IGC_IPCNFG_EEE_100M_AN;
|
||||
else
|
||||
ipcnfg &= ~IGC_IPCNFG_EEE_100M_AN;
|
||||
|
||||
if (adv1G)
|
||||
ipcnfg |= IGC_IPCNFG_EEE_1G_AN;
|
||||
else
|
||||
ipcnfg &= ~IGC_IPCNFG_EEE_1G_AN;
|
||||
|
||||
if (adv2p5G)
|
||||
ipcnfg |= IGC_IPCNFG_EEE_2_5G_AN;
|
||||
else
|
||||
ipcnfg &= ~IGC_IPCNFG_EEE_2_5G_AN;
|
||||
|
||||
eeer |= (IGC_EEER_TX_LPI_EN | IGC_EEER_RX_LPI_EN |
|
||||
IGC_EEER_LPI_FC);
|
||||
|
||||
/* This bit should not be set in normal operation. */
|
||||
if (eee_su & IGC_EEE_SU_LPI_CLK_STP)
|
||||
hw_dbg("LPI Clock Stop Bit should not be set!\n");
|
||||
} else {
|
||||
ipcnfg &= ~(IGC_IPCNFG_EEE_2_5G_AN | IGC_IPCNFG_EEE_1G_AN |
|
||||
IGC_IPCNFG_EEE_100M_AN);
|
||||
eeer &= ~(IGC_EEER_TX_LPI_EN | IGC_EEER_RX_LPI_EN |
|
||||
IGC_EEER_LPI_FC);
|
||||
}
|
||||
wr32(IGC_IPCNFG, ipcnfg);
|
||||
wr32(IGC_EEER, eeer);
|
||||
rd32(IGC_IPCNFG);
|
||||
rd32(IGC_EEER);
|
||||
|
||||
return IGC_SUCCESS;
|
||||
}
|
||||
|
||||
/* igc_set_ltr_i225 - Set Latency Tolerance Reporting thresholds
|
||||
* @hw: pointer to the HW structure
|
||||
* @link: bool indicating link status
|
||||
*
|
||||
* Set the LTR thresholds based on the link speed (Mbps), EEE, and DMAC
|
||||
* settings, otherwise specify that there is no LTR requirement.
|
||||
*/
|
||||
s32 igc_set_ltr_i225(struct igc_hw *hw, bool link)
|
||||
{
|
||||
u32 tw_system, ltrc, ltrv, ltr_min, ltr_max, scale_min, scale_max;
|
||||
u16 speed, duplex;
|
||||
s32 size;
|
||||
|
||||
/* If we do not have link, LTR thresholds are zero. */
|
||||
if (link) {
|
||||
hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
|
||||
|
||||
/* Check if using copper interface with EEE enabled or if the
|
||||
* link speed is 10 Mbps.
|
||||
*/
|
||||
if (hw->dev_spec._base.eee_enable &&
|
||||
speed != SPEED_10) {
|
||||
/* EEE enabled, so send LTRMAX threshold. */
|
||||
ltrc = rd32(IGC_LTRC) |
|
||||
IGC_LTRC_EEEMS_EN;
|
||||
wr32(IGC_LTRC, ltrc);
|
||||
|
||||
/* Calculate tw_system (nsec). */
|
||||
if (speed == SPEED_100) {
|
||||
tw_system = ((rd32(IGC_EEE_SU) &
|
||||
IGC_TW_SYSTEM_100_MASK) >>
|
||||
IGC_TW_SYSTEM_100_SHIFT) * 500;
|
||||
} else {
|
||||
tw_system = (rd32(IGC_EEE_SU) &
|
||||
IGC_TW_SYSTEM_1000_MASK) * 500;
|
||||
}
|
||||
} else {
|
||||
tw_system = 0;
|
||||
}
|
||||
|
||||
/* Get the Rx packet buffer size. */
|
||||
size = rd32(IGC_RXPBS) &
|
||||
IGC_RXPBS_SIZE_I225_MASK;
|
||||
|
||||
/* Convert size to bytes, subtract the MTU, and then
|
||||
* convert the size to bits.
|
||||
*/
|
||||
size *= 1024;
|
||||
size *= 8;
|
||||
|
||||
if (size < 0) {
|
||||
hw_dbg("Invalid effective Rx buffer size %d\n",
|
||||
size);
|
||||
return -IGC_ERR_CONFIG;
|
||||
}
|
||||
|
||||
/* Calculate the thresholds. Since speed is in Mbps, simplify
|
||||
* the calculation by multiplying size/speed by 1000 for result
|
||||
* to be in nsec before dividing by the scale in nsec. Set the
|
||||
* scale such that the LTR threshold fits in the register.
|
||||
*/
|
||||
ltr_min = (1000 * size) / speed;
|
||||
ltr_max = ltr_min + tw_system;
|
||||
scale_min = (ltr_min / 1024) < 1024 ? IGC_LTRMINV_SCALE_1024 :
|
||||
IGC_LTRMINV_SCALE_32768;
|
||||
scale_max = (ltr_max / 1024) < 1024 ? IGC_LTRMAXV_SCALE_1024 :
|
||||
IGC_LTRMAXV_SCALE_32768;
|
||||
ltr_min /= scale_min == IGC_LTRMINV_SCALE_1024 ? 1024 : 32768;
|
||||
ltr_min -= 1;
|
||||
ltr_max /= scale_max == IGC_LTRMAXV_SCALE_1024 ? 1024 : 32768;
|
||||
ltr_max -= 1;
|
||||
|
||||
/* Only write the LTR thresholds if they differ from before. */
|
||||
ltrv = rd32(IGC_LTRMINV);
|
||||
if (ltr_min != (ltrv & IGC_LTRMINV_LTRV_MASK)) {
|
||||
ltrv = IGC_LTRMINV_LSNP_REQ | ltr_min |
|
||||
(scale_min << IGC_LTRMINV_SCALE_SHIFT);
|
||||
wr32(IGC_LTRMINV, ltrv);
|
||||
}
|
||||
|
||||
ltrv = rd32(IGC_LTRMAXV);
|
||||
if (ltr_max != (ltrv & IGC_LTRMAXV_LTRV_MASK)) {
|
||||
ltrv = IGC_LTRMAXV_LSNP_REQ | ltr_max |
|
||||
(scale_max << IGC_LTRMAXV_SCALE_SHIFT);
|
||||
wr32(IGC_LTRMAXV, ltrv);
|
||||
}
|
||||
}
|
||||
|
||||
return IGC_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_I225_H_
|
||||
#define _IGC_I225_H_
|
||||
|
||||
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_nvm_params_i225(struct igc_hw *hw);
|
||||
bool igc_get_flash_presence_i225(struct igc_hw *hw);
|
||||
s32 igc_set_eee_i225(struct igc_hw *hw, bool adv2p5G, bool adv1G,
|
||||
bool adv100M);
|
||||
s32 igc_set_ltr_i225(struct igc_hw *hw, bool link);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,641 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "igc_hw-6.6-ethercat.h"
|
||||
|
||||
/**
|
||||
* igc_acquire_nvm_i225 - Acquire exclusive access to EEPROM
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Acquire the necessary semaphores for exclusive access to the EEPROM.
|
||||
* 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).
|
||||
*/
|
||||
static s32 igc_acquire_nvm_i225(struct igc_hw *hw)
|
||||
{
|
||||
return igc_acquire_swfw_sync_i225(hw, IGC_SWFW_EEP_SM);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_release_nvm_i225 - Release exclusive access to EEPROM
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Stop any current commands to the EEPROM and clear the EEPROM request bit,
|
||||
* then release the semaphores acquired.
|
||||
*/
|
||||
static void igc_release_nvm_i225(struct igc_hw *hw)
|
||||
{
|
||||
igc_release_swfw_sync_i225(hw, IGC_SWFW_EEP_SM);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_hw_semaphore_i225 - Acquire hardware semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Acquire the HW semaphore to access the PHY or NVM
|
||||
*/
|
||||
static s32 igc_get_hw_semaphore_i225(struct igc_hw *hw)
|
||||
{
|
||||
s32 timeout = hw->nvm.word_size + 1;
|
||||
s32 i = 0;
|
||||
u32 swsm;
|
||||
|
||||
/* Get the SW semaphore */
|
||||
while (i < timeout) {
|
||||
swsm = rd32(IGC_SWSM);
|
||||
if (!(swsm & IGC_SWSM_SMBI))
|
||||
break;
|
||||
|
||||
usleep_range(500, 600);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == timeout) {
|
||||
/* In rare circumstances, the SW semaphore may already be held
|
||||
* unintentionally. Clear the semaphore once before giving up.
|
||||
*/
|
||||
if (hw->dev_spec._base.clear_semaphore_once) {
|
||||
hw->dev_spec._base.clear_semaphore_once = false;
|
||||
igc_put_hw_semaphore(hw);
|
||||
for (i = 0; i < timeout; i++) {
|
||||
swsm = rd32(IGC_SWSM);
|
||||
if (!(swsm & IGC_SWSM_SMBI))
|
||||
break;
|
||||
|
||||
usleep_range(500, 600);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we do not have the semaphore here, we have to give up. */
|
||||
if (i == timeout) {
|
||||
hw_dbg("Driver can't access device - SMBI bit is set.\n");
|
||||
return -IGC_ERR_NVM;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the FW semaphore. */
|
||||
for (i = 0; i < timeout; i++) {
|
||||
swsm = rd32(IGC_SWSM);
|
||||
wr32(IGC_SWSM, swsm | IGC_SWSM_SWESMBI);
|
||||
|
||||
/* Semaphore acquired if bit latched */
|
||||
if (rd32(IGC_SWSM) & IGC_SWSM_SWESMBI)
|
||||
break;
|
||||
|
||||
usleep_range(500, 600);
|
||||
}
|
||||
|
||||
if (i == timeout) {
|
||||
/* Release semaphores */
|
||||
igc_put_hw_semaphore(hw);
|
||||
hw_dbg("Driver can't access the NVM\n");
|
||||
return -IGC_ERR_NVM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_acquire_swfw_sync_i225 - Acquire SW/FW semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
* @mask: specifies which semaphore to acquire
|
||||
*
|
||||
* Acquire the SW/FW semaphore to access the PHY or NVM. The mask
|
||||
* will also specify which port we're acquiring the lock for.
|
||||
*/
|
||||
s32 igc_acquire_swfw_sync_i225(struct igc_hw *hw, u16 mask)
|
||||
{
|
||||
s32 i = 0, timeout = 200;
|
||||
u32 fwmask = mask << 16;
|
||||
u32 swmask = mask;
|
||||
s32 ret_val = 0;
|
||||
u32 swfw_sync;
|
||||
|
||||
while (i < timeout) {
|
||||
if (igc_get_hw_semaphore_i225(hw)) {
|
||||
ret_val = -IGC_ERR_SWFW_SYNC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
swfw_sync = rd32(IGC_SW_FW_SYNC);
|
||||
if (!(swfw_sync & (fwmask | swmask)))
|
||||
break;
|
||||
|
||||
/* Firmware currently using resource (fwmask) */
|
||||
igc_put_hw_semaphore(hw);
|
||||
mdelay(5);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == timeout) {
|
||||
hw_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n");
|
||||
ret_val = -IGC_ERR_SWFW_SYNC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
swfw_sync |= swmask;
|
||||
wr32(IGC_SW_FW_SYNC, swfw_sync);
|
||||
|
||||
igc_put_hw_semaphore(hw);
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_release_swfw_sync_i225 - Release SW/FW semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
* @mask: specifies which semaphore to acquire
|
||||
*
|
||||
* Release the SW/FW semaphore used to access the PHY or NVM. The mask
|
||||
* will also specify which port we're releasing the lock for.
|
||||
*/
|
||||
void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask)
|
||||
{
|
||||
u32 swfw_sync;
|
||||
|
||||
/* Releasing the resource requires first getting the HW semaphore.
|
||||
* If we fail to get the semaphore, there is nothing we can do,
|
||||
* except log an error and quit. We are not allowed to hang here
|
||||
* indefinitely, as it may cause denial of service or system crash.
|
||||
*/
|
||||
if (igc_get_hw_semaphore_i225(hw)) {
|
||||
hw_dbg("Failed to release SW_FW_SYNC.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
swfw_sync = rd32(IGC_SW_FW_SYNC);
|
||||
swfw_sync &= ~mask;
|
||||
wr32(IGC_SW_FW_SYNC, swfw_sync);
|
||||
|
||||
igc_put_hw_semaphore(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_nvm_srrd_i225 - Reads Shadow Ram using EERD register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset of word in the Shadow Ram to read
|
||||
* @words: number of words to read
|
||||
* @data: word read from the Shadow Ram
|
||||
*
|
||||
* Reads a 16 bit word from the Shadow Ram using the EERD register.
|
||||
* Uses necessary synchronization semaphores.
|
||||
*/
|
||||
static s32 igc_read_nvm_srrd_i225(struct igc_hw *hw, u16 offset, u16 words,
|
||||
u16 *data)
|
||||
{
|
||||
s32 status = 0;
|
||||
u16 i, count;
|
||||
|
||||
/* We cannot hold synchronization semaphores for too long,
|
||||
* because of forceful takeover procedure. However it is more efficient
|
||||
* to read in bursts than synchronizing access for each word.
|
||||
*/
|
||||
for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) {
|
||||
count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ?
|
||||
IGC_EERD_EEWR_MAX_COUNT : (words - i);
|
||||
|
||||
status = hw->nvm.ops.acquire(hw);
|
||||
if (status)
|
||||
break;
|
||||
|
||||
status = igc_read_nvm_eerd(hw, offset, count, data + i);
|
||||
hw->nvm.ops.release(hw);
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_nvm_srwr - Write to Shadow Ram using EEWR
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset within the Shadow Ram to be written to
|
||||
* @words: number of words to write
|
||||
* @data: 16 bit word(s) to be written to the Shadow Ram
|
||||
*
|
||||
* Writes data to Shadow Ram at offset using EEWR register.
|
||||
*
|
||||
* If igc_update_nvm_checksum is not called after this function , the
|
||||
* Shadow Ram will most likely contain an invalid checksum.
|
||||
*/
|
||||
static s32 igc_write_nvm_srwr(struct igc_hw *hw, u16 offset, u16 words,
|
||||
u16 *data)
|
||||
{
|
||||
struct igc_nvm_info *nvm = &hw->nvm;
|
||||
s32 ret_val = -IGC_ERR_NVM;
|
||||
u32 attempts = 100000;
|
||||
u32 i, k, eewr = 0;
|
||||
|
||||
/* 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) {
|
||||
hw_dbg("nvm parameter(s) out of bounds\n");
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
for (i = 0; i < words; i++) {
|
||||
ret_val = -IGC_ERR_NVM;
|
||||
eewr = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) |
|
||||
(data[i] << IGC_NVM_RW_REG_DATA) |
|
||||
IGC_NVM_RW_REG_START;
|
||||
|
||||
wr32(IGC_SRWR, eewr);
|
||||
|
||||
for (k = 0; k < attempts; k++) {
|
||||
if (IGC_NVM_RW_REG_DONE &
|
||||
rd32(IGC_SRWR)) {
|
||||
ret_val = 0;
|
||||
break;
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
if (ret_val) {
|
||||
hw_dbg("Shadow RAM write EEWR timed out\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_nvm_srwr_i225 - Write to Shadow RAM using EEWR
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset within the Shadow RAM to be written to
|
||||
* @words: number of words to write
|
||||
* @data: 16 bit word(s) to be written to the Shadow RAM
|
||||
*
|
||||
* Writes data to Shadow RAM at offset using EEWR register.
|
||||
*
|
||||
* If igc_update_nvm_checksum is not called after this function , the
|
||||
* data will not be committed to FLASH and also Shadow RAM will most likely
|
||||
* contain an invalid checksum.
|
||||
*
|
||||
* If error code is returned, data and Shadow RAM may be inconsistent - buffer
|
||||
* partially written.
|
||||
*/
|
||||
static s32 igc_write_nvm_srwr_i225(struct igc_hw *hw, u16 offset, u16 words,
|
||||
u16 *data)
|
||||
{
|
||||
s32 status = 0;
|
||||
u16 i, count;
|
||||
|
||||
/* We cannot hold synchronization semaphores for too long,
|
||||
* because of forceful takeover procedure. However it is more efficient
|
||||
* to write in bursts than synchronizing access for each word.
|
||||
*/
|
||||
for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) {
|
||||
count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ?
|
||||
IGC_EERD_EEWR_MAX_COUNT : (words - i);
|
||||
|
||||
status = hw->nvm.ops.acquire(hw);
|
||||
if (status)
|
||||
break;
|
||||
|
||||
status = igc_write_nvm_srwr(hw, offset, count, data + i);
|
||||
hw->nvm.ops.release(hw);
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_validate_nvm_checksum_i225 - 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.
|
||||
*/
|
||||
static s32 igc_validate_nvm_checksum_i225(struct igc_hw *hw)
|
||||
{
|
||||
s32 (*read_op_ptr)(struct igc_hw *hw, u16 offset, u16 count,
|
||||
u16 *data);
|
||||
s32 status = 0;
|
||||
|
||||
status = hw->nvm.ops.acquire(hw);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
/* Replace the read function with semaphore grabbing with
|
||||
* the one that skips this for a while.
|
||||
* We have semaphore taken already here.
|
||||
*/
|
||||
read_op_ptr = hw->nvm.ops.read;
|
||||
hw->nvm.ops.read = igc_read_nvm_eerd;
|
||||
|
||||
status = igc_validate_nvm_checksum(hw);
|
||||
|
||||
/* Revert original read operation. */
|
||||
hw->nvm.ops.read = read_op_ptr;
|
||||
|
||||
hw->nvm.ops.release(hw);
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_pool_flash_update_done_i225 - Pool FLUDONE status
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_pool_flash_update_done_i225(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = -IGC_ERR_NVM;
|
||||
u32 i, reg;
|
||||
|
||||
for (i = 0; i < IGC_FLUDONE_ATTEMPTS; i++) {
|
||||
reg = rd32(IGC_EECD);
|
||||
if (reg & IGC_EECD_FLUDONE_I225) {
|
||||
ret_val = 0;
|
||||
break;
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_update_flash_i225 - Commit EEPROM to the flash
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_update_flash_i225(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
u32 flup;
|
||||
|
||||
ret_val = igc_pool_flash_update_done_i225(hw);
|
||||
if (ret_val == -IGC_ERR_NVM) {
|
||||
hw_dbg("Flash update time out\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
flup = rd32(IGC_EECD) | IGC_EECD_FLUPD_I225;
|
||||
wr32(IGC_EECD, flup);
|
||||
|
||||
ret_val = igc_pool_flash_update_done_i225(hw);
|
||||
if (ret_val)
|
||||
hw_dbg("Flash update time out\n");
|
||||
else
|
||||
hw_dbg("Flash update complete\n");
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_update_nvm_checksum_i225 - 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. Next commit EEPROM data onto the Flash.
|
||||
*/
|
||||
static s32 igc_update_nvm_checksum_i225(struct igc_hw *hw)
|
||||
{
|
||||
u16 checksum = 0;
|
||||
s32 ret_val = 0;
|
||||
u16 i, nvm_data;
|
||||
|
||||
/* Read the first word from the EEPROM. If this times out or fails, do
|
||||
* not continue or we could be in for a very long wait while every
|
||||
* EEPROM read fails
|
||||
*/
|
||||
ret_val = igc_read_nvm_eerd(hw, 0, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("EEPROM read failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_val = hw->nvm.ops.acquire(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* Do not use hw->nvm.ops.write, hw->nvm.ops.read
|
||||
* because we do not want to take the synchronization
|
||||
* semaphores twice here.
|
||||
*/
|
||||
|
||||
for (i = 0; i < NVM_CHECKSUM_REG; i++) {
|
||||
ret_val = igc_read_nvm_eerd(hw, i, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw->nvm.ops.release(hw);
|
||||
hw_dbg("NVM Read Error while updating checksum.\n");
|
||||
goto out;
|
||||
}
|
||||
checksum += nvm_data;
|
||||
}
|
||||
checksum = (u16)NVM_SUM - checksum;
|
||||
ret_val = igc_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1,
|
||||
&checksum);
|
||||
if (ret_val) {
|
||||
hw->nvm.ops.release(hw);
|
||||
hw_dbg("NVM Write Error while updating checksum.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
hw->nvm.ops.release(hw);
|
||||
|
||||
ret_val = igc_update_flash_i225(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_flash_presence_i225 - Check if flash device is detected
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
bool igc_get_flash_presence_i225(struct igc_hw *hw)
|
||||
{
|
||||
bool ret_val = false;
|
||||
u32 eec = 0;
|
||||
|
||||
eec = rd32(IGC_EECD);
|
||||
if (eec & IGC_EECD_FLASH_DETECTED_I225)
|
||||
ret_val = true;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_nvm_params_i225 - Init NVM func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
s32 igc_init_nvm_params_i225(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_nvm_info *nvm = &hw->nvm;
|
||||
|
||||
nvm->ops.acquire = igc_acquire_nvm_i225;
|
||||
nvm->ops.release = igc_release_nvm_i225;
|
||||
|
||||
/* NVM Function Pointers */
|
||||
if (igc_get_flash_presence_i225(hw)) {
|
||||
nvm->ops.read = igc_read_nvm_srrd_i225;
|
||||
nvm->ops.write = igc_write_nvm_srwr_i225;
|
||||
nvm->ops.validate = igc_validate_nvm_checksum_i225;
|
||||
nvm->ops.update = igc_update_nvm_checksum_i225;
|
||||
} else {
|
||||
nvm->ops.read = igc_read_nvm_eerd;
|
||||
nvm->ops.write = NULL;
|
||||
nvm->ops.validate = NULL;
|
||||
nvm->ops.update = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_set_eee_i225 - Enable/disable EEE support
|
||||
* @hw: pointer to the HW structure
|
||||
* @adv2p5G: boolean flag enabling 2.5G EEE advertisement
|
||||
* @adv1G: boolean flag enabling 1G EEE advertisement
|
||||
* @adv100M: boolean flag enabling 100M EEE advertisement
|
||||
*
|
||||
* Enable/disable EEE based on setting in dev_spec structure.
|
||||
**/
|
||||
s32 igc_set_eee_i225(struct igc_hw *hw, bool adv2p5G, bool adv1G,
|
||||
bool adv100M)
|
||||
{
|
||||
u32 ipcnfg, eeer;
|
||||
|
||||
ipcnfg = rd32(IGC_IPCNFG);
|
||||
eeer = rd32(IGC_EEER);
|
||||
|
||||
/* enable or disable per user setting */
|
||||
if (hw->dev_spec._base.eee_enable) {
|
||||
u32 eee_su = rd32(IGC_EEE_SU);
|
||||
|
||||
if (adv100M)
|
||||
ipcnfg |= IGC_IPCNFG_EEE_100M_AN;
|
||||
else
|
||||
ipcnfg &= ~IGC_IPCNFG_EEE_100M_AN;
|
||||
|
||||
if (adv1G)
|
||||
ipcnfg |= IGC_IPCNFG_EEE_1G_AN;
|
||||
else
|
||||
ipcnfg &= ~IGC_IPCNFG_EEE_1G_AN;
|
||||
|
||||
if (adv2p5G)
|
||||
ipcnfg |= IGC_IPCNFG_EEE_2_5G_AN;
|
||||
else
|
||||
ipcnfg &= ~IGC_IPCNFG_EEE_2_5G_AN;
|
||||
|
||||
eeer |= (IGC_EEER_TX_LPI_EN | IGC_EEER_RX_LPI_EN |
|
||||
IGC_EEER_LPI_FC);
|
||||
|
||||
/* This bit should not be set in normal operation. */
|
||||
if (eee_su & IGC_EEE_SU_LPI_CLK_STP)
|
||||
hw_dbg("LPI Clock Stop Bit should not be set!\n");
|
||||
} else {
|
||||
ipcnfg &= ~(IGC_IPCNFG_EEE_2_5G_AN | IGC_IPCNFG_EEE_1G_AN |
|
||||
IGC_IPCNFG_EEE_100M_AN);
|
||||
eeer &= ~(IGC_EEER_TX_LPI_EN | IGC_EEER_RX_LPI_EN |
|
||||
IGC_EEER_LPI_FC);
|
||||
}
|
||||
wr32(IGC_IPCNFG, ipcnfg);
|
||||
wr32(IGC_EEER, eeer);
|
||||
rd32(IGC_IPCNFG);
|
||||
rd32(IGC_EEER);
|
||||
|
||||
return IGC_SUCCESS;
|
||||
}
|
||||
|
||||
/* igc_set_ltr_i225 - Set Latency Tolerance Reporting thresholds
|
||||
* @hw: pointer to the HW structure
|
||||
* @link: bool indicating link status
|
||||
*
|
||||
* Set the LTR thresholds based on the link speed (Mbps), EEE, and DMAC
|
||||
* settings, otherwise specify that there is no LTR requirement.
|
||||
*/
|
||||
s32 igc_set_ltr_i225(struct igc_hw *hw, bool link)
|
||||
{
|
||||
u32 tw_system, ltrc, ltrv, ltr_min, ltr_max, scale_min, scale_max;
|
||||
u16 speed, duplex;
|
||||
s32 size;
|
||||
|
||||
/* If we do not have link, LTR thresholds are zero. */
|
||||
if (link) {
|
||||
hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
|
||||
|
||||
/* Check if using copper interface with EEE enabled or if the
|
||||
* link speed is 10 Mbps.
|
||||
*/
|
||||
if (hw->dev_spec._base.eee_enable &&
|
||||
speed != SPEED_10) {
|
||||
/* EEE enabled, so send LTRMAX threshold. */
|
||||
ltrc = rd32(IGC_LTRC) |
|
||||
IGC_LTRC_EEEMS_EN;
|
||||
wr32(IGC_LTRC, ltrc);
|
||||
|
||||
/* Calculate tw_system (nsec). */
|
||||
if (speed == SPEED_100) {
|
||||
tw_system = ((rd32(IGC_EEE_SU) &
|
||||
IGC_TW_SYSTEM_100_MASK) >>
|
||||
IGC_TW_SYSTEM_100_SHIFT) * 500;
|
||||
} else {
|
||||
tw_system = (rd32(IGC_EEE_SU) &
|
||||
IGC_TW_SYSTEM_1000_MASK) * 500;
|
||||
}
|
||||
} else {
|
||||
tw_system = 0;
|
||||
}
|
||||
|
||||
/* Get the Rx packet buffer size. */
|
||||
size = rd32(IGC_RXPBS) &
|
||||
IGC_RXPBS_SIZE_I225_MASK;
|
||||
|
||||
/* Convert size to bytes, subtract the MTU, and then
|
||||
* convert the size to bits.
|
||||
*/
|
||||
size *= 1024;
|
||||
size *= 8;
|
||||
|
||||
if (size < 0) {
|
||||
hw_dbg("Invalid effective Rx buffer size %d\n",
|
||||
size);
|
||||
return -IGC_ERR_CONFIG;
|
||||
}
|
||||
|
||||
/* Calculate the thresholds. Since speed is in Mbps, simplify
|
||||
* the calculation by multiplying size/speed by 1000 for result
|
||||
* to be in nsec before dividing by the scale in nsec. Set the
|
||||
* scale such that the LTR threshold fits in the register.
|
||||
*/
|
||||
ltr_min = (1000 * size) / speed;
|
||||
ltr_max = ltr_min + tw_system;
|
||||
scale_min = (ltr_min / 1024) < 1024 ? IGC_LTRMINV_SCALE_1024 :
|
||||
IGC_LTRMINV_SCALE_32768;
|
||||
scale_max = (ltr_max / 1024) < 1024 ? IGC_LTRMAXV_SCALE_1024 :
|
||||
IGC_LTRMAXV_SCALE_32768;
|
||||
ltr_min /= scale_min == IGC_LTRMINV_SCALE_1024 ? 1024 : 32768;
|
||||
ltr_min -= 1;
|
||||
ltr_max /= scale_max == IGC_LTRMAXV_SCALE_1024 ? 1024 : 32768;
|
||||
ltr_max -= 1;
|
||||
|
||||
/* Only write the LTR thresholds if they differ from before. */
|
||||
ltrv = rd32(IGC_LTRMINV);
|
||||
if (ltr_min != (ltrv & IGC_LTRMINV_LTRV_MASK)) {
|
||||
ltrv = IGC_LTRMINV_LSNP_REQ | ltr_min |
|
||||
(scale_min << IGC_LTRMINV_SCALE_SHIFT);
|
||||
wr32(IGC_LTRMINV, ltrv);
|
||||
}
|
||||
|
||||
ltrv = rd32(IGC_LTRMAXV);
|
||||
if (ltr_max != (ltrv & IGC_LTRMAXV_LTRV_MASK)) {
|
||||
ltrv = IGC_LTRMAXV_LSNP_REQ | ltr_max |
|
||||
(scale_max << IGC_LTRMAXV_SCALE_SHIFT);
|
||||
wr32(IGC_LTRMAXV, ltrv);
|
||||
}
|
||||
}
|
||||
|
||||
return IGC_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_I225_H_
|
||||
#define _IGC_I225_H_
|
||||
|
||||
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_nvm_params_i225(struct igc_hw *hw);
|
||||
bool igc_get_flash_presence_i225(struct igc_hw *hw);
|
||||
s32 igc_set_eee_i225(struct igc_hw *hw, bool adv2p5G, bool adv1G,
|
||||
bool adv100M);
|
||||
s32 igc_set_ltr_i225(struct igc_hw *hw, bool link);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,641 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "igc_hw.h"
|
||||
|
||||
/**
|
||||
* igc_acquire_nvm_i225 - Acquire exclusive access to EEPROM
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Acquire the necessary semaphores for exclusive access to the EEPROM.
|
||||
* 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).
|
||||
*/
|
||||
static s32 igc_acquire_nvm_i225(struct igc_hw *hw)
|
||||
{
|
||||
return igc_acquire_swfw_sync_i225(hw, IGC_SWFW_EEP_SM);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_release_nvm_i225 - Release exclusive access to EEPROM
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Stop any current commands to the EEPROM and clear the EEPROM request bit,
|
||||
* then release the semaphores acquired.
|
||||
*/
|
||||
static void igc_release_nvm_i225(struct igc_hw *hw)
|
||||
{
|
||||
igc_release_swfw_sync_i225(hw, IGC_SWFW_EEP_SM);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_hw_semaphore_i225 - Acquire hardware semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Acquire the HW semaphore to access the PHY or NVM
|
||||
*/
|
||||
static s32 igc_get_hw_semaphore_i225(struct igc_hw *hw)
|
||||
{
|
||||
s32 timeout = hw->nvm.word_size + 1;
|
||||
s32 i = 0;
|
||||
u32 swsm;
|
||||
|
||||
/* Get the SW semaphore */
|
||||
while (i < timeout) {
|
||||
swsm = rd32(IGC_SWSM);
|
||||
if (!(swsm & IGC_SWSM_SMBI))
|
||||
break;
|
||||
|
||||
usleep_range(500, 600);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == timeout) {
|
||||
/* In rare circumstances, the SW semaphore may already be held
|
||||
* unintentionally. Clear the semaphore once before giving up.
|
||||
*/
|
||||
if (hw->dev_spec._base.clear_semaphore_once) {
|
||||
hw->dev_spec._base.clear_semaphore_once = false;
|
||||
igc_put_hw_semaphore(hw);
|
||||
for (i = 0; i < timeout; i++) {
|
||||
swsm = rd32(IGC_SWSM);
|
||||
if (!(swsm & IGC_SWSM_SMBI))
|
||||
break;
|
||||
|
||||
usleep_range(500, 600);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we do not have the semaphore here, we have to give up. */
|
||||
if (i == timeout) {
|
||||
hw_dbg("Driver can't access device - SMBI bit is set.\n");
|
||||
return -IGC_ERR_NVM;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the FW semaphore. */
|
||||
for (i = 0; i < timeout; i++) {
|
||||
swsm = rd32(IGC_SWSM);
|
||||
wr32(IGC_SWSM, swsm | IGC_SWSM_SWESMBI);
|
||||
|
||||
/* Semaphore acquired if bit latched */
|
||||
if (rd32(IGC_SWSM) & IGC_SWSM_SWESMBI)
|
||||
break;
|
||||
|
||||
usleep_range(500, 600);
|
||||
}
|
||||
|
||||
if (i == timeout) {
|
||||
/* Release semaphores */
|
||||
igc_put_hw_semaphore(hw);
|
||||
hw_dbg("Driver can't access the NVM\n");
|
||||
return -IGC_ERR_NVM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_acquire_swfw_sync_i225 - Acquire SW/FW semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
* @mask: specifies which semaphore to acquire
|
||||
*
|
||||
* Acquire the SW/FW semaphore to access the PHY or NVM. The mask
|
||||
* will also specify which port we're acquiring the lock for.
|
||||
*/
|
||||
s32 igc_acquire_swfw_sync_i225(struct igc_hw *hw, u16 mask)
|
||||
{
|
||||
s32 i = 0, timeout = 200;
|
||||
u32 fwmask = mask << 16;
|
||||
u32 swmask = mask;
|
||||
s32 ret_val = 0;
|
||||
u32 swfw_sync;
|
||||
|
||||
while (i < timeout) {
|
||||
if (igc_get_hw_semaphore_i225(hw)) {
|
||||
ret_val = -IGC_ERR_SWFW_SYNC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
swfw_sync = rd32(IGC_SW_FW_SYNC);
|
||||
if (!(swfw_sync & (fwmask | swmask)))
|
||||
break;
|
||||
|
||||
/* Firmware currently using resource (fwmask) */
|
||||
igc_put_hw_semaphore(hw);
|
||||
mdelay(5);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == timeout) {
|
||||
hw_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n");
|
||||
ret_val = -IGC_ERR_SWFW_SYNC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
swfw_sync |= swmask;
|
||||
wr32(IGC_SW_FW_SYNC, swfw_sync);
|
||||
|
||||
igc_put_hw_semaphore(hw);
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_release_swfw_sync_i225 - Release SW/FW semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
* @mask: specifies which semaphore to acquire
|
||||
*
|
||||
* Release the SW/FW semaphore used to access the PHY or NVM. The mask
|
||||
* will also specify which port we're releasing the lock for.
|
||||
*/
|
||||
void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask)
|
||||
{
|
||||
u32 swfw_sync;
|
||||
|
||||
/* Releasing the resource requires first getting the HW semaphore.
|
||||
* If we fail to get the semaphore, there is nothing we can do,
|
||||
* except log an error and quit. We are not allowed to hang here
|
||||
* indefinitely, as it may cause denial of service or system crash.
|
||||
*/
|
||||
if (igc_get_hw_semaphore_i225(hw)) {
|
||||
hw_dbg("Failed to release SW_FW_SYNC.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
swfw_sync = rd32(IGC_SW_FW_SYNC);
|
||||
swfw_sync &= ~mask;
|
||||
wr32(IGC_SW_FW_SYNC, swfw_sync);
|
||||
|
||||
igc_put_hw_semaphore(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_nvm_srrd_i225 - Reads Shadow Ram using EERD register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset of word in the Shadow Ram to read
|
||||
* @words: number of words to read
|
||||
* @data: word read from the Shadow Ram
|
||||
*
|
||||
* Reads a 16 bit word from the Shadow Ram using the EERD register.
|
||||
* Uses necessary synchronization semaphores.
|
||||
*/
|
||||
static s32 igc_read_nvm_srrd_i225(struct igc_hw *hw, u16 offset, u16 words,
|
||||
u16 *data)
|
||||
{
|
||||
s32 status = 0;
|
||||
u16 i, count;
|
||||
|
||||
/* We cannot hold synchronization semaphores for too long,
|
||||
* because of forceful takeover procedure. However it is more efficient
|
||||
* to read in bursts than synchronizing access for each word.
|
||||
*/
|
||||
for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) {
|
||||
count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ?
|
||||
IGC_EERD_EEWR_MAX_COUNT : (words - i);
|
||||
|
||||
status = hw->nvm.ops.acquire(hw);
|
||||
if (status)
|
||||
break;
|
||||
|
||||
status = igc_read_nvm_eerd(hw, offset, count, data + i);
|
||||
hw->nvm.ops.release(hw);
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_nvm_srwr - Write to Shadow Ram using EEWR
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset within the Shadow Ram to be written to
|
||||
* @words: number of words to write
|
||||
* @data: 16 bit word(s) to be written to the Shadow Ram
|
||||
*
|
||||
* Writes data to Shadow Ram at offset using EEWR register.
|
||||
*
|
||||
* If igc_update_nvm_checksum is not called after this function , the
|
||||
* Shadow Ram will most likely contain an invalid checksum.
|
||||
*/
|
||||
static s32 igc_write_nvm_srwr(struct igc_hw *hw, u16 offset, u16 words,
|
||||
u16 *data)
|
||||
{
|
||||
struct igc_nvm_info *nvm = &hw->nvm;
|
||||
s32 ret_val = -IGC_ERR_NVM;
|
||||
u32 attempts = 100000;
|
||||
u32 i, k, eewr = 0;
|
||||
|
||||
/* 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) {
|
||||
hw_dbg("nvm parameter(s) out of bounds\n");
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
for (i = 0; i < words; i++) {
|
||||
ret_val = -IGC_ERR_NVM;
|
||||
eewr = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) |
|
||||
(data[i] << IGC_NVM_RW_REG_DATA) |
|
||||
IGC_NVM_RW_REG_START;
|
||||
|
||||
wr32(IGC_SRWR, eewr);
|
||||
|
||||
for (k = 0; k < attempts; k++) {
|
||||
if (IGC_NVM_RW_REG_DONE &
|
||||
rd32(IGC_SRWR)) {
|
||||
ret_val = 0;
|
||||
break;
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
if (ret_val) {
|
||||
hw_dbg("Shadow RAM write EEWR timed out\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_nvm_srwr_i225 - Write to Shadow RAM using EEWR
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: offset within the Shadow RAM to be written to
|
||||
* @words: number of words to write
|
||||
* @data: 16 bit word(s) to be written to the Shadow RAM
|
||||
*
|
||||
* Writes data to Shadow RAM at offset using EEWR register.
|
||||
*
|
||||
* If igc_update_nvm_checksum is not called after this function , the
|
||||
* data will not be committed to FLASH and also Shadow RAM will most likely
|
||||
* contain an invalid checksum.
|
||||
*
|
||||
* If error code is returned, data and Shadow RAM may be inconsistent - buffer
|
||||
* partially written.
|
||||
*/
|
||||
static s32 igc_write_nvm_srwr_i225(struct igc_hw *hw, u16 offset, u16 words,
|
||||
u16 *data)
|
||||
{
|
||||
s32 status = 0;
|
||||
u16 i, count;
|
||||
|
||||
/* We cannot hold synchronization semaphores for too long,
|
||||
* because of forceful takeover procedure. However it is more efficient
|
||||
* to write in bursts than synchronizing access for each word.
|
||||
*/
|
||||
for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) {
|
||||
count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ?
|
||||
IGC_EERD_EEWR_MAX_COUNT : (words - i);
|
||||
|
||||
status = hw->nvm.ops.acquire(hw);
|
||||
if (status)
|
||||
break;
|
||||
|
||||
status = igc_write_nvm_srwr(hw, offset, count, data + i);
|
||||
hw->nvm.ops.release(hw);
|
||||
if (status)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_validate_nvm_checksum_i225 - 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.
|
||||
*/
|
||||
static s32 igc_validate_nvm_checksum_i225(struct igc_hw *hw)
|
||||
{
|
||||
s32 (*read_op_ptr)(struct igc_hw *hw, u16 offset, u16 count,
|
||||
u16 *data);
|
||||
s32 status = 0;
|
||||
|
||||
status = hw->nvm.ops.acquire(hw);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
/* Replace the read function with semaphore grabbing with
|
||||
* the one that skips this for a while.
|
||||
* We have semaphore taken already here.
|
||||
*/
|
||||
read_op_ptr = hw->nvm.ops.read;
|
||||
hw->nvm.ops.read = igc_read_nvm_eerd;
|
||||
|
||||
status = igc_validate_nvm_checksum(hw);
|
||||
|
||||
/* Revert original read operation. */
|
||||
hw->nvm.ops.read = read_op_ptr;
|
||||
|
||||
hw->nvm.ops.release(hw);
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_pool_flash_update_done_i225 - Pool FLUDONE status
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_pool_flash_update_done_i225(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = -IGC_ERR_NVM;
|
||||
u32 i, reg;
|
||||
|
||||
for (i = 0; i < IGC_FLUDONE_ATTEMPTS; i++) {
|
||||
reg = rd32(IGC_EECD);
|
||||
if (reg & IGC_EECD_FLUDONE_I225) {
|
||||
ret_val = 0;
|
||||
break;
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_update_flash_i225 - Commit EEPROM to the flash
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
static s32 igc_update_flash_i225(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
u32 flup;
|
||||
|
||||
ret_val = igc_pool_flash_update_done_i225(hw);
|
||||
if (ret_val == -IGC_ERR_NVM) {
|
||||
hw_dbg("Flash update time out\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
flup = rd32(IGC_EECD) | IGC_EECD_FLUPD_I225;
|
||||
wr32(IGC_EECD, flup);
|
||||
|
||||
ret_val = igc_pool_flash_update_done_i225(hw);
|
||||
if (ret_val)
|
||||
hw_dbg("Flash update time out\n");
|
||||
else
|
||||
hw_dbg("Flash update complete\n");
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_update_nvm_checksum_i225 - 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. Next commit EEPROM data onto the Flash.
|
||||
*/
|
||||
static s32 igc_update_nvm_checksum_i225(struct igc_hw *hw)
|
||||
{
|
||||
u16 checksum = 0;
|
||||
s32 ret_val = 0;
|
||||
u16 i, nvm_data;
|
||||
|
||||
/* Read the first word from the EEPROM. If this times out or fails, do
|
||||
* not continue or we could be in for a very long wait while every
|
||||
* EEPROM read fails
|
||||
*/
|
||||
ret_val = igc_read_nvm_eerd(hw, 0, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("EEPROM read failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_val = hw->nvm.ops.acquire(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* Do not use hw->nvm.ops.write, hw->nvm.ops.read
|
||||
* because we do not want to take the synchronization
|
||||
* semaphores twice here.
|
||||
*/
|
||||
|
||||
for (i = 0; i < NVM_CHECKSUM_REG; i++) {
|
||||
ret_val = igc_read_nvm_eerd(hw, i, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw->nvm.ops.release(hw);
|
||||
hw_dbg("NVM Read Error while updating checksum.\n");
|
||||
goto out;
|
||||
}
|
||||
checksum += nvm_data;
|
||||
}
|
||||
checksum = (u16)NVM_SUM - checksum;
|
||||
ret_val = igc_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1,
|
||||
&checksum);
|
||||
if (ret_val) {
|
||||
hw->nvm.ops.release(hw);
|
||||
hw_dbg("NVM Write Error while updating checksum.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
hw->nvm.ops.release(hw);
|
||||
|
||||
ret_val = igc_update_flash_i225(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_flash_presence_i225 - Check if flash device is detected
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
bool igc_get_flash_presence_i225(struct igc_hw *hw)
|
||||
{
|
||||
bool ret_val = false;
|
||||
u32 eec = 0;
|
||||
|
||||
eec = rd32(IGC_EECD);
|
||||
if (eec & IGC_EECD_FLASH_DETECTED_I225)
|
||||
ret_val = true;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_nvm_params_i225 - Init NVM func ptrs.
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
s32 igc_init_nvm_params_i225(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_nvm_info *nvm = &hw->nvm;
|
||||
|
||||
nvm->ops.acquire = igc_acquire_nvm_i225;
|
||||
nvm->ops.release = igc_release_nvm_i225;
|
||||
|
||||
/* NVM Function Pointers */
|
||||
if (igc_get_flash_presence_i225(hw)) {
|
||||
nvm->ops.read = igc_read_nvm_srrd_i225;
|
||||
nvm->ops.write = igc_write_nvm_srwr_i225;
|
||||
nvm->ops.validate = igc_validate_nvm_checksum_i225;
|
||||
nvm->ops.update = igc_update_nvm_checksum_i225;
|
||||
} else {
|
||||
nvm->ops.read = igc_read_nvm_eerd;
|
||||
nvm->ops.write = NULL;
|
||||
nvm->ops.validate = NULL;
|
||||
nvm->ops.update = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_set_eee_i225 - Enable/disable EEE support
|
||||
* @hw: pointer to the HW structure
|
||||
* @adv2p5G: boolean flag enabling 2.5G EEE advertisement
|
||||
* @adv1G: boolean flag enabling 1G EEE advertisement
|
||||
* @adv100M: boolean flag enabling 100M EEE advertisement
|
||||
*
|
||||
* Enable/disable EEE based on setting in dev_spec structure.
|
||||
**/
|
||||
s32 igc_set_eee_i225(struct igc_hw *hw, bool adv2p5G, bool adv1G,
|
||||
bool adv100M)
|
||||
{
|
||||
u32 ipcnfg, eeer;
|
||||
|
||||
ipcnfg = rd32(IGC_IPCNFG);
|
||||
eeer = rd32(IGC_EEER);
|
||||
|
||||
/* enable or disable per user setting */
|
||||
if (hw->dev_spec._base.eee_enable) {
|
||||
u32 eee_su = rd32(IGC_EEE_SU);
|
||||
|
||||
if (adv100M)
|
||||
ipcnfg |= IGC_IPCNFG_EEE_100M_AN;
|
||||
else
|
||||
ipcnfg &= ~IGC_IPCNFG_EEE_100M_AN;
|
||||
|
||||
if (adv1G)
|
||||
ipcnfg |= IGC_IPCNFG_EEE_1G_AN;
|
||||
else
|
||||
ipcnfg &= ~IGC_IPCNFG_EEE_1G_AN;
|
||||
|
||||
if (adv2p5G)
|
||||
ipcnfg |= IGC_IPCNFG_EEE_2_5G_AN;
|
||||
else
|
||||
ipcnfg &= ~IGC_IPCNFG_EEE_2_5G_AN;
|
||||
|
||||
eeer |= (IGC_EEER_TX_LPI_EN | IGC_EEER_RX_LPI_EN |
|
||||
IGC_EEER_LPI_FC);
|
||||
|
||||
/* This bit should not be set in normal operation. */
|
||||
if (eee_su & IGC_EEE_SU_LPI_CLK_STP)
|
||||
hw_dbg("LPI Clock Stop Bit should not be set!\n");
|
||||
} else {
|
||||
ipcnfg &= ~(IGC_IPCNFG_EEE_2_5G_AN | IGC_IPCNFG_EEE_1G_AN |
|
||||
IGC_IPCNFG_EEE_100M_AN);
|
||||
eeer &= ~(IGC_EEER_TX_LPI_EN | IGC_EEER_RX_LPI_EN |
|
||||
IGC_EEER_LPI_FC);
|
||||
}
|
||||
wr32(IGC_IPCNFG, ipcnfg);
|
||||
wr32(IGC_EEER, eeer);
|
||||
rd32(IGC_IPCNFG);
|
||||
rd32(IGC_EEER);
|
||||
|
||||
return IGC_SUCCESS;
|
||||
}
|
||||
|
||||
/* igc_set_ltr_i225 - Set Latency Tolerance Reporting thresholds
|
||||
* @hw: pointer to the HW structure
|
||||
* @link: bool indicating link status
|
||||
*
|
||||
* Set the LTR thresholds based on the link speed (Mbps), EEE, and DMAC
|
||||
* settings, otherwise specify that there is no LTR requirement.
|
||||
*/
|
||||
s32 igc_set_ltr_i225(struct igc_hw *hw, bool link)
|
||||
{
|
||||
u32 tw_system, ltrc, ltrv, ltr_min, ltr_max, scale_min, scale_max;
|
||||
u16 speed, duplex;
|
||||
s32 size;
|
||||
|
||||
/* If we do not have link, LTR thresholds are zero. */
|
||||
if (link) {
|
||||
hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
|
||||
|
||||
/* Check if using copper interface with EEE enabled or if the
|
||||
* link speed is 10 Mbps.
|
||||
*/
|
||||
if (hw->dev_spec._base.eee_enable &&
|
||||
speed != SPEED_10) {
|
||||
/* EEE enabled, so send LTRMAX threshold. */
|
||||
ltrc = rd32(IGC_LTRC) |
|
||||
IGC_LTRC_EEEMS_EN;
|
||||
wr32(IGC_LTRC, ltrc);
|
||||
|
||||
/* Calculate tw_system (nsec). */
|
||||
if (speed == SPEED_100) {
|
||||
tw_system = ((rd32(IGC_EEE_SU) &
|
||||
IGC_TW_SYSTEM_100_MASK) >>
|
||||
IGC_TW_SYSTEM_100_SHIFT) * 500;
|
||||
} else {
|
||||
tw_system = (rd32(IGC_EEE_SU) &
|
||||
IGC_TW_SYSTEM_1000_MASK) * 500;
|
||||
}
|
||||
} else {
|
||||
tw_system = 0;
|
||||
}
|
||||
|
||||
/* Get the Rx packet buffer size. */
|
||||
size = rd32(IGC_RXPBS) &
|
||||
IGC_RXPBS_SIZE_I225_MASK;
|
||||
|
||||
/* Convert size to bytes, subtract the MTU, and then
|
||||
* convert the size to bits.
|
||||
*/
|
||||
size *= 1024;
|
||||
size *= 8;
|
||||
|
||||
if (size < 0) {
|
||||
hw_dbg("Invalid effective Rx buffer size %d\n",
|
||||
size);
|
||||
return -IGC_ERR_CONFIG;
|
||||
}
|
||||
|
||||
/* Calculate the thresholds. Since speed is in Mbps, simplify
|
||||
* the calculation by multiplying size/speed by 1000 for result
|
||||
* to be in nsec before dividing by the scale in nsec. Set the
|
||||
* scale such that the LTR threshold fits in the register.
|
||||
*/
|
||||
ltr_min = (1000 * size) / speed;
|
||||
ltr_max = ltr_min + tw_system;
|
||||
scale_min = (ltr_min / 1024) < 1024 ? IGC_LTRMINV_SCALE_1024 :
|
||||
IGC_LTRMINV_SCALE_32768;
|
||||
scale_max = (ltr_max / 1024) < 1024 ? IGC_LTRMAXV_SCALE_1024 :
|
||||
IGC_LTRMAXV_SCALE_32768;
|
||||
ltr_min /= scale_min == IGC_LTRMINV_SCALE_1024 ? 1024 : 32768;
|
||||
ltr_min -= 1;
|
||||
ltr_max /= scale_max == IGC_LTRMAXV_SCALE_1024 ? 1024 : 32768;
|
||||
ltr_max -= 1;
|
||||
|
||||
/* Only write the LTR thresholds if they differ from before. */
|
||||
ltrv = rd32(IGC_LTRMINV);
|
||||
if (ltr_min != (ltrv & IGC_LTRMINV_LTRV_MASK)) {
|
||||
ltrv = IGC_LTRMINV_LSNP_REQ | ltr_min |
|
||||
(scale_min << IGC_LTRMINV_SCALE_SHIFT);
|
||||
wr32(IGC_LTRMINV, ltrv);
|
||||
}
|
||||
|
||||
ltrv = rd32(IGC_LTRMAXV);
|
||||
if (ltr_max != (ltrv & IGC_LTRMAXV_LTRV_MASK)) {
|
||||
ltrv = IGC_LTRMAXV_LSNP_REQ | ltr_max |
|
||||
(scale_max << IGC_LTRMAXV_SCALE_SHIFT);
|
||||
wr32(IGC_LTRMAXV, ltrv);
|
||||
}
|
||||
}
|
||||
|
||||
return IGC_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_I225_H_
|
||||
#define _IGC_I225_H_
|
||||
|
||||
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_nvm_params_i225(struct igc_hw *hw);
|
||||
bool igc_get_flash_presence_i225(struct igc_hw *hw);
|
||||
s32 igc_set_eee_i225(struct igc_hw *hw, bool adv2p5G, bool adv1G,
|
||||
bool adv100M);
|
||||
s32 igc_set_ltr_i225(struct igc_hw *hw, bool link);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,881 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "igc_mac-6.4-ethercat.h"
|
||||
#include "igc_hw-6.4-ethercat.h"
|
||||
|
||||
/**
|
||||
* igc_disable_pcie_master - Disables PCI-express master access
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Returns 0 (0) if successful, else returns -10
|
||||
* (-IGC_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
|
||||
* the master requests to be disabled.
|
||||
*
|
||||
* Disables PCI-Express master access and verifies there are no pending
|
||||
* requests.
|
||||
*/
|
||||
s32 igc_disable_pcie_master(struct igc_hw *hw)
|
||||
{
|
||||
s32 timeout = MASTER_DISABLE_TIMEOUT;
|
||||
s32 ret_val = 0;
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
ctrl |= IGC_CTRL_GIO_MASTER_DISABLE;
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
|
||||
while (timeout) {
|
||||
if (!(rd32(IGC_STATUS) &
|
||||
IGC_STATUS_GIO_MASTER_ENABLE))
|
||||
break;
|
||||
usleep_range(2000, 3000);
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
hw_dbg("Master requests are pending.\n");
|
||||
ret_val = -IGC_ERR_MASTER_REQUESTS_PENDING;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_rx_addrs - Initialize receive addresses
|
||||
* @hw: pointer to the HW structure
|
||||
* @rar_count: receive address registers
|
||||
*
|
||||
* Setup the receive address registers by setting the base receive address
|
||||
* register to the devices MAC address and clearing all the other receive
|
||||
* address registers to 0.
|
||||
*/
|
||||
void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count)
|
||||
{
|
||||
u8 mac_addr[ETH_ALEN] = {0};
|
||||
u32 i;
|
||||
|
||||
/* Setup the receive address */
|
||||
hw_dbg("Programming MAC Address into RAR[0]\n");
|
||||
|
||||
hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
|
||||
|
||||
/* Zero out the other (rar_entry_count - 1) receive addresses */
|
||||
hw_dbg("Clearing RAR[1-%u]\n", rar_count - 1);
|
||||
for (i = 1; i < rar_count; i++)
|
||||
hw->mac.ops.rar_set(hw, mac_addr, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_set_fc_watermarks - Set flow control high/low watermarks
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Sets the flow control high/low threshold (watermark) registers. If
|
||||
* flow control XON frame transmission is enabled, then set XON frame
|
||||
* transmission as well.
|
||||
*/
|
||||
static s32 igc_set_fc_watermarks(struct igc_hw *hw)
|
||||
{
|
||||
u32 fcrtl = 0, fcrth = 0;
|
||||
|
||||
/* Set the flow control receive threshold registers. Normally,
|
||||
* these registers will be set to a default threshold that may be
|
||||
* adjusted later by the driver's runtime code. However, if the
|
||||
* ability to transmit pause frames is not enabled, then these
|
||||
* registers will be set to 0.
|
||||
*/
|
||||
if (hw->fc.current_mode & igc_fc_tx_pause) {
|
||||
/* We need to set up the Receive Threshold high and low water
|
||||
* marks as well as (optionally) enabling the transmission of
|
||||
* XON frames.
|
||||
*/
|
||||
fcrtl = hw->fc.low_water;
|
||||
if (hw->fc.send_xon)
|
||||
fcrtl |= IGC_FCRTL_XONE;
|
||||
|
||||
fcrth = hw->fc.high_water;
|
||||
}
|
||||
wr32(IGC_FCRTL, fcrtl);
|
||||
wr32(IGC_FCRTH, fcrth);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_setup_link - Setup flow control and link settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Determines which flow control settings to use, then configures flow
|
||||
* control. Calls the appropriate media-specific link configuration
|
||||
* function. Assuming the adapter has a valid link partner, a valid link
|
||||
* should be established. Assumes the hardware has previously been reset
|
||||
* and the transmitter and receiver are not enabled.
|
||||
*/
|
||||
s32 igc_setup_link(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* In the case of the phy reset being blocked, we already have a link.
|
||||
* We do not need to set it up again.
|
||||
*/
|
||||
if (igc_check_reset_block(hw))
|
||||
goto out;
|
||||
|
||||
/* If requested flow control is set to default, set flow control
|
||||
* to the both 'rx' and 'tx' pause frames.
|
||||
*/
|
||||
if (hw->fc.requested_mode == igc_fc_default)
|
||||
hw->fc.requested_mode = igc_fc_full;
|
||||
|
||||
/* We want to save off the original Flow Control configuration just
|
||||
* in case we get disconnected and then reconnected into a different
|
||||
* hub or switch with different Flow Control capabilities.
|
||||
*/
|
||||
hw->fc.current_mode = hw->fc.requested_mode;
|
||||
|
||||
hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode);
|
||||
|
||||
/* Call the necessary media_type subroutine to configure the link. */
|
||||
ret_val = hw->mac.ops.setup_physical_interface(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* Initialize the flow control address, type, and PAUSE timer
|
||||
* registers to their default values. This is done even if flow
|
||||
* control is disabled, because it does not hurt anything to
|
||||
* initialize these registers.
|
||||
*/
|
||||
hw_dbg("Initializing the Flow Control address, type and timer regs\n");
|
||||
wr32(IGC_FCT, FLOW_CONTROL_TYPE);
|
||||
wr32(IGC_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
|
||||
wr32(IGC_FCAL, FLOW_CONTROL_ADDRESS_LOW);
|
||||
|
||||
wr32(IGC_FCTTV, hw->fc.pause_time);
|
||||
|
||||
ret_val = igc_set_fc_watermarks(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_force_mac_fc - Force the MAC's flow control settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the
|
||||
* device control register to reflect the adapter settings. TFCE and RFCE
|
||||
* need to be explicitly set by software when a copper PHY is used because
|
||||
* autonegotiation is managed by the PHY rather than the MAC. Software must
|
||||
* also configure these bits when link is forced on a fiber connection.
|
||||
*/
|
||||
s32 igc_force_mac_fc(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
|
||||
/* Because we didn't get link via the internal auto-negotiation
|
||||
* mechanism (we either forced link or we got link via PHY
|
||||
* auto-neg), we have to manually enable/disable transmit an
|
||||
* receive flow control.
|
||||
*
|
||||
* The "Case" statement below enables/disable flow control
|
||||
* according to the "hw->fc.current_mode" parameter.
|
||||
*
|
||||
* The possible values of the "fc" parameter are:
|
||||
* 0: Flow control is completely disabled
|
||||
* 1: Rx flow control is enabled (we can receive pause
|
||||
* frames but not send pause frames).
|
||||
* 2: Tx flow control is enabled (we can send pause frames
|
||||
* but we do not receive pause frames).
|
||||
* 3: Both Rx and TX flow control (symmetric) is enabled.
|
||||
* other: No other values should be possible at this point.
|
||||
*/
|
||||
hw_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode);
|
||||
|
||||
switch (hw->fc.current_mode) {
|
||||
case igc_fc_none:
|
||||
ctrl &= (~(IGC_CTRL_TFCE | IGC_CTRL_RFCE));
|
||||
break;
|
||||
case igc_fc_rx_pause:
|
||||
ctrl &= (~IGC_CTRL_TFCE);
|
||||
ctrl |= IGC_CTRL_RFCE;
|
||||
break;
|
||||
case igc_fc_tx_pause:
|
||||
ctrl &= (~IGC_CTRL_RFCE);
|
||||
ctrl |= IGC_CTRL_TFCE;
|
||||
break;
|
||||
case igc_fc_full:
|
||||
ctrl |= (IGC_CTRL_TFCE | IGC_CTRL_RFCE);
|
||||
break;
|
||||
default:
|
||||
hw_dbg("Flow control param set incorrectly\n");
|
||||
ret_val = -IGC_ERR_CONFIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_clear_hw_cntrs_base - Clear base hardware counters
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Clears the base hardware counters by reading the counter registers.
|
||||
*/
|
||||
void igc_clear_hw_cntrs_base(struct igc_hw *hw)
|
||||
{
|
||||
rd32(IGC_CRCERRS);
|
||||
rd32(IGC_MPC);
|
||||
rd32(IGC_SCC);
|
||||
rd32(IGC_ECOL);
|
||||
rd32(IGC_MCC);
|
||||
rd32(IGC_LATECOL);
|
||||
rd32(IGC_COLC);
|
||||
rd32(IGC_RERC);
|
||||
rd32(IGC_DC);
|
||||
rd32(IGC_RLEC);
|
||||
rd32(IGC_XONRXC);
|
||||
rd32(IGC_XONTXC);
|
||||
rd32(IGC_XOFFRXC);
|
||||
rd32(IGC_XOFFTXC);
|
||||
rd32(IGC_FCRUC);
|
||||
rd32(IGC_GPRC);
|
||||
rd32(IGC_BPRC);
|
||||
rd32(IGC_MPRC);
|
||||
rd32(IGC_GPTC);
|
||||
rd32(IGC_GORCL);
|
||||
rd32(IGC_GORCH);
|
||||
rd32(IGC_GOTCL);
|
||||
rd32(IGC_GOTCH);
|
||||
rd32(IGC_RNBC);
|
||||
rd32(IGC_RUC);
|
||||
rd32(IGC_RFC);
|
||||
rd32(IGC_ROC);
|
||||
rd32(IGC_RJC);
|
||||
rd32(IGC_TORL);
|
||||
rd32(IGC_TORH);
|
||||
rd32(IGC_TOTL);
|
||||
rd32(IGC_TOTH);
|
||||
rd32(IGC_TPR);
|
||||
rd32(IGC_TPT);
|
||||
rd32(IGC_MPTC);
|
||||
rd32(IGC_BPTC);
|
||||
|
||||
rd32(IGC_PRC64);
|
||||
rd32(IGC_PRC127);
|
||||
rd32(IGC_PRC255);
|
||||
rd32(IGC_PRC511);
|
||||
rd32(IGC_PRC1023);
|
||||
rd32(IGC_PRC1522);
|
||||
rd32(IGC_PTC64);
|
||||
rd32(IGC_PTC127);
|
||||
rd32(IGC_PTC255);
|
||||
rd32(IGC_PTC511);
|
||||
rd32(IGC_PTC1023);
|
||||
rd32(IGC_PTC1522);
|
||||
|
||||
rd32(IGC_ALGNERRC);
|
||||
rd32(IGC_RXERRC);
|
||||
rd32(IGC_TNCRS);
|
||||
rd32(IGC_HTDPMC);
|
||||
rd32(IGC_TSCTC);
|
||||
|
||||
rd32(IGC_MGTPRC);
|
||||
rd32(IGC_MGTPDC);
|
||||
rd32(IGC_MGTPTC);
|
||||
|
||||
rd32(IGC_IAC);
|
||||
|
||||
rd32(IGC_RPTHC);
|
||||
rd32(IGC_TLPIC);
|
||||
rd32(IGC_RLPIC);
|
||||
rd32(IGC_HGPTC);
|
||||
rd32(IGC_RXDMTC);
|
||||
rd32(IGC_HGORCL);
|
||||
rd32(IGC_HGORCH);
|
||||
rd32(IGC_HGOTCL);
|
||||
rd32(IGC_HGOTCH);
|
||||
rd32(IGC_LENERRS);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_rar_set - Set receive address register
|
||||
* @hw: pointer to the HW structure
|
||||
* @addr: pointer to the receive address
|
||||
* @index: receive address array register
|
||||
*
|
||||
* Sets the receive address array register at index to the address passed
|
||||
* in by addr.
|
||||
*/
|
||||
void igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index)
|
||||
{
|
||||
u32 rar_low, rar_high;
|
||||
|
||||
/* HW expects these in little endian so we reverse the byte order
|
||||
* from network order (big endian) to little endian
|
||||
*/
|
||||
rar_low = ((u32)addr[0] |
|
||||
((u32)addr[1] << 8) |
|
||||
((u32)addr[2] << 16) | ((u32)addr[3] << 24));
|
||||
|
||||
rar_high = ((u32)addr[4] | ((u32)addr[5] << 8));
|
||||
|
||||
/* If MAC address zero, no need to set the AV bit */
|
||||
if (rar_low || rar_high)
|
||||
rar_high |= IGC_RAH_AV;
|
||||
|
||||
/* Some bridges will combine consecutive 32-bit writes into
|
||||
* a single burst write, which will malfunction on some parts.
|
||||
* The flushes avoid this.
|
||||
*/
|
||||
wr32(IGC_RAL(index), rar_low);
|
||||
wrfl();
|
||||
wr32(IGC_RAH(index), rar_high);
|
||||
wrfl();
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_check_for_copper_link - Check for link (Copper)
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Checks to see of the link status of the hardware has changed. If a
|
||||
* change in link status has been detected, then we read the PHY registers
|
||||
* to get the current speed/duplex if link exists.
|
||||
*/
|
||||
s32 igc_check_for_copper_link(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
bool link = false;
|
||||
s32 ret_val;
|
||||
|
||||
/* We only want to go out to the PHY registers to see if Auto-Neg
|
||||
* has completed and/or if our link status has changed. The
|
||||
* get_link_status flag is set upon receiving a Link Status
|
||||
* Change or Rx Sequence Error interrupt.
|
||||
*/
|
||||
if (!mac->get_link_status) {
|
||||
ret_val = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* First we want to see if the MII Status Register reports
|
||||
* link. If so, then we want to get the current speed/duplex
|
||||
* of the PHY.
|
||||
*/
|
||||
ret_val = igc_phy_has_link(hw, 1, 0, &link);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
if (!link)
|
||||
goto out; /* No link detected */
|
||||
|
||||
mac->get_link_status = false;
|
||||
|
||||
/* Check if there was DownShift, must be checked
|
||||
* immediately after link-up
|
||||
*/
|
||||
igc_check_downshift(hw);
|
||||
|
||||
/* If we are forcing speed/duplex, then we simply return since
|
||||
* we have already determined whether we have link or not.
|
||||
*/
|
||||
if (!mac->autoneg) {
|
||||
ret_val = -IGC_ERR_CONFIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Auto-Neg is enabled. Auto Speed Detection takes care
|
||||
* of MAC speed/duplex configuration. So we only need to
|
||||
* configure Collision Distance in the MAC.
|
||||
*/
|
||||
igc_config_collision_dist(hw);
|
||||
|
||||
/* Configure Flow Control now that Auto-Neg has completed.
|
||||
* First, we need to restore the desired flow control
|
||||
* settings because we may have had to re-autoneg with a
|
||||
* different link partner.
|
||||
*/
|
||||
ret_val = igc_config_fc_after_link_up(hw);
|
||||
if (ret_val)
|
||||
hw_dbg("Error configuring flow control\n");
|
||||
|
||||
out:
|
||||
/* Now that we are aware of our link settings, we can set the LTR
|
||||
* thresholds.
|
||||
*/
|
||||
ret_val = igc_set_ltr_i225(hw, link);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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. Currently no func pointer exists and all
|
||||
* implementations are handled in the generic version of this function.
|
||||
*/
|
||||
void igc_config_collision_dist(struct igc_hw *hw)
|
||||
{
|
||||
u32 tctl;
|
||||
|
||||
tctl = rd32(IGC_TCTL);
|
||||
|
||||
tctl &= ~IGC_TCTL_COLD;
|
||||
tctl |= IGC_COLLISION_DISTANCE << IGC_COLD_SHIFT;
|
||||
|
||||
wr32(IGC_TCTL, tctl);
|
||||
wrfl();
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_config_fc_after_link_up - Configures flow control after link
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Checks the status of auto-negotiation after link up to ensure that the
|
||||
* speed and duplex were not forced. If the link needed to be forced, then
|
||||
* flow control needs to be forced also. If auto-negotiation is enabled
|
||||
* and did not fail, then we configure flow control based on our link
|
||||
* partner.
|
||||
*/
|
||||
s32 igc_config_fc_after_link_up(struct igc_hw *hw)
|
||||
{
|
||||
u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
u16 speed, duplex;
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* Check for the case where we have fiber media and auto-neg failed
|
||||
* so we had to force link. In this case, we need to force the
|
||||
* configuration of the MAC to match the "fc" parameter.
|
||||
*/
|
||||
if (mac->autoneg_failed)
|
||||
ret_val = igc_force_mac_fc(hw);
|
||||
|
||||
if (ret_val) {
|
||||
hw_dbg("Error forcing flow control settings\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check for the case where we have copper media and auto-neg is
|
||||
* enabled. In this case, we need to check and see if Auto-Neg
|
||||
* has completed, and if so, how the PHY and link partner has
|
||||
* flow control configured.
|
||||
*/
|
||||
if (mac->autoneg) {
|
||||
/* Read the MII Status Register and check to see if AutoNeg
|
||||
* has completed. We read this twice because this reg has
|
||||
* some "sticky" (latched) bits.
|
||||
*/
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
|
||||
&mii_status_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
|
||||
&mii_status_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
|
||||
hw_dbg("Copper PHY and Auto Neg has not completed.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The AutoNeg process has completed, so we now need to
|
||||
* read both the Auto Negotiation Advertisement
|
||||
* Register (Address 4) and the Auto_Negotiation Base
|
||||
* Page Ability Register (Address 5) to determine how
|
||||
* flow control was negotiated.
|
||||
*/
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
|
||||
&mii_nway_adv_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
|
||||
&mii_nway_lp_ability_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
/* Two bits in the Auto Negotiation Advertisement Register
|
||||
* (Address 4) and two bits in the Auto Negotiation Base
|
||||
* Page Ability Register (Address 5) determine flow control
|
||||
* for both the PHY and the link partner. The following
|
||||
* table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
|
||||
* 1999, describes these PAUSE resolution bits and how flow
|
||||
* control is determined based upon these settings.
|
||||
* NOTE: DC = Don't Care
|
||||
*
|
||||
* LOCAL DEVICE | LINK PARTNER
|
||||
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
|
||||
*-------|---------|-------|---------|--------------------
|
||||
* 0 | 0 | DC | DC | igc_fc_none
|
||||
* 0 | 1 | 0 | DC | igc_fc_none
|
||||
* 0 | 1 | 1 | 0 | igc_fc_none
|
||||
* 0 | 1 | 1 | 1 | igc_fc_tx_pause
|
||||
* 1 | 0 | 0 | DC | igc_fc_none
|
||||
* 1 | DC | 1 | DC | igc_fc_full
|
||||
* 1 | 1 | 0 | 0 | igc_fc_none
|
||||
* 1 | 1 | 0 | 1 | igc_fc_rx_pause
|
||||
*
|
||||
* Are both PAUSE bits set to 1? If so, this implies
|
||||
* Symmetric Flow Control is enabled at both ends. The
|
||||
* ASM_DIR bits are irrelevant per the spec.
|
||||
*
|
||||
* For Symmetric Flow Control:
|
||||
*
|
||||
* LOCAL DEVICE | LINK PARTNER
|
||||
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
|
||||
*-------|---------|-------|---------|--------------------
|
||||
* 1 | DC | 1 | DC | IGC_fc_full
|
||||
*
|
||||
*/
|
||||
if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
|
||||
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
|
||||
/* Now we need to check if the user selected RX ONLY
|
||||
* of pause frames. In this case, we had to advertise
|
||||
* FULL flow control because we could not advertise RX
|
||||
* ONLY. Hence, we must now check to see if we need to
|
||||
* turn OFF the TRANSMISSION of PAUSE frames.
|
||||
*/
|
||||
if (hw->fc.requested_mode == igc_fc_full) {
|
||||
hw->fc.current_mode = igc_fc_full;
|
||||
hw_dbg("Flow Control = FULL.\n");
|
||||
} else {
|
||||
hw->fc.current_mode = igc_fc_rx_pause;
|
||||
hw_dbg("Flow Control = RX PAUSE frames only.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* For receiving PAUSE frames ONLY.
|
||||
*
|
||||
* LOCAL DEVICE | LINK PARTNER
|
||||
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
|
||||
*-------|---------|-------|---------|--------------------
|
||||
* 0 | 1 | 1 | 1 | igc_fc_tx_pause
|
||||
*/
|
||||
else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
|
||||
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
|
||||
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
|
||||
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
|
||||
hw->fc.current_mode = igc_fc_tx_pause;
|
||||
hw_dbg("Flow Control = TX PAUSE frames only.\n");
|
||||
}
|
||||
/* For transmitting PAUSE frames ONLY.
|
||||
*
|
||||
* LOCAL DEVICE | LINK PARTNER
|
||||
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
|
||||
*-------|---------|-------|---------|--------------------
|
||||
* 1 | 1 | 0 | 1 | igc_fc_rx_pause
|
||||
*/
|
||||
else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
|
||||
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
|
||||
!(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
|
||||
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
|
||||
hw->fc.current_mode = igc_fc_rx_pause;
|
||||
hw_dbg("Flow Control = RX PAUSE frames only.\n");
|
||||
}
|
||||
/* Per the IEEE spec, at this point flow control should be
|
||||
* disabled. However, we want to consider that we could
|
||||
* be connected to a legacy switch that doesn't advertise
|
||||
* desired flow control, but can be forced on the link
|
||||
* partner. So if we advertised no flow control, that is
|
||||
* what we will resolve to. If we advertised some kind of
|
||||
* receive capability (Rx Pause Only or Full Flow Control)
|
||||
* and the link partner advertised none, we will configure
|
||||
* ourselves to enable Rx Flow Control only. We can do
|
||||
* this safely for two reasons: If the link partner really
|
||||
* didn't want flow control enabled, and we enable Rx, no
|
||||
* harm done since we won't be receiving any PAUSE frames
|
||||
* anyway. If the intent on the link partner was to have
|
||||
* flow control enabled, then by us enabling RX only, we
|
||||
* can at least receive pause frames and process them.
|
||||
* This is a good idea because in most cases, since we are
|
||||
* predominantly a server NIC, more times than not we will
|
||||
* be asked to delay transmission of packets than asking
|
||||
* our link partner to pause transmission of frames.
|
||||
*/
|
||||
else if ((hw->fc.requested_mode == igc_fc_none) ||
|
||||
(hw->fc.requested_mode == igc_fc_tx_pause) ||
|
||||
(hw->fc.strict_ieee)) {
|
||||
hw->fc.current_mode = igc_fc_none;
|
||||
hw_dbg("Flow Control = NONE.\n");
|
||||
} else {
|
||||
hw->fc.current_mode = igc_fc_rx_pause;
|
||||
hw_dbg("Flow Control = RX PAUSE frames only.\n");
|
||||
}
|
||||
|
||||
/* Now we need to do one last check... If we auto-
|
||||
* negotiated to HALF DUPLEX, flow control should not be
|
||||
* enabled per IEEE 802.3 spec.
|
||||
*/
|
||||
ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error getting link speed and duplex\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (duplex == HALF_DUPLEX)
|
||||
hw->fc.current_mode = igc_fc_none;
|
||||
|
||||
/* Now we call a subroutine to actually force the MAC
|
||||
* controller to use the correct flow control settings.
|
||||
*/
|
||||
ret_val = igc_force_mac_fc(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error forcing flow control settings\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_auto_rd_done - Check for auto read completion
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Check EEPROM for Auto Read done bit.
|
||||
*/
|
||||
s32 igc_get_auto_rd_done(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
s32 i = 0;
|
||||
|
||||
while (i < AUTO_READ_DONE_TIMEOUT) {
|
||||
if (rd32(IGC_EECD) & IGC_EECD_AUTO_RD)
|
||||
break;
|
||||
usleep_range(1000, 2000);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == AUTO_READ_DONE_TIMEOUT) {
|
||||
hw_dbg("Auto read by HW from NVM has not completed.\n");
|
||||
ret_val = -IGC_ERR_RESET;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_speed_and_duplex_copper - Retrieve current speed/duplex
|
||||
* @hw: pointer to the HW structure
|
||||
* @speed: stores the current speed
|
||||
* @duplex: stores the current duplex
|
||||
*
|
||||
* Read the status register for the current speed/duplex and store the current
|
||||
* speed and duplex for copper connections.
|
||||
*/
|
||||
s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,
|
||||
u16 *duplex)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
status = rd32(IGC_STATUS);
|
||||
if (status & IGC_STATUS_SPEED_1000) {
|
||||
/* For I225, STATUS will indicate 1G speed in both 1 Gbps
|
||||
* and 2.5 Gbps link modes. An additional bit is used
|
||||
* to differentiate between 1 Gbps and 2.5 Gbps.
|
||||
*/
|
||||
if (hw->mac.type == igc_i225 &&
|
||||
(status & IGC_STATUS_SPEED_2500)) {
|
||||
*speed = SPEED_2500;
|
||||
hw_dbg("2500 Mbs, ");
|
||||
} else {
|
||||
*speed = SPEED_1000;
|
||||
hw_dbg("1000 Mbs, ");
|
||||
}
|
||||
} else if (status & IGC_STATUS_SPEED_100) {
|
||||
*speed = SPEED_100;
|
||||
hw_dbg("100 Mbs, ");
|
||||
} else {
|
||||
*speed = SPEED_10;
|
||||
hw_dbg("10 Mbs, ");
|
||||
}
|
||||
|
||||
if (status & IGC_STATUS_FD) {
|
||||
*duplex = FULL_DUPLEX;
|
||||
hw_dbg("Full Duplex\n");
|
||||
} else {
|
||||
*duplex = HALF_DUPLEX;
|
||||
hw_dbg("Half Duplex\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_put_hw_semaphore - Release hardware semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Release hardware semaphore used to access the PHY or NVM
|
||||
*/
|
||||
void igc_put_hw_semaphore(struct igc_hw *hw)
|
||||
{
|
||||
u32 swsm;
|
||||
|
||||
swsm = rd32(IGC_SWSM);
|
||||
|
||||
swsm &= ~(IGC_SWSM_SMBI | IGC_SWSM_SWESMBI);
|
||||
|
||||
wr32(IGC_SWSM, swsm);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_enable_mng_pass_thru - Enable processing of ARP's
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Verifies the hardware needs to leave interface enabled so that frames can
|
||||
* be directed to and from the management interface.
|
||||
*/
|
||||
bool igc_enable_mng_pass_thru(struct igc_hw *hw)
|
||||
{
|
||||
bool ret_val = false;
|
||||
u32 fwsm, factps;
|
||||
u32 manc;
|
||||
|
||||
if (!hw->mac.asf_firmware_present)
|
||||
goto out;
|
||||
|
||||
manc = rd32(IGC_MANC);
|
||||
|
||||
if (!(manc & IGC_MANC_RCV_TCO_EN))
|
||||
goto out;
|
||||
|
||||
if (hw->mac.arc_subsystem_valid) {
|
||||
fwsm = rd32(IGC_FWSM);
|
||||
factps = rd32(IGC_FACTPS);
|
||||
|
||||
if (!(factps & IGC_FACTPS_MNGCG) &&
|
||||
((fwsm & IGC_FWSM_MODE_MASK) ==
|
||||
(igc_mng_mode_pt << IGC_FWSM_MODE_SHIFT))) {
|
||||
ret_val = true;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if ((manc & IGC_MANC_SMBUS_EN) &&
|
||||
!(manc & IGC_MANC_ASF_EN)) {
|
||||
ret_val = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_hash_mc_addr - Generate a multicast hash value
|
||||
* @hw: pointer to the HW structure
|
||||
* @mc_addr: pointer to a multicast address
|
||||
*
|
||||
* Generates a multicast address hash value which is used to determine
|
||||
* the multicast filter table array address and new table value. See
|
||||
* igc_mta_set()
|
||||
**/
|
||||
static u32 igc_hash_mc_addr(struct igc_hw *hw, u8 *mc_addr)
|
||||
{
|
||||
u32 hash_value, hash_mask;
|
||||
u8 bit_shift = 0;
|
||||
|
||||
/* Register count multiplied by bits per register */
|
||||
hash_mask = (hw->mac.mta_reg_count * 32) - 1;
|
||||
|
||||
/* For a mc_filter_type of 0, bit_shift is the number of left-shifts
|
||||
* where 0xFF would still fall within the hash mask.
|
||||
*/
|
||||
while (hash_mask >> bit_shift != 0xFF)
|
||||
bit_shift++;
|
||||
|
||||
/* The portion of the address that is used for the hash table
|
||||
* is determined by the mc_filter_type setting.
|
||||
* The algorithm is such that there is a total of 8 bits of shifting.
|
||||
* The bit_shift for a mc_filter_type of 0 represents the number of
|
||||
* left-shifts where the MSB of mc_addr[5] would still fall within
|
||||
* the hash_mask. Case 0 does this exactly. Since there are a total
|
||||
* of 8 bits of shifting, then mc_addr[4] will shift right the
|
||||
* remaining number of bits. Thus 8 - bit_shift. The rest of the
|
||||
* cases are a variation of this algorithm...essentially raising the
|
||||
* number of bits to shift mc_addr[5] left, while still keeping the
|
||||
* 8-bit shifting total.
|
||||
*
|
||||
* For example, given the following Destination MAC Address and an
|
||||
* MTA register count of 128 (thus a 4096-bit vector and 0xFFF mask),
|
||||
* we can see that the bit_shift for case 0 is 4. These are the hash
|
||||
* values resulting from each mc_filter_type...
|
||||
* [0] [1] [2] [3] [4] [5]
|
||||
* 01 AA 00 12 34 56
|
||||
* LSB MSB
|
||||
*
|
||||
* case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
|
||||
* case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
|
||||
* case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
|
||||
* case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
|
||||
*/
|
||||
switch (hw->mac.mc_filter_type) {
|
||||
default:
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
bit_shift += 1;
|
||||
break;
|
||||
case 2:
|
||||
bit_shift += 2;
|
||||
break;
|
||||
case 3:
|
||||
bit_shift += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
|
||||
(((u16)mc_addr[5]) << bit_shift)));
|
||||
|
||||
return hash_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 entire 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)
|
||||
{
|
||||
u32 hash_value, hash_bit, hash_reg;
|
||||
int i;
|
||||
|
||||
/* clear mta_shadow */
|
||||
memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
|
||||
|
||||
/* update mta_shadow from mc_addr_list */
|
||||
for (i = 0; (u32)i < mc_addr_count; i++) {
|
||||
hash_value = igc_hash_mc_addr(hw, mc_addr_list);
|
||||
|
||||
hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
|
||||
hash_bit = hash_value & 0x1F;
|
||||
|
||||
hw->mac.mta_shadow[hash_reg] |= BIT(hash_bit);
|
||||
mc_addr_list += ETH_ALEN;
|
||||
}
|
||||
|
||||
/* replace the entire MTA table */
|
||||
for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
|
||||
array_wr32(IGC_MTA, i, hw->mac.mta_shadow[i]);
|
||||
wrfl();
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_MAC_H_
|
||||
#define _IGC_MAC_H_
|
||||
|
||||
#include "igc_hw-6.4-ethercat.h"
|
||||
#include "igc_phy-6.4-ethercat.h"
|
||||
#include "igc_defines-6.4-ethercat.h"
|
||||
|
||||
/* forward declaration */
|
||||
s32 igc_disable_pcie_master(struct igc_hw *hw);
|
||||
s32 igc_check_for_copper_link(struct igc_hw *hw);
|
||||
s32 igc_config_fc_after_link_up(struct igc_hw *hw);
|
||||
s32 igc_force_mac_fc(struct igc_hw *hw);
|
||||
void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count);
|
||||
s32 igc_setup_link(struct igc_hw *hw);
|
||||
void igc_clear_hw_cntrs_base(struct igc_hw *hw);
|
||||
s32 igc_get_auto_rd_done(struct igc_hw *hw);
|
||||
void igc_put_hw_semaphore(struct igc_hw *hw);
|
||||
void igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index);
|
||||
void igc_config_collision_dist(struct igc_hw *hw);
|
||||
|
||||
s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,
|
||||
u16 *duplex);
|
||||
|
||||
bool igc_enable_mng_pass_thru(struct igc_hw *hw);
|
||||
void igc_update_mc_addr_list(struct igc_hw *hw,
|
||||
u8 *mc_addr_list, u32 mc_addr_count);
|
||||
|
||||
enum igc_mng_mode {
|
||||
igc_mng_mode_none = 0,
|
||||
igc_mng_mode_asf,
|
||||
igc_mng_mode_pt,
|
||||
igc_mng_mode_ipmi,
|
||||
igc_mng_mode_host_if_only
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,881 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "igc_mac.h"
|
||||
#include "igc_hw.h"
|
||||
|
||||
/**
|
||||
* igc_disable_pcie_master - Disables PCI-express master access
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Returns 0 (0) if successful, else returns -10
|
||||
* (-IGC_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
|
||||
* the master requests to be disabled.
|
||||
*
|
||||
* Disables PCI-Express master access and verifies there are no pending
|
||||
* requests.
|
||||
*/
|
||||
s32 igc_disable_pcie_master(struct igc_hw *hw)
|
||||
{
|
||||
s32 timeout = MASTER_DISABLE_TIMEOUT;
|
||||
s32 ret_val = 0;
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
ctrl |= IGC_CTRL_GIO_MASTER_DISABLE;
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
|
||||
while (timeout) {
|
||||
if (!(rd32(IGC_STATUS) &
|
||||
IGC_STATUS_GIO_MASTER_ENABLE))
|
||||
break;
|
||||
usleep_range(2000, 3000);
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
hw_dbg("Master requests are pending.\n");
|
||||
ret_val = -IGC_ERR_MASTER_REQUESTS_PENDING;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_rx_addrs - Initialize receive addresses
|
||||
* @hw: pointer to the HW structure
|
||||
* @rar_count: receive address registers
|
||||
*
|
||||
* Setup the receive address registers by setting the base receive address
|
||||
* register to the devices MAC address and clearing all the other receive
|
||||
* address registers to 0.
|
||||
*/
|
||||
void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count)
|
||||
{
|
||||
u8 mac_addr[ETH_ALEN] = {0};
|
||||
u32 i;
|
||||
|
||||
/* Setup the receive address */
|
||||
hw_dbg("Programming MAC Address into RAR[0]\n");
|
||||
|
||||
hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
|
||||
|
||||
/* Zero out the other (rar_entry_count - 1) receive addresses */
|
||||
hw_dbg("Clearing RAR[1-%u]\n", rar_count - 1);
|
||||
for (i = 1; i < rar_count; i++)
|
||||
hw->mac.ops.rar_set(hw, mac_addr, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_set_fc_watermarks - Set flow control high/low watermarks
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Sets the flow control high/low threshold (watermark) registers. If
|
||||
* flow control XON frame transmission is enabled, then set XON frame
|
||||
* transmission as well.
|
||||
*/
|
||||
static s32 igc_set_fc_watermarks(struct igc_hw *hw)
|
||||
{
|
||||
u32 fcrtl = 0, fcrth = 0;
|
||||
|
||||
/* Set the flow control receive threshold registers. Normally,
|
||||
* these registers will be set to a default threshold that may be
|
||||
* adjusted later by the driver's runtime code. However, if the
|
||||
* ability to transmit pause frames is not enabled, then these
|
||||
* registers will be set to 0.
|
||||
*/
|
||||
if (hw->fc.current_mode & igc_fc_tx_pause) {
|
||||
/* We need to set up the Receive Threshold high and low water
|
||||
* marks as well as (optionally) enabling the transmission of
|
||||
* XON frames.
|
||||
*/
|
||||
fcrtl = hw->fc.low_water;
|
||||
if (hw->fc.send_xon)
|
||||
fcrtl |= IGC_FCRTL_XONE;
|
||||
|
||||
fcrth = hw->fc.high_water;
|
||||
}
|
||||
wr32(IGC_FCRTL, fcrtl);
|
||||
wr32(IGC_FCRTH, fcrth);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_setup_link - Setup flow control and link settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Determines which flow control settings to use, then configures flow
|
||||
* control. Calls the appropriate media-specific link configuration
|
||||
* function. Assuming the adapter has a valid link partner, a valid link
|
||||
* should be established. Assumes the hardware has previously been reset
|
||||
* and the transmitter and receiver are not enabled.
|
||||
*/
|
||||
s32 igc_setup_link(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* In the case of the phy reset being blocked, we already have a link.
|
||||
* We do not need to set it up again.
|
||||
*/
|
||||
if (igc_check_reset_block(hw))
|
||||
goto out;
|
||||
|
||||
/* If requested flow control is set to default, set flow control
|
||||
* to the both 'rx' and 'tx' pause frames.
|
||||
*/
|
||||
if (hw->fc.requested_mode == igc_fc_default)
|
||||
hw->fc.requested_mode = igc_fc_full;
|
||||
|
||||
/* We want to save off the original Flow Control configuration just
|
||||
* in case we get disconnected and then reconnected into a different
|
||||
* hub or switch with different Flow Control capabilities.
|
||||
*/
|
||||
hw->fc.current_mode = hw->fc.requested_mode;
|
||||
|
||||
hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode);
|
||||
|
||||
/* Call the necessary media_type subroutine to configure the link. */
|
||||
ret_val = hw->mac.ops.setup_physical_interface(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* Initialize the flow control address, type, and PAUSE timer
|
||||
* registers to their default values. This is done even if flow
|
||||
* control is disabled, because it does not hurt anything to
|
||||
* initialize these registers.
|
||||
*/
|
||||
hw_dbg("Initializing the Flow Control address, type and timer regs\n");
|
||||
wr32(IGC_FCT, FLOW_CONTROL_TYPE);
|
||||
wr32(IGC_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
|
||||
wr32(IGC_FCAL, FLOW_CONTROL_ADDRESS_LOW);
|
||||
|
||||
wr32(IGC_FCTTV, hw->fc.pause_time);
|
||||
|
||||
ret_val = igc_set_fc_watermarks(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_force_mac_fc - Force the MAC's flow control settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the
|
||||
* device control register to reflect the adapter settings. TFCE and RFCE
|
||||
* need to be explicitly set by software when a copper PHY is used because
|
||||
* autonegotiation is managed by the PHY rather than the MAC. Software must
|
||||
* also configure these bits when link is forced on a fiber connection.
|
||||
*/
|
||||
s32 igc_force_mac_fc(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
|
||||
/* Because we didn't get link via the internal auto-negotiation
|
||||
* mechanism (we either forced link or we got link via PHY
|
||||
* auto-neg), we have to manually enable/disable transmit an
|
||||
* receive flow control.
|
||||
*
|
||||
* The "Case" statement below enables/disable flow control
|
||||
* according to the "hw->fc.current_mode" parameter.
|
||||
*
|
||||
* The possible values of the "fc" parameter are:
|
||||
* 0: Flow control is completely disabled
|
||||
* 1: Rx flow control is enabled (we can receive pause
|
||||
* frames but not send pause frames).
|
||||
* 2: Tx flow control is enabled (we can send pause frames
|
||||
* but we do not receive pause frames).
|
||||
* 3: Both Rx and TX flow control (symmetric) is enabled.
|
||||
* other: No other values should be possible at this point.
|
||||
*/
|
||||
hw_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode);
|
||||
|
||||
switch (hw->fc.current_mode) {
|
||||
case igc_fc_none:
|
||||
ctrl &= (~(IGC_CTRL_TFCE | IGC_CTRL_RFCE));
|
||||
break;
|
||||
case igc_fc_rx_pause:
|
||||
ctrl &= (~IGC_CTRL_TFCE);
|
||||
ctrl |= IGC_CTRL_RFCE;
|
||||
break;
|
||||
case igc_fc_tx_pause:
|
||||
ctrl &= (~IGC_CTRL_RFCE);
|
||||
ctrl |= IGC_CTRL_TFCE;
|
||||
break;
|
||||
case igc_fc_full:
|
||||
ctrl |= (IGC_CTRL_TFCE | IGC_CTRL_RFCE);
|
||||
break;
|
||||
default:
|
||||
hw_dbg("Flow control param set incorrectly\n");
|
||||
ret_val = -IGC_ERR_CONFIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_clear_hw_cntrs_base - Clear base hardware counters
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Clears the base hardware counters by reading the counter registers.
|
||||
*/
|
||||
void igc_clear_hw_cntrs_base(struct igc_hw *hw)
|
||||
{
|
||||
rd32(IGC_CRCERRS);
|
||||
rd32(IGC_MPC);
|
||||
rd32(IGC_SCC);
|
||||
rd32(IGC_ECOL);
|
||||
rd32(IGC_MCC);
|
||||
rd32(IGC_LATECOL);
|
||||
rd32(IGC_COLC);
|
||||
rd32(IGC_RERC);
|
||||
rd32(IGC_DC);
|
||||
rd32(IGC_RLEC);
|
||||
rd32(IGC_XONRXC);
|
||||
rd32(IGC_XONTXC);
|
||||
rd32(IGC_XOFFRXC);
|
||||
rd32(IGC_XOFFTXC);
|
||||
rd32(IGC_FCRUC);
|
||||
rd32(IGC_GPRC);
|
||||
rd32(IGC_BPRC);
|
||||
rd32(IGC_MPRC);
|
||||
rd32(IGC_GPTC);
|
||||
rd32(IGC_GORCL);
|
||||
rd32(IGC_GORCH);
|
||||
rd32(IGC_GOTCL);
|
||||
rd32(IGC_GOTCH);
|
||||
rd32(IGC_RNBC);
|
||||
rd32(IGC_RUC);
|
||||
rd32(IGC_RFC);
|
||||
rd32(IGC_ROC);
|
||||
rd32(IGC_RJC);
|
||||
rd32(IGC_TORL);
|
||||
rd32(IGC_TORH);
|
||||
rd32(IGC_TOTL);
|
||||
rd32(IGC_TOTH);
|
||||
rd32(IGC_TPR);
|
||||
rd32(IGC_TPT);
|
||||
rd32(IGC_MPTC);
|
||||
rd32(IGC_BPTC);
|
||||
|
||||
rd32(IGC_PRC64);
|
||||
rd32(IGC_PRC127);
|
||||
rd32(IGC_PRC255);
|
||||
rd32(IGC_PRC511);
|
||||
rd32(IGC_PRC1023);
|
||||
rd32(IGC_PRC1522);
|
||||
rd32(IGC_PTC64);
|
||||
rd32(IGC_PTC127);
|
||||
rd32(IGC_PTC255);
|
||||
rd32(IGC_PTC511);
|
||||
rd32(IGC_PTC1023);
|
||||
rd32(IGC_PTC1522);
|
||||
|
||||
rd32(IGC_ALGNERRC);
|
||||
rd32(IGC_RXERRC);
|
||||
rd32(IGC_TNCRS);
|
||||
rd32(IGC_HTDPMC);
|
||||
rd32(IGC_TSCTC);
|
||||
|
||||
rd32(IGC_MGTPRC);
|
||||
rd32(IGC_MGTPDC);
|
||||
rd32(IGC_MGTPTC);
|
||||
|
||||
rd32(IGC_IAC);
|
||||
|
||||
rd32(IGC_RPTHC);
|
||||
rd32(IGC_TLPIC);
|
||||
rd32(IGC_RLPIC);
|
||||
rd32(IGC_HGPTC);
|
||||
rd32(IGC_RXDMTC);
|
||||
rd32(IGC_HGORCL);
|
||||
rd32(IGC_HGORCH);
|
||||
rd32(IGC_HGOTCL);
|
||||
rd32(IGC_HGOTCH);
|
||||
rd32(IGC_LENERRS);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_rar_set - Set receive address register
|
||||
* @hw: pointer to the HW structure
|
||||
* @addr: pointer to the receive address
|
||||
* @index: receive address array register
|
||||
*
|
||||
* Sets the receive address array register at index to the address passed
|
||||
* in by addr.
|
||||
*/
|
||||
void igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index)
|
||||
{
|
||||
u32 rar_low, rar_high;
|
||||
|
||||
/* HW expects these in little endian so we reverse the byte order
|
||||
* from network order (big endian) to little endian
|
||||
*/
|
||||
rar_low = ((u32)addr[0] |
|
||||
((u32)addr[1] << 8) |
|
||||
((u32)addr[2] << 16) | ((u32)addr[3] << 24));
|
||||
|
||||
rar_high = ((u32)addr[4] | ((u32)addr[5] << 8));
|
||||
|
||||
/* If MAC address zero, no need to set the AV bit */
|
||||
if (rar_low || rar_high)
|
||||
rar_high |= IGC_RAH_AV;
|
||||
|
||||
/* Some bridges will combine consecutive 32-bit writes into
|
||||
* a single burst write, which will malfunction on some parts.
|
||||
* The flushes avoid this.
|
||||
*/
|
||||
wr32(IGC_RAL(index), rar_low);
|
||||
wrfl();
|
||||
wr32(IGC_RAH(index), rar_high);
|
||||
wrfl();
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_check_for_copper_link - Check for link (Copper)
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Checks to see of the link status of the hardware has changed. If a
|
||||
* change in link status has been detected, then we read the PHY registers
|
||||
* to get the current speed/duplex if link exists.
|
||||
*/
|
||||
s32 igc_check_for_copper_link(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
bool link = false;
|
||||
s32 ret_val;
|
||||
|
||||
/* We only want to go out to the PHY registers to see if Auto-Neg
|
||||
* has completed and/or if our link status has changed. The
|
||||
* get_link_status flag is set upon receiving a Link Status
|
||||
* Change or Rx Sequence Error interrupt.
|
||||
*/
|
||||
if (!mac->get_link_status) {
|
||||
ret_val = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* First we want to see if the MII Status Register reports
|
||||
* link. If so, then we want to get the current speed/duplex
|
||||
* of the PHY.
|
||||
*/
|
||||
ret_val = igc_phy_has_link(hw, 1, 0, &link);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
if (!link)
|
||||
goto out; /* No link detected */
|
||||
|
||||
mac->get_link_status = false;
|
||||
|
||||
/* Check if there was DownShift, must be checked
|
||||
* immediately after link-up
|
||||
*/
|
||||
igc_check_downshift(hw);
|
||||
|
||||
/* If we are forcing speed/duplex, then we simply return since
|
||||
* we have already determined whether we have link or not.
|
||||
*/
|
||||
if (!mac->autoneg) {
|
||||
ret_val = -IGC_ERR_CONFIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Auto-Neg is enabled. Auto Speed Detection takes care
|
||||
* of MAC speed/duplex configuration. So we only need to
|
||||
* configure Collision Distance in the MAC.
|
||||
*/
|
||||
igc_config_collision_dist(hw);
|
||||
|
||||
/* Configure Flow Control now that Auto-Neg has completed.
|
||||
* First, we need to restore the desired flow control
|
||||
* settings because we may have had to re-autoneg with a
|
||||
* different link partner.
|
||||
*/
|
||||
ret_val = igc_config_fc_after_link_up(hw);
|
||||
if (ret_val)
|
||||
hw_dbg("Error configuring flow control\n");
|
||||
|
||||
out:
|
||||
/* Now that we are aware of our link settings, we can set the LTR
|
||||
* thresholds.
|
||||
*/
|
||||
ret_val = igc_set_ltr_i225(hw, link);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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. Currently no func pointer exists and all
|
||||
* implementations are handled in the generic version of this function.
|
||||
*/
|
||||
void igc_config_collision_dist(struct igc_hw *hw)
|
||||
{
|
||||
u32 tctl;
|
||||
|
||||
tctl = rd32(IGC_TCTL);
|
||||
|
||||
tctl &= ~IGC_TCTL_COLD;
|
||||
tctl |= IGC_COLLISION_DISTANCE << IGC_COLD_SHIFT;
|
||||
|
||||
wr32(IGC_TCTL, tctl);
|
||||
wrfl();
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_config_fc_after_link_up - Configures flow control after link
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Checks the status of auto-negotiation after link up to ensure that the
|
||||
* speed and duplex were not forced. If the link needed to be forced, then
|
||||
* flow control needs to be forced also. If auto-negotiation is enabled
|
||||
* and did not fail, then we configure flow control based on our link
|
||||
* partner.
|
||||
*/
|
||||
s32 igc_config_fc_after_link_up(struct igc_hw *hw)
|
||||
{
|
||||
u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
u16 speed, duplex;
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* Check for the case where we have fiber media and auto-neg failed
|
||||
* so we had to force link. In this case, we need to force the
|
||||
* configuration of the MAC to match the "fc" parameter.
|
||||
*/
|
||||
if (mac->autoneg_failed)
|
||||
ret_val = igc_force_mac_fc(hw);
|
||||
|
||||
if (ret_val) {
|
||||
hw_dbg("Error forcing flow control settings\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check for the case where we have copper media and auto-neg is
|
||||
* enabled. In this case, we need to check and see if Auto-Neg
|
||||
* has completed, and if so, how the PHY and link partner has
|
||||
* flow control configured.
|
||||
*/
|
||||
if (mac->autoneg) {
|
||||
/* Read the MII Status Register and check to see if AutoNeg
|
||||
* has completed. We read this twice because this reg has
|
||||
* some "sticky" (latched) bits.
|
||||
*/
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
|
||||
&mii_status_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
|
||||
&mii_status_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
|
||||
hw_dbg("Copper PHY and Auto Neg has not completed.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The AutoNeg process has completed, so we now need to
|
||||
* read both the Auto Negotiation Advertisement
|
||||
* Register (Address 4) and the Auto_Negotiation Base
|
||||
* Page Ability Register (Address 5) to determine how
|
||||
* flow control was negotiated.
|
||||
*/
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
|
||||
&mii_nway_adv_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
|
||||
&mii_nway_lp_ability_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
/* Two bits in the Auto Negotiation Advertisement Register
|
||||
* (Address 4) and two bits in the Auto Negotiation Base
|
||||
* Page Ability Register (Address 5) determine flow control
|
||||
* for both the PHY and the link partner. The following
|
||||
* table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
|
||||
* 1999, describes these PAUSE resolution bits and how flow
|
||||
* control is determined based upon these settings.
|
||||
* NOTE: DC = Don't Care
|
||||
*
|
||||
* LOCAL DEVICE | LINK PARTNER
|
||||
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
|
||||
*-------|---------|-------|---------|--------------------
|
||||
* 0 | 0 | DC | DC | igc_fc_none
|
||||
* 0 | 1 | 0 | DC | igc_fc_none
|
||||
* 0 | 1 | 1 | 0 | igc_fc_none
|
||||
* 0 | 1 | 1 | 1 | igc_fc_tx_pause
|
||||
* 1 | 0 | 0 | DC | igc_fc_none
|
||||
* 1 | DC | 1 | DC | igc_fc_full
|
||||
* 1 | 1 | 0 | 0 | igc_fc_none
|
||||
* 1 | 1 | 0 | 1 | igc_fc_rx_pause
|
||||
*
|
||||
* Are both PAUSE bits set to 1? If so, this implies
|
||||
* Symmetric Flow Control is enabled at both ends. The
|
||||
* ASM_DIR bits are irrelevant per the spec.
|
||||
*
|
||||
* For Symmetric Flow Control:
|
||||
*
|
||||
* LOCAL DEVICE | LINK PARTNER
|
||||
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
|
||||
*-------|---------|-------|---------|--------------------
|
||||
* 1 | DC | 1 | DC | IGC_fc_full
|
||||
*
|
||||
*/
|
||||
if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
|
||||
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
|
||||
/* Now we need to check if the user selected RX ONLY
|
||||
* of pause frames. In this case, we had to advertise
|
||||
* FULL flow control because we could not advertise RX
|
||||
* ONLY. Hence, we must now check to see if we need to
|
||||
* turn OFF the TRANSMISSION of PAUSE frames.
|
||||
*/
|
||||
if (hw->fc.requested_mode == igc_fc_full) {
|
||||
hw->fc.current_mode = igc_fc_full;
|
||||
hw_dbg("Flow Control = FULL.\n");
|
||||
} else {
|
||||
hw->fc.current_mode = igc_fc_rx_pause;
|
||||
hw_dbg("Flow Control = RX PAUSE frames only.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* For receiving PAUSE frames ONLY.
|
||||
*
|
||||
* LOCAL DEVICE | LINK PARTNER
|
||||
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
|
||||
*-------|---------|-------|---------|--------------------
|
||||
* 0 | 1 | 1 | 1 | igc_fc_tx_pause
|
||||
*/
|
||||
else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
|
||||
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
|
||||
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
|
||||
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
|
||||
hw->fc.current_mode = igc_fc_tx_pause;
|
||||
hw_dbg("Flow Control = TX PAUSE frames only.\n");
|
||||
}
|
||||
/* For transmitting PAUSE frames ONLY.
|
||||
*
|
||||
* LOCAL DEVICE | LINK PARTNER
|
||||
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
|
||||
*-------|---------|-------|---------|--------------------
|
||||
* 1 | 1 | 0 | 1 | igc_fc_rx_pause
|
||||
*/
|
||||
else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
|
||||
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
|
||||
!(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
|
||||
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
|
||||
hw->fc.current_mode = igc_fc_rx_pause;
|
||||
hw_dbg("Flow Control = RX PAUSE frames only.\n");
|
||||
}
|
||||
/* Per the IEEE spec, at this point flow control should be
|
||||
* disabled. However, we want to consider that we could
|
||||
* be connected to a legacy switch that doesn't advertise
|
||||
* desired flow control, but can be forced on the link
|
||||
* partner. So if we advertised no flow control, that is
|
||||
* what we will resolve to. If we advertised some kind of
|
||||
* receive capability (Rx Pause Only or Full Flow Control)
|
||||
* and the link partner advertised none, we will configure
|
||||
* ourselves to enable Rx Flow Control only. We can do
|
||||
* this safely for two reasons: If the link partner really
|
||||
* didn't want flow control enabled, and we enable Rx, no
|
||||
* harm done since we won't be receiving any PAUSE frames
|
||||
* anyway. If the intent on the link partner was to have
|
||||
* flow control enabled, then by us enabling RX only, we
|
||||
* can at least receive pause frames and process them.
|
||||
* This is a good idea because in most cases, since we are
|
||||
* predominantly a server NIC, more times than not we will
|
||||
* be asked to delay transmission of packets than asking
|
||||
* our link partner to pause transmission of frames.
|
||||
*/
|
||||
else if ((hw->fc.requested_mode == igc_fc_none) ||
|
||||
(hw->fc.requested_mode == igc_fc_tx_pause) ||
|
||||
(hw->fc.strict_ieee)) {
|
||||
hw->fc.current_mode = igc_fc_none;
|
||||
hw_dbg("Flow Control = NONE.\n");
|
||||
} else {
|
||||
hw->fc.current_mode = igc_fc_rx_pause;
|
||||
hw_dbg("Flow Control = RX PAUSE frames only.\n");
|
||||
}
|
||||
|
||||
/* Now we need to do one last check... If we auto-
|
||||
* negotiated to HALF DUPLEX, flow control should not be
|
||||
* enabled per IEEE 802.3 spec.
|
||||
*/
|
||||
ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error getting link speed and duplex\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (duplex == HALF_DUPLEX)
|
||||
hw->fc.current_mode = igc_fc_none;
|
||||
|
||||
/* Now we call a subroutine to actually force the MAC
|
||||
* controller to use the correct flow control settings.
|
||||
*/
|
||||
ret_val = igc_force_mac_fc(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error forcing flow control settings\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_auto_rd_done - Check for auto read completion
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Check EEPROM for Auto Read done bit.
|
||||
*/
|
||||
s32 igc_get_auto_rd_done(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
s32 i = 0;
|
||||
|
||||
while (i < AUTO_READ_DONE_TIMEOUT) {
|
||||
if (rd32(IGC_EECD) & IGC_EECD_AUTO_RD)
|
||||
break;
|
||||
usleep_range(1000, 2000);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == AUTO_READ_DONE_TIMEOUT) {
|
||||
hw_dbg("Auto read by HW from NVM has not completed.\n");
|
||||
ret_val = -IGC_ERR_RESET;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_speed_and_duplex_copper - Retrieve current speed/duplex
|
||||
* @hw: pointer to the HW structure
|
||||
* @speed: stores the current speed
|
||||
* @duplex: stores the current duplex
|
||||
*
|
||||
* Read the status register for the current speed/duplex and store the current
|
||||
* speed and duplex for copper connections.
|
||||
*/
|
||||
s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,
|
||||
u16 *duplex)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
status = rd32(IGC_STATUS);
|
||||
if (status & IGC_STATUS_SPEED_1000) {
|
||||
/* For I225, STATUS will indicate 1G speed in both 1 Gbps
|
||||
* and 2.5 Gbps link modes. An additional bit is used
|
||||
* to differentiate between 1 Gbps and 2.5 Gbps.
|
||||
*/
|
||||
if (hw->mac.type == igc_i225 &&
|
||||
(status & IGC_STATUS_SPEED_2500)) {
|
||||
*speed = SPEED_2500;
|
||||
hw_dbg("2500 Mbs, ");
|
||||
} else {
|
||||
*speed = SPEED_1000;
|
||||
hw_dbg("1000 Mbs, ");
|
||||
}
|
||||
} else if (status & IGC_STATUS_SPEED_100) {
|
||||
*speed = SPEED_100;
|
||||
hw_dbg("100 Mbs, ");
|
||||
} else {
|
||||
*speed = SPEED_10;
|
||||
hw_dbg("10 Mbs, ");
|
||||
}
|
||||
|
||||
if (status & IGC_STATUS_FD) {
|
||||
*duplex = FULL_DUPLEX;
|
||||
hw_dbg("Full Duplex\n");
|
||||
} else {
|
||||
*duplex = HALF_DUPLEX;
|
||||
hw_dbg("Half Duplex\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_put_hw_semaphore - Release hardware semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Release hardware semaphore used to access the PHY or NVM
|
||||
*/
|
||||
void igc_put_hw_semaphore(struct igc_hw *hw)
|
||||
{
|
||||
u32 swsm;
|
||||
|
||||
swsm = rd32(IGC_SWSM);
|
||||
|
||||
swsm &= ~(IGC_SWSM_SMBI | IGC_SWSM_SWESMBI);
|
||||
|
||||
wr32(IGC_SWSM, swsm);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_enable_mng_pass_thru - Enable processing of ARP's
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Verifies the hardware needs to leave interface enabled so that frames can
|
||||
* be directed to and from the management interface.
|
||||
*/
|
||||
bool igc_enable_mng_pass_thru(struct igc_hw *hw)
|
||||
{
|
||||
bool ret_val = false;
|
||||
u32 fwsm, factps;
|
||||
u32 manc;
|
||||
|
||||
if (!hw->mac.asf_firmware_present)
|
||||
goto out;
|
||||
|
||||
manc = rd32(IGC_MANC);
|
||||
|
||||
if (!(manc & IGC_MANC_RCV_TCO_EN))
|
||||
goto out;
|
||||
|
||||
if (hw->mac.arc_subsystem_valid) {
|
||||
fwsm = rd32(IGC_FWSM);
|
||||
factps = rd32(IGC_FACTPS);
|
||||
|
||||
if (!(factps & IGC_FACTPS_MNGCG) &&
|
||||
((fwsm & IGC_FWSM_MODE_MASK) ==
|
||||
(igc_mng_mode_pt << IGC_FWSM_MODE_SHIFT))) {
|
||||
ret_val = true;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if ((manc & IGC_MANC_SMBUS_EN) &&
|
||||
!(manc & IGC_MANC_ASF_EN)) {
|
||||
ret_val = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_hash_mc_addr - Generate a multicast hash value
|
||||
* @hw: pointer to the HW structure
|
||||
* @mc_addr: pointer to a multicast address
|
||||
*
|
||||
* Generates a multicast address hash value which is used to determine
|
||||
* the multicast filter table array address and new table value. See
|
||||
* igc_mta_set()
|
||||
**/
|
||||
static u32 igc_hash_mc_addr(struct igc_hw *hw, u8 *mc_addr)
|
||||
{
|
||||
u32 hash_value, hash_mask;
|
||||
u8 bit_shift = 0;
|
||||
|
||||
/* Register count multiplied by bits per register */
|
||||
hash_mask = (hw->mac.mta_reg_count * 32) - 1;
|
||||
|
||||
/* For a mc_filter_type of 0, bit_shift is the number of left-shifts
|
||||
* where 0xFF would still fall within the hash mask.
|
||||
*/
|
||||
while (hash_mask >> bit_shift != 0xFF)
|
||||
bit_shift++;
|
||||
|
||||
/* The portion of the address that is used for the hash table
|
||||
* is determined by the mc_filter_type setting.
|
||||
* The algorithm is such that there is a total of 8 bits of shifting.
|
||||
* The bit_shift for a mc_filter_type of 0 represents the number of
|
||||
* left-shifts where the MSB of mc_addr[5] would still fall within
|
||||
* the hash_mask. Case 0 does this exactly. Since there are a total
|
||||
* of 8 bits of shifting, then mc_addr[4] will shift right the
|
||||
* remaining number of bits. Thus 8 - bit_shift. The rest of the
|
||||
* cases are a variation of this algorithm...essentially raising the
|
||||
* number of bits to shift mc_addr[5] left, while still keeping the
|
||||
* 8-bit shifting total.
|
||||
*
|
||||
* For example, given the following Destination MAC Address and an
|
||||
* MTA register count of 128 (thus a 4096-bit vector and 0xFFF mask),
|
||||
* we can see that the bit_shift for case 0 is 4. These are the hash
|
||||
* values resulting from each mc_filter_type...
|
||||
* [0] [1] [2] [3] [4] [5]
|
||||
* 01 AA 00 12 34 56
|
||||
* LSB MSB
|
||||
*
|
||||
* case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
|
||||
* case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
|
||||
* case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
|
||||
* case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
|
||||
*/
|
||||
switch (hw->mac.mc_filter_type) {
|
||||
default:
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
bit_shift += 1;
|
||||
break;
|
||||
case 2:
|
||||
bit_shift += 2;
|
||||
break;
|
||||
case 3:
|
||||
bit_shift += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
|
||||
(((u16)mc_addr[5]) << bit_shift)));
|
||||
|
||||
return hash_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 entire 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)
|
||||
{
|
||||
u32 hash_value, hash_bit, hash_reg;
|
||||
int i;
|
||||
|
||||
/* clear mta_shadow */
|
||||
memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
|
||||
|
||||
/* update mta_shadow from mc_addr_list */
|
||||
for (i = 0; (u32)i < mc_addr_count; i++) {
|
||||
hash_value = igc_hash_mc_addr(hw, mc_addr_list);
|
||||
|
||||
hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
|
||||
hash_bit = hash_value & 0x1F;
|
||||
|
||||
hw->mac.mta_shadow[hash_reg] |= BIT(hash_bit);
|
||||
mc_addr_list += ETH_ALEN;
|
||||
}
|
||||
|
||||
/* replace the entire MTA table */
|
||||
for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
|
||||
array_wr32(IGC_MTA, i, hw->mac.mta_shadow[i]);
|
||||
wrfl();
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_MAC_H_
|
||||
#define _IGC_MAC_H_
|
||||
|
||||
#include "igc_hw.h"
|
||||
#include "igc_phy.h"
|
||||
#include "igc_defines.h"
|
||||
|
||||
/* forward declaration */
|
||||
s32 igc_disable_pcie_master(struct igc_hw *hw);
|
||||
s32 igc_check_for_copper_link(struct igc_hw *hw);
|
||||
s32 igc_config_fc_after_link_up(struct igc_hw *hw);
|
||||
s32 igc_force_mac_fc(struct igc_hw *hw);
|
||||
void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count);
|
||||
s32 igc_setup_link(struct igc_hw *hw);
|
||||
void igc_clear_hw_cntrs_base(struct igc_hw *hw);
|
||||
s32 igc_get_auto_rd_done(struct igc_hw *hw);
|
||||
void igc_put_hw_semaphore(struct igc_hw *hw);
|
||||
void igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index);
|
||||
void igc_config_collision_dist(struct igc_hw *hw);
|
||||
|
||||
s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,
|
||||
u16 *duplex);
|
||||
|
||||
bool igc_enable_mng_pass_thru(struct igc_hw *hw);
|
||||
void igc_update_mc_addr_list(struct igc_hw *hw,
|
||||
u8 *mc_addr_list, u32 mc_addr_count);
|
||||
|
||||
enum igc_mng_mode {
|
||||
igc_mng_mode_none = 0,
|
||||
igc_mng_mode_asf,
|
||||
igc_mng_mode_pt,
|
||||
igc_mng_mode_ipmi,
|
||||
igc_mng_mode_host_if_only
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,881 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "igc_mac-6.6-ethercat.h"
|
||||
#include "igc_hw-6.6-ethercat.h"
|
||||
|
||||
/**
|
||||
* igc_disable_pcie_master - Disables PCI-express master access
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Returns 0 (0) if successful, else returns -10
|
||||
* (-IGC_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
|
||||
* the master requests to be disabled.
|
||||
*
|
||||
* Disables PCI-Express master access and verifies there are no pending
|
||||
* requests.
|
||||
*/
|
||||
s32 igc_disable_pcie_master(struct igc_hw *hw)
|
||||
{
|
||||
s32 timeout = MASTER_DISABLE_TIMEOUT;
|
||||
s32 ret_val = 0;
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
ctrl |= IGC_CTRL_GIO_MASTER_DISABLE;
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
|
||||
while (timeout) {
|
||||
if (!(rd32(IGC_STATUS) &
|
||||
IGC_STATUS_GIO_MASTER_ENABLE))
|
||||
break;
|
||||
usleep_range(2000, 3000);
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
hw_dbg("Master requests are pending.\n");
|
||||
ret_val = -IGC_ERR_MASTER_REQUESTS_PENDING;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_rx_addrs - Initialize receive addresses
|
||||
* @hw: pointer to the HW structure
|
||||
* @rar_count: receive address registers
|
||||
*
|
||||
* Setup the receive address registers by setting the base receive address
|
||||
* register to the devices MAC address and clearing all the other receive
|
||||
* address registers to 0.
|
||||
*/
|
||||
void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count)
|
||||
{
|
||||
u8 mac_addr[ETH_ALEN] = {0};
|
||||
u32 i;
|
||||
|
||||
/* Setup the receive address */
|
||||
hw_dbg("Programming MAC Address into RAR[0]\n");
|
||||
|
||||
hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
|
||||
|
||||
/* Zero out the other (rar_entry_count - 1) receive addresses */
|
||||
hw_dbg("Clearing RAR[1-%u]\n", rar_count - 1);
|
||||
for (i = 1; i < rar_count; i++)
|
||||
hw->mac.ops.rar_set(hw, mac_addr, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_set_fc_watermarks - Set flow control high/low watermarks
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Sets the flow control high/low threshold (watermark) registers. If
|
||||
* flow control XON frame transmission is enabled, then set XON frame
|
||||
* transmission as well.
|
||||
*/
|
||||
static s32 igc_set_fc_watermarks(struct igc_hw *hw)
|
||||
{
|
||||
u32 fcrtl = 0, fcrth = 0;
|
||||
|
||||
/* Set the flow control receive threshold registers. Normally,
|
||||
* these registers will be set to a default threshold that may be
|
||||
* adjusted later by the driver's runtime code. However, if the
|
||||
* ability to transmit pause frames is not enabled, then these
|
||||
* registers will be set to 0.
|
||||
*/
|
||||
if (hw->fc.current_mode & igc_fc_tx_pause) {
|
||||
/* We need to set up the Receive Threshold high and low water
|
||||
* marks as well as (optionally) enabling the transmission of
|
||||
* XON frames.
|
||||
*/
|
||||
fcrtl = hw->fc.low_water;
|
||||
if (hw->fc.send_xon)
|
||||
fcrtl |= IGC_FCRTL_XONE;
|
||||
|
||||
fcrth = hw->fc.high_water;
|
||||
}
|
||||
wr32(IGC_FCRTL, fcrtl);
|
||||
wr32(IGC_FCRTH, fcrth);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_setup_link - Setup flow control and link settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Determines which flow control settings to use, then configures flow
|
||||
* control. Calls the appropriate media-specific link configuration
|
||||
* function. Assuming the adapter has a valid link partner, a valid link
|
||||
* should be established. Assumes the hardware has previously been reset
|
||||
* and the transmitter and receiver are not enabled.
|
||||
*/
|
||||
s32 igc_setup_link(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* In the case of the phy reset being blocked, we already have a link.
|
||||
* We do not need to set it up again.
|
||||
*/
|
||||
if (igc_check_reset_block(hw))
|
||||
goto out;
|
||||
|
||||
/* If requested flow control is set to default, set flow control
|
||||
* to the both 'rx' and 'tx' pause frames.
|
||||
*/
|
||||
if (hw->fc.requested_mode == igc_fc_default)
|
||||
hw->fc.requested_mode = igc_fc_full;
|
||||
|
||||
/* We want to save off the original Flow Control configuration just
|
||||
* in case we get disconnected and then reconnected into a different
|
||||
* hub or switch with different Flow Control capabilities.
|
||||
*/
|
||||
hw->fc.current_mode = hw->fc.requested_mode;
|
||||
|
||||
hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode);
|
||||
|
||||
/* Call the necessary media_type subroutine to configure the link. */
|
||||
ret_val = hw->mac.ops.setup_physical_interface(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* Initialize the flow control address, type, and PAUSE timer
|
||||
* registers to their default values. This is done even if flow
|
||||
* control is disabled, because it does not hurt anything to
|
||||
* initialize these registers.
|
||||
*/
|
||||
hw_dbg("Initializing the Flow Control address, type and timer regs\n");
|
||||
wr32(IGC_FCT, FLOW_CONTROL_TYPE);
|
||||
wr32(IGC_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
|
||||
wr32(IGC_FCAL, FLOW_CONTROL_ADDRESS_LOW);
|
||||
|
||||
wr32(IGC_FCTTV, hw->fc.pause_time);
|
||||
|
||||
ret_val = igc_set_fc_watermarks(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_force_mac_fc - Force the MAC's flow control settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the
|
||||
* device control register to reflect the adapter settings. TFCE and RFCE
|
||||
* need to be explicitly set by software when a copper PHY is used because
|
||||
* autonegotiation is managed by the PHY rather than the MAC. Software must
|
||||
* also configure these bits when link is forced on a fiber connection.
|
||||
*/
|
||||
s32 igc_force_mac_fc(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
|
||||
/* Because we didn't get link via the internal auto-negotiation
|
||||
* mechanism (we either forced link or we got link via PHY
|
||||
* auto-neg), we have to manually enable/disable transmit an
|
||||
* receive flow control.
|
||||
*
|
||||
* The "Case" statement below enables/disable flow control
|
||||
* according to the "hw->fc.current_mode" parameter.
|
||||
*
|
||||
* The possible values of the "fc" parameter are:
|
||||
* 0: Flow control is completely disabled
|
||||
* 1: Rx flow control is enabled (we can receive pause
|
||||
* frames but not send pause frames).
|
||||
* 2: Tx flow control is enabled (we can send pause frames
|
||||
* but we do not receive pause frames).
|
||||
* 3: Both Rx and TX flow control (symmetric) is enabled.
|
||||
* other: No other values should be possible at this point.
|
||||
*/
|
||||
hw_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode);
|
||||
|
||||
switch (hw->fc.current_mode) {
|
||||
case igc_fc_none:
|
||||
ctrl &= (~(IGC_CTRL_TFCE | IGC_CTRL_RFCE));
|
||||
break;
|
||||
case igc_fc_rx_pause:
|
||||
ctrl &= (~IGC_CTRL_TFCE);
|
||||
ctrl |= IGC_CTRL_RFCE;
|
||||
break;
|
||||
case igc_fc_tx_pause:
|
||||
ctrl &= (~IGC_CTRL_RFCE);
|
||||
ctrl |= IGC_CTRL_TFCE;
|
||||
break;
|
||||
case igc_fc_full:
|
||||
ctrl |= (IGC_CTRL_TFCE | IGC_CTRL_RFCE);
|
||||
break;
|
||||
default:
|
||||
hw_dbg("Flow control param set incorrectly\n");
|
||||
ret_val = -IGC_ERR_CONFIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_clear_hw_cntrs_base - Clear base hardware counters
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Clears the base hardware counters by reading the counter registers.
|
||||
*/
|
||||
void igc_clear_hw_cntrs_base(struct igc_hw *hw)
|
||||
{
|
||||
rd32(IGC_CRCERRS);
|
||||
rd32(IGC_MPC);
|
||||
rd32(IGC_SCC);
|
||||
rd32(IGC_ECOL);
|
||||
rd32(IGC_MCC);
|
||||
rd32(IGC_LATECOL);
|
||||
rd32(IGC_COLC);
|
||||
rd32(IGC_RERC);
|
||||
rd32(IGC_DC);
|
||||
rd32(IGC_RLEC);
|
||||
rd32(IGC_XONRXC);
|
||||
rd32(IGC_XONTXC);
|
||||
rd32(IGC_XOFFRXC);
|
||||
rd32(IGC_XOFFTXC);
|
||||
rd32(IGC_FCRUC);
|
||||
rd32(IGC_GPRC);
|
||||
rd32(IGC_BPRC);
|
||||
rd32(IGC_MPRC);
|
||||
rd32(IGC_GPTC);
|
||||
rd32(IGC_GORCL);
|
||||
rd32(IGC_GORCH);
|
||||
rd32(IGC_GOTCL);
|
||||
rd32(IGC_GOTCH);
|
||||
rd32(IGC_RNBC);
|
||||
rd32(IGC_RUC);
|
||||
rd32(IGC_RFC);
|
||||
rd32(IGC_ROC);
|
||||
rd32(IGC_RJC);
|
||||
rd32(IGC_TORL);
|
||||
rd32(IGC_TORH);
|
||||
rd32(IGC_TOTL);
|
||||
rd32(IGC_TOTH);
|
||||
rd32(IGC_TPR);
|
||||
rd32(IGC_TPT);
|
||||
rd32(IGC_MPTC);
|
||||
rd32(IGC_BPTC);
|
||||
|
||||
rd32(IGC_PRC64);
|
||||
rd32(IGC_PRC127);
|
||||
rd32(IGC_PRC255);
|
||||
rd32(IGC_PRC511);
|
||||
rd32(IGC_PRC1023);
|
||||
rd32(IGC_PRC1522);
|
||||
rd32(IGC_PTC64);
|
||||
rd32(IGC_PTC127);
|
||||
rd32(IGC_PTC255);
|
||||
rd32(IGC_PTC511);
|
||||
rd32(IGC_PTC1023);
|
||||
rd32(IGC_PTC1522);
|
||||
|
||||
rd32(IGC_ALGNERRC);
|
||||
rd32(IGC_RXERRC);
|
||||
rd32(IGC_TNCRS);
|
||||
rd32(IGC_HTDPMC);
|
||||
rd32(IGC_TSCTC);
|
||||
|
||||
rd32(IGC_MGTPRC);
|
||||
rd32(IGC_MGTPDC);
|
||||
rd32(IGC_MGTPTC);
|
||||
|
||||
rd32(IGC_IAC);
|
||||
|
||||
rd32(IGC_RPTHC);
|
||||
rd32(IGC_TLPIC);
|
||||
rd32(IGC_RLPIC);
|
||||
rd32(IGC_HGPTC);
|
||||
rd32(IGC_RXDMTC);
|
||||
rd32(IGC_HGORCL);
|
||||
rd32(IGC_HGORCH);
|
||||
rd32(IGC_HGOTCL);
|
||||
rd32(IGC_HGOTCH);
|
||||
rd32(IGC_LENERRS);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_rar_set - Set receive address register
|
||||
* @hw: pointer to the HW structure
|
||||
* @addr: pointer to the receive address
|
||||
* @index: receive address array register
|
||||
*
|
||||
* Sets the receive address array register at index to the address passed
|
||||
* in by addr.
|
||||
*/
|
||||
void igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index)
|
||||
{
|
||||
u32 rar_low, rar_high;
|
||||
|
||||
/* HW expects these in little endian so we reverse the byte order
|
||||
* from network order (big endian) to little endian
|
||||
*/
|
||||
rar_low = ((u32)addr[0] |
|
||||
((u32)addr[1] << 8) |
|
||||
((u32)addr[2] << 16) | ((u32)addr[3] << 24));
|
||||
|
||||
rar_high = ((u32)addr[4] | ((u32)addr[5] << 8));
|
||||
|
||||
/* If MAC address zero, no need to set the AV bit */
|
||||
if (rar_low || rar_high)
|
||||
rar_high |= IGC_RAH_AV;
|
||||
|
||||
/* Some bridges will combine consecutive 32-bit writes into
|
||||
* a single burst write, which will malfunction on some parts.
|
||||
* The flushes avoid this.
|
||||
*/
|
||||
wr32(IGC_RAL(index), rar_low);
|
||||
wrfl();
|
||||
wr32(IGC_RAH(index), rar_high);
|
||||
wrfl();
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_check_for_copper_link - Check for link (Copper)
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Checks to see of the link status of the hardware has changed. If a
|
||||
* change in link status has been detected, then we read the PHY registers
|
||||
* to get the current speed/duplex if link exists.
|
||||
*/
|
||||
s32 igc_check_for_copper_link(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
bool link = false;
|
||||
s32 ret_val;
|
||||
|
||||
/* We only want to go out to the PHY registers to see if Auto-Neg
|
||||
* has completed and/or if our link status has changed. The
|
||||
* get_link_status flag is set upon receiving a Link Status
|
||||
* Change or Rx Sequence Error interrupt.
|
||||
*/
|
||||
if (!mac->get_link_status) {
|
||||
ret_val = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* First we want to see if the MII Status Register reports
|
||||
* link. If so, then we want to get the current speed/duplex
|
||||
* of the PHY.
|
||||
*/
|
||||
ret_val = igc_phy_has_link(hw, 1, 0, &link);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
if (!link)
|
||||
goto out; /* No link detected */
|
||||
|
||||
mac->get_link_status = false;
|
||||
|
||||
/* Check if there was DownShift, must be checked
|
||||
* immediately after link-up
|
||||
*/
|
||||
igc_check_downshift(hw);
|
||||
|
||||
/* If we are forcing speed/duplex, then we simply return since
|
||||
* we have already determined whether we have link or not.
|
||||
*/
|
||||
if (!mac->autoneg) {
|
||||
ret_val = -IGC_ERR_CONFIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Auto-Neg is enabled. Auto Speed Detection takes care
|
||||
* of MAC speed/duplex configuration. So we only need to
|
||||
* configure Collision Distance in the MAC.
|
||||
*/
|
||||
igc_config_collision_dist(hw);
|
||||
|
||||
/* Configure Flow Control now that Auto-Neg has completed.
|
||||
* First, we need to restore the desired flow control
|
||||
* settings because we may have had to re-autoneg with a
|
||||
* different link partner.
|
||||
*/
|
||||
ret_val = igc_config_fc_after_link_up(hw);
|
||||
if (ret_val)
|
||||
hw_dbg("Error configuring flow control\n");
|
||||
|
||||
out:
|
||||
/* Now that we are aware of our link settings, we can set the LTR
|
||||
* thresholds.
|
||||
*/
|
||||
ret_val = igc_set_ltr_i225(hw, link);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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. Currently no func pointer exists and all
|
||||
* implementations are handled in the generic version of this function.
|
||||
*/
|
||||
void igc_config_collision_dist(struct igc_hw *hw)
|
||||
{
|
||||
u32 tctl;
|
||||
|
||||
tctl = rd32(IGC_TCTL);
|
||||
|
||||
tctl &= ~IGC_TCTL_COLD;
|
||||
tctl |= IGC_COLLISION_DISTANCE << IGC_COLD_SHIFT;
|
||||
|
||||
wr32(IGC_TCTL, tctl);
|
||||
wrfl();
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_config_fc_after_link_up - Configures flow control after link
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Checks the status of auto-negotiation after link up to ensure that the
|
||||
* speed and duplex were not forced. If the link needed to be forced, then
|
||||
* flow control needs to be forced also. If auto-negotiation is enabled
|
||||
* and did not fail, then we configure flow control based on our link
|
||||
* partner.
|
||||
*/
|
||||
s32 igc_config_fc_after_link_up(struct igc_hw *hw)
|
||||
{
|
||||
u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
u16 speed, duplex;
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* Check for the case where we have fiber media and auto-neg failed
|
||||
* so we had to force link. In this case, we need to force the
|
||||
* configuration of the MAC to match the "fc" parameter.
|
||||
*/
|
||||
if (mac->autoneg_failed)
|
||||
ret_val = igc_force_mac_fc(hw);
|
||||
|
||||
if (ret_val) {
|
||||
hw_dbg("Error forcing flow control settings\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check for the case where we have copper media and auto-neg is
|
||||
* enabled. In this case, we need to check and see if Auto-Neg
|
||||
* has completed, and if so, how the PHY and link partner has
|
||||
* flow control configured.
|
||||
*/
|
||||
if (mac->autoneg) {
|
||||
/* Read the MII Status Register and check to see if AutoNeg
|
||||
* has completed. We read this twice because this reg has
|
||||
* some "sticky" (latched) bits.
|
||||
*/
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
|
||||
&mii_status_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
|
||||
&mii_status_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
|
||||
hw_dbg("Copper PHY and Auto Neg has not completed.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The AutoNeg process has completed, so we now need to
|
||||
* read both the Auto Negotiation Advertisement
|
||||
* Register (Address 4) and the Auto_Negotiation Base
|
||||
* Page Ability Register (Address 5) to determine how
|
||||
* flow control was negotiated.
|
||||
*/
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
|
||||
&mii_nway_adv_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
|
||||
&mii_nway_lp_ability_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
/* Two bits in the Auto Negotiation Advertisement Register
|
||||
* (Address 4) and two bits in the Auto Negotiation Base
|
||||
* Page Ability Register (Address 5) determine flow control
|
||||
* for both the PHY and the link partner. The following
|
||||
* table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
|
||||
* 1999, describes these PAUSE resolution bits and how flow
|
||||
* control is determined based upon these settings.
|
||||
* NOTE: DC = Don't Care
|
||||
*
|
||||
* LOCAL DEVICE | LINK PARTNER
|
||||
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
|
||||
*-------|---------|-------|---------|--------------------
|
||||
* 0 | 0 | DC | DC | igc_fc_none
|
||||
* 0 | 1 | 0 | DC | igc_fc_none
|
||||
* 0 | 1 | 1 | 0 | igc_fc_none
|
||||
* 0 | 1 | 1 | 1 | igc_fc_tx_pause
|
||||
* 1 | 0 | 0 | DC | igc_fc_none
|
||||
* 1 | DC | 1 | DC | igc_fc_full
|
||||
* 1 | 1 | 0 | 0 | igc_fc_none
|
||||
* 1 | 1 | 0 | 1 | igc_fc_rx_pause
|
||||
*
|
||||
* Are both PAUSE bits set to 1? If so, this implies
|
||||
* Symmetric Flow Control is enabled at both ends. The
|
||||
* ASM_DIR bits are irrelevant per the spec.
|
||||
*
|
||||
* For Symmetric Flow Control:
|
||||
*
|
||||
* LOCAL DEVICE | LINK PARTNER
|
||||
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
|
||||
*-------|---------|-------|---------|--------------------
|
||||
* 1 | DC | 1 | DC | IGC_fc_full
|
||||
*
|
||||
*/
|
||||
if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
|
||||
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
|
||||
/* Now we need to check if the user selected RX ONLY
|
||||
* of pause frames. In this case, we had to advertise
|
||||
* FULL flow control because we could not advertise RX
|
||||
* ONLY. Hence, we must now check to see if we need to
|
||||
* turn OFF the TRANSMISSION of PAUSE frames.
|
||||
*/
|
||||
if (hw->fc.requested_mode == igc_fc_full) {
|
||||
hw->fc.current_mode = igc_fc_full;
|
||||
hw_dbg("Flow Control = FULL.\n");
|
||||
} else {
|
||||
hw->fc.current_mode = igc_fc_rx_pause;
|
||||
hw_dbg("Flow Control = RX PAUSE frames only.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* For receiving PAUSE frames ONLY.
|
||||
*
|
||||
* LOCAL DEVICE | LINK PARTNER
|
||||
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
|
||||
*-------|---------|-------|---------|--------------------
|
||||
* 0 | 1 | 1 | 1 | igc_fc_tx_pause
|
||||
*/
|
||||
else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
|
||||
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
|
||||
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
|
||||
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
|
||||
hw->fc.current_mode = igc_fc_tx_pause;
|
||||
hw_dbg("Flow Control = TX PAUSE frames only.\n");
|
||||
}
|
||||
/* For transmitting PAUSE frames ONLY.
|
||||
*
|
||||
* LOCAL DEVICE | LINK PARTNER
|
||||
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
|
||||
*-------|---------|-------|---------|--------------------
|
||||
* 1 | 1 | 0 | 1 | igc_fc_rx_pause
|
||||
*/
|
||||
else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
|
||||
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
|
||||
!(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
|
||||
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
|
||||
hw->fc.current_mode = igc_fc_rx_pause;
|
||||
hw_dbg("Flow Control = RX PAUSE frames only.\n");
|
||||
}
|
||||
/* Per the IEEE spec, at this point flow control should be
|
||||
* disabled. However, we want to consider that we could
|
||||
* be connected to a legacy switch that doesn't advertise
|
||||
* desired flow control, but can be forced on the link
|
||||
* partner. So if we advertised no flow control, that is
|
||||
* what we will resolve to. If we advertised some kind of
|
||||
* receive capability (Rx Pause Only or Full Flow Control)
|
||||
* and the link partner advertised none, we will configure
|
||||
* ourselves to enable Rx Flow Control only. We can do
|
||||
* this safely for two reasons: If the link partner really
|
||||
* didn't want flow control enabled, and we enable Rx, no
|
||||
* harm done since we won't be receiving any PAUSE frames
|
||||
* anyway. If the intent on the link partner was to have
|
||||
* flow control enabled, then by us enabling RX only, we
|
||||
* can at least receive pause frames and process them.
|
||||
* This is a good idea because in most cases, since we are
|
||||
* predominantly a server NIC, more times than not we will
|
||||
* be asked to delay transmission of packets than asking
|
||||
* our link partner to pause transmission of frames.
|
||||
*/
|
||||
else if ((hw->fc.requested_mode == igc_fc_none) ||
|
||||
(hw->fc.requested_mode == igc_fc_tx_pause) ||
|
||||
(hw->fc.strict_ieee)) {
|
||||
hw->fc.current_mode = igc_fc_none;
|
||||
hw_dbg("Flow Control = NONE.\n");
|
||||
} else {
|
||||
hw->fc.current_mode = igc_fc_rx_pause;
|
||||
hw_dbg("Flow Control = RX PAUSE frames only.\n");
|
||||
}
|
||||
|
||||
/* Now we need to do one last check... If we auto-
|
||||
* negotiated to HALF DUPLEX, flow control should not be
|
||||
* enabled per IEEE 802.3 spec.
|
||||
*/
|
||||
ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error getting link speed and duplex\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (duplex == HALF_DUPLEX)
|
||||
hw->fc.current_mode = igc_fc_none;
|
||||
|
||||
/* Now we call a subroutine to actually force the MAC
|
||||
* controller to use the correct flow control settings.
|
||||
*/
|
||||
ret_val = igc_force_mac_fc(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error forcing flow control settings\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_auto_rd_done - Check for auto read completion
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Check EEPROM for Auto Read done bit.
|
||||
*/
|
||||
s32 igc_get_auto_rd_done(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
s32 i = 0;
|
||||
|
||||
while (i < AUTO_READ_DONE_TIMEOUT) {
|
||||
if (rd32(IGC_EECD) & IGC_EECD_AUTO_RD)
|
||||
break;
|
||||
usleep_range(1000, 2000);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == AUTO_READ_DONE_TIMEOUT) {
|
||||
hw_dbg("Auto read by HW from NVM has not completed.\n");
|
||||
ret_val = -IGC_ERR_RESET;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_speed_and_duplex_copper - Retrieve current speed/duplex
|
||||
* @hw: pointer to the HW structure
|
||||
* @speed: stores the current speed
|
||||
* @duplex: stores the current duplex
|
||||
*
|
||||
* Read the status register for the current speed/duplex and store the current
|
||||
* speed and duplex for copper connections.
|
||||
*/
|
||||
s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,
|
||||
u16 *duplex)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
status = rd32(IGC_STATUS);
|
||||
if (status & IGC_STATUS_SPEED_1000) {
|
||||
/* For I225, STATUS will indicate 1G speed in both 1 Gbps
|
||||
* and 2.5 Gbps link modes. An additional bit is used
|
||||
* to differentiate between 1 Gbps and 2.5 Gbps.
|
||||
*/
|
||||
if (hw->mac.type == igc_i225 &&
|
||||
(status & IGC_STATUS_SPEED_2500)) {
|
||||
*speed = SPEED_2500;
|
||||
hw_dbg("2500 Mbs, ");
|
||||
} else {
|
||||
*speed = SPEED_1000;
|
||||
hw_dbg("1000 Mbs, ");
|
||||
}
|
||||
} else if (status & IGC_STATUS_SPEED_100) {
|
||||
*speed = SPEED_100;
|
||||
hw_dbg("100 Mbs, ");
|
||||
} else {
|
||||
*speed = SPEED_10;
|
||||
hw_dbg("10 Mbs, ");
|
||||
}
|
||||
|
||||
if (status & IGC_STATUS_FD) {
|
||||
*duplex = FULL_DUPLEX;
|
||||
hw_dbg("Full Duplex\n");
|
||||
} else {
|
||||
*duplex = HALF_DUPLEX;
|
||||
hw_dbg("Half Duplex\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_put_hw_semaphore - Release hardware semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Release hardware semaphore used to access the PHY or NVM
|
||||
*/
|
||||
void igc_put_hw_semaphore(struct igc_hw *hw)
|
||||
{
|
||||
u32 swsm;
|
||||
|
||||
swsm = rd32(IGC_SWSM);
|
||||
|
||||
swsm &= ~(IGC_SWSM_SMBI | IGC_SWSM_SWESMBI);
|
||||
|
||||
wr32(IGC_SWSM, swsm);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_enable_mng_pass_thru - Enable processing of ARP's
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Verifies the hardware needs to leave interface enabled so that frames can
|
||||
* be directed to and from the management interface.
|
||||
*/
|
||||
bool igc_enable_mng_pass_thru(struct igc_hw *hw)
|
||||
{
|
||||
bool ret_val = false;
|
||||
u32 fwsm, factps;
|
||||
u32 manc;
|
||||
|
||||
if (!hw->mac.asf_firmware_present)
|
||||
goto out;
|
||||
|
||||
manc = rd32(IGC_MANC);
|
||||
|
||||
if (!(manc & IGC_MANC_RCV_TCO_EN))
|
||||
goto out;
|
||||
|
||||
if (hw->mac.arc_subsystem_valid) {
|
||||
fwsm = rd32(IGC_FWSM);
|
||||
factps = rd32(IGC_FACTPS);
|
||||
|
||||
if (!(factps & IGC_FACTPS_MNGCG) &&
|
||||
((fwsm & IGC_FWSM_MODE_MASK) ==
|
||||
(igc_mng_mode_pt << IGC_FWSM_MODE_SHIFT))) {
|
||||
ret_val = true;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if ((manc & IGC_MANC_SMBUS_EN) &&
|
||||
!(manc & IGC_MANC_ASF_EN)) {
|
||||
ret_val = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_hash_mc_addr - Generate a multicast hash value
|
||||
* @hw: pointer to the HW structure
|
||||
* @mc_addr: pointer to a multicast address
|
||||
*
|
||||
* Generates a multicast address hash value which is used to determine
|
||||
* the multicast filter table array address and new table value. See
|
||||
* igc_mta_set()
|
||||
**/
|
||||
static u32 igc_hash_mc_addr(struct igc_hw *hw, u8 *mc_addr)
|
||||
{
|
||||
u32 hash_value, hash_mask;
|
||||
u8 bit_shift = 0;
|
||||
|
||||
/* Register count multiplied by bits per register */
|
||||
hash_mask = (hw->mac.mta_reg_count * 32) - 1;
|
||||
|
||||
/* For a mc_filter_type of 0, bit_shift is the number of left-shifts
|
||||
* where 0xFF would still fall within the hash mask.
|
||||
*/
|
||||
while (hash_mask >> bit_shift != 0xFF)
|
||||
bit_shift++;
|
||||
|
||||
/* The portion of the address that is used for the hash table
|
||||
* is determined by the mc_filter_type setting.
|
||||
* The algorithm is such that there is a total of 8 bits of shifting.
|
||||
* The bit_shift for a mc_filter_type of 0 represents the number of
|
||||
* left-shifts where the MSB of mc_addr[5] would still fall within
|
||||
* the hash_mask. Case 0 does this exactly. Since there are a total
|
||||
* of 8 bits of shifting, then mc_addr[4] will shift right the
|
||||
* remaining number of bits. Thus 8 - bit_shift. The rest of the
|
||||
* cases are a variation of this algorithm...essentially raising the
|
||||
* number of bits to shift mc_addr[5] left, while still keeping the
|
||||
* 8-bit shifting total.
|
||||
*
|
||||
* For example, given the following Destination MAC Address and an
|
||||
* MTA register count of 128 (thus a 4096-bit vector and 0xFFF mask),
|
||||
* we can see that the bit_shift for case 0 is 4. These are the hash
|
||||
* values resulting from each mc_filter_type...
|
||||
* [0] [1] [2] [3] [4] [5]
|
||||
* 01 AA 00 12 34 56
|
||||
* LSB MSB
|
||||
*
|
||||
* case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
|
||||
* case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
|
||||
* case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
|
||||
* case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
|
||||
*/
|
||||
switch (hw->mac.mc_filter_type) {
|
||||
default:
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
bit_shift += 1;
|
||||
break;
|
||||
case 2:
|
||||
bit_shift += 2;
|
||||
break;
|
||||
case 3:
|
||||
bit_shift += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
|
||||
(((u16)mc_addr[5]) << bit_shift)));
|
||||
|
||||
return hash_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 entire 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)
|
||||
{
|
||||
u32 hash_value, hash_bit, hash_reg;
|
||||
int i;
|
||||
|
||||
/* clear mta_shadow */
|
||||
memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
|
||||
|
||||
/* update mta_shadow from mc_addr_list */
|
||||
for (i = 0; (u32)i < mc_addr_count; i++) {
|
||||
hash_value = igc_hash_mc_addr(hw, mc_addr_list);
|
||||
|
||||
hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
|
||||
hash_bit = hash_value & 0x1F;
|
||||
|
||||
hw->mac.mta_shadow[hash_reg] |= BIT(hash_bit);
|
||||
mc_addr_list += ETH_ALEN;
|
||||
}
|
||||
|
||||
/* replace the entire MTA table */
|
||||
for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
|
||||
array_wr32(IGC_MTA, i, hw->mac.mta_shadow[i]);
|
||||
wrfl();
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_MAC_H_
|
||||
#define _IGC_MAC_H_
|
||||
|
||||
#include "igc_hw-6.6-ethercat.h"
|
||||
#include "igc_phy-6.6-ethercat.h"
|
||||
#include "igc_defines-6.6-ethercat.h"
|
||||
|
||||
/* forward declaration */
|
||||
s32 igc_disable_pcie_master(struct igc_hw *hw);
|
||||
s32 igc_check_for_copper_link(struct igc_hw *hw);
|
||||
s32 igc_config_fc_after_link_up(struct igc_hw *hw);
|
||||
s32 igc_force_mac_fc(struct igc_hw *hw);
|
||||
void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count);
|
||||
s32 igc_setup_link(struct igc_hw *hw);
|
||||
void igc_clear_hw_cntrs_base(struct igc_hw *hw);
|
||||
s32 igc_get_auto_rd_done(struct igc_hw *hw);
|
||||
void igc_put_hw_semaphore(struct igc_hw *hw);
|
||||
void igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index);
|
||||
void igc_config_collision_dist(struct igc_hw *hw);
|
||||
|
||||
s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,
|
||||
u16 *duplex);
|
||||
|
||||
bool igc_enable_mng_pass_thru(struct igc_hw *hw);
|
||||
void igc_update_mc_addr_list(struct igc_hw *hw,
|
||||
u8 *mc_addr_list, u32 mc_addr_count);
|
||||
|
||||
enum igc_mng_mode {
|
||||
igc_mng_mode_none = 0,
|
||||
igc_mng_mode_asf,
|
||||
igc_mng_mode_pt,
|
||||
igc_mng_mode_ipmi,
|
||||
igc_mng_mode_host_if_only
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,881 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "igc_mac.h"
|
||||
#include "igc_hw.h"
|
||||
|
||||
/**
|
||||
* igc_disable_pcie_master - Disables PCI-express master access
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Returns 0 (0) if successful, else returns -10
|
||||
* (-IGC_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
|
||||
* the master requests to be disabled.
|
||||
*
|
||||
* Disables PCI-Express master access and verifies there are no pending
|
||||
* requests.
|
||||
*/
|
||||
s32 igc_disable_pcie_master(struct igc_hw *hw)
|
||||
{
|
||||
s32 timeout = MASTER_DISABLE_TIMEOUT;
|
||||
s32 ret_val = 0;
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
ctrl |= IGC_CTRL_GIO_MASTER_DISABLE;
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
|
||||
while (timeout) {
|
||||
if (!(rd32(IGC_STATUS) &
|
||||
IGC_STATUS_GIO_MASTER_ENABLE))
|
||||
break;
|
||||
usleep_range(2000, 3000);
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
hw_dbg("Master requests are pending.\n");
|
||||
ret_val = -IGC_ERR_MASTER_REQUESTS_PENDING;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_init_rx_addrs - Initialize receive addresses
|
||||
* @hw: pointer to the HW structure
|
||||
* @rar_count: receive address registers
|
||||
*
|
||||
* Setup the receive address registers by setting the base receive address
|
||||
* register to the devices MAC address and clearing all the other receive
|
||||
* address registers to 0.
|
||||
*/
|
||||
void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count)
|
||||
{
|
||||
u8 mac_addr[ETH_ALEN] = {0};
|
||||
u32 i;
|
||||
|
||||
/* Setup the receive address */
|
||||
hw_dbg("Programming MAC Address into RAR[0]\n");
|
||||
|
||||
hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
|
||||
|
||||
/* Zero out the other (rar_entry_count - 1) receive addresses */
|
||||
hw_dbg("Clearing RAR[1-%u]\n", rar_count - 1);
|
||||
for (i = 1; i < rar_count; i++)
|
||||
hw->mac.ops.rar_set(hw, mac_addr, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_set_fc_watermarks - Set flow control high/low watermarks
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Sets the flow control high/low threshold (watermark) registers. If
|
||||
* flow control XON frame transmission is enabled, then set XON frame
|
||||
* transmission as well.
|
||||
*/
|
||||
static s32 igc_set_fc_watermarks(struct igc_hw *hw)
|
||||
{
|
||||
u32 fcrtl = 0, fcrth = 0;
|
||||
|
||||
/* Set the flow control receive threshold registers. Normally,
|
||||
* these registers will be set to a default threshold that may be
|
||||
* adjusted later by the driver's runtime code. However, if the
|
||||
* ability to transmit pause frames is not enabled, then these
|
||||
* registers will be set to 0.
|
||||
*/
|
||||
if (hw->fc.current_mode & igc_fc_tx_pause) {
|
||||
/* We need to set up the Receive Threshold high and low water
|
||||
* marks as well as (optionally) enabling the transmission of
|
||||
* XON frames.
|
||||
*/
|
||||
fcrtl = hw->fc.low_water;
|
||||
if (hw->fc.send_xon)
|
||||
fcrtl |= IGC_FCRTL_XONE;
|
||||
|
||||
fcrth = hw->fc.high_water;
|
||||
}
|
||||
wr32(IGC_FCRTL, fcrtl);
|
||||
wr32(IGC_FCRTH, fcrth);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_setup_link - Setup flow control and link settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Determines which flow control settings to use, then configures flow
|
||||
* control. Calls the appropriate media-specific link configuration
|
||||
* function. Assuming the adapter has a valid link partner, a valid link
|
||||
* should be established. Assumes the hardware has previously been reset
|
||||
* and the transmitter and receiver are not enabled.
|
||||
*/
|
||||
s32 igc_setup_link(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* In the case of the phy reset being blocked, we already have a link.
|
||||
* We do not need to set it up again.
|
||||
*/
|
||||
if (igc_check_reset_block(hw))
|
||||
goto out;
|
||||
|
||||
/* If requested flow control is set to default, set flow control
|
||||
* to the both 'rx' and 'tx' pause frames.
|
||||
*/
|
||||
if (hw->fc.requested_mode == igc_fc_default)
|
||||
hw->fc.requested_mode = igc_fc_full;
|
||||
|
||||
/* We want to save off the original Flow Control configuration just
|
||||
* in case we get disconnected and then reconnected into a different
|
||||
* hub or switch with different Flow Control capabilities.
|
||||
*/
|
||||
hw->fc.current_mode = hw->fc.requested_mode;
|
||||
|
||||
hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode);
|
||||
|
||||
/* Call the necessary media_type subroutine to configure the link. */
|
||||
ret_val = hw->mac.ops.setup_physical_interface(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* Initialize the flow control address, type, and PAUSE timer
|
||||
* registers to their default values. This is done even if flow
|
||||
* control is disabled, because it does not hurt anything to
|
||||
* initialize these registers.
|
||||
*/
|
||||
hw_dbg("Initializing the Flow Control address, type and timer regs\n");
|
||||
wr32(IGC_FCT, FLOW_CONTROL_TYPE);
|
||||
wr32(IGC_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
|
||||
wr32(IGC_FCAL, FLOW_CONTROL_ADDRESS_LOW);
|
||||
|
||||
wr32(IGC_FCTTV, hw->fc.pause_time);
|
||||
|
||||
ret_val = igc_set_fc_watermarks(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_force_mac_fc - Force the MAC's flow control settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the
|
||||
* device control register to reflect the adapter settings. TFCE and RFCE
|
||||
* need to be explicitly set by software when a copper PHY is used because
|
||||
* autonegotiation is managed by the PHY rather than the MAC. Software must
|
||||
* also configure these bits when link is forced on a fiber connection.
|
||||
*/
|
||||
s32 igc_force_mac_fc(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
|
||||
/* Because we didn't get link via the internal auto-negotiation
|
||||
* mechanism (we either forced link or we got link via PHY
|
||||
* auto-neg), we have to manually enable/disable transmit an
|
||||
* receive flow control.
|
||||
*
|
||||
* The "Case" statement below enables/disable flow control
|
||||
* according to the "hw->fc.current_mode" parameter.
|
||||
*
|
||||
* The possible values of the "fc" parameter are:
|
||||
* 0: Flow control is completely disabled
|
||||
* 1: Rx flow control is enabled (we can receive pause
|
||||
* frames but not send pause frames).
|
||||
* 2: Tx flow control is enabled (we can send pause frames
|
||||
* but we do not receive pause frames).
|
||||
* 3: Both Rx and TX flow control (symmetric) is enabled.
|
||||
* other: No other values should be possible at this point.
|
||||
*/
|
||||
hw_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode);
|
||||
|
||||
switch (hw->fc.current_mode) {
|
||||
case igc_fc_none:
|
||||
ctrl &= (~(IGC_CTRL_TFCE | IGC_CTRL_RFCE));
|
||||
break;
|
||||
case igc_fc_rx_pause:
|
||||
ctrl &= (~IGC_CTRL_TFCE);
|
||||
ctrl |= IGC_CTRL_RFCE;
|
||||
break;
|
||||
case igc_fc_tx_pause:
|
||||
ctrl &= (~IGC_CTRL_RFCE);
|
||||
ctrl |= IGC_CTRL_TFCE;
|
||||
break;
|
||||
case igc_fc_full:
|
||||
ctrl |= (IGC_CTRL_TFCE | IGC_CTRL_RFCE);
|
||||
break;
|
||||
default:
|
||||
hw_dbg("Flow control param set incorrectly\n");
|
||||
ret_val = -IGC_ERR_CONFIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_clear_hw_cntrs_base - Clear base hardware counters
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Clears the base hardware counters by reading the counter registers.
|
||||
*/
|
||||
void igc_clear_hw_cntrs_base(struct igc_hw *hw)
|
||||
{
|
||||
rd32(IGC_CRCERRS);
|
||||
rd32(IGC_MPC);
|
||||
rd32(IGC_SCC);
|
||||
rd32(IGC_ECOL);
|
||||
rd32(IGC_MCC);
|
||||
rd32(IGC_LATECOL);
|
||||
rd32(IGC_COLC);
|
||||
rd32(IGC_RERC);
|
||||
rd32(IGC_DC);
|
||||
rd32(IGC_RLEC);
|
||||
rd32(IGC_XONRXC);
|
||||
rd32(IGC_XONTXC);
|
||||
rd32(IGC_XOFFRXC);
|
||||
rd32(IGC_XOFFTXC);
|
||||
rd32(IGC_FCRUC);
|
||||
rd32(IGC_GPRC);
|
||||
rd32(IGC_BPRC);
|
||||
rd32(IGC_MPRC);
|
||||
rd32(IGC_GPTC);
|
||||
rd32(IGC_GORCL);
|
||||
rd32(IGC_GORCH);
|
||||
rd32(IGC_GOTCL);
|
||||
rd32(IGC_GOTCH);
|
||||
rd32(IGC_RNBC);
|
||||
rd32(IGC_RUC);
|
||||
rd32(IGC_RFC);
|
||||
rd32(IGC_ROC);
|
||||
rd32(IGC_RJC);
|
||||
rd32(IGC_TORL);
|
||||
rd32(IGC_TORH);
|
||||
rd32(IGC_TOTL);
|
||||
rd32(IGC_TOTH);
|
||||
rd32(IGC_TPR);
|
||||
rd32(IGC_TPT);
|
||||
rd32(IGC_MPTC);
|
||||
rd32(IGC_BPTC);
|
||||
|
||||
rd32(IGC_PRC64);
|
||||
rd32(IGC_PRC127);
|
||||
rd32(IGC_PRC255);
|
||||
rd32(IGC_PRC511);
|
||||
rd32(IGC_PRC1023);
|
||||
rd32(IGC_PRC1522);
|
||||
rd32(IGC_PTC64);
|
||||
rd32(IGC_PTC127);
|
||||
rd32(IGC_PTC255);
|
||||
rd32(IGC_PTC511);
|
||||
rd32(IGC_PTC1023);
|
||||
rd32(IGC_PTC1522);
|
||||
|
||||
rd32(IGC_ALGNERRC);
|
||||
rd32(IGC_RXERRC);
|
||||
rd32(IGC_TNCRS);
|
||||
rd32(IGC_HTDPMC);
|
||||
rd32(IGC_TSCTC);
|
||||
|
||||
rd32(IGC_MGTPRC);
|
||||
rd32(IGC_MGTPDC);
|
||||
rd32(IGC_MGTPTC);
|
||||
|
||||
rd32(IGC_IAC);
|
||||
|
||||
rd32(IGC_RPTHC);
|
||||
rd32(IGC_TLPIC);
|
||||
rd32(IGC_RLPIC);
|
||||
rd32(IGC_HGPTC);
|
||||
rd32(IGC_RXDMTC);
|
||||
rd32(IGC_HGORCL);
|
||||
rd32(IGC_HGORCH);
|
||||
rd32(IGC_HGOTCL);
|
||||
rd32(IGC_HGOTCH);
|
||||
rd32(IGC_LENERRS);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_rar_set - Set receive address register
|
||||
* @hw: pointer to the HW structure
|
||||
* @addr: pointer to the receive address
|
||||
* @index: receive address array register
|
||||
*
|
||||
* Sets the receive address array register at index to the address passed
|
||||
* in by addr.
|
||||
*/
|
||||
void igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index)
|
||||
{
|
||||
u32 rar_low, rar_high;
|
||||
|
||||
/* HW expects these in little endian so we reverse the byte order
|
||||
* from network order (big endian) to little endian
|
||||
*/
|
||||
rar_low = ((u32)addr[0] |
|
||||
((u32)addr[1] << 8) |
|
||||
((u32)addr[2] << 16) | ((u32)addr[3] << 24));
|
||||
|
||||
rar_high = ((u32)addr[4] | ((u32)addr[5] << 8));
|
||||
|
||||
/* If MAC address zero, no need to set the AV bit */
|
||||
if (rar_low || rar_high)
|
||||
rar_high |= IGC_RAH_AV;
|
||||
|
||||
/* Some bridges will combine consecutive 32-bit writes into
|
||||
* a single burst write, which will malfunction on some parts.
|
||||
* The flushes avoid this.
|
||||
*/
|
||||
wr32(IGC_RAL(index), rar_low);
|
||||
wrfl();
|
||||
wr32(IGC_RAH(index), rar_high);
|
||||
wrfl();
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_check_for_copper_link - Check for link (Copper)
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Checks to see of the link status of the hardware has changed. If a
|
||||
* change in link status has been detected, then we read the PHY registers
|
||||
* to get the current speed/duplex if link exists.
|
||||
*/
|
||||
s32 igc_check_for_copper_link(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
bool link = false;
|
||||
s32 ret_val;
|
||||
|
||||
/* We only want to go out to the PHY registers to see if Auto-Neg
|
||||
* has completed and/or if our link status has changed. The
|
||||
* get_link_status flag is set upon receiving a Link Status
|
||||
* Change or Rx Sequence Error interrupt.
|
||||
*/
|
||||
if (!mac->get_link_status) {
|
||||
ret_val = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* First we want to see if the MII Status Register reports
|
||||
* link. If so, then we want to get the current speed/duplex
|
||||
* of the PHY.
|
||||
*/
|
||||
ret_val = igc_phy_has_link(hw, 1, 0, &link);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
if (!link)
|
||||
goto out; /* No link detected */
|
||||
|
||||
mac->get_link_status = false;
|
||||
|
||||
/* Check if there was DownShift, must be checked
|
||||
* immediately after link-up
|
||||
*/
|
||||
igc_check_downshift(hw);
|
||||
|
||||
/* If we are forcing speed/duplex, then we simply return since
|
||||
* we have already determined whether we have link or not.
|
||||
*/
|
||||
if (!mac->autoneg) {
|
||||
ret_val = -IGC_ERR_CONFIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Auto-Neg is enabled. Auto Speed Detection takes care
|
||||
* of MAC speed/duplex configuration. So we only need to
|
||||
* configure Collision Distance in the MAC.
|
||||
*/
|
||||
igc_config_collision_dist(hw);
|
||||
|
||||
/* Configure Flow Control now that Auto-Neg has completed.
|
||||
* First, we need to restore the desired flow control
|
||||
* settings because we may have had to re-autoneg with a
|
||||
* different link partner.
|
||||
*/
|
||||
ret_val = igc_config_fc_after_link_up(hw);
|
||||
if (ret_val)
|
||||
hw_dbg("Error configuring flow control\n");
|
||||
|
||||
out:
|
||||
/* Now that we are aware of our link settings, we can set the LTR
|
||||
* thresholds.
|
||||
*/
|
||||
ret_val = igc_set_ltr_i225(hw, link);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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. Currently no func pointer exists and all
|
||||
* implementations are handled in the generic version of this function.
|
||||
*/
|
||||
void igc_config_collision_dist(struct igc_hw *hw)
|
||||
{
|
||||
u32 tctl;
|
||||
|
||||
tctl = rd32(IGC_TCTL);
|
||||
|
||||
tctl &= ~IGC_TCTL_COLD;
|
||||
tctl |= IGC_COLLISION_DISTANCE << IGC_COLD_SHIFT;
|
||||
|
||||
wr32(IGC_TCTL, tctl);
|
||||
wrfl();
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_config_fc_after_link_up - Configures flow control after link
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Checks the status of auto-negotiation after link up to ensure that the
|
||||
* speed and duplex were not forced. If the link needed to be forced, then
|
||||
* flow control needs to be forced also. If auto-negotiation is enabled
|
||||
* and did not fail, then we configure flow control based on our link
|
||||
* partner.
|
||||
*/
|
||||
s32 igc_config_fc_after_link_up(struct igc_hw *hw)
|
||||
{
|
||||
u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
u16 speed, duplex;
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* Check for the case where we have fiber media and auto-neg failed
|
||||
* so we had to force link. In this case, we need to force the
|
||||
* configuration of the MAC to match the "fc" parameter.
|
||||
*/
|
||||
if (mac->autoneg_failed)
|
||||
ret_val = igc_force_mac_fc(hw);
|
||||
|
||||
if (ret_val) {
|
||||
hw_dbg("Error forcing flow control settings\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check for the case where we have copper media and auto-neg is
|
||||
* enabled. In this case, we need to check and see if Auto-Neg
|
||||
* has completed, and if so, how the PHY and link partner has
|
||||
* flow control configured.
|
||||
*/
|
||||
if (mac->autoneg) {
|
||||
/* Read the MII Status Register and check to see if AutoNeg
|
||||
* has completed. We read this twice because this reg has
|
||||
* some "sticky" (latched) bits.
|
||||
*/
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
|
||||
&mii_status_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
|
||||
&mii_status_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
|
||||
hw_dbg("Copper PHY and Auto Neg has not completed.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The AutoNeg process has completed, so we now need to
|
||||
* read both the Auto Negotiation Advertisement
|
||||
* Register (Address 4) and the Auto_Negotiation Base
|
||||
* Page Ability Register (Address 5) to determine how
|
||||
* flow control was negotiated.
|
||||
*/
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
|
||||
&mii_nway_adv_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
|
||||
&mii_nway_lp_ability_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
/* Two bits in the Auto Negotiation Advertisement Register
|
||||
* (Address 4) and two bits in the Auto Negotiation Base
|
||||
* Page Ability Register (Address 5) determine flow control
|
||||
* for both the PHY and the link partner. The following
|
||||
* table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
|
||||
* 1999, describes these PAUSE resolution bits and how flow
|
||||
* control is determined based upon these settings.
|
||||
* NOTE: DC = Don't Care
|
||||
*
|
||||
* LOCAL DEVICE | LINK PARTNER
|
||||
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
|
||||
*-------|---------|-------|---------|--------------------
|
||||
* 0 | 0 | DC | DC | igc_fc_none
|
||||
* 0 | 1 | 0 | DC | igc_fc_none
|
||||
* 0 | 1 | 1 | 0 | igc_fc_none
|
||||
* 0 | 1 | 1 | 1 | igc_fc_tx_pause
|
||||
* 1 | 0 | 0 | DC | igc_fc_none
|
||||
* 1 | DC | 1 | DC | igc_fc_full
|
||||
* 1 | 1 | 0 | 0 | igc_fc_none
|
||||
* 1 | 1 | 0 | 1 | igc_fc_rx_pause
|
||||
*
|
||||
* Are both PAUSE bits set to 1? If so, this implies
|
||||
* Symmetric Flow Control is enabled at both ends. The
|
||||
* ASM_DIR bits are irrelevant per the spec.
|
||||
*
|
||||
* For Symmetric Flow Control:
|
||||
*
|
||||
* LOCAL DEVICE | LINK PARTNER
|
||||
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
|
||||
*-------|---------|-------|---------|--------------------
|
||||
* 1 | DC | 1 | DC | IGC_fc_full
|
||||
*
|
||||
*/
|
||||
if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
|
||||
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
|
||||
/* Now we need to check if the user selected RX ONLY
|
||||
* of pause frames. In this case, we had to advertise
|
||||
* FULL flow control because we could not advertise RX
|
||||
* ONLY. Hence, we must now check to see if we need to
|
||||
* turn OFF the TRANSMISSION of PAUSE frames.
|
||||
*/
|
||||
if (hw->fc.requested_mode == igc_fc_full) {
|
||||
hw->fc.current_mode = igc_fc_full;
|
||||
hw_dbg("Flow Control = FULL.\n");
|
||||
} else {
|
||||
hw->fc.current_mode = igc_fc_rx_pause;
|
||||
hw_dbg("Flow Control = RX PAUSE frames only.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* For receiving PAUSE frames ONLY.
|
||||
*
|
||||
* LOCAL DEVICE | LINK PARTNER
|
||||
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
|
||||
*-------|---------|-------|---------|--------------------
|
||||
* 0 | 1 | 1 | 1 | igc_fc_tx_pause
|
||||
*/
|
||||
else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
|
||||
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
|
||||
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
|
||||
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
|
||||
hw->fc.current_mode = igc_fc_tx_pause;
|
||||
hw_dbg("Flow Control = TX PAUSE frames only.\n");
|
||||
}
|
||||
/* For transmitting PAUSE frames ONLY.
|
||||
*
|
||||
* LOCAL DEVICE | LINK PARTNER
|
||||
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
|
||||
*-------|---------|-------|---------|--------------------
|
||||
* 1 | 1 | 0 | 1 | igc_fc_rx_pause
|
||||
*/
|
||||
else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
|
||||
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
|
||||
!(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
|
||||
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
|
||||
hw->fc.current_mode = igc_fc_rx_pause;
|
||||
hw_dbg("Flow Control = RX PAUSE frames only.\n");
|
||||
}
|
||||
/* Per the IEEE spec, at this point flow control should be
|
||||
* disabled. However, we want to consider that we could
|
||||
* be connected to a legacy switch that doesn't advertise
|
||||
* desired flow control, but can be forced on the link
|
||||
* partner. So if we advertised no flow control, that is
|
||||
* what we will resolve to. If we advertised some kind of
|
||||
* receive capability (Rx Pause Only or Full Flow Control)
|
||||
* and the link partner advertised none, we will configure
|
||||
* ourselves to enable Rx Flow Control only. We can do
|
||||
* this safely for two reasons: If the link partner really
|
||||
* didn't want flow control enabled, and we enable Rx, no
|
||||
* harm done since we won't be receiving any PAUSE frames
|
||||
* anyway. If the intent on the link partner was to have
|
||||
* flow control enabled, then by us enabling RX only, we
|
||||
* can at least receive pause frames and process them.
|
||||
* This is a good idea because in most cases, since we are
|
||||
* predominantly a server NIC, more times than not we will
|
||||
* be asked to delay transmission of packets than asking
|
||||
* our link partner to pause transmission of frames.
|
||||
*/
|
||||
else if ((hw->fc.requested_mode == igc_fc_none) ||
|
||||
(hw->fc.requested_mode == igc_fc_tx_pause) ||
|
||||
(hw->fc.strict_ieee)) {
|
||||
hw->fc.current_mode = igc_fc_none;
|
||||
hw_dbg("Flow Control = NONE.\n");
|
||||
} else {
|
||||
hw->fc.current_mode = igc_fc_rx_pause;
|
||||
hw_dbg("Flow Control = RX PAUSE frames only.\n");
|
||||
}
|
||||
|
||||
/* Now we need to do one last check... If we auto-
|
||||
* negotiated to HALF DUPLEX, flow control should not be
|
||||
* enabled per IEEE 802.3 spec.
|
||||
*/
|
||||
ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error getting link speed and duplex\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (duplex == HALF_DUPLEX)
|
||||
hw->fc.current_mode = igc_fc_none;
|
||||
|
||||
/* Now we call a subroutine to actually force the MAC
|
||||
* controller to use the correct flow control settings.
|
||||
*/
|
||||
ret_val = igc_force_mac_fc(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error forcing flow control settings\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_auto_rd_done - Check for auto read completion
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Check EEPROM for Auto Read done bit.
|
||||
*/
|
||||
s32 igc_get_auto_rd_done(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
s32 i = 0;
|
||||
|
||||
while (i < AUTO_READ_DONE_TIMEOUT) {
|
||||
if (rd32(IGC_EECD) & IGC_EECD_AUTO_RD)
|
||||
break;
|
||||
usleep_range(1000, 2000);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == AUTO_READ_DONE_TIMEOUT) {
|
||||
hw_dbg("Auto read by HW from NVM has not completed.\n");
|
||||
ret_val = -IGC_ERR_RESET;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_speed_and_duplex_copper - Retrieve current speed/duplex
|
||||
* @hw: pointer to the HW structure
|
||||
* @speed: stores the current speed
|
||||
* @duplex: stores the current duplex
|
||||
*
|
||||
* Read the status register for the current speed/duplex and store the current
|
||||
* speed and duplex for copper connections.
|
||||
*/
|
||||
s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,
|
||||
u16 *duplex)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
status = rd32(IGC_STATUS);
|
||||
if (status & IGC_STATUS_SPEED_1000) {
|
||||
/* For I225, STATUS will indicate 1G speed in both 1 Gbps
|
||||
* and 2.5 Gbps link modes. An additional bit is used
|
||||
* to differentiate between 1 Gbps and 2.5 Gbps.
|
||||
*/
|
||||
if (hw->mac.type == igc_i225 &&
|
||||
(status & IGC_STATUS_SPEED_2500)) {
|
||||
*speed = SPEED_2500;
|
||||
hw_dbg("2500 Mbs, ");
|
||||
} else {
|
||||
*speed = SPEED_1000;
|
||||
hw_dbg("1000 Mbs, ");
|
||||
}
|
||||
} else if (status & IGC_STATUS_SPEED_100) {
|
||||
*speed = SPEED_100;
|
||||
hw_dbg("100 Mbs, ");
|
||||
} else {
|
||||
*speed = SPEED_10;
|
||||
hw_dbg("10 Mbs, ");
|
||||
}
|
||||
|
||||
if (status & IGC_STATUS_FD) {
|
||||
*duplex = FULL_DUPLEX;
|
||||
hw_dbg("Full Duplex\n");
|
||||
} else {
|
||||
*duplex = HALF_DUPLEX;
|
||||
hw_dbg("Half Duplex\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_put_hw_semaphore - Release hardware semaphore
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Release hardware semaphore used to access the PHY or NVM
|
||||
*/
|
||||
void igc_put_hw_semaphore(struct igc_hw *hw)
|
||||
{
|
||||
u32 swsm;
|
||||
|
||||
swsm = rd32(IGC_SWSM);
|
||||
|
||||
swsm &= ~(IGC_SWSM_SMBI | IGC_SWSM_SWESMBI);
|
||||
|
||||
wr32(IGC_SWSM, swsm);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_enable_mng_pass_thru - Enable processing of ARP's
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Verifies the hardware needs to leave interface enabled so that frames can
|
||||
* be directed to and from the management interface.
|
||||
*/
|
||||
bool igc_enable_mng_pass_thru(struct igc_hw *hw)
|
||||
{
|
||||
bool ret_val = false;
|
||||
u32 fwsm, factps;
|
||||
u32 manc;
|
||||
|
||||
if (!hw->mac.asf_firmware_present)
|
||||
goto out;
|
||||
|
||||
manc = rd32(IGC_MANC);
|
||||
|
||||
if (!(manc & IGC_MANC_RCV_TCO_EN))
|
||||
goto out;
|
||||
|
||||
if (hw->mac.arc_subsystem_valid) {
|
||||
fwsm = rd32(IGC_FWSM);
|
||||
factps = rd32(IGC_FACTPS);
|
||||
|
||||
if (!(factps & IGC_FACTPS_MNGCG) &&
|
||||
((fwsm & IGC_FWSM_MODE_MASK) ==
|
||||
(igc_mng_mode_pt << IGC_FWSM_MODE_SHIFT))) {
|
||||
ret_val = true;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if ((manc & IGC_MANC_SMBUS_EN) &&
|
||||
!(manc & IGC_MANC_ASF_EN)) {
|
||||
ret_val = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_hash_mc_addr - Generate a multicast hash value
|
||||
* @hw: pointer to the HW structure
|
||||
* @mc_addr: pointer to a multicast address
|
||||
*
|
||||
* Generates a multicast address hash value which is used to determine
|
||||
* the multicast filter table array address and new table value. See
|
||||
* igc_mta_set()
|
||||
**/
|
||||
static u32 igc_hash_mc_addr(struct igc_hw *hw, u8 *mc_addr)
|
||||
{
|
||||
u32 hash_value, hash_mask;
|
||||
u8 bit_shift = 0;
|
||||
|
||||
/* Register count multiplied by bits per register */
|
||||
hash_mask = (hw->mac.mta_reg_count * 32) - 1;
|
||||
|
||||
/* For a mc_filter_type of 0, bit_shift is the number of left-shifts
|
||||
* where 0xFF would still fall within the hash mask.
|
||||
*/
|
||||
while (hash_mask >> bit_shift != 0xFF)
|
||||
bit_shift++;
|
||||
|
||||
/* The portion of the address that is used for the hash table
|
||||
* is determined by the mc_filter_type setting.
|
||||
* The algorithm is such that there is a total of 8 bits of shifting.
|
||||
* The bit_shift for a mc_filter_type of 0 represents the number of
|
||||
* left-shifts where the MSB of mc_addr[5] would still fall within
|
||||
* the hash_mask. Case 0 does this exactly. Since there are a total
|
||||
* of 8 bits of shifting, then mc_addr[4] will shift right the
|
||||
* remaining number of bits. Thus 8 - bit_shift. The rest of the
|
||||
* cases are a variation of this algorithm...essentially raising the
|
||||
* number of bits to shift mc_addr[5] left, while still keeping the
|
||||
* 8-bit shifting total.
|
||||
*
|
||||
* For example, given the following Destination MAC Address and an
|
||||
* MTA register count of 128 (thus a 4096-bit vector and 0xFFF mask),
|
||||
* we can see that the bit_shift for case 0 is 4. These are the hash
|
||||
* values resulting from each mc_filter_type...
|
||||
* [0] [1] [2] [3] [4] [5]
|
||||
* 01 AA 00 12 34 56
|
||||
* LSB MSB
|
||||
*
|
||||
* case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
|
||||
* case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
|
||||
* case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
|
||||
* case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
|
||||
*/
|
||||
switch (hw->mac.mc_filter_type) {
|
||||
default:
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
bit_shift += 1;
|
||||
break;
|
||||
case 2:
|
||||
bit_shift += 2;
|
||||
break;
|
||||
case 3:
|
||||
bit_shift += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
|
||||
(((u16)mc_addr[5]) << bit_shift)));
|
||||
|
||||
return hash_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 entire 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)
|
||||
{
|
||||
u32 hash_value, hash_bit, hash_reg;
|
||||
int i;
|
||||
|
||||
/* clear mta_shadow */
|
||||
memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
|
||||
|
||||
/* update mta_shadow from mc_addr_list */
|
||||
for (i = 0; (u32)i < mc_addr_count; i++) {
|
||||
hash_value = igc_hash_mc_addr(hw, mc_addr_list);
|
||||
|
||||
hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
|
||||
hash_bit = hash_value & 0x1F;
|
||||
|
||||
hw->mac.mta_shadow[hash_reg] |= BIT(hash_bit);
|
||||
mc_addr_list += ETH_ALEN;
|
||||
}
|
||||
|
||||
/* replace the entire MTA table */
|
||||
for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
|
||||
array_wr32(IGC_MTA, i, hw->mac.mta_shadow[i]);
|
||||
wrfl();
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_MAC_H_
|
||||
#define _IGC_MAC_H_
|
||||
|
||||
#include "igc_hw.h"
|
||||
#include "igc_phy.h"
|
||||
#include "igc_defines.h"
|
||||
|
||||
/* forward declaration */
|
||||
s32 igc_disable_pcie_master(struct igc_hw *hw);
|
||||
s32 igc_check_for_copper_link(struct igc_hw *hw);
|
||||
s32 igc_config_fc_after_link_up(struct igc_hw *hw);
|
||||
s32 igc_force_mac_fc(struct igc_hw *hw);
|
||||
void igc_init_rx_addrs(struct igc_hw *hw, u16 rar_count);
|
||||
s32 igc_setup_link(struct igc_hw *hw);
|
||||
void igc_clear_hw_cntrs_base(struct igc_hw *hw);
|
||||
s32 igc_get_auto_rd_done(struct igc_hw *hw);
|
||||
void igc_put_hw_semaphore(struct igc_hw *hw);
|
||||
void igc_rar_set(struct igc_hw *hw, u8 *addr, u32 index);
|
||||
void igc_config_collision_dist(struct igc_hw *hw);
|
||||
|
||||
s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,
|
||||
u16 *duplex);
|
||||
|
||||
bool igc_enable_mng_pass_thru(struct igc_hw *hw);
|
||||
void igc_update_mc_addr_list(struct igc_hw *hw,
|
||||
u8 *mc_addr_list, u32 mc_addr_count);
|
||||
|
||||
enum igc_mng_mode {
|
||||
igc_mng_mode_none = 0,
|
||||
igc_mng_mode_asf,
|
||||
igc_mng_mode_pt,
|
||||
igc_mng_mode_ipmi,
|
||||
igc_mng_mode_host_if_only
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,215 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include "igc_mac-6.4-ethercat.h"
|
||||
#include "igc_nvm-6.4-ethercat.h"
|
||||
|
||||
/**
|
||||
* 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'.
|
||||
*/
|
||||
static s32 igc_poll_eerd_eewr_done(struct igc_hw *hw, int ee_reg)
|
||||
{
|
||||
s32 ret_val = -IGC_ERR_NVM;
|
||||
u32 attempts = 100000;
|
||||
u32 i, reg = 0;
|
||||
|
||||
for (i = 0; i < attempts; i++) {
|
||||
if (ee_reg == IGC_NVM_POLL_READ)
|
||||
reg = rd32(IGC_EERD);
|
||||
else
|
||||
reg = rd32(IGC_EEWR);
|
||||
|
||||
if (reg & IGC_NVM_RW_REG_DONE) {
|
||||
ret_val = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_acquire_nvm - 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(struct igc_hw *hw)
|
||||
{
|
||||
s32 timeout = IGC_NVM_GRANT_ATTEMPTS;
|
||||
u32 eecd = rd32(IGC_EECD);
|
||||
s32 ret_val = 0;
|
||||
|
||||
wr32(IGC_EECD, eecd | IGC_EECD_REQ);
|
||||
eecd = rd32(IGC_EECD);
|
||||
|
||||
while (timeout) {
|
||||
if (eecd & IGC_EECD_GNT)
|
||||
break;
|
||||
udelay(5);
|
||||
eecd = rd32(IGC_EECD);
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
eecd &= ~IGC_EECD_REQ;
|
||||
wr32(IGC_EECD, eecd);
|
||||
hw_dbg("Could not acquire NVM grant\n");
|
||||
ret_val = -IGC_ERR_NVM;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_release_nvm - 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(struct igc_hw *hw)
|
||||
{
|
||||
u32 eecd;
|
||||
|
||||
eecd = rd32(IGC_EECD);
|
||||
eecd &= ~IGC_EECD_REQ;
|
||||
wr32(IGC_EECD, eecd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = 0;
|
||||
|
||||
/* 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) {
|
||||
hw_dbg("nvm parameter(s) out of bounds\n");
|
||||
ret_val = -IGC_ERR_NVM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < words; i++) {
|
||||
eerd = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) +
|
||||
IGC_NVM_RW_REG_START;
|
||||
|
||||
wr32(IGC_EERD, eerd);
|
||||
ret_val = igc_poll_eerd_eewr_done(hw, IGC_NVM_POLL_READ);
|
||||
if (ret_val)
|
||||
break;
|
||||
|
||||
data[i] = (rd32(IGC_EERD) >> IGC_NVM_RW_REG_DATA);
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_mac_addr - Read device MAC address
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
s32 igc_read_mac_addr(struct igc_hw *hw)
|
||||
{
|
||||
u32 rar_high;
|
||||
u32 rar_low;
|
||||
u16 i;
|
||||
|
||||
rar_high = rd32(IGC_RAH(0));
|
||||
rar_low = rd32(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_ALEN; i++)
|
||||
hw->mac.addr[i] = hw->mac.perm_addr[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_validate_nvm_checksum - 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(struct igc_hw *hw)
|
||||
{
|
||||
u16 checksum = 0;
|
||||
u16 i, nvm_data;
|
||||
s32 ret_val = 0;
|
||||
|
||||
for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
|
||||
ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("NVM Read Error\n");
|
||||
goto out;
|
||||
}
|
||||
checksum += nvm_data;
|
||||
}
|
||||
|
||||
if (checksum != (u16)NVM_SUM) {
|
||||
hw_dbg("NVM Checksum Invalid\n");
|
||||
ret_val = -IGC_ERR_NVM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_update_nvm_checksum - 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(struct igc_hw *hw)
|
||||
{
|
||||
u16 checksum = 0;
|
||||
u16 i, nvm_data;
|
||||
s32 ret_val;
|
||||
|
||||
for (i = 0; i < NVM_CHECKSUM_REG; i++) {
|
||||
ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("NVM Read Error while updating checksum.\n");
|
||||
goto out;
|
||||
}
|
||||
checksum += nvm_data;
|
||||
}
|
||||
checksum = (u16)NVM_SUM - checksum;
|
||||
ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
|
||||
if (ret_val)
|
||||
hw_dbg("NVM Write Error while updating checksum.\n");
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_NVM_H_
|
||||
#define _IGC_NVM_H_
|
||||
|
||||
s32 igc_acquire_nvm(struct igc_hw *hw);
|
||||
void igc_release_nvm(struct igc_hw *hw);
|
||||
s32 igc_read_mac_addr(struct igc_hw *hw);
|
||||
s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words, u16 *data);
|
||||
s32 igc_validate_nvm_checksum(struct igc_hw *hw);
|
||||
s32 igc_update_nvm_checksum(struct igc_hw *hw);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include "igc_mac.h"
|
||||
#include "igc_nvm.h"
|
||||
|
||||
/**
|
||||
* 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'.
|
||||
*/
|
||||
static s32 igc_poll_eerd_eewr_done(struct igc_hw *hw, int ee_reg)
|
||||
{
|
||||
s32 ret_val = -IGC_ERR_NVM;
|
||||
u32 attempts = 100000;
|
||||
u32 i, reg = 0;
|
||||
|
||||
for (i = 0; i < attempts; i++) {
|
||||
if (ee_reg == IGC_NVM_POLL_READ)
|
||||
reg = rd32(IGC_EERD);
|
||||
else
|
||||
reg = rd32(IGC_EEWR);
|
||||
|
||||
if (reg & IGC_NVM_RW_REG_DONE) {
|
||||
ret_val = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_acquire_nvm - 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(struct igc_hw *hw)
|
||||
{
|
||||
s32 timeout = IGC_NVM_GRANT_ATTEMPTS;
|
||||
u32 eecd = rd32(IGC_EECD);
|
||||
s32 ret_val = 0;
|
||||
|
||||
wr32(IGC_EECD, eecd | IGC_EECD_REQ);
|
||||
eecd = rd32(IGC_EECD);
|
||||
|
||||
while (timeout) {
|
||||
if (eecd & IGC_EECD_GNT)
|
||||
break;
|
||||
udelay(5);
|
||||
eecd = rd32(IGC_EECD);
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
eecd &= ~IGC_EECD_REQ;
|
||||
wr32(IGC_EECD, eecd);
|
||||
hw_dbg("Could not acquire NVM grant\n");
|
||||
ret_val = -IGC_ERR_NVM;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_release_nvm - 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(struct igc_hw *hw)
|
||||
{
|
||||
u32 eecd;
|
||||
|
||||
eecd = rd32(IGC_EECD);
|
||||
eecd &= ~IGC_EECD_REQ;
|
||||
wr32(IGC_EECD, eecd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = 0;
|
||||
|
||||
/* 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) {
|
||||
hw_dbg("nvm parameter(s) out of bounds\n");
|
||||
ret_val = -IGC_ERR_NVM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < words; i++) {
|
||||
eerd = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) +
|
||||
IGC_NVM_RW_REG_START;
|
||||
|
||||
wr32(IGC_EERD, eerd);
|
||||
ret_val = igc_poll_eerd_eewr_done(hw, IGC_NVM_POLL_READ);
|
||||
if (ret_val)
|
||||
break;
|
||||
|
||||
data[i] = (rd32(IGC_EERD) >> IGC_NVM_RW_REG_DATA);
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_mac_addr - Read device MAC address
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
s32 igc_read_mac_addr(struct igc_hw *hw)
|
||||
{
|
||||
u32 rar_high;
|
||||
u32 rar_low;
|
||||
u16 i;
|
||||
|
||||
rar_high = rd32(IGC_RAH(0));
|
||||
rar_low = rd32(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_ALEN; i++)
|
||||
hw->mac.addr[i] = hw->mac.perm_addr[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_validate_nvm_checksum - 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(struct igc_hw *hw)
|
||||
{
|
||||
u16 checksum = 0;
|
||||
u16 i, nvm_data;
|
||||
s32 ret_val = 0;
|
||||
|
||||
for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
|
||||
ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("NVM Read Error\n");
|
||||
goto out;
|
||||
}
|
||||
checksum += nvm_data;
|
||||
}
|
||||
|
||||
if (checksum != (u16)NVM_SUM) {
|
||||
hw_dbg("NVM Checksum Invalid\n");
|
||||
ret_val = -IGC_ERR_NVM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_update_nvm_checksum - 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(struct igc_hw *hw)
|
||||
{
|
||||
u16 checksum = 0;
|
||||
u16 i, nvm_data;
|
||||
s32 ret_val;
|
||||
|
||||
for (i = 0; i < NVM_CHECKSUM_REG; i++) {
|
||||
ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("NVM Read Error while updating checksum.\n");
|
||||
goto out;
|
||||
}
|
||||
checksum += nvm_data;
|
||||
}
|
||||
checksum = (u16)NVM_SUM - checksum;
|
||||
ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
|
||||
if (ret_val)
|
||||
hw_dbg("NVM Write Error while updating checksum.\n");
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_NVM_H_
|
||||
#define _IGC_NVM_H_
|
||||
|
||||
s32 igc_acquire_nvm(struct igc_hw *hw);
|
||||
void igc_release_nvm(struct igc_hw *hw);
|
||||
s32 igc_read_mac_addr(struct igc_hw *hw);
|
||||
s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words, u16 *data);
|
||||
s32 igc_validate_nvm_checksum(struct igc_hw *hw);
|
||||
s32 igc_update_nvm_checksum(struct igc_hw *hw);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include "igc_mac-6.6-ethercat.h"
|
||||
#include "igc_nvm-6.6-ethercat.h"
|
||||
|
||||
/**
|
||||
* 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'.
|
||||
*/
|
||||
static s32 igc_poll_eerd_eewr_done(struct igc_hw *hw, int ee_reg)
|
||||
{
|
||||
s32 ret_val = -IGC_ERR_NVM;
|
||||
u32 attempts = 100000;
|
||||
u32 i, reg = 0;
|
||||
|
||||
for (i = 0; i < attempts; i++) {
|
||||
if (ee_reg == IGC_NVM_POLL_READ)
|
||||
reg = rd32(IGC_EERD);
|
||||
else
|
||||
reg = rd32(IGC_EEWR);
|
||||
|
||||
if (reg & IGC_NVM_RW_REG_DONE) {
|
||||
ret_val = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_acquire_nvm - 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(struct igc_hw *hw)
|
||||
{
|
||||
s32 timeout = IGC_NVM_GRANT_ATTEMPTS;
|
||||
u32 eecd = rd32(IGC_EECD);
|
||||
s32 ret_val = 0;
|
||||
|
||||
wr32(IGC_EECD, eecd | IGC_EECD_REQ);
|
||||
eecd = rd32(IGC_EECD);
|
||||
|
||||
while (timeout) {
|
||||
if (eecd & IGC_EECD_GNT)
|
||||
break;
|
||||
udelay(5);
|
||||
eecd = rd32(IGC_EECD);
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
eecd &= ~IGC_EECD_REQ;
|
||||
wr32(IGC_EECD, eecd);
|
||||
hw_dbg("Could not acquire NVM grant\n");
|
||||
ret_val = -IGC_ERR_NVM;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_release_nvm - 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(struct igc_hw *hw)
|
||||
{
|
||||
u32 eecd;
|
||||
|
||||
eecd = rd32(IGC_EECD);
|
||||
eecd &= ~IGC_EECD_REQ;
|
||||
wr32(IGC_EECD, eecd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = 0;
|
||||
|
||||
/* 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) {
|
||||
hw_dbg("nvm parameter(s) out of bounds\n");
|
||||
ret_val = -IGC_ERR_NVM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < words; i++) {
|
||||
eerd = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) +
|
||||
IGC_NVM_RW_REG_START;
|
||||
|
||||
wr32(IGC_EERD, eerd);
|
||||
ret_val = igc_poll_eerd_eewr_done(hw, IGC_NVM_POLL_READ);
|
||||
if (ret_val)
|
||||
break;
|
||||
|
||||
data[i] = (rd32(IGC_EERD) >> IGC_NVM_RW_REG_DATA);
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_mac_addr - Read device MAC address
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
s32 igc_read_mac_addr(struct igc_hw *hw)
|
||||
{
|
||||
u32 rar_high;
|
||||
u32 rar_low;
|
||||
u16 i;
|
||||
|
||||
rar_high = rd32(IGC_RAH(0));
|
||||
rar_low = rd32(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_ALEN; i++)
|
||||
hw->mac.addr[i] = hw->mac.perm_addr[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_validate_nvm_checksum - 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(struct igc_hw *hw)
|
||||
{
|
||||
u16 checksum = 0;
|
||||
u16 i, nvm_data;
|
||||
s32 ret_val = 0;
|
||||
|
||||
for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
|
||||
ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("NVM Read Error\n");
|
||||
goto out;
|
||||
}
|
||||
checksum += nvm_data;
|
||||
}
|
||||
|
||||
if (checksum != (u16)NVM_SUM) {
|
||||
hw_dbg("NVM Checksum Invalid\n");
|
||||
ret_val = -IGC_ERR_NVM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_update_nvm_checksum - 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(struct igc_hw *hw)
|
||||
{
|
||||
u16 checksum = 0;
|
||||
u16 i, nvm_data;
|
||||
s32 ret_val;
|
||||
|
||||
for (i = 0; i < NVM_CHECKSUM_REG; i++) {
|
||||
ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("NVM Read Error while updating checksum.\n");
|
||||
goto out;
|
||||
}
|
||||
checksum += nvm_data;
|
||||
}
|
||||
checksum = (u16)NVM_SUM - checksum;
|
||||
ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
|
||||
if (ret_val)
|
||||
hw_dbg("NVM Write Error while updating checksum.\n");
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_NVM_H_
|
||||
#define _IGC_NVM_H_
|
||||
|
||||
s32 igc_acquire_nvm(struct igc_hw *hw);
|
||||
void igc_release_nvm(struct igc_hw *hw);
|
||||
s32 igc_read_mac_addr(struct igc_hw *hw);
|
||||
s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words, u16 *data);
|
||||
s32 igc_validate_nvm_checksum(struct igc_hw *hw);
|
||||
s32 igc_update_nvm_checksum(struct igc_hw *hw);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include "igc_mac.h"
|
||||
#include "igc_nvm.h"
|
||||
|
||||
/**
|
||||
* 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'.
|
||||
*/
|
||||
static s32 igc_poll_eerd_eewr_done(struct igc_hw *hw, int ee_reg)
|
||||
{
|
||||
s32 ret_val = -IGC_ERR_NVM;
|
||||
u32 attempts = 100000;
|
||||
u32 i, reg = 0;
|
||||
|
||||
for (i = 0; i < attempts; i++) {
|
||||
if (ee_reg == IGC_NVM_POLL_READ)
|
||||
reg = rd32(IGC_EERD);
|
||||
else
|
||||
reg = rd32(IGC_EEWR);
|
||||
|
||||
if (reg & IGC_NVM_RW_REG_DONE) {
|
||||
ret_val = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_acquire_nvm - 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(struct igc_hw *hw)
|
||||
{
|
||||
s32 timeout = IGC_NVM_GRANT_ATTEMPTS;
|
||||
u32 eecd = rd32(IGC_EECD);
|
||||
s32 ret_val = 0;
|
||||
|
||||
wr32(IGC_EECD, eecd | IGC_EECD_REQ);
|
||||
eecd = rd32(IGC_EECD);
|
||||
|
||||
while (timeout) {
|
||||
if (eecd & IGC_EECD_GNT)
|
||||
break;
|
||||
udelay(5);
|
||||
eecd = rd32(IGC_EECD);
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
eecd &= ~IGC_EECD_REQ;
|
||||
wr32(IGC_EECD, eecd);
|
||||
hw_dbg("Could not acquire NVM grant\n");
|
||||
ret_val = -IGC_ERR_NVM;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_release_nvm - 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(struct igc_hw *hw)
|
||||
{
|
||||
u32 eecd;
|
||||
|
||||
eecd = rd32(IGC_EECD);
|
||||
eecd &= ~IGC_EECD_REQ;
|
||||
wr32(IGC_EECD, eecd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = 0;
|
||||
|
||||
/* 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) {
|
||||
hw_dbg("nvm parameter(s) out of bounds\n");
|
||||
ret_val = -IGC_ERR_NVM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < words; i++) {
|
||||
eerd = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) +
|
||||
IGC_NVM_RW_REG_START;
|
||||
|
||||
wr32(IGC_EERD, eerd);
|
||||
ret_val = igc_poll_eerd_eewr_done(hw, IGC_NVM_POLL_READ);
|
||||
if (ret_val)
|
||||
break;
|
||||
|
||||
data[i] = (rd32(IGC_EERD) >> IGC_NVM_RW_REG_DATA);
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_mac_addr - Read device MAC address
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
s32 igc_read_mac_addr(struct igc_hw *hw)
|
||||
{
|
||||
u32 rar_high;
|
||||
u32 rar_low;
|
||||
u16 i;
|
||||
|
||||
rar_high = rd32(IGC_RAH(0));
|
||||
rar_low = rd32(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_ALEN; i++)
|
||||
hw->mac.addr[i] = hw->mac.perm_addr[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_validate_nvm_checksum - 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(struct igc_hw *hw)
|
||||
{
|
||||
u16 checksum = 0;
|
||||
u16 i, nvm_data;
|
||||
s32 ret_val = 0;
|
||||
|
||||
for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
|
||||
ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("NVM Read Error\n");
|
||||
goto out;
|
||||
}
|
||||
checksum += nvm_data;
|
||||
}
|
||||
|
||||
if (checksum != (u16)NVM_SUM) {
|
||||
hw_dbg("NVM Checksum Invalid\n");
|
||||
ret_val = -IGC_ERR_NVM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_update_nvm_checksum - 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(struct igc_hw *hw)
|
||||
{
|
||||
u16 checksum = 0;
|
||||
u16 i, nvm_data;
|
||||
s32 ret_val;
|
||||
|
||||
for (i = 0; i < NVM_CHECKSUM_REG; i++) {
|
||||
ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
|
||||
if (ret_val) {
|
||||
hw_dbg("NVM Read Error while updating checksum.\n");
|
||||
goto out;
|
||||
}
|
||||
checksum += nvm_data;
|
||||
}
|
||||
checksum = (u16)NVM_SUM - checksum;
|
||||
ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
|
||||
if (ret_val)
|
||||
hw_dbg("NVM Write Error while updating checksum.\n");
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_NVM_H_
|
||||
#define _IGC_NVM_H_
|
||||
|
||||
s32 igc_acquire_nvm(struct igc_hw *hw);
|
||||
void igc_release_nvm(struct igc_hw *hw);
|
||||
s32 igc_read_mac_addr(struct igc_hw *hw);
|
||||
s32 igc_read_nvm_eerd(struct igc_hw *hw, u16 offset, u16 words, u16 *data);
|
||||
s32 igc_validate_nvm_checksum(struct igc_hw *hw);
|
||||
s32 igc_update_nvm_checksum(struct igc_hw *hw);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,795 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include "igc_phy-6.4-ethercat.h"
|
||||
|
||||
/**
|
||||
* igc_check_reset_block - Check if PHY reset is blocked
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Read the PHY management control register and check whether a PHY reset
|
||||
* is blocked. If a reset is not blocked return 0, otherwise
|
||||
* return IGC_ERR_BLK_PHY_RESET (12).
|
||||
*/
|
||||
s32 igc_check_reset_block(struct igc_hw *hw)
|
||||
{
|
||||
u32 manc;
|
||||
|
||||
manc = rd32(IGC_MANC);
|
||||
|
||||
return (manc & IGC_MANC_BLK_PHY_RST_ON_IDE) ?
|
||||
IGC_ERR_BLK_PHY_RESET : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_phy_id - Retrieve the PHY ID and revision
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Reads the PHY registers and stores the PHY ID and possibly the PHY
|
||||
* revision in the hardware structure.
|
||||
*/
|
||||
s32 igc_get_phy_id(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
s32 ret_val = 0;
|
||||
u16 phy_id;
|
||||
|
||||
ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
phy->id = (u32)(phy_id << 16);
|
||||
usleep_range(200, 500);
|
||||
ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
|
||||
phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_phy_has_link - Polls PHY for link
|
||||
* @hw: pointer to the HW structure
|
||||
* @iterations: number of times to poll for link
|
||||
* @usec_interval: delay between polling attempts
|
||||
* @success: pointer to whether polling was successful or not
|
||||
*
|
||||
* Polls the PHY status register for link, 'iterations' number of times.
|
||||
*/
|
||||
s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations,
|
||||
u32 usec_interval, bool *success)
|
||||
{
|
||||
u16 i, phy_status;
|
||||
s32 ret_val = 0;
|
||||
|
||||
for (i = 0; i < iterations; i++) {
|
||||
/* Some PHYs require the PHY_STATUS register to be read
|
||||
* twice due to the link bit being sticky. No harm doing
|
||||
* it across the board.
|
||||
*/
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
|
||||
if (ret_val && usec_interval > 0) {
|
||||
/* If the first read fails, another entity may have
|
||||
* ownership of the resources, wait and try again to
|
||||
* see if they have relinquished the resources yet.
|
||||
*/
|
||||
if (usec_interval >= 1000)
|
||||
mdelay(usec_interval / 1000);
|
||||
else
|
||||
udelay(usec_interval);
|
||||
}
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
|
||||
if (ret_val)
|
||||
break;
|
||||
if (phy_status & MII_SR_LINK_STATUS)
|
||||
break;
|
||||
if (usec_interval >= 1000)
|
||||
mdelay(usec_interval / 1000);
|
||||
else
|
||||
udelay(usec_interval);
|
||||
}
|
||||
|
||||
*success = (i < iterations) ? true : false;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_power_up_phy_copper - Restore copper link in case of 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, restore the link to previous settings.
|
||||
*/
|
||||
void igc_power_up_phy_copper(struct igc_hw *hw)
|
||||
{
|
||||
u16 mii_reg = 0;
|
||||
|
||||
/* The PHY will retain its settings across a power down/up cycle */
|
||||
hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
|
||||
mii_reg &= ~MII_CR_POWER_DOWN;
|
||||
hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_power_down_phy_copper - Power down copper PHY
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Power down PHY to save power when interface is down and wake on lan
|
||||
* is not enabled.
|
||||
*/
|
||||
void igc_power_down_phy_copper(struct igc_hw *hw)
|
||||
{
|
||||
u16 mii_reg = 0;
|
||||
|
||||
/* The PHY will retain its settings across a power down/up cycle */
|
||||
hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
|
||||
mii_reg |= MII_CR_POWER_DOWN;
|
||||
|
||||
/* Temporary workaround - should be removed when PHY will implement
|
||||
* IEEE registers as properly
|
||||
*/
|
||||
/* hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);*/
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_check_downshift - Checks whether a downshift in speed occurred
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* A downshift is detected by querying the PHY link health.
|
||||
*/
|
||||
void igc_check_downshift(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
|
||||
/* speed downshift not supported */
|
||||
phy->speed_downgraded = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_phy_hw_reset - PHY hardware reset
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Verify the reset block is not blocking us from resetting. Acquire
|
||||
* semaphore (if necessary) and read/set/write the device control reset
|
||||
* bit in the PHY. Wait the appropriate delay time for the device to
|
||||
* reset and release the semaphore (if necessary).
|
||||
*/
|
||||
s32 igc_phy_hw_reset(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u32 phpm = 0, timeout = 10000;
|
||||
s32 ret_val;
|
||||
u32 ctrl;
|
||||
|
||||
ret_val = igc_check_reset_block(hw);
|
||||
if (ret_val) {
|
||||
ret_val = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_val = phy->ops.acquire(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
phpm = rd32(IGC_I225_PHPM);
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
wr32(IGC_CTRL, ctrl | IGC_CTRL_PHY_RST);
|
||||
wrfl();
|
||||
|
||||
udelay(phy->reset_delay_us);
|
||||
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
wrfl();
|
||||
|
||||
/* SW should guarantee 100us for the completion of the PHY reset */
|
||||
usleep_range(100, 150);
|
||||
do {
|
||||
phpm = rd32(IGC_I225_PHPM);
|
||||
timeout--;
|
||||
udelay(1);
|
||||
} while (!(phpm & IGC_PHY_RST_COMP) && timeout);
|
||||
|
||||
if (!timeout)
|
||||
hw_dbg("Timeout is expired after a phy reset\n");
|
||||
|
||||
usleep_range(100, 150);
|
||||
|
||||
phy->ops.release(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_phy_setup_autoneg - Configure PHY for auto-negotiation
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Reads the MII auto-neg advertisement register and/or the 1000T control
|
||||
* register and if the PHY is already setup for auto-negotiation, then
|
||||
* return successful. Otherwise, setup advertisement and flow control to
|
||||
* the appropriate values for the wanted auto-negotiation.
|
||||
*/
|
||||
static s32 igc_phy_setup_autoneg(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u16 aneg_multigbt_an_ctrl = 0;
|
||||
u16 mii_1000t_ctrl_reg = 0;
|
||||
u16 mii_autoneg_adv_reg;
|
||||
s32 ret_val;
|
||||
|
||||
phy->autoneg_advertised &= phy->autoneg_mask;
|
||||
|
||||
/* Read the MII Auto-Neg Advertisement Register (Address 4). */
|
||||
ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
|
||||
/* Read the MII 1000Base-T Control Register (Address 9). */
|
||||
ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
|
||||
&mii_1000t_ctrl_reg);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
if (phy->autoneg_mask & ADVERTISE_2500_FULL) {
|
||||
/* Read the MULTI GBT AN Control Register - reg 7.32 */
|
||||
ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK <<
|
||||
MMD_DEVADDR_SHIFT) |
|
||||
ANEG_MULTIGBT_AN_CTRL,
|
||||
&aneg_multigbt_an_ctrl);
|
||||
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/* Need to parse both autoneg_advertised and fc and set up
|
||||
* the appropriate PHY registers. First we will parse for
|
||||
* autoneg_advertised software override. Since we can advertise
|
||||
* a plethora of combinations, we need to check each bit
|
||||
* individually.
|
||||
*/
|
||||
|
||||
/* First we clear all the 10/100 mb speed bits in the Auto-Neg
|
||||
* Advertisement Register (Address 4) and the 1000 mb speed bits in
|
||||
* the 1000Base-T Control Register (Address 9).
|
||||
*/
|
||||
mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
|
||||
NWAY_AR_100TX_HD_CAPS |
|
||||
NWAY_AR_10T_FD_CAPS |
|
||||
NWAY_AR_10T_HD_CAPS);
|
||||
mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
|
||||
|
||||
hw_dbg("autoneg_advertised %x\n", phy->autoneg_advertised);
|
||||
|
||||
/* Do we want to advertise 10 Mb Half Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
|
||||
hw_dbg("Advertise 10mb Half duplex\n");
|
||||
mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
|
||||
}
|
||||
|
||||
/* Do we want to advertise 10 Mb Full Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
|
||||
hw_dbg("Advertise 10mb Full duplex\n");
|
||||
mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
|
||||
}
|
||||
|
||||
/* Do we want to advertise 100 Mb Half Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
|
||||
hw_dbg("Advertise 100mb Half duplex\n");
|
||||
mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
|
||||
}
|
||||
|
||||
/* Do we want to advertise 100 Mb Full Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
|
||||
hw_dbg("Advertise 100mb Full duplex\n");
|
||||
mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
|
||||
}
|
||||
|
||||
/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
|
||||
if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
|
||||
hw_dbg("Advertise 1000mb Half duplex request denied!\n");
|
||||
|
||||
/* Do we want to advertise 1000 Mb Full Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
|
||||
hw_dbg("Advertise 1000mb Full duplex\n");
|
||||
mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
|
||||
}
|
||||
|
||||
/* We do not allow the Phy to advertise 2500 Mb Half Duplex */
|
||||
if (phy->autoneg_advertised & ADVERTISE_2500_HALF)
|
||||
hw_dbg("Advertise 2500mb Half duplex request denied!\n");
|
||||
|
||||
/* Do we want to advertise 2500 Mb Full Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_2500_FULL) {
|
||||
hw_dbg("Advertise 2500mb Full duplex\n");
|
||||
aneg_multigbt_an_ctrl |= CR_2500T_FD_CAPS;
|
||||
} else {
|
||||
aneg_multigbt_an_ctrl &= ~CR_2500T_FD_CAPS;
|
||||
}
|
||||
|
||||
/* Check for a software override of the flow control settings, and
|
||||
* setup the PHY advertisement registers accordingly. If
|
||||
* auto-negotiation is enabled, then software will have to set the
|
||||
* "PAUSE" bits to the correct value in the Auto-Negotiation
|
||||
* Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
|
||||
* negotiation.
|
||||
*
|
||||
* The possible values of the "fc" parameter are:
|
||||
* 0: Flow control is completely disabled
|
||||
* 1: Rx flow control is enabled (we can receive pause frames
|
||||
* but not send pause frames).
|
||||
* 2: Tx flow control is enabled (we can send pause frames
|
||||
* but we do not support receiving pause frames).
|
||||
* 3: Both Rx and Tx flow control (symmetric) are enabled.
|
||||
* other: No software override. The flow control configuration
|
||||
* in the EEPROM is used.
|
||||
*/
|
||||
switch (hw->fc.current_mode) {
|
||||
case igc_fc_none:
|
||||
/* Flow control (Rx & Tx) is completely disabled by a
|
||||
* software over-ride.
|
||||
*/
|
||||
mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
|
||||
break;
|
||||
case igc_fc_rx_pause:
|
||||
/* Rx Flow control is enabled, and Tx Flow control is
|
||||
* disabled, by a software over-ride.
|
||||
*
|
||||
* Since there really isn't a way to advertise that we are
|
||||
* capable of Rx Pause ONLY, we will advertise that we
|
||||
* support both symmetric and asymmetric Rx PAUSE. Later
|
||||
* (in igc_config_fc_after_link_up) we will disable the
|
||||
* hw's ability to send PAUSE frames.
|
||||
*/
|
||||
mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
|
||||
break;
|
||||
case igc_fc_tx_pause:
|
||||
/* Tx Flow control is enabled, and Rx Flow control is
|
||||
* disabled, by a software over-ride.
|
||||
*/
|
||||
mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
|
||||
mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
|
||||
break;
|
||||
case igc_fc_full:
|
||||
/* Flow control (both Rx and Tx) is enabled by a software
|
||||
* over-ride.
|
||||
*/
|
||||
mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
|
||||
break;
|
||||
default:
|
||||
hw_dbg("Flow control param set incorrectly\n");
|
||||
return -IGC_ERR_CONFIG;
|
||||
}
|
||||
|
||||
ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
hw_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
|
||||
|
||||
if (phy->autoneg_mask & ADVERTISE_1000_FULL)
|
||||
ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL,
|
||||
mii_1000t_ctrl_reg);
|
||||
|
||||
if (phy->autoneg_mask & ADVERTISE_2500_FULL)
|
||||
ret_val = phy->ops.write_reg(hw,
|
||||
(STANDARD_AN_REG_MASK <<
|
||||
MMD_DEVADDR_SHIFT) |
|
||||
ANEG_MULTIGBT_AN_CTRL,
|
||||
aneg_multigbt_an_ctrl);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_wait_autoneg - Wait for auto-neg completion
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Waits for auto-negotiation to complete or for the auto-negotiation time
|
||||
* limit to expire, which ever happens first.
|
||||
*/
|
||||
static s32 igc_wait_autoneg(struct igc_hw *hw)
|
||||
{
|
||||
u16 i, phy_status;
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
|
||||
for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
|
||||
if (ret_val)
|
||||
break;
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
|
||||
if (ret_val)
|
||||
break;
|
||||
if (phy_status & MII_SR_AUTONEG_COMPLETE)
|
||||
break;
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
/* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
|
||||
* has completed.
|
||||
*/
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_copper_link_autoneg - Setup/Enable autoneg for copper link
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Performs initial bounds checking on autoneg advertisement parameter, then
|
||||
* configure to advertise the full capability. Setup the PHY to autoneg
|
||||
* and restart the negotiation process between the link partner. If
|
||||
* autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
|
||||
*/
|
||||
static s32 igc_copper_link_autoneg(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u16 phy_ctrl;
|
||||
s32 ret_val;
|
||||
|
||||
/* Perform some bounds checking on the autoneg advertisement
|
||||
* parameter.
|
||||
*/
|
||||
phy->autoneg_advertised &= phy->autoneg_mask;
|
||||
|
||||
/* If autoneg_advertised is zero, we assume it was not defaulted
|
||||
* by the calling code so we set to advertise full capability.
|
||||
*/
|
||||
if (phy->autoneg_advertised == 0)
|
||||
phy->autoneg_advertised = phy->autoneg_mask;
|
||||
|
||||
hw_dbg("Reconfiguring auto-neg advertisement params\n");
|
||||
ret_val = igc_phy_setup_autoneg(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error Setting up Auto-Negotiation\n");
|
||||
goto out;
|
||||
}
|
||||
hw_dbg("Restarting Auto-Neg\n");
|
||||
|
||||
/* Restart auto-negotiation by setting the Auto Neg Enable bit and
|
||||
* the Auto Neg Restart bit in the PHY control register.
|
||||
*/
|
||||
ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
|
||||
ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* Does the user want to wait for Auto-Neg to complete here, or
|
||||
* check at a later time (for example, callback routine).
|
||||
*/
|
||||
if (phy->autoneg_wait_to_complete) {
|
||||
ret_val = igc_wait_autoneg(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error while waiting for autoneg to complete\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
hw->mac.get_link_status = true;
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_setup_copper_link - Configure copper link settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Calls the appropriate function to configure the link for auto-neg or forced
|
||||
* speed and duplex. Then we check for link, once link is established calls
|
||||
* to configure collision distance and flow control are called. If link is
|
||||
* not established, we return -IGC_ERR_PHY (-2).
|
||||
*/
|
||||
s32 igc_setup_copper_link(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
bool link;
|
||||
|
||||
if (hw->mac.autoneg) {
|
||||
/* Setup autoneg and flow control advertisement and perform
|
||||
* autonegotiation.
|
||||
*/
|
||||
ret_val = igc_copper_link_autoneg(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
} else {
|
||||
/* PHY will be set to 10H, 10F, 100H or 100F
|
||||
* depending on user settings.
|
||||
*/
|
||||
hw_dbg("Forcing Speed and Duplex\n");
|
||||
ret_val = hw->phy.ops.force_speed_duplex(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error Forcing Speed and Duplex\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check link status. Wait up to 100 microseconds for link to become
|
||||
* valid.
|
||||
*/
|
||||
ret_val = igc_phy_has_link(hw, COPPER_LINK_UP_LIMIT, 10, &link);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
if (link) {
|
||||
hw_dbg("Valid link established!!!\n");
|
||||
igc_config_collision_dist(hw);
|
||||
ret_val = igc_config_fc_after_link_up(hw);
|
||||
} else {
|
||||
hw_dbg("Unable to establish link!!!\n");
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_phy_reg_mdic - Read MDI control register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: register offset to be read
|
||||
* @data: pointer to the read data
|
||||
*
|
||||
* Reads the MDI control register in the PHY at offset and stores the
|
||||
* information read to data.
|
||||
*/
|
||||
static s32 igc_read_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 *data)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u32 i, mdic = 0;
|
||||
s32 ret_val = 0;
|
||||
|
||||
if (offset > MAX_PHY_REG_ADDRESS) {
|
||||
hw_dbg("PHY Address %d is out of range\n", offset);
|
||||
ret_val = -IGC_ERR_PARAM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set up Op-code, Phy Address, and register offset in the MDI
|
||||
* Control register. The MAC will take care of interfacing with the
|
||||
* PHY to retrieve the desired data.
|
||||
*/
|
||||
mdic = ((offset << IGC_MDIC_REG_SHIFT) |
|
||||
(phy->addr << IGC_MDIC_PHY_SHIFT) |
|
||||
(IGC_MDIC_OP_READ));
|
||||
|
||||
wr32(IGC_MDIC, mdic);
|
||||
|
||||
/* Poll the ready bit to see if the MDI read completed
|
||||
* Increasing the time out as testing showed failures with
|
||||
* the lower time out
|
||||
*/
|
||||
for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {
|
||||
udelay(50);
|
||||
mdic = rd32(IGC_MDIC);
|
||||
if (mdic & IGC_MDIC_READY)
|
||||
break;
|
||||
}
|
||||
if (!(mdic & IGC_MDIC_READY)) {
|
||||
hw_dbg("MDI Read did not complete\n");
|
||||
ret_val = -IGC_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
if (mdic & IGC_MDIC_ERROR) {
|
||||
hw_dbg("MDI Error\n");
|
||||
ret_val = -IGC_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
*data = (u16)mdic;
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_phy_reg_mdic - Write MDI control register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: register offset to write to
|
||||
* @data: data to write to register at offset
|
||||
*
|
||||
* Writes data to MDI control register in the PHY at offset.
|
||||
*/
|
||||
static s32 igc_write_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 data)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u32 i, mdic = 0;
|
||||
s32 ret_val = 0;
|
||||
|
||||
if (offset > MAX_PHY_REG_ADDRESS) {
|
||||
hw_dbg("PHY Address %d is out of range\n", offset);
|
||||
ret_val = -IGC_ERR_PARAM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set up Op-code, Phy Address, and register offset in the MDI
|
||||
* Control register. The MAC will take care of interfacing with the
|
||||
* PHY to write the desired data.
|
||||
*/
|
||||
mdic = (((u32)data) |
|
||||
(offset << IGC_MDIC_REG_SHIFT) |
|
||||
(phy->addr << IGC_MDIC_PHY_SHIFT) |
|
||||
(IGC_MDIC_OP_WRITE));
|
||||
|
||||
wr32(IGC_MDIC, mdic);
|
||||
|
||||
/* Poll the ready bit to see if the MDI read completed
|
||||
* Increasing the time out as testing showed failures with
|
||||
* the lower time out
|
||||
*/
|
||||
for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {
|
||||
udelay(50);
|
||||
mdic = rd32(IGC_MDIC);
|
||||
if (mdic & IGC_MDIC_READY)
|
||||
break;
|
||||
}
|
||||
if (!(mdic & IGC_MDIC_READY)) {
|
||||
hw_dbg("MDI Write did not complete\n");
|
||||
ret_val = -IGC_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
if (mdic & IGC_MDIC_ERROR) {
|
||||
hw_dbg("MDI Error\n");
|
||||
ret_val = -IGC_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* __igc_access_xmdio_reg - Read/write XMDIO register
|
||||
* @hw: pointer to the HW structure
|
||||
* @address: XMDIO address to program
|
||||
* @dev_addr: device address to program
|
||||
* @data: pointer to value to read/write from/to the XMDIO address
|
||||
* @read: boolean flag to indicate read or write
|
||||
*/
|
||||
static s32 __igc_access_xmdio_reg(struct igc_hw *hw, u16 address,
|
||||
u8 dev_addr, u16 *data, bool read)
|
||||
{
|
||||
s32 ret_val;
|
||||
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, dev_addr);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, address);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, IGC_MMDAC_FUNC_DATA |
|
||||
dev_addr);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
if (read)
|
||||
ret_val = hw->phy.ops.read_reg(hw, IGC_MMDAAD, data);
|
||||
else
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, *data);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
/* Recalibrate the device back to 0 */
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, 0);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_xmdio_reg - Read XMDIO register
|
||||
* @hw: pointer to the HW structure
|
||||
* @addr: XMDIO address to program
|
||||
* @dev_addr: device address to program
|
||||
* @data: value to be read from the EMI address
|
||||
*/
|
||||
static s32 igc_read_xmdio_reg(struct igc_hw *hw, u16 addr,
|
||||
u8 dev_addr, u16 *data)
|
||||
{
|
||||
return __igc_access_xmdio_reg(hw, addr, dev_addr, data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_xmdio_reg - Write XMDIO register
|
||||
* @hw: pointer to the HW structure
|
||||
* @addr: XMDIO address to program
|
||||
* @dev_addr: device address to program
|
||||
* @data: value to be written to the XMDIO address
|
||||
*/
|
||||
static s32 igc_write_xmdio_reg(struct igc_hw *hw, u16 addr,
|
||||
u8 dev_addr, u16 data)
|
||||
{
|
||||
return __igc_access_xmdio_reg(hw, addr, dev_addr, &data, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_phy_reg_gpy - Write GPY PHY register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: register offset to write to
|
||||
* @data: data to write at register offset
|
||||
*
|
||||
* Acquires semaphore, if necessary, then writes the data to PHY register
|
||||
* at the offset. Release any acquired semaphores before exiting.
|
||||
*/
|
||||
s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data)
|
||||
{
|
||||
u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
|
||||
s32 ret_val;
|
||||
|
||||
offset = offset & GPY_REG_MASK;
|
||||
|
||||
if (!dev_addr) {
|
||||
ret_val = hw->phy.ops.acquire(hw);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
ret_val = igc_write_phy_reg_mdic(hw, offset, data);
|
||||
hw->phy.ops.release(hw);
|
||||
} else {
|
||||
ret_val = igc_write_xmdio_reg(hw, (u16)offset, dev_addr,
|
||||
data);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_phy_reg_gpy - Read GPY PHY register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: lower half is register offset to read to
|
||||
* upper half is MMD to use.
|
||||
* @data: data to read at register offset
|
||||
*
|
||||
* Acquires semaphore, if necessary, then reads the data in the PHY register
|
||||
* at the offset. Release any acquired semaphores before exiting.
|
||||
*/
|
||||
s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data)
|
||||
{
|
||||
u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
|
||||
s32 ret_val;
|
||||
|
||||
offset = offset & GPY_REG_MASK;
|
||||
|
||||
if (!dev_addr) {
|
||||
ret_val = hw->phy.ops.acquire(hw);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
ret_val = igc_read_phy_reg_mdic(hw, offset, data);
|
||||
hw->phy.ops.release(hw);
|
||||
} else {
|
||||
ret_val = igc_read_xmdio_reg(hw, (u16)offset, dev_addr,
|
||||
data);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_phy_fw_version - Read gPHY firmware version
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
u16 igc_read_phy_fw_version(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u16 gphy_version = 0;
|
||||
u16 ret_val;
|
||||
|
||||
/* NVM image version is reported as firmware version for i225 device */
|
||||
ret_val = phy->ops.read_reg(hw, IGC_GPHY_VERSION, &gphy_version);
|
||||
if (ret_val)
|
||||
hw_dbg("igc_phy: read wrong gphy version\n");
|
||||
|
||||
return gphy_version;
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_PHY_H_
|
||||
#define _IGC_PHY_H_
|
||||
|
||||
#include "igc_mac-6.4-ethercat.h"
|
||||
|
||||
s32 igc_check_reset_block(struct igc_hw *hw);
|
||||
s32 igc_phy_hw_reset(struct igc_hw *hw);
|
||||
s32 igc_get_phy_id(struct igc_hw *hw);
|
||||
s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations,
|
||||
u32 usec_interval, bool *success);
|
||||
void igc_check_downshift(struct igc_hw *hw);
|
||||
s32 igc_setup_copper_link(struct igc_hw *hw);
|
||||
void igc_power_up_phy_copper(struct igc_hw *hw);
|
||||
void igc_power_down_phy_copper(struct igc_hw *hw);
|
||||
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);
|
||||
u16 igc_read_phy_fw_version(struct igc_hw *hw);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,795 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include "igc_phy.h"
|
||||
|
||||
/**
|
||||
* igc_check_reset_block - Check if PHY reset is blocked
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Read the PHY management control register and check whether a PHY reset
|
||||
* is blocked. If a reset is not blocked return 0, otherwise
|
||||
* return IGC_ERR_BLK_PHY_RESET (12).
|
||||
*/
|
||||
s32 igc_check_reset_block(struct igc_hw *hw)
|
||||
{
|
||||
u32 manc;
|
||||
|
||||
manc = rd32(IGC_MANC);
|
||||
|
||||
return (manc & IGC_MANC_BLK_PHY_RST_ON_IDE) ?
|
||||
IGC_ERR_BLK_PHY_RESET : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_phy_id - Retrieve the PHY ID and revision
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Reads the PHY registers and stores the PHY ID and possibly the PHY
|
||||
* revision in the hardware structure.
|
||||
*/
|
||||
s32 igc_get_phy_id(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
s32 ret_val = 0;
|
||||
u16 phy_id;
|
||||
|
||||
ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
phy->id = (u32)(phy_id << 16);
|
||||
usleep_range(200, 500);
|
||||
ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
|
||||
phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_phy_has_link - Polls PHY for link
|
||||
* @hw: pointer to the HW structure
|
||||
* @iterations: number of times to poll for link
|
||||
* @usec_interval: delay between polling attempts
|
||||
* @success: pointer to whether polling was successful or not
|
||||
*
|
||||
* Polls the PHY status register for link, 'iterations' number of times.
|
||||
*/
|
||||
s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations,
|
||||
u32 usec_interval, bool *success)
|
||||
{
|
||||
u16 i, phy_status;
|
||||
s32 ret_val = 0;
|
||||
|
||||
for (i = 0; i < iterations; i++) {
|
||||
/* Some PHYs require the PHY_STATUS register to be read
|
||||
* twice due to the link bit being sticky. No harm doing
|
||||
* it across the board.
|
||||
*/
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
|
||||
if (ret_val && usec_interval > 0) {
|
||||
/* If the first read fails, another entity may have
|
||||
* ownership of the resources, wait and try again to
|
||||
* see if they have relinquished the resources yet.
|
||||
*/
|
||||
if (usec_interval >= 1000)
|
||||
mdelay(usec_interval / 1000);
|
||||
else
|
||||
udelay(usec_interval);
|
||||
}
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
|
||||
if (ret_val)
|
||||
break;
|
||||
if (phy_status & MII_SR_LINK_STATUS)
|
||||
break;
|
||||
if (usec_interval >= 1000)
|
||||
mdelay(usec_interval / 1000);
|
||||
else
|
||||
udelay(usec_interval);
|
||||
}
|
||||
|
||||
*success = (i < iterations) ? true : false;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_power_up_phy_copper - Restore copper link in case of 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, restore the link to previous settings.
|
||||
*/
|
||||
void igc_power_up_phy_copper(struct igc_hw *hw)
|
||||
{
|
||||
u16 mii_reg = 0;
|
||||
|
||||
/* The PHY will retain its settings across a power down/up cycle */
|
||||
hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
|
||||
mii_reg &= ~MII_CR_POWER_DOWN;
|
||||
hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_power_down_phy_copper - Power down copper PHY
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Power down PHY to save power when interface is down and wake on lan
|
||||
* is not enabled.
|
||||
*/
|
||||
void igc_power_down_phy_copper(struct igc_hw *hw)
|
||||
{
|
||||
u16 mii_reg = 0;
|
||||
|
||||
/* The PHY will retain its settings across a power down/up cycle */
|
||||
hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
|
||||
mii_reg |= MII_CR_POWER_DOWN;
|
||||
|
||||
/* Temporary workaround - should be removed when PHY will implement
|
||||
* IEEE registers as properly
|
||||
*/
|
||||
/* hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);*/
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_check_downshift - Checks whether a downshift in speed occurred
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* A downshift is detected by querying the PHY link health.
|
||||
*/
|
||||
void igc_check_downshift(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
|
||||
/* speed downshift not supported */
|
||||
phy->speed_downgraded = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_phy_hw_reset - PHY hardware reset
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Verify the reset block is not blocking us from resetting. Acquire
|
||||
* semaphore (if necessary) and read/set/write the device control reset
|
||||
* bit in the PHY. Wait the appropriate delay time for the device to
|
||||
* reset and release the semaphore (if necessary).
|
||||
*/
|
||||
s32 igc_phy_hw_reset(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u32 phpm = 0, timeout = 10000;
|
||||
s32 ret_val;
|
||||
u32 ctrl;
|
||||
|
||||
ret_val = igc_check_reset_block(hw);
|
||||
if (ret_val) {
|
||||
ret_val = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_val = phy->ops.acquire(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
phpm = rd32(IGC_I225_PHPM);
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
wr32(IGC_CTRL, ctrl | IGC_CTRL_PHY_RST);
|
||||
wrfl();
|
||||
|
||||
udelay(phy->reset_delay_us);
|
||||
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
wrfl();
|
||||
|
||||
/* SW should guarantee 100us for the completion of the PHY reset */
|
||||
usleep_range(100, 150);
|
||||
do {
|
||||
phpm = rd32(IGC_I225_PHPM);
|
||||
timeout--;
|
||||
udelay(1);
|
||||
} while (!(phpm & IGC_PHY_RST_COMP) && timeout);
|
||||
|
||||
if (!timeout)
|
||||
hw_dbg("Timeout is expired after a phy reset\n");
|
||||
|
||||
usleep_range(100, 150);
|
||||
|
||||
phy->ops.release(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_phy_setup_autoneg - Configure PHY for auto-negotiation
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Reads the MII auto-neg advertisement register and/or the 1000T control
|
||||
* register and if the PHY is already setup for auto-negotiation, then
|
||||
* return successful. Otherwise, setup advertisement and flow control to
|
||||
* the appropriate values for the wanted auto-negotiation.
|
||||
*/
|
||||
static s32 igc_phy_setup_autoneg(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u16 aneg_multigbt_an_ctrl = 0;
|
||||
u16 mii_1000t_ctrl_reg = 0;
|
||||
u16 mii_autoneg_adv_reg;
|
||||
s32 ret_val;
|
||||
|
||||
phy->autoneg_advertised &= phy->autoneg_mask;
|
||||
|
||||
/* Read the MII Auto-Neg Advertisement Register (Address 4). */
|
||||
ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
|
||||
/* Read the MII 1000Base-T Control Register (Address 9). */
|
||||
ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
|
||||
&mii_1000t_ctrl_reg);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
if (phy->autoneg_mask & ADVERTISE_2500_FULL) {
|
||||
/* Read the MULTI GBT AN Control Register - reg 7.32 */
|
||||
ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK <<
|
||||
MMD_DEVADDR_SHIFT) |
|
||||
ANEG_MULTIGBT_AN_CTRL,
|
||||
&aneg_multigbt_an_ctrl);
|
||||
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/* Need to parse both autoneg_advertised and fc and set up
|
||||
* the appropriate PHY registers. First we will parse for
|
||||
* autoneg_advertised software override. Since we can advertise
|
||||
* a plethora of combinations, we need to check each bit
|
||||
* individually.
|
||||
*/
|
||||
|
||||
/* First we clear all the 10/100 mb speed bits in the Auto-Neg
|
||||
* Advertisement Register (Address 4) and the 1000 mb speed bits in
|
||||
* the 1000Base-T Control Register (Address 9).
|
||||
*/
|
||||
mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
|
||||
NWAY_AR_100TX_HD_CAPS |
|
||||
NWAY_AR_10T_FD_CAPS |
|
||||
NWAY_AR_10T_HD_CAPS);
|
||||
mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
|
||||
|
||||
hw_dbg("autoneg_advertised %x\n", phy->autoneg_advertised);
|
||||
|
||||
/* Do we want to advertise 10 Mb Half Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
|
||||
hw_dbg("Advertise 10mb Half duplex\n");
|
||||
mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
|
||||
}
|
||||
|
||||
/* Do we want to advertise 10 Mb Full Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
|
||||
hw_dbg("Advertise 10mb Full duplex\n");
|
||||
mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
|
||||
}
|
||||
|
||||
/* Do we want to advertise 100 Mb Half Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
|
||||
hw_dbg("Advertise 100mb Half duplex\n");
|
||||
mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
|
||||
}
|
||||
|
||||
/* Do we want to advertise 100 Mb Full Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
|
||||
hw_dbg("Advertise 100mb Full duplex\n");
|
||||
mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
|
||||
}
|
||||
|
||||
/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
|
||||
if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
|
||||
hw_dbg("Advertise 1000mb Half duplex request denied!\n");
|
||||
|
||||
/* Do we want to advertise 1000 Mb Full Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
|
||||
hw_dbg("Advertise 1000mb Full duplex\n");
|
||||
mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
|
||||
}
|
||||
|
||||
/* We do not allow the Phy to advertise 2500 Mb Half Duplex */
|
||||
if (phy->autoneg_advertised & ADVERTISE_2500_HALF)
|
||||
hw_dbg("Advertise 2500mb Half duplex request denied!\n");
|
||||
|
||||
/* Do we want to advertise 2500 Mb Full Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_2500_FULL) {
|
||||
hw_dbg("Advertise 2500mb Full duplex\n");
|
||||
aneg_multigbt_an_ctrl |= CR_2500T_FD_CAPS;
|
||||
} else {
|
||||
aneg_multigbt_an_ctrl &= ~CR_2500T_FD_CAPS;
|
||||
}
|
||||
|
||||
/* Check for a software override of the flow control settings, and
|
||||
* setup the PHY advertisement registers accordingly. If
|
||||
* auto-negotiation is enabled, then software will have to set the
|
||||
* "PAUSE" bits to the correct value in the Auto-Negotiation
|
||||
* Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
|
||||
* negotiation.
|
||||
*
|
||||
* The possible values of the "fc" parameter are:
|
||||
* 0: Flow control is completely disabled
|
||||
* 1: Rx flow control is enabled (we can receive pause frames
|
||||
* but not send pause frames).
|
||||
* 2: Tx flow control is enabled (we can send pause frames
|
||||
* but we do not support receiving pause frames).
|
||||
* 3: Both Rx and Tx flow control (symmetric) are enabled.
|
||||
* other: No software override. The flow control configuration
|
||||
* in the EEPROM is used.
|
||||
*/
|
||||
switch (hw->fc.current_mode) {
|
||||
case igc_fc_none:
|
||||
/* Flow control (Rx & Tx) is completely disabled by a
|
||||
* software over-ride.
|
||||
*/
|
||||
mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
|
||||
break;
|
||||
case igc_fc_rx_pause:
|
||||
/* Rx Flow control is enabled, and Tx Flow control is
|
||||
* disabled, by a software over-ride.
|
||||
*
|
||||
* Since there really isn't a way to advertise that we are
|
||||
* capable of Rx Pause ONLY, we will advertise that we
|
||||
* support both symmetric and asymmetric Rx PAUSE. Later
|
||||
* (in igc_config_fc_after_link_up) we will disable the
|
||||
* hw's ability to send PAUSE frames.
|
||||
*/
|
||||
mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
|
||||
break;
|
||||
case igc_fc_tx_pause:
|
||||
/* Tx Flow control is enabled, and Rx Flow control is
|
||||
* disabled, by a software over-ride.
|
||||
*/
|
||||
mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
|
||||
mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
|
||||
break;
|
||||
case igc_fc_full:
|
||||
/* Flow control (both Rx and Tx) is enabled by a software
|
||||
* over-ride.
|
||||
*/
|
||||
mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
|
||||
break;
|
||||
default:
|
||||
hw_dbg("Flow control param set incorrectly\n");
|
||||
return -IGC_ERR_CONFIG;
|
||||
}
|
||||
|
||||
ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
hw_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
|
||||
|
||||
if (phy->autoneg_mask & ADVERTISE_1000_FULL)
|
||||
ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL,
|
||||
mii_1000t_ctrl_reg);
|
||||
|
||||
if (phy->autoneg_mask & ADVERTISE_2500_FULL)
|
||||
ret_val = phy->ops.write_reg(hw,
|
||||
(STANDARD_AN_REG_MASK <<
|
||||
MMD_DEVADDR_SHIFT) |
|
||||
ANEG_MULTIGBT_AN_CTRL,
|
||||
aneg_multigbt_an_ctrl);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_wait_autoneg - Wait for auto-neg completion
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Waits for auto-negotiation to complete or for the auto-negotiation time
|
||||
* limit to expire, which ever happens first.
|
||||
*/
|
||||
static s32 igc_wait_autoneg(struct igc_hw *hw)
|
||||
{
|
||||
u16 i, phy_status;
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
|
||||
for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
|
||||
if (ret_val)
|
||||
break;
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
|
||||
if (ret_val)
|
||||
break;
|
||||
if (phy_status & MII_SR_AUTONEG_COMPLETE)
|
||||
break;
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
/* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
|
||||
* has completed.
|
||||
*/
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_copper_link_autoneg - Setup/Enable autoneg for copper link
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Performs initial bounds checking on autoneg advertisement parameter, then
|
||||
* configure to advertise the full capability. Setup the PHY to autoneg
|
||||
* and restart the negotiation process between the link partner. If
|
||||
* autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
|
||||
*/
|
||||
static s32 igc_copper_link_autoneg(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u16 phy_ctrl;
|
||||
s32 ret_val;
|
||||
|
||||
/* Perform some bounds checking on the autoneg advertisement
|
||||
* parameter.
|
||||
*/
|
||||
phy->autoneg_advertised &= phy->autoneg_mask;
|
||||
|
||||
/* If autoneg_advertised is zero, we assume it was not defaulted
|
||||
* by the calling code so we set to advertise full capability.
|
||||
*/
|
||||
if (phy->autoneg_advertised == 0)
|
||||
phy->autoneg_advertised = phy->autoneg_mask;
|
||||
|
||||
hw_dbg("Reconfiguring auto-neg advertisement params\n");
|
||||
ret_val = igc_phy_setup_autoneg(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error Setting up Auto-Negotiation\n");
|
||||
goto out;
|
||||
}
|
||||
hw_dbg("Restarting Auto-Neg\n");
|
||||
|
||||
/* Restart auto-negotiation by setting the Auto Neg Enable bit and
|
||||
* the Auto Neg Restart bit in the PHY control register.
|
||||
*/
|
||||
ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
|
||||
ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* Does the user want to wait for Auto-Neg to complete here, or
|
||||
* check at a later time (for example, callback routine).
|
||||
*/
|
||||
if (phy->autoneg_wait_to_complete) {
|
||||
ret_val = igc_wait_autoneg(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error while waiting for autoneg to complete\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
hw->mac.get_link_status = true;
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_setup_copper_link - Configure copper link settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Calls the appropriate function to configure the link for auto-neg or forced
|
||||
* speed and duplex. Then we check for link, once link is established calls
|
||||
* to configure collision distance and flow control are called. If link is
|
||||
* not established, we return -IGC_ERR_PHY (-2).
|
||||
*/
|
||||
s32 igc_setup_copper_link(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
bool link;
|
||||
|
||||
if (hw->mac.autoneg) {
|
||||
/* Setup autoneg and flow control advertisement and perform
|
||||
* autonegotiation.
|
||||
*/
|
||||
ret_val = igc_copper_link_autoneg(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
} else {
|
||||
/* PHY will be set to 10H, 10F, 100H or 100F
|
||||
* depending on user settings.
|
||||
*/
|
||||
hw_dbg("Forcing Speed and Duplex\n");
|
||||
ret_val = hw->phy.ops.force_speed_duplex(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error Forcing Speed and Duplex\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check link status. Wait up to 100 microseconds for link to become
|
||||
* valid.
|
||||
*/
|
||||
ret_val = igc_phy_has_link(hw, COPPER_LINK_UP_LIMIT, 10, &link);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
if (link) {
|
||||
hw_dbg("Valid link established!!!\n");
|
||||
igc_config_collision_dist(hw);
|
||||
ret_val = igc_config_fc_after_link_up(hw);
|
||||
} else {
|
||||
hw_dbg("Unable to establish link!!!\n");
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_phy_reg_mdic - Read MDI control register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: register offset to be read
|
||||
* @data: pointer to the read data
|
||||
*
|
||||
* Reads the MDI control register in the PHY at offset and stores the
|
||||
* information read to data.
|
||||
*/
|
||||
static s32 igc_read_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 *data)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u32 i, mdic = 0;
|
||||
s32 ret_val = 0;
|
||||
|
||||
if (offset > MAX_PHY_REG_ADDRESS) {
|
||||
hw_dbg("PHY Address %d is out of range\n", offset);
|
||||
ret_val = -IGC_ERR_PARAM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set up Op-code, Phy Address, and register offset in the MDI
|
||||
* Control register. The MAC will take care of interfacing with the
|
||||
* PHY to retrieve the desired data.
|
||||
*/
|
||||
mdic = ((offset << IGC_MDIC_REG_SHIFT) |
|
||||
(phy->addr << IGC_MDIC_PHY_SHIFT) |
|
||||
(IGC_MDIC_OP_READ));
|
||||
|
||||
wr32(IGC_MDIC, mdic);
|
||||
|
||||
/* Poll the ready bit to see if the MDI read completed
|
||||
* Increasing the time out as testing showed failures with
|
||||
* the lower time out
|
||||
*/
|
||||
for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {
|
||||
udelay(50);
|
||||
mdic = rd32(IGC_MDIC);
|
||||
if (mdic & IGC_MDIC_READY)
|
||||
break;
|
||||
}
|
||||
if (!(mdic & IGC_MDIC_READY)) {
|
||||
hw_dbg("MDI Read did not complete\n");
|
||||
ret_val = -IGC_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
if (mdic & IGC_MDIC_ERROR) {
|
||||
hw_dbg("MDI Error\n");
|
||||
ret_val = -IGC_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
*data = (u16)mdic;
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_phy_reg_mdic - Write MDI control register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: register offset to write to
|
||||
* @data: data to write to register at offset
|
||||
*
|
||||
* Writes data to MDI control register in the PHY at offset.
|
||||
*/
|
||||
static s32 igc_write_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 data)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u32 i, mdic = 0;
|
||||
s32 ret_val = 0;
|
||||
|
||||
if (offset > MAX_PHY_REG_ADDRESS) {
|
||||
hw_dbg("PHY Address %d is out of range\n", offset);
|
||||
ret_val = -IGC_ERR_PARAM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set up Op-code, Phy Address, and register offset in the MDI
|
||||
* Control register. The MAC will take care of interfacing with the
|
||||
* PHY to write the desired data.
|
||||
*/
|
||||
mdic = (((u32)data) |
|
||||
(offset << IGC_MDIC_REG_SHIFT) |
|
||||
(phy->addr << IGC_MDIC_PHY_SHIFT) |
|
||||
(IGC_MDIC_OP_WRITE));
|
||||
|
||||
wr32(IGC_MDIC, mdic);
|
||||
|
||||
/* Poll the ready bit to see if the MDI read completed
|
||||
* Increasing the time out as testing showed failures with
|
||||
* the lower time out
|
||||
*/
|
||||
for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {
|
||||
udelay(50);
|
||||
mdic = rd32(IGC_MDIC);
|
||||
if (mdic & IGC_MDIC_READY)
|
||||
break;
|
||||
}
|
||||
if (!(mdic & IGC_MDIC_READY)) {
|
||||
hw_dbg("MDI Write did not complete\n");
|
||||
ret_val = -IGC_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
if (mdic & IGC_MDIC_ERROR) {
|
||||
hw_dbg("MDI Error\n");
|
||||
ret_val = -IGC_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* __igc_access_xmdio_reg - Read/write XMDIO register
|
||||
* @hw: pointer to the HW structure
|
||||
* @address: XMDIO address to program
|
||||
* @dev_addr: device address to program
|
||||
* @data: pointer to value to read/write from/to the XMDIO address
|
||||
* @read: boolean flag to indicate read or write
|
||||
*/
|
||||
static s32 __igc_access_xmdio_reg(struct igc_hw *hw, u16 address,
|
||||
u8 dev_addr, u16 *data, bool read)
|
||||
{
|
||||
s32 ret_val;
|
||||
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, dev_addr);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, address);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, IGC_MMDAC_FUNC_DATA |
|
||||
dev_addr);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
if (read)
|
||||
ret_val = hw->phy.ops.read_reg(hw, IGC_MMDAAD, data);
|
||||
else
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, *data);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
/* Recalibrate the device back to 0 */
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, 0);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_xmdio_reg - Read XMDIO register
|
||||
* @hw: pointer to the HW structure
|
||||
* @addr: XMDIO address to program
|
||||
* @dev_addr: device address to program
|
||||
* @data: value to be read from the EMI address
|
||||
*/
|
||||
static s32 igc_read_xmdio_reg(struct igc_hw *hw, u16 addr,
|
||||
u8 dev_addr, u16 *data)
|
||||
{
|
||||
return __igc_access_xmdio_reg(hw, addr, dev_addr, data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_xmdio_reg - Write XMDIO register
|
||||
* @hw: pointer to the HW structure
|
||||
* @addr: XMDIO address to program
|
||||
* @dev_addr: device address to program
|
||||
* @data: value to be written to the XMDIO address
|
||||
*/
|
||||
static s32 igc_write_xmdio_reg(struct igc_hw *hw, u16 addr,
|
||||
u8 dev_addr, u16 data)
|
||||
{
|
||||
return __igc_access_xmdio_reg(hw, addr, dev_addr, &data, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_phy_reg_gpy - Write GPY PHY register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: register offset to write to
|
||||
* @data: data to write at register offset
|
||||
*
|
||||
* Acquires semaphore, if necessary, then writes the data to PHY register
|
||||
* at the offset. Release any acquired semaphores before exiting.
|
||||
*/
|
||||
s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data)
|
||||
{
|
||||
u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
|
||||
s32 ret_val;
|
||||
|
||||
offset = offset & GPY_REG_MASK;
|
||||
|
||||
if (!dev_addr) {
|
||||
ret_val = hw->phy.ops.acquire(hw);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
ret_val = igc_write_phy_reg_mdic(hw, offset, data);
|
||||
hw->phy.ops.release(hw);
|
||||
} else {
|
||||
ret_val = igc_write_xmdio_reg(hw, (u16)offset, dev_addr,
|
||||
data);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_phy_reg_gpy - Read GPY PHY register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: lower half is register offset to read to
|
||||
* upper half is MMD to use.
|
||||
* @data: data to read at register offset
|
||||
*
|
||||
* Acquires semaphore, if necessary, then reads the data in the PHY register
|
||||
* at the offset. Release any acquired semaphores before exiting.
|
||||
*/
|
||||
s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data)
|
||||
{
|
||||
u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
|
||||
s32 ret_val;
|
||||
|
||||
offset = offset & GPY_REG_MASK;
|
||||
|
||||
if (!dev_addr) {
|
||||
ret_val = hw->phy.ops.acquire(hw);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
ret_val = igc_read_phy_reg_mdic(hw, offset, data);
|
||||
hw->phy.ops.release(hw);
|
||||
} else {
|
||||
ret_val = igc_read_xmdio_reg(hw, (u16)offset, dev_addr,
|
||||
data);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_phy_fw_version - Read gPHY firmware version
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
u16 igc_read_phy_fw_version(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u16 gphy_version = 0;
|
||||
u16 ret_val;
|
||||
|
||||
/* NVM image version is reported as firmware version for i225 device */
|
||||
ret_val = phy->ops.read_reg(hw, IGC_GPHY_VERSION, &gphy_version);
|
||||
if (ret_val)
|
||||
hw_dbg("igc_phy: read wrong gphy version\n");
|
||||
|
||||
return gphy_version;
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_PHY_H_
|
||||
#define _IGC_PHY_H_
|
||||
|
||||
#include "igc_mac.h"
|
||||
|
||||
s32 igc_check_reset_block(struct igc_hw *hw);
|
||||
s32 igc_phy_hw_reset(struct igc_hw *hw);
|
||||
s32 igc_get_phy_id(struct igc_hw *hw);
|
||||
s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations,
|
||||
u32 usec_interval, bool *success);
|
||||
void igc_check_downshift(struct igc_hw *hw);
|
||||
s32 igc_setup_copper_link(struct igc_hw *hw);
|
||||
void igc_power_up_phy_copper(struct igc_hw *hw);
|
||||
void igc_power_down_phy_copper(struct igc_hw *hw);
|
||||
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);
|
||||
u16 igc_read_phy_fw_version(struct igc_hw *hw);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,795 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include "igc_phy-6.6-ethercat.h"
|
||||
|
||||
/**
|
||||
* igc_check_reset_block - Check if PHY reset is blocked
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Read the PHY management control register and check whether a PHY reset
|
||||
* is blocked. If a reset is not blocked return 0, otherwise
|
||||
* return IGC_ERR_BLK_PHY_RESET (12).
|
||||
*/
|
||||
s32 igc_check_reset_block(struct igc_hw *hw)
|
||||
{
|
||||
u32 manc;
|
||||
|
||||
manc = rd32(IGC_MANC);
|
||||
|
||||
return (manc & IGC_MANC_BLK_PHY_RST_ON_IDE) ?
|
||||
IGC_ERR_BLK_PHY_RESET : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_phy_id - Retrieve the PHY ID and revision
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Reads the PHY registers and stores the PHY ID and possibly the PHY
|
||||
* revision in the hardware structure.
|
||||
*/
|
||||
s32 igc_get_phy_id(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
s32 ret_val = 0;
|
||||
u16 phy_id;
|
||||
|
||||
ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
phy->id = (u32)(phy_id << 16);
|
||||
usleep_range(200, 500);
|
||||
ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
|
||||
phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_phy_has_link - Polls PHY for link
|
||||
* @hw: pointer to the HW structure
|
||||
* @iterations: number of times to poll for link
|
||||
* @usec_interval: delay between polling attempts
|
||||
* @success: pointer to whether polling was successful or not
|
||||
*
|
||||
* Polls the PHY status register for link, 'iterations' number of times.
|
||||
*/
|
||||
s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations,
|
||||
u32 usec_interval, bool *success)
|
||||
{
|
||||
u16 i, phy_status;
|
||||
s32 ret_val = 0;
|
||||
|
||||
for (i = 0; i < iterations; i++) {
|
||||
/* Some PHYs require the PHY_STATUS register to be read
|
||||
* twice due to the link bit being sticky. No harm doing
|
||||
* it across the board.
|
||||
*/
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
|
||||
if (ret_val && usec_interval > 0) {
|
||||
/* If the first read fails, another entity may have
|
||||
* ownership of the resources, wait and try again to
|
||||
* see if they have relinquished the resources yet.
|
||||
*/
|
||||
if (usec_interval >= 1000)
|
||||
mdelay(usec_interval / 1000);
|
||||
else
|
||||
udelay(usec_interval);
|
||||
}
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
|
||||
if (ret_val)
|
||||
break;
|
||||
if (phy_status & MII_SR_LINK_STATUS)
|
||||
break;
|
||||
if (usec_interval >= 1000)
|
||||
mdelay(usec_interval / 1000);
|
||||
else
|
||||
udelay(usec_interval);
|
||||
}
|
||||
|
||||
*success = (i < iterations) ? true : false;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_power_up_phy_copper - Restore copper link in case of 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, restore the link to previous settings.
|
||||
*/
|
||||
void igc_power_up_phy_copper(struct igc_hw *hw)
|
||||
{
|
||||
u16 mii_reg = 0;
|
||||
|
||||
/* The PHY will retain its settings across a power down/up cycle */
|
||||
hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
|
||||
mii_reg &= ~MII_CR_POWER_DOWN;
|
||||
hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_power_down_phy_copper - Power down copper PHY
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Power down PHY to save power when interface is down and wake on lan
|
||||
* is not enabled.
|
||||
*/
|
||||
void igc_power_down_phy_copper(struct igc_hw *hw)
|
||||
{
|
||||
u16 mii_reg = 0;
|
||||
|
||||
/* The PHY will retain its settings across a power down/up cycle */
|
||||
hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
|
||||
mii_reg |= MII_CR_POWER_DOWN;
|
||||
|
||||
/* Temporary workaround - should be removed when PHY will implement
|
||||
* IEEE registers as properly
|
||||
*/
|
||||
/* hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);*/
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_check_downshift - Checks whether a downshift in speed occurred
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* A downshift is detected by querying the PHY link health.
|
||||
*/
|
||||
void igc_check_downshift(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
|
||||
/* speed downshift not supported */
|
||||
phy->speed_downgraded = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_phy_hw_reset - PHY hardware reset
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Verify the reset block is not blocking us from resetting. Acquire
|
||||
* semaphore (if necessary) and read/set/write the device control reset
|
||||
* bit in the PHY. Wait the appropriate delay time for the device to
|
||||
* reset and release the semaphore (if necessary).
|
||||
*/
|
||||
s32 igc_phy_hw_reset(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u32 phpm = 0, timeout = 10000;
|
||||
s32 ret_val;
|
||||
u32 ctrl;
|
||||
|
||||
ret_val = igc_check_reset_block(hw);
|
||||
if (ret_val) {
|
||||
ret_val = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_val = phy->ops.acquire(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
phpm = rd32(IGC_I225_PHPM);
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
wr32(IGC_CTRL, ctrl | IGC_CTRL_PHY_RST);
|
||||
wrfl();
|
||||
|
||||
udelay(phy->reset_delay_us);
|
||||
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
wrfl();
|
||||
|
||||
/* SW should guarantee 100us for the completion of the PHY reset */
|
||||
usleep_range(100, 150);
|
||||
do {
|
||||
phpm = rd32(IGC_I225_PHPM);
|
||||
timeout--;
|
||||
udelay(1);
|
||||
} while (!(phpm & IGC_PHY_RST_COMP) && timeout);
|
||||
|
||||
if (!timeout)
|
||||
hw_dbg("Timeout is expired after a phy reset\n");
|
||||
|
||||
usleep_range(100, 150);
|
||||
|
||||
phy->ops.release(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_phy_setup_autoneg - Configure PHY for auto-negotiation
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Reads the MII auto-neg advertisement register and/or the 1000T control
|
||||
* register and if the PHY is already setup for auto-negotiation, then
|
||||
* return successful. Otherwise, setup advertisement and flow control to
|
||||
* the appropriate values for the wanted auto-negotiation.
|
||||
*/
|
||||
static s32 igc_phy_setup_autoneg(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u16 aneg_multigbt_an_ctrl = 0;
|
||||
u16 mii_1000t_ctrl_reg = 0;
|
||||
u16 mii_autoneg_adv_reg;
|
||||
s32 ret_val;
|
||||
|
||||
phy->autoneg_advertised &= phy->autoneg_mask;
|
||||
|
||||
/* Read the MII Auto-Neg Advertisement Register (Address 4). */
|
||||
ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
|
||||
/* Read the MII 1000Base-T Control Register (Address 9). */
|
||||
ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
|
||||
&mii_1000t_ctrl_reg);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
if (phy->autoneg_mask & ADVERTISE_2500_FULL) {
|
||||
/* Read the MULTI GBT AN Control Register - reg 7.32 */
|
||||
ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK <<
|
||||
MMD_DEVADDR_SHIFT) |
|
||||
ANEG_MULTIGBT_AN_CTRL,
|
||||
&aneg_multigbt_an_ctrl);
|
||||
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/* Need to parse both autoneg_advertised and fc and set up
|
||||
* the appropriate PHY registers. First we will parse for
|
||||
* autoneg_advertised software override. Since we can advertise
|
||||
* a plethora of combinations, we need to check each bit
|
||||
* individually.
|
||||
*/
|
||||
|
||||
/* First we clear all the 10/100 mb speed bits in the Auto-Neg
|
||||
* Advertisement Register (Address 4) and the 1000 mb speed bits in
|
||||
* the 1000Base-T Control Register (Address 9).
|
||||
*/
|
||||
mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
|
||||
NWAY_AR_100TX_HD_CAPS |
|
||||
NWAY_AR_10T_FD_CAPS |
|
||||
NWAY_AR_10T_HD_CAPS);
|
||||
mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
|
||||
|
||||
hw_dbg("autoneg_advertised %x\n", phy->autoneg_advertised);
|
||||
|
||||
/* Do we want to advertise 10 Mb Half Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
|
||||
hw_dbg("Advertise 10mb Half duplex\n");
|
||||
mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
|
||||
}
|
||||
|
||||
/* Do we want to advertise 10 Mb Full Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
|
||||
hw_dbg("Advertise 10mb Full duplex\n");
|
||||
mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
|
||||
}
|
||||
|
||||
/* Do we want to advertise 100 Mb Half Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
|
||||
hw_dbg("Advertise 100mb Half duplex\n");
|
||||
mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
|
||||
}
|
||||
|
||||
/* Do we want to advertise 100 Mb Full Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
|
||||
hw_dbg("Advertise 100mb Full duplex\n");
|
||||
mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
|
||||
}
|
||||
|
||||
/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
|
||||
if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
|
||||
hw_dbg("Advertise 1000mb Half duplex request denied!\n");
|
||||
|
||||
/* Do we want to advertise 1000 Mb Full Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
|
||||
hw_dbg("Advertise 1000mb Full duplex\n");
|
||||
mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
|
||||
}
|
||||
|
||||
/* We do not allow the Phy to advertise 2500 Mb Half Duplex */
|
||||
if (phy->autoneg_advertised & ADVERTISE_2500_HALF)
|
||||
hw_dbg("Advertise 2500mb Half duplex request denied!\n");
|
||||
|
||||
/* Do we want to advertise 2500 Mb Full Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_2500_FULL) {
|
||||
hw_dbg("Advertise 2500mb Full duplex\n");
|
||||
aneg_multigbt_an_ctrl |= CR_2500T_FD_CAPS;
|
||||
} else {
|
||||
aneg_multigbt_an_ctrl &= ~CR_2500T_FD_CAPS;
|
||||
}
|
||||
|
||||
/* Check for a software override of the flow control settings, and
|
||||
* setup the PHY advertisement registers accordingly. If
|
||||
* auto-negotiation is enabled, then software will have to set the
|
||||
* "PAUSE" bits to the correct value in the Auto-Negotiation
|
||||
* Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
|
||||
* negotiation.
|
||||
*
|
||||
* The possible values of the "fc" parameter are:
|
||||
* 0: Flow control is completely disabled
|
||||
* 1: Rx flow control is enabled (we can receive pause frames
|
||||
* but not send pause frames).
|
||||
* 2: Tx flow control is enabled (we can send pause frames
|
||||
* but we do not support receiving pause frames).
|
||||
* 3: Both Rx and Tx flow control (symmetric) are enabled.
|
||||
* other: No software override. The flow control configuration
|
||||
* in the EEPROM is used.
|
||||
*/
|
||||
switch (hw->fc.current_mode) {
|
||||
case igc_fc_none:
|
||||
/* Flow control (Rx & Tx) is completely disabled by a
|
||||
* software over-ride.
|
||||
*/
|
||||
mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
|
||||
break;
|
||||
case igc_fc_rx_pause:
|
||||
/* Rx Flow control is enabled, and Tx Flow control is
|
||||
* disabled, by a software over-ride.
|
||||
*
|
||||
* Since there really isn't a way to advertise that we are
|
||||
* capable of Rx Pause ONLY, we will advertise that we
|
||||
* support both symmetric and asymmetric Rx PAUSE. Later
|
||||
* (in igc_config_fc_after_link_up) we will disable the
|
||||
* hw's ability to send PAUSE frames.
|
||||
*/
|
||||
mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
|
||||
break;
|
||||
case igc_fc_tx_pause:
|
||||
/* Tx Flow control is enabled, and Rx Flow control is
|
||||
* disabled, by a software over-ride.
|
||||
*/
|
||||
mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
|
||||
mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
|
||||
break;
|
||||
case igc_fc_full:
|
||||
/* Flow control (both Rx and Tx) is enabled by a software
|
||||
* over-ride.
|
||||
*/
|
||||
mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
|
||||
break;
|
||||
default:
|
||||
hw_dbg("Flow control param set incorrectly\n");
|
||||
return -IGC_ERR_CONFIG;
|
||||
}
|
||||
|
||||
ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
hw_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
|
||||
|
||||
if (phy->autoneg_mask & ADVERTISE_1000_FULL)
|
||||
ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL,
|
||||
mii_1000t_ctrl_reg);
|
||||
|
||||
if (phy->autoneg_mask & ADVERTISE_2500_FULL)
|
||||
ret_val = phy->ops.write_reg(hw,
|
||||
(STANDARD_AN_REG_MASK <<
|
||||
MMD_DEVADDR_SHIFT) |
|
||||
ANEG_MULTIGBT_AN_CTRL,
|
||||
aneg_multigbt_an_ctrl);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_wait_autoneg - Wait for auto-neg completion
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Waits for auto-negotiation to complete or for the auto-negotiation time
|
||||
* limit to expire, which ever happens first.
|
||||
*/
|
||||
static s32 igc_wait_autoneg(struct igc_hw *hw)
|
||||
{
|
||||
u16 i, phy_status;
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
|
||||
for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
|
||||
if (ret_val)
|
||||
break;
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
|
||||
if (ret_val)
|
||||
break;
|
||||
if (phy_status & MII_SR_AUTONEG_COMPLETE)
|
||||
break;
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
/* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
|
||||
* has completed.
|
||||
*/
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_copper_link_autoneg - Setup/Enable autoneg for copper link
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Performs initial bounds checking on autoneg advertisement parameter, then
|
||||
* configure to advertise the full capability. Setup the PHY to autoneg
|
||||
* and restart the negotiation process between the link partner. If
|
||||
* autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
|
||||
*/
|
||||
static s32 igc_copper_link_autoneg(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u16 phy_ctrl;
|
||||
s32 ret_val;
|
||||
|
||||
/* Perform some bounds checking on the autoneg advertisement
|
||||
* parameter.
|
||||
*/
|
||||
phy->autoneg_advertised &= phy->autoneg_mask;
|
||||
|
||||
/* If autoneg_advertised is zero, we assume it was not defaulted
|
||||
* by the calling code so we set to advertise full capability.
|
||||
*/
|
||||
if (phy->autoneg_advertised == 0)
|
||||
phy->autoneg_advertised = phy->autoneg_mask;
|
||||
|
||||
hw_dbg("Reconfiguring auto-neg advertisement params\n");
|
||||
ret_val = igc_phy_setup_autoneg(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error Setting up Auto-Negotiation\n");
|
||||
goto out;
|
||||
}
|
||||
hw_dbg("Restarting Auto-Neg\n");
|
||||
|
||||
/* Restart auto-negotiation by setting the Auto Neg Enable bit and
|
||||
* the Auto Neg Restart bit in the PHY control register.
|
||||
*/
|
||||
ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
|
||||
ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* Does the user want to wait for Auto-Neg to complete here, or
|
||||
* check at a later time (for example, callback routine).
|
||||
*/
|
||||
if (phy->autoneg_wait_to_complete) {
|
||||
ret_val = igc_wait_autoneg(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error while waiting for autoneg to complete\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
hw->mac.get_link_status = true;
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_setup_copper_link - Configure copper link settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Calls the appropriate function to configure the link for auto-neg or forced
|
||||
* speed and duplex. Then we check for link, once link is established calls
|
||||
* to configure collision distance and flow control are called. If link is
|
||||
* not established, we return -IGC_ERR_PHY (-2).
|
||||
*/
|
||||
s32 igc_setup_copper_link(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
bool link;
|
||||
|
||||
if (hw->mac.autoneg) {
|
||||
/* Setup autoneg and flow control advertisement and perform
|
||||
* autonegotiation.
|
||||
*/
|
||||
ret_val = igc_copper_link_autoneg(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
} else {
|
||||
/* PHY will be set to 10H, 10F, 100H or 100F
|
||||
* depending on user settings.
|
||||
*/
|
||||
hw_dbg("Forcing Speed and Duplex\n");
|
||||
ret_val = hw->phy.ops.force_speed_duplex(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error Forcing Speed and Duplex\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check link status. Wait up to 100 microseconds for link to become
|
||||
* valid.
|
||||
*/
|
||||
ret_val = igc_phy_has_link(hw, COPPER_LINK_UP_LIMIT, 10, &link);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
if (link) {
|
||||
hw_dbg("Valid link established!!!\n");
|
||||
igc_config_collision_dist(hw);
|
||||
ret_val = igc_config_fc_after_link_up(hw);
|
||||
} else {
|
||||
hw_dbg("Unable to establish link!!!\n");
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_phy_reg_mdic - Read MDI control register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: register offset to be read
|
||||
* @data: pointer to the read data
|
||||
*
|
||||
* Reads the MDI control register in the PHY at offset and stores the
|
||||
* information read to data.
|
||||
*/
|
||||
static s32 igc_read_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 *data)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u32 i, mdic = 0;
|
||||
s32 ret_val = 0;
|
||||
|
||||
if (offset > MAX_PHY_REG_ADDRESS) {
|
||||
hw_dbg("PHY Address %d is out of range\n", offset);
|
||||
ret_val = -IGC_ERR_PARAM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set up Op-code, Phy Address, and register offset in the MDI
|
||||
* Control register. The MAC will take care of interfacing with the
|
||||
* PHY to retrieve the desired data.
|
||||
*/
|
||||
mdic = ((offset << IGC_MDIC_REG_SHIFT) |
|
||||
(phy->addr << IGC_MDIC_PHY_SHIFT) |
|
||||
(IGC_MDIC_OP_READ));
|
||||
|
||||
wr32(IGC_MDIC, mdic);
|
||||
|
||||
/* Poll the ready bit to see if the MDI read completed
|
||||
* Increasing the time out as testing showed failures with
|
||||
* the lower time out
|
||||
*/
|
||||
for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {
|
||||
udelay(50);
|
||||
mdic = rd32(IGC_MDIC);
|
||||
if (mdic & IGC_MDIC_READY)
|
||||
break;
|
||||
}
|
||||
if (!(mdic & IGC_MDIC_READY)) {
|
||||
hw_dbg("MDI Read did not complete\n");
|
||||
ret_val = -IGC_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
if (mdic & IGC_MDIC_ERROR) {
|
||||
hw_dbg("MDI Error\n");
|
||||
ret_val = -IGC_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
*data = (u16)mdic;
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_phy_reg_mdic - Write MDI control register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: register offset to write to
|
||||
* @data: data to write to register at offset
|
||||
*
|
||||
* Writes data to MDI control register in the PHY at offset.
|
||||
*/
|
||||
static s32 igc_write_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 data)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u32 i, mdic = 0;
|
||||
s32 ret_val = 0;
|
||||
|
||||
if (offset > MAX_PHY_REG_ADDRESS) {
|
||||
hw_dbg("PHY Address %d is out of range\n", offset);
|
||||
ret_val = -IGC_ERR_PARAM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set up Op-code, Phy Address, and register offset in the MDI
|
||||
* Control register. The MAC will take care of interfacing with the
|
||||
* PHY to write the desired data.
|
||||
*/
|
||||
mdic = (((u32)data) |
|
||||
(offset << IGC_MDIC_REG_SHIFT) |
|
||||
(phy->addr << IGC_MDIC_PHY_SHIFT) |
|
||||
(IGC_MDIC_OP_WRITE));
|
||||
|
||||
wr32(IGC_MDIC, mdic);
|
||||
|
||||
/* Poll the ready bit to see if the MDI read completed
|
||||
* Increasing the time out as testing showed failures with
|
||||
* the lower time out
|
||||
*/
|
||||
for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {
|
||||
udelay(50);
|
||||
mdic = rd32(IGC_MDIC);
|
||||
if (mdic & IGC_MDIC_READY)
|
||||
break;
|
||||
}
|
||||
if (!(mdic & IGC_MDIC_READY)) {
|
||||
hw_dbg("MDI Write did not complete\n");
|
||||
ret_val = -IGC_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
if (mdic & IGC_MDIC_ERROR) {
|
||||
hw_dbg("MDI Error\n");
|
||||
ret_val = -IGC_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* __igc_access_xmdio_reg - Read/write XMDIO register
|
||||
* @hw: pointer to the HW structure
|
||||
* @address: XMDIO address to program
|
||||
* @dev_addr: device address to program
|
||||
* @data: pointer to value to read/write from/to the XMDIO address
|
||||
* @read: boolean flag to indicate read or write
|
||||
*/
|
||||
static s32 __igc_access_xmdio_reg(struct igc_hw *hw, u16 address,
|
||||
u8 dev_addr, u16 *data, bool read)
|
||||
{
|
||||
s32 ret_val;
|
||||
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, dev_addr);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, address);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, IGC_MMDAC_FUNC_DATA |
|
||||
dev_addr);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
if (read)
|
||||
ret_val = hw->phy.ops.read_reg(hw, IGC_MMDAAD, data);
|
||||
else
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, *data);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
/* Recalibrate the device back to 0 */
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, 0);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_xmdio_reg - Read XMDIO register
|
||||
* @hw: pointer to the HW structure
|
||||
* @addr: XMDIO address to program
|
||||
* @dev_addr: device address to program
|
||||
* @data: value to be read from the EMI address
|
||||
*/
|
||||
static s32 igc_read_xmdio_reg(struct igc_hw *hw, u16 addr,
|
||||
u8 dev_addr, u16 *data)
|
||||
{
|
||||
return __igc_access_xmdio_reg(hw, addr, dev_addr, data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_xmdio_reg - Write XMDIO register
|
||||
* @hw: pointer to the HW structure
|
||||
* @addr: XMDIO address to program
|
||||
* @dev_addr: device address to program
|
||||
* @data: value to be written to the XMDIO address
|
||||
*/
|
||||
static s32 igc_write_xmdio_reg(struct igc_hw *hw, u16 addr,
|
||||
u8 dev_addr, u16 data)
|
||||
{
|
||||
return __igc_access_xmdio_reg(hw, addr, dev_addr, &data, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_phy_reg_gpy - Write GPY PHY register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: register offset to write to
|
||||
* @data: data to write at register offset
|
||||
*
|
||||
* Acquires semaphore, if necessary, then writes the data to PHY register
|
||||
* at the offset. Release any acquired semaphores before exiting.
|
||||
*/
|
||||
s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data)
|
||||
{
|
||||
u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
|
||||
s32 ret_val;
|
||||
|
||||
offset = offset & GPY_REG_MASK;
|
||||
|
||||
if (!dev_addr) {
|
||||
ret_val = hw->phy.ops.acquire(hw);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
ret_val = igc_write_phy_reg_mdic(hw, offset, data);
|
||||
hw->phy.ops.release(hw);
|
||||
} else {
|
||||
ret_val = igc_write_xmdio_reg(hw, (u16)offset, dev_addr,
|
||||
data);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_phy_reg_gpy - Read GPY PHY register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: lower half is register offset to read to
|
||||
* upper half is MMD to use.
|
||||
* @data: data to read at register offset
|
||||
*
|
||||
* Acquires semaphore, if necessary, then reads the data in the PHY register
|
||||
* at the offset. Release any acquired semaphores before exiting.
|
||||
*/
|
||||
s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data)
|
||||
{
|
||||
u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
|
||||
s32 ret_val;
|
||||
|
||||
offset = offset & GPY_REG_MASK;
|
||||
|
||||
if (!dev_addr) {
|
||||
ret_val = hw->phy.ops.acquire(hw);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
ret_val = igc_read_phy_reg_mdic(hw, offset, data);
|
||||
hw->phy.ops.release(hw);
|
||||
} else {
|
||||
ret_val = igc_read_xmdio_reg(hw, (u16)offset, dev_addr,
|
||||
data);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_phy_fw_version - Read gPHY firmware version
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
u16 igc_read_phy_fw_version(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u16 gphy_version = 0;
|
||||
u16 ret_val;
|
||||
|
||||
/* NVM image version is reported as firmware version for i225 device */
|
||||
ret_val = phy->ops.read_reg(hw, IGC_GPHY_VERSION, &gphy_version);
|
||||
if (ret_val)
|
||||
hw_dbg("igc_phy: read wrong gphy version\n");
|
||||
|
||||
return gphy_version;
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_PHY_H_
|
||||
#define _IGC_PHY_H_
|
||||
|
||||
#include "igc_mac-6.6-ethercat.h"
|
||||
|
||||
s32 igc_check_reset_block(struct igc_hw *hw);
|
||||
s32 igc_phy_hw_reset(struct igc_hw *hw);
|
||||
s32 igc_get_phy_id(struct igc_hw *hw);
|
||||
s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations,
|
||||
u32 usec_interval, bool *success);
|
||||
void igc_check_downshift(struct igc_hw *hw);
|
||||
s32 igc_setup_copper_link(struct igc_hw *hw);
|
||||
void igc_power_up_phy_copper(struct igc_hw *hw);
|
||||
void igc_power_down_phy_copper(struct igc_hw *hw);
|
||||
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);
|
||||
u16 igc_read_phy_fw_version(struct igc_hw *hw);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,795 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#include "igc_phy.h"
|
||||
|
||||
/**
|
||||
* igc_check_reset_block - Check if PHY reset is blocked
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Read the PHY management control register and check whether a PHY reset
|
||||
* is blocked. If a reset is not blocked return 0, otherwise
|
||||
* return IGC_ERR_BLK_PHY_RESET (12).
|
||||
*/
|
||||
s32 igc_check_reset_block(struct igc_hw *hw)
|
||||
{
|
||||
u32 manc;
|
||||
|
||||
manc = rd32(IGC_MANC);
|
||||
|
||||
return (manc & IGC_MANC_BLK_PHY_RST_ON_IDE) ?
|
||||
IGC_ERR_BLK_PHY_RESET : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_get_phy_id - Retrieve the PHY ID and revision
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Reads the PHY registers and stores the PHY ID and possibly the PHY
|
||||
* revision in the hardware structure.
|
||||
*/
|
||||
s32 igc_get_phy_id(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
s32 ret_val = 0;
|
||||
u16 phy_id;
|
||||
|
||||
ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
phy->id = (u32)(phy_id << 16);
|
||||
usleep_range(200, 500);
|
||||
ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
|
||||
phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_phy_has_link - Polls PHY for link
|
||||
* @hw: pointer to the HW structure
|
||||
* @iterations: number of times to poll for link
|
||||
* @usec_interval: delay between polling attempts
|
||||
* @success: pointer to whether polling was successful or not
|
||||
*
|
||||
* Polls the PHY status register for link, 'iterations' number of times.
|
||||
*/
|
||||
s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations,
|
||||
u32 usec_interval, bool *success)
|
||||
{
|
||||
u16 i, phy_status;
|
||||
s32 ret_val = 0;
|
||||
|
||||
for (i = 0; i < iterations; i++) {
|
||||
/* Some PHYs require the PHY_STATUS register to be read
|
||||
* twice due to the link bit being sticky. No harm doing
|
||||
* it across the board.
|
||||
*/
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
|
||||
if (ret_val && usec_interval > 0) {
|
||||
/* If the first read fails, another entity may have
|
||||
* ownership of the resources, wait and try again to
|
||||
* see if they have relinquished the resources yet.
|
||||
*/
|
||||
if (usec_interval >= 1000)
|
||||
mdelay(usec_interval / 1000);
|
||||
else
|
||||
udelay(usec_interval);
|
||||
}
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
|
||||
if (ret_val)
|
||||
break;
|
||||
if (phy_status & MII_SR_LINK_STATUS)
|
||||
break;
|
||||
if (usec_interval >= 1000)
|
||||
mdelay(usec_interval / 1000);
|
||||
else
|
||||
udelay(usec_interval);
|
||||
}
|
||||
|
||||
*success = (i < iterations) ? true : false;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_power_up_phy_copper - Restore copper link in case of 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, restore the link to previous settings.
|
||||
*/
|
||||
void igc_power_up_phy_copper(struct igc_hw *hw)
|
||||
{
|
||||
u16 mii_reg = 0;
|
||||
|
||||
/* The PHY will retain its settings across a power down/up cycle */
|
||||
hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
|
||||
mii_reg &= ~MII_CR_POWER_DOWN;
|
||||
hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_power_down_phy_copper - Power down copper PHY
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Power down PHY to save power when interface is down and wake on lan
|
||||
* is not enabled.
|
||||
*/
|
||||
void igc_power_down_phy_copper(struct igc_hw *hw)
|
||||
{
|
||||
u16 mii_reg = 0;
|
||||
|
||||
/* The PHY will retain its settings across a power down/up cycle */
|
||||
hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
|
||||
mii_reg |= MII_CR_POWER_DOWN;
|
||||
|
||||
/* Temporary workaround - should be removed when PHY will implement
|
||||
* IEEE registers as properly
|
||||
*/
|
||||
/* hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);*/
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_check_downshift - Checks whether a downshift in speed occurred
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* A downshift is detected by querying the PHY link health.
|
||||
*/
|
||||
void igc_check_downshift(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
|
||||
/* speed downshift not supported */
|
||||
phy->speed_downgraded = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_phy_hw_reset - PHY hardware reset
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Verify the reset block is not blocking us from resetting. Acquire
|
||||
* semaphore (if necessary) and read/set/write the device control reset
|
||||
* bit in the PHY. Wait the appropriate delay time for the device to
|
||||
* reset and release the semaphore (if necessary).
|
||||
*/
|
||||
s32 igc_phy_hw_reset(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u32 phpm = 0, timeout = 10000;
|
||||
s32 ret_val;
|
||||
u32 ctrl;
|
||||
|
||||
ret_val = igc_check_reset_block(hw);
|
||||
if (ret_val) {
|
||||
ret_val = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret_val = phy->ops.acquire(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
phpm = rd32(IGC_I225_PHPM);
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
wr32(IGC_CTRL, ctrl | IGC_CTRL_PHY_RST);
|
||||
wrfl();
|
||||
|
||||
udelay(phy->reset_delay_us);
|
||||
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
wrfl();
|
||||
|
||||
/* SW should guarantee 100us for the completion of the PHY reset */
|
||||
usleep_range(100, 150);
|
||||
do {
|
||||
phpm = rd32(IGC_I225_PHPM);
|
||||
timeout--;
|
||||
udelay(1);
|
||||
} while (!(phpm & IGC_PHY_RST_COMP) && timeout);
|
||||
|
||||
if (!timeout)
|
||||
hw_dbg("Timeout is expired after a phy reset\n");
|
||||
|
||||
usleep_range(100, 150);
|
||||
|
||||
phy->ops.release(hw);
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_phy_setup_autoneg - Configure PHY for auto-negotiation
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Reads the MII auto-neg advertisement register and/or the 1000T control
|
||||
* register and if the PHY is already setup for auto-negotiation, then
|
||||
* return successful. Otherwise, setup advertisement and flow control to
|
||||
* the appropriate values for the wanted auto-negotiation.
|
||||
*/
|
||||
static s32 igc_phy_setup_autoneg(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u16 aneg_multigbt_an_ctrl = 0;
|
||||
u16 mii_1000t_ctrl_reg = 0;
|
||||
u16 mii_autoneg_adv_reg;
|
||||
s32 ret_val;
|
||||
|
||||
phy->autoneg_advertised &= phy->autoneg_mask;
|
||||
|
||||
/* Read the MII Auto-Neg Advertisement Register (Address 4). */
|
||||
ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
|
||||
/* Read the MII 1000Base-T Control Register (Address 9). */
|
||||
ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
|
||||
&mii_1000t_ctrl_reg);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
if (phy->autoneg_mask & ADVERTISE_2500_FULL) {
|
||||
/* Read the MULTI GBT AN Control Register - reg 7.32 */
|
||||
ret_val = phy->ops.read_reg(hw, (STANDARD_AN_REG_MASK <<
|
||||
MMD_DEVADDR_SHIFT) |
|
||||
ANEG_MULTIGBT_AN_CTRL,
|
||||
&aneg_multigbt_an_ctrl);
|
||||
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/* Need to parse both autoneg_advertised and fc and set up
|
||||
* the appropriate PHY registers. First we will parse for
|
||||
* autoneg_advertised software override. Since we can advertise
|
||||
* a plethora of combinations, we need to check each bit
|
||||
* individually.
|
||||
*/
|
||||
|
||||
/* First we clear all the 10/100 mb speed bits in the Auto-Neg
|
||||
* Advertisement Register (Address 4) and the 1000 mb speed bits in
|
||||
* the 1000Base-T Control Register (Address 9).
|
||||
*/
|
||||
mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
|
||||
NWAY_AR_100TX_HD_CAPS |
|
||||
NWAY_AR_10T_FD_CAPS |
|
||||
NWAY_AR_10T_HD_CAPS);
|
||||
mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
|
||||
|
||||
hw_dbg("autoneg_advertised %x\n", phy->autoneg_advertised);
|
||||
|
||||
/* Do we want to advertise 10 Mb Half Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
|
||||
hw_dbg("Advertise 10mb Half duplex\n");
|
||||
mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
|
||||
}
|
||||
|
||||
/* Do we want to advertise 10 Mb Full Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
|
||||
hw_dbg("Advertise 10mb Full duplex\n");
|
||||
mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
|
||||
}
|
||||
|
||||
/* Do we want to advertise 100 Mb Half Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
|
||||
hw_dbg("Advertise 100mb Half duplex\n");
|
||||
mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
|
||||
}
|
||||
|
||||
/* Do we want to advertise 100 Mb Full Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
|
||||
hw_dbg("Advertise 100mb Full duplex\n");
|
||||
mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
|
||||
}
|
||||
|
||||
/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
|
||||
if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
|
||||
hw_dbg("Advertise 1000mb Half duplex request denied!\n");
|
||||
|
||||
/* Do we want to advertise 1000 Mb Full Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
|
||||
hw_dbg("Advertise 1000mb Full duplex\n");
|
||||
mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
|
||||
}
|
||||
|
||||
/* We do not allow the Phy to advertise 2500 Mb Half Duplex */
|
||||
if (phy->autoneg_advertised & ADVERTISE_2500_HALF)
|
||||
hw_dbg("Advertise 2500mb Half duplex request denied!\n");
|
||||
|
||||
/* Do we want to advertise 2500 Mb Full Duplex? */
|
||||
if (phy->autoneg_advertised & ADVERTISE_2500_FULL) {
|
||||
hw_dbg("Advertise 2500mb Full duplex\n");
|
||||
aneg_multigbt_an_ctrl |= CR_2500T_FD_CAPS;
|
||||
} else {
|
||||
aneg_multigbt_an_ctrl &= ~CR_2500T_FD_CAPS;
|
||||
}
|
||||
|
||||
/* Check for a software override of the flow control settings, and
|
||||
* setup the PHY advertisement registers accordingly. If
|
||||
* auto-negotiation is enabled, then software will have to set the
|
||||
* "PAUSE" bits to the correct value in the Auto-Negotiation
|
||||
* Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
|
||||
* negotiation.
|
||||
*
|
||||
* The possible values of the "fc" parameter are:
|
||||
* 0: Flow control is completely disabled
|
||||
* 1: Rx flow control is enabled (we can receive pause frames
|
||||
* but not send pause frames).
|
||||
* 2: Tx flow control is enabled (we can send pause frames
|
||||
* but we do not support receiving pause frames).
|
||||
* 3: Both Rx and Tx flow control (symmetric) are enabled.
|
||||
* other: No software override. The flow control configuration
|
||||
* in the EEPROM is used.
|
||||
*/
|
||||
switch (hw->fc.current_mode) {
|
||||
case igc_fc_none:
|
||||
/* Flow control (Rx & Tx) is completely disabled by a
|
||||
* software over-ride.
|
||||
*/
|
||||
mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
|
||||
break;
|
||||
case igc_fc_rx_pause:
|
||||
/* Rx Flow control is enabled, and Tx Flow control is
|
||||
* disabled, by a software over-ride.
|
||||
*
|
||||
* Since there really isn't a way to advertise that we are
|
||||
* capable of Rx Pause ONLY, we will advertise that we
|
||||
* support both symmetric and asymmetric Rx PAUSE. Later
|
||||
* (in igc_config_fc_after_link_up) we will disable the
|
||||
* hw's ability to send PAUSE frames.
|
||||
*/
|
||||
mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
|
||||
break;
|
||||
case igc_fc_tx_pause:
|
||||
/* Tx Flow control is enabled, and Rx Flow control is
|
||||
* disabled, by a software over-ride.
|
||||
*/
|
||||
mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
|
||||
mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
|
||||
break;
|
||||
case igc_fc_full:
|
||||
/* Flow control (both Rx and Tx) is enabled by a software
|
||||
* over-ride.
|
||||
*/
|
||||
mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
|
||||
break;
|
||||
default:
|
||||
hw_dbg("Flow control param set incorrectly\n");
|
||||
return -IGC_ERR_CONFIG;
|
||||
}
|
||||
|
||||
ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
hw_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
|
||||
|
||||
if (phy->autoneg_mask & ADVERTISE_1000_FULL)
|
||||
ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL,
|
||||
mii_1000t_ctrl_reg);
|
||||
|
||||
if (phy->autoneg_mask & ADVERTISE_2500_FULL)
|
||||
ret_val = phy->ops.write_reg(hw,
|
||||
(STANDARD_AN_REG_MASK <<
|
||||
MMD_DEVADDR_SHIFT) |
|
||||
ANEG_MULTIGBT_AN_CTRL,
|
||||
aneg_multigbt_an_ctrl);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_wait_autoneg - Wait for auto-neg completion
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Waits for auto-negotiation to complete or for the auto-negotiation time
|
||||
* limit to expire, which ever happens first.
|
||||
*/
|
||||
static s32 igc_wait_autoneg(struct igc_hw *hw)
|
||||
{
|
||||
u16 i, phy_status;
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
|
||||
for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
|
||||
if (ret_val)
|
||||
break;
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
|
||||
if (ret_val)
|
||||
break;
|
||||
if (phy_status & MII_SR_AUTONEG_COMPLETE)
|
||||
break;
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
/* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
|
||||
* has completed.
|
||||
*/
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_copper_link_autoneg - Setup/Enable autoneg for copper link
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Performs initial bounds checking on autoneg advertisement parameter, then
|
||||
* configure to advertise the full capability. Setup the PHY to autoneg
|
||||
* and restart the negotiation process between the link partner. If
|
||||
* autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
|
||||
*/
|
||||
static s32 igc_copper_link_autoneg(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u16 phy_ctrl;
|
||||
s32 ret_val;
|
||||
|
||||
/* Perform some bounds checking on the autoneg advertisement
|
||||
* parameter.
|
||||
*/
|
||||
phy->autoneg_advertised &= phy->autoneg_mask;
|
||||
|
||||
/* If autoneg_advertised is zero, we assume it was not defaulted
|
||||
* by the calling code so we set to advertise full capability.
|
||||
*/
|
||||
if (phy->autoneg_advertised == 0)
|
||||
phy->autoneg_advertised = phy->autoneg_mask;
|
||||
|
||||
hw_dbg("Reconfiguring auto-neg advertisement params\n");
|
||||
ret_val = igc_phy_setup_autoneg(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error Setting up Auto-Negotiation\n");
|
||||
goto out;
|
||||
}
|
||||
hw_dbg("Restarting Auto-Neg\n");
|
||||
|
||||
/* Restart auto-negotiation by setting the Auto Neg Enable bit and
|
||||
* the Auto Neg Restart bit in the PHY control register.
|
||||
*/
|
||||
ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
|
||||
ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
/* Does the user want to wait for Auto-Neg to complete here, or
|
||||
* check at a later time (for example, callback routine).
|
||||
*/
|
||||
if (phy->autoneg_wait_to_complete) {
|
||||
ret_val = igc_wait_autoneg(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error while waiting for autoneg to complete\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
hw->mac.get_link_status = true;
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_setup_copper_link - Configure copper link settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Calls the appropriate function to configure the link for auto-neg or forced
|
||||
* speed and duplex. Then we check for link, once link is established calls
|
||||
* to configure collision distance and flow control are called. If link is
|
||||
* not established, we return -IGC_ERR_PHY (-2).
|
||||
*/
|
||||
s32 igc_setup_copper_link(struct igc_hw *hw)
|
||||
{
|
||||
s32 ret_val = 0;
|
||||
bool link;
|
||||
|
||||
if (hw->mac.autoneg) {
|
||||
/* Setup autoneg and flow control advertisement and perform
|
||||
* autonegotiation.
|
||||
*/
|
||||
ret_val = igc_copper_link_autoneg(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
} else {
|
||||
/* PHY will be set to 10H, 10F, 100H or 100F
|
||||
* depending on user settings.
|
||||
*/
|
||||
hw_dbg("Forcing Speed and Duplex\n");
|
||||
ret_val = hw->phy.ops.force_speed_duplex(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error Forcing Speed and Duplex\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check link status. Wait up to 100 microseconds for link to become
|
||||
* valid.
|
||||
*/
|
||||
ret_val = igc_phy_has_link(hw, COPPER_LINK_UP_LIMIT, 10, &link);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
|
||||
if (link) {
|
||||
hw_dbg("Valid link established!!!\n");
|
||||
igc_config_collision_dist(hw);
|
||||
ret_val = igc_config_fc_after_link_up(hw);
|
||||
} else {
|
||||
hw_dbg("Unable to establish link!!!\n");
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_phy_reg_mdic - Read MDI control register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: register offset to be read
|
||||
* @data: pointer to the read data
|
||||
*
|
||||
* Reads the MDI control register in the PHY at offset and stores the
|
||||
* information read to data.
|
||||
*/
|
||||
static s32 igc_read_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 *data)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u32 i, mdic = 0;
|
||||
s32 ret_val = 0;
|
||||
|
||||
if (offset > MAX_PHY_REG_ADDRESS) {
|
||||
hw_dbg("PHY Address %d is out of range\n", offset);
|
||||
ret_val = -IGC_ERR_PARAM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set up Op-code, Phy Address, and register offset in the MDI
|
||||
* Control register. The MAC will take care of interfacing with the
|
||||
* PHY to retrieve the desired data.
|
||||
*/
|
||||
mdic = ((offset << IGC_MDIC_REG_SHIFT) |
|
||||
(phy->addr << IGC_MDIC_PHY_SHIFT) |
|
||||
(IGC_MDIC_OP_READ));
|
||||
|
||||
wr32(IGC_MDIC, mdic);
|
||||
|
||||
/* Poll the ready bit to see if the MDI read completed
|
||||
* Increasing the time out as testing showed failures with
|
||||
* the lower time out
|
||||
*/
|
||||
for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {
|
||||
udelay(50);
|
||||
mdic = rd32(IGC_MDIC);
|
||||
if (mdic & IGC_MDIC_READY)
|
||||
break;
|
||||
}
|
||||
if (!(mdic & IGC_MDIC_READY)) {
|
||||
hw_dbg("MDI Read did not complete\n");
|
||||
ret_val = -IGC_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
if (mdic & IGC_MDIC_ERROR) {
|
||||
hw_dbg("MDI Error\n");
|
||||
ret_val = -IGC_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
*data = (u16)mdic;
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_phy_reg_mdic - Write MDI control register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: register offset to write to
|
||||
* @data: data to write to register at offset
|
||||
*
|
||||
* Writes data to MDI control register in the PHY at offset.
|
||||
*/
|
||||
static s32 igc_write_phy_reg_mdic(struct igc_hw *hw, u32 offset, u16 data)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u32 i, mdic = 0;
|
||||
s32 ret_val = 0;
|
||||
|
||||
if (offset > MAX_PHY_REG_ADDRESS) {
|
||||
hw_dbg("PHY Address %d is out of range\n", offset);
|
||||
ret_val = -IGC_ERR_PARAM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set up Op-code, Phy Address, and register offset in the MDI
|
||||
* Control register. The MAC will take care of interfacing with the
|
||||
* PHY to write the desired data.
|
||||
*/
|
||||
mdic = (((u32)data) |
|
||||
(offset << IGC_MDIC_REG_SHIFT) |
|
||||
(phy->addr << IGC_MDIC_PHY_SHIFT) |
|
||||
(IGC_MDIC_OP_WRITE));
|
||||
|
||||
wr32(IGC_MDIC, mdic);
|
||||
|
||||
/* Poll the ready bit to see if the MDI read completed
|
||||
* Increasing the time out as testing showed failures with
|
||||
* the lower time out
|
||||
*/
|
||||
for (i = 0; i < IGC_GEN_POLL_TIMEOUT; i++) {
|
||||
udelay(50);
|
||||
mdic = rd32(IGC_MDIC);
|
||||
if (mdic & IGC_MDIC_READY)
|
||||
break;
|
||||
}
|
||||
if (!(mdic & IGC_MDIC_READY)) {
|
||||
hw_dbg("MDI Write did not complete\n");
|
||||
ret_val = -IGC_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
if (mdic & IGC_MDIC_ERROR) {
|
||||
hw_dbg("MDI Error\n");
|
||||
ret_val = -IGC_ERR_PHY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* __igc_access_xmdio_reg - Read/write XMDIO register
|
||||
* @hw: pointer to the HW structure
|
||||
* @address: XMDIO address to program
|
||||
* @dev_addr: device address to program
|
||||
* @data: pointer to value to read/write from/to the XMDIO address
|
||||
* @read: boolean flag to indicate read or write
|
||||
*/
|
||||
static s32 __igc_access_xmdio_reg(struct igc_hw *hw, u16 address,
|
||||
u8 dev_addr, u16 *data, bool read)
|
||||
{
|
||||
s32 ret_val;
|
||||
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, dev_addr);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, address);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, IGC_MMDAC_FUNC_DATA |
|
||||
dev_addr);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
if (read)
|
||||
ret_val = hw->phy.ops.read_reg(hw, IGC_MMDAAD, data);
|
||||
else
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAAD, *data);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
/* Recalibrate the device back to 0 */
|
||||
ret_val = hw->phy.ops.write_reg(hw, IGC_MMDAC, 0);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_xmdio_reg - Read XMDIO register
|
||||
* @hw: pointer to the HW structure
|
||||
* @addr: XMDIO address to program
|
||||
* @dev_addr: device address to program
|
||||
* @data: value to be read from the EMI address
|
||||
*/
|
||||
static s32 igc_read_xmdio_reg(struct igc_hw *hw, u16 addr,
|
||||
u8 dev_addr, u16 *data)
|
||||
{
|
||||
return __igc_access_xmdio_reg(hw, addr, dev_addr, data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_xmdio_reg - Write XMDIO register
|
||||
* @hw: pointer to the HW structure
|
||||
* @addr: XMDIO address to program
|
||||
* @dev_addr: device address to program
|
||||
* @data: value to be written to the XMDIO address
|
||||
*/
|
||||
static s32 igc_write_xmdio_reg(struct igc_hw *hw, u16 addr,
|
||||
u8 dev_addr, u16 data)
|
||||
{
|
||||
return __igc_access_xmdio_reg(hw, addr, dev_addr, &data, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_phy_reg_gpy - Write GPY PHY register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: register offset to write to
|
||||
* @data: data to write at register offset
|
||||
*
|
||||
* Acquires semaphore, if necessary, then writes the data to PHY register
|
||||
* at the offset. Release any acquired semaphores before exiting.
|
||||
*/
|
||||
s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data)
|
||||
{
|
||||
u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
|
||||
s32 ret_val;
|
||||
|
||||
offset = offset & GPY_REG_MASK;
|
||||
|
||||
if (!dev_addr) {
|
||||
ret_val = hw->phy.ops.acquire(hw);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
ret_val = igc_write_phy_reg_mdic(hw, offset, data);
|
||||
hw->phy.ops.release(hw);
|
||||
} else {
|
||||
ret_val = igc_write_xmdio_reg(hw, (u16)offset, dev_addr,
|
||||
data);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_phy_reg_gpy - Read GPY PHY register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: lower half is register offset to read to
|
||||
* upper half is MMD to use.
|
||||
* @data: data to read at register offset
|
||||
*
|
||||
* Acquires semaphore, if necessary, then reads the data in the PHY register
|
||||
* at the offset. Release any acquired semaphores before exiting.
|
||||
*/
|
||||
s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data)
|
||||
{
|
||||
u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
|
||||
s32 ret_val;
|
||||
|
||||
offset = offset & GPY_REG_MASK;
|
||||
|
||||
if (!dev_addr) {
|
||||
ret_val = hw->phy.ops.acquire(hw);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
ret_val = igc_read_phy_reg_mdic(hw, offset, data);
|
||||
hw->phy.ops.release(hw);
|
||||
} else {
|
||||
ret_val = igc_read_xmdio_reg(hw, (u16)offset, dev_addr,
|
||||
data);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_read_phy_fw_version - Read gPHY firmware version
|
||||
* @hw: pointer to the HW structure
|
||||
*/
|
||||
u16 igc_read_phy_fw_version(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u16 gphy_version = 0;
|
||||
u16 ret_val;
|
||||
|
||||
/* NVM image version is reported as firmware version for i225 device */
|
||||
ret_val = phy->ops.read_reg(hw, IGC_GPHY_VERSION, &gphy_version);
|
||||
if (ret_val)
|
||||
hw_dbg("igc_phy: read wrong gphy version\n");
|
||||
|
||||
return gphy_version;
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_PHY_H_
|
||||
#define _IGC_PHY_H_
|
||||
|
||||
#include "igc_mac.h"
|
||||
|
||||
s32 igc_check_reset_block(struct igc_hw *hw);
|
||||
s32 igc_phy_hw_reset(struct igc_hw *hw);
|
||||
s32 igc_get_phy_id(struct igc_hw *hw);
|
||||
s32 igc_phy_has_link(struct igc_hw *hw, u32 iterations,
|
||||
u32 usec_interval, bool *success);
|
||||
void igc_check_downshift(struct igc_hw *hw);
|
||||
s32 igc_setup_copper_link(struct igc_hw *hw);
|
||||
void igc_power_up_phy_copper(struct igc_hw *hw);
|
||||
void igc_power_down_phy_copper(struct igc_hw *hw);
|
||||
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);
|
||||
u16 igc_read_phy_fw_version(struct igc_hw *hw);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,321 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#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 */
|
||||
#define IGC_CTRL_EXT 0x00018 /* Extended Device Control - RW */
|
||||
#define IGC_MDIC 0x00020 /* MDI Control - RW */
|
||||
#define IGC_CONNSW 0x00034 /* Copper/Fiber switch control - RW */
|
||||
#define IGC_VET 0x00038 /* VLAN Ether Type - RW */
|
||||
#define IGC_I225_PHPM 0x00E14 /* I225 PHY Power Management */
|
||||
#define IGC_GPHY_VERSION 0x0001E /* I225 gPHY Firmware Version */
|
||||
|
||||
/* Internal Packet Buffer Size Registers */
|
||||
#define IGC_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */
|
||||
#define IGC_TXPBS 0x03404 /* Tx Packet Buffer Size - RW */
|
||||
|
||||
/* NVM Register Descriptions */
|
||||
#define IGC_EERD 0x12014 /* EEprom mode read - RW */
|
||||
#define IGC_EEWR 0x12018 /* EEprom mode write - RW */
|
||||
|
||||
/* Flow Control Register Descriptions */
|
||||
#define IGC_FCAL 0x00028 /* FC Address Low - RW */
|
||||
#define IGC_FCAH 0x0002C /* FC Address High - RW */
|
||||
#define IGC_FCT 0x00030 /* FC Type - RW */
|
||||
#define IGC_FCTTV 0x00170 /* FC Transmit Timer - RW */
|
||||
#define IGC_FCRTL 0x02160 /* FC Receive Threshold Low - RW */
|
||||
#define IGC_FCRTH 0x02168 /* FC Receive Threshold High - RW */
|
||||
#define IGC_FCRTV 0x02460 /* FC Refresh Timer Value - RW */
|
||||
|
||||
/* Semaphore registers */
|
||||
#define IGC_SW_FW_SYNC 0x05B5C /* SW-FW Synchronization - RW */
|
||||
#define IGC_SWSM 0x05B50 /* SW Semaphore */
|
||||
#define IGC_FWSM 0x05B54 /* FW Semaphore */
|
||||
|
||||
/* Function Active and Power State to MNG */
|
||||
#define IGC_FACTPS 0x05B30
|
||||
|
||||
/* Interrupt Register Description */
|
||||
#define IGC_EICR 0x01580 /* Ext. Interrupt Cause read - W0 */
|
||||
#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 Auto Mask - RW */
|
||||
#define IGC_ICR 0x01500 /* Intr Cause Read - RC/W1C */
|
||||
#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 */
|
||||
/* Intr Throttle - RW */
|
||||
#define IGC_EITR(_n) (0x01680 + (0x4 * (_n)))
|
||||
/* Interrupt Vector Allocation - RW */
|
||||
#define IGC_IVAR0 0x01700
|
||||
#define IGC_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */
|
||||
#define IGC_GPIE 0x01514 /* General Purpose Intr Enable - RW */
|
||||
|
||||
/* RSS registers */
|
||||
#define IGC_MRQC 0x05818 /* Multiple Receive Control - RW */
|
||||
|
||||
/* Filtering Registers */
|
||||
#define IGC_ETQF(_n) (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */
|
||||
#define IGC_FHFT(_n) (0x09000 + (256 * (_n))) /* Flexible Host Filter */
|
||||
#define IGC_FHFT_EXT(_n) (0x09A00 + (256 * (_n))) /* Flexible Host Filter Extended */
|
||||
#define IGC_FHFTSL 0x05804 /* Flex Filter indirect table select */
|
||||
|
||||
/* ETQF register bit definitions */
|
||||
#define IGC_ETQF_FILTER_ENABLE BIT(26)
|
||||
#define IGC_ETQF_QUEUE_ENABLE BIT(31)
|
||||
#define IGC_ETQF_QUEUE_SHIFT 16
|
||||
#define IGC_ETQF_QUEUE_MASK 0x00070000
|
||||
#define IGC_ETQF_ETYPE_MASK 0x0000FFFF
|
||||
|
||||
/* FHFT register bit definitions */
|
||||
#define IGC_FHFT_LENGTH_MASK GENMASK(7, 0)
|
||||
#define IGC_FHFT_QUEUE_SHIFT 8
|
||||
#define IGC_FHFT_QUEUE_MASK GENMASK(10, 8)
|
||||
#define IGC_FHFT_PRIO_SHIFT 16
|
||||
#define IGC_FHFT_PRIO_MASK GENMASK(18, 16)
|
||||
#define IGC_FHFT_IMM_INT BIT(24)
|
||||
#define IGC_FHFT_DROP BIT(25)
|
||||
|
||||
/* FHFTSL register bit definitions */
|
||||
#define IGC_FHFTSL_FTSL_SHIFT 0
|
||||
#define IGC_FHFTSL_FTSL_MASK GENMASK(1, 0)
|
||||
|
||||
/* Redirection Table - RW Array */
|
||||
#define IGC_RETA(_i) (0x05C00 + ((_i) * 4))
|
||||
/* RSS Random Key - RW Array */
|
||||
#define IGC_RSSRK(_i) (0x05C80 + ((_i) * 4))
|
||||
|
||||
/* Receive Register Descriptions */
|
||||
#define IGC_RCTL 0x00100 /* Rx Control - RW */
|
||||
#define IGC_SRRCTL(_n) (0x0C00C + ((_n) * 0x40))
|
||||
#define IGC_PSRTYPE(_i) (0x05480 + ((_i) * 4))
|
||||
#define IGC_RDBAL(_n) (0x0C000 + ((_n) * 0x40))
|
||||
#define IGC_RDBAH(_n) (0x0C004 + ((_n) * 0x40))
|
||||
#define IGC_RDLEN(_n) (0x0C008 + ((_n) * 0x40))
|
||||
#define IGC_RDH(_n) (0x0C010 + ((_n) * 0x40))
|
||||
#define IGC_RDT(_n) (0x0C018 + ((_n) * 0x40))
|
||||
#define IGC_RXDCTL(_n) (0x0C028 + ((_n) * 0x40))
|
||||
#define IGC_RQDPC(_n) (0x0C030 + ((_n) * 0x40))
|
||||
#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_UTA 0x0A000 /* Unicast Table Array - RW */
|
||||
#define IGC_RAL(_n) (0x05400 + ((_n) * 0x08))
|
||||
#define IGC_RAH(_n) (0x05404 + ((_n) * 0x08))
|
||||
#define IGC_VLANPQF 0x055B0 /* VLAN Priority Queue Filter - RW */
|
||||
|
||||
/* Transmit Register Descriptions */
|
||||
#define IGC_TCTL 0x00400 /* Tx Control - RW */
|
||||
#define IGC_TIPG 0x00410 /* Tx Inter-packet gap - RW */
|
||||
#define IGC_TDBAL(_n) (0x0E000 + ((_n) * 0x40))
|
||||
#define IGC_TDBAH(_n) (0x0E004 + ((_n) * 0x40))
|
||||
#define IGC_TDLEN(_n) (0x0E008 + ((_n) * 0x40))
|
||||
#define IGC_TDH(_n) (0x0E010 + ((_n) * 0x40))
|
||||
#define IGC_TDT(_n) (0x0E018 + ((_n) * 0x40))
|
||||
#define IGC_TXDCTL(_n) (0x0E028 + ((_n) * 0x40))
|
||||
|
||||
/* MMD Register Descriptions */
|
||||
#define IGC_MMDAC 13 /* MMD Access Control */
|
||||
#define IGC_MMDAAD 14 /* MMD Access Address/Data */
|
||||
|
||||
/* Statistics Register Descriptions */
|
||||
#define IGC_CRCERRS 0x04000 /* CRC Error Count - R/clr */
|
||||
#define IGC_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */
|
||||
#define IGC_RXERRC 0x0400C /* Receive 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_RPTHC 0x04104 /* Rx Packets To Host */
|
||||
#define IGC_TLPIC 0x04148 /* EEE Tx LPI Count */
|
||||
#define IGC_RLPIC 0x0414C /* EEE Rx LPI Count */
|
||||
#define IGC_HGPTC 0x04118 /* Host Good Packets Tx Count */
|
||||
#define IGC_RXDMTC 0x04120 /* Rx Descriptor Minimum Threshold Count */
|
||||
#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 */
|
||||
|
||||
/* Time sync registers */
|
||||
#define IGC_TSICR 0x0B66C /* Time Sync Interrupt Cause */
|
||||
#define IGC_TSIM 0x0B674 /* Time Sync Interrupt Mask Register */
|
||||
#define IGC_TSAUXC 0x0B640 /* Timesync Auxiliary Control register */
|
||||
#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_TSSDP 0x0003C /* Time Sync SDP Configuration Register - RW */
|
||||
#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_AUXSTMPL0 0x0B65C /* Auxiliary Time Stamp 0 Register Low - RO */
|
||||
#define IGC_AUXSTMPH0 0x0B660 /* Auxiliary Time Stamp 0 Register High - RO */
|
||||
#define IGC_AUXSTMPL1 0x0B664 /* Auxiliary Time Stamp 1 Register Low - RO */
|
||||
#define IGC_AUXSTMPH1 0x0B668 /* Auxiliary Time Stamp 1 Register High - RO */
|
||||
|
||||
#define IGC_IMIR(_i) (0x05A80 + ((_i) * 4)) /* Immediate Interrupt */
|
||||
#define IGC_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* Immediate INTR Ext*/
|
||||
|
||||
#define IGC_FTQF(_n) (0x059E0 + (4 * (_n))) /* 5-tuple Queue Fltr */
|
||||
|
||||
/* Transmit Scheduling Registers */
|
||||
#define IGC_TQAVCTRL 0x3570
|
||||
#define IGC_TXQCTL(_n) (0x3344 + 0x4 * (_n))
|
||||
#define IGC_GTXOFFSET 0x3310
|
||||
#define IGC_BASET_L 0x3314
|
||||
#define IGC_BASET_H 0x3318
|
||||
#define IGC_QBVCYCLET 0x331C
|
||||
#define IGC_QBVCYCLET_S 0x3320
|
||||
|
||||
#define IGC_STQT(_n) (0x3324 + 0x4 * (_n))
|
||||
#define IGC_ENDQT(_n) (0x3334 + 0x4 * (_n))
|
||||
#define IGC_DTXMXPKTSZ 0x355C
|
||||
|
||||
#define IGC_TQAVCC(_n) (0x3004 + ((_n) * 0x40))
|
||||
#define IGC_TQAVHC(_n) (0x300C + ((_n) * 0x40))
|
||||
|
||||
/* System Time Registers */
|
||||
#define IGC_SYSTIML 0x0B600 /* System time register Low - RO */
|
||||
#define IGC_SYSTIMH 0x0B604 /* System time register High - RO */
|
||||
#define IGC_SYSTIMR 0x0B6F8 /* System time register Residue */
|
||||
#define IGC_TIMINCA 0x0B608 /* Increment attributes register - RW */
|
||||
|
||||
#define IGC_TXSTMPL 0x0B618 /* Tx timestamp value Low - RO */
|
||||
#define IGC_TXSTMPH 0x0B61C /* Tx timestamp value High - RO */
|
||||
|
||||
#define IGC_TIMADJ 0x0B60C /* Time Adjustment Offset Register */
|
||||
|
||||
/* PCIe Registers */
|
||||
#define IGC_PTM_CTRL 0x12540 /* PTM Control */
|
||||
#define IGC_PTM_STAT 0x12544 /* PTM Status */
|
||||
#define IGC_PTM_CYCLE_CTRL 0x1254C /* PTM Cycle Control */
|
||||
|
||||
/* PTM Time registers */
|
||||
#define IGC_PTM_T1_TIM0_L 0x12558 /* T1 on Timer 0 Low */
|
||||
#define IGC_PTM_T1_TIM0_H 0x1255C /* T1 on Timer 0 High */
|
||||
|
||||
#define IGC_PTM_CURR_T2_L 0x1258C /* Current T2 Low */
|
||||
#define IGC_PTM_CURR_T2_H 0x12590 /* Current T2 High */
|
||||
#define IGC_PTM_PREV_T2_L 0x12584 /* Previous T2 Low */
|
||||
#define IGC_PTM_PREV_T2_H 0x12588 /* Previous T2 High */
|
||||
#define IGC_PTM_PREV_T4M1 0x12578 /* T4 Minus T1 on previous PTM Cycle */
|
||||
#define IGC_PTM_CURR_T4M1 0x1257C /* T4 Minus T1 on this PTM Cycle */
|
||||
#define IGC_PTM_PREV_T3M2 0x12580 /* T3 Minus T2 on previous PTM Cycle */
|
||||
#define IGC_PTM_TDELAY 0x12594 /* PTM PCIe Link Delay */
|
||||
|
||||
#define IGC_PCIE_DIG_DELAY 0x12550 /* PCIe Digital Delay */
|
||||
#define IGC_PCIE_PHY_DELAY 0x12554 /* PCIe PHY Delay */
|
||||
|
||||
/* Management registers */
|
||||
#define IGC_MANC 0x05820 /* Management Control - RW */
|
||||
|
||||
/* Shadow Ram Write Register - RW */
|
||||
#define IGC_SRWR 0x12018
|
||||
|
||||
/* Wake Up registers */
|
||||
#define IGC_WUC 0x05800 /* Wakeup Control - RW */
|
||||
#define IGC_WUFC 0x05808 /* Wakeup Filter Control - RW */
|
||||
#define IGC_WUS 0x05810 /* Wakeup Status - R/W1C */
|
||||
#define IGC_WUPL 0x05900 /* Wakeup Packet Length - RW */
|
||||
#define IGC_WUFC_EXT 0x0580C /* Wakeup Filter Control Register Extended - RW */
|
||||
|
||||
/* Wake Up packet memory */
|
||||
#define IGC_WUPM_REG(_i) (0x05A00 + ((_i) * 4))
|
||||
|
||||
/* Energy Efficient Ethernet "EEE" registers */
|
||||
#define IGC_EEER 0x0E30 /* Energy Efficient Ethernet "EEE"*/
|
||||
#define IGC_IPCNFG 0x0E38 /* Internal PHY Configuration */
|
||||
#define IGC_EEE_SU 0x0E34 /* EEE Setup */
|
||||
|
||||
/* LTR registers */
|
||||
#define IGC_LTRC 0x01A0 /* Latency Tolerance Reporting Control */
|
||||
#define IGC_LTRMINV 0x5BB0 /* LTR Minimum Value */
|
||||
#define IGC_LTRMAXV 0x5BB4 /* LTR Maximum Value */
|
||||
|
||||
/* forward declaration */
|
||||
struct igc_hw;
|
||||
u32 igc_rd32(struct igc_hw *hw, u32 reg);
|
||||
|
||||
/* write operations, indexed using DWORDS */
|
||||
#define wr32(reg, val) \
|
||||
do { \
|
||||
u8 __iomem *hw_addr = READ_ONCE((hw)->hw_addr); \
|
||||
if (!IGC_REMOVED(hw_addr)) \
|
||||
writel((val), &hw_addr[(reg)]); \
|
||||
} while (0)
|
||||
|
||||
#define rd32(reg) (igc_rd32(hw, reg))
|
||||
|
||||
#define wrfl() ((void)rd32(IGC_STATUS))
|
||||
|
||||
#define array_wr32(reg, offset, value) \
|
||||
wr32((reg) + ((offset) << 2), (value))
|
||||
|
||||
#define array_rd32(reg, offset) (igc_rd32(hw, (reg) + ((offset) << 2)))
|
||||
|
||||
#define IGC_REMOVED(h) unlikely(!(h))
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#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 */
|
||||
#define IGC_CTRL_EXT 0x00018 /* Extended Device Control - RW */
|
||||
#define IGC_MDIC 0x00020 /* MDI Control - RW */
|
||||
#define IGC_CONNSW 0x00034 /* Copper/Fiber switch control - RW */
|
||||
#define IGC_VET 0x00038 /* VLAN Ether Type - RW */
|
||||
#define IGC_I225_PHPM 0x00E14 /* I225 PHY Power Management */
|
||||
#define IGC_GPHY_VERSION 0x0001E /* I225 gPHY Firmware Version */
|
||||
|
||||
/* Internal Packet Buffer Size Registers */
|
||||
#define IGC_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */
|
||||
#define IGC_TXPBS 0x03404 /* Tx Packet Buffer Size - RW */
|
||||
|
||||
/* NVM Register Descriptions */
|
||||
#define IGC_EERD 0x12014 /* EEprom mode read - RW */
|
||||
#define IGC_EEWR 0x12018 /* EEprom mode write - RW */
|
||||
|
||||
/* Flow Control Register Descriptions */
|
||||
#define IGC_FCAL 0x00028 /* FC Address Low - RW */
|
||||
#define IGC_FCAH 0x0002C /* FC Address High - RW */
|
||||
#define IGC_FCT 0x00030 /* FC Type - RW */
|
||||
#define IGC_FCTTV 0x00170 /* FC Transmit Timer - RW */
|
||||
#define IGC_FCRTL 0x02160 /* FC Receive Threshold Low - RW */
|
||||
#define IGC_FCRTH 0x02168 /* FC Receive Threshold High - RW */
|
||||
#define IGC_FCRTV 0x02460 /* FC Refresh Timer Value - RW */
|
||||
|
||||
/* Semaphore registers */
|
||||
#define IGC_SW_FW_SYNC 0x05B5C /* SW-FW Synchronization - RW */
|
||||
#define IGC_SWSM 0x05B50 /* SW Semaphore */
|
||||
#define IGC_FWSM 0x05B54 /* FW Semaphore */
|
||||
|
||||
/* Function Active and Power State to MNG */
|
||||
#define IGC_FACTPS 0x05B30
|
||||
|
||||
/* Interrupt Register Description */
|
||||
#define IGC_EICR 0x01580 /* Ext. Interrupt Cause read - W0 */
|
||||
#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 Auto Mask - RW */
|
||||
#define IGC_ICR 0x01500 /* Intr Cause Read - RC/W1C */
|
||||
#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 */
|
||||
/* Intr Throttle - RW */
|
||||
#define IGC_EITR(_n) (0x01680 + (0x4 * (_n)))
|
||||
/* Interrupt Vector Allocation - RW */
|
||||
#define IGC_IVAR0 0x01700
|
||||
#define IGC_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */
|
||||
#define IGC_GPIE 0x01514 /* General Purpose Intr Enable - RW */
|
||||
|
||||
/* RSS registers */
|
||||
#define IGC_MRQC 0x05818 /* Multiple Receive Control - RW */
|
||||
|
||||
/* Filtering Registers */
|
||||
#define IGC_ETQF(_n) (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */
|
||||
#define IGC_FHFT(_n) (0x09000 + (256 * (_n))) /* Flexible Host Filter */
|
||||
#define IGC_FHFT_EXT(_n) (0x09A00 + (256 * (_n))) /* Flexible Host Filter Extended */
|
||||
#define IGC_FHFTSL 0x05804 /* Flex Filter indirect table select */
|
||||
|
||||
/* ETQF register bit definitions */
|
||||
#define IGC_ETQF_FILTER_ENABLE BIT(26)
|
||||
#define IGC_ETQF_QUEUE_ENABLE BIT(31)
|
||||
#define IGC_ETQF_QUEUE_SHIFT 16
|
||||
#define IGC_ETQF_QUEUE_MASK 0x00070000
|
||||
#define IGC_ETQF_ETYPE_MASK 0x0000FFFF
|
||||
|
||||
/* FHFT register bit definitions */
|
||||
#define IGC_FHFT_LENGTH_MASK GENMASK(7, 0)
|
||||
#define IGC_FHFT_QUEUE_SHIFT 8
|
||||
#define IGC_FHFT_QUEUE_MASK GENMASK(10, 8)
|
||||
#define IGC_FHFT_PRIO_SHIFT 16
|
||||
#define IGC_FHFT_PRIO_MASK GENMASK(18, 16)
|
||||
#define IGC_FHFT_IMM_INT BIT(24)
|
||||
#define IGC_FHFT_DROP BIT(25)
|
||||
|
||||
/* FHFTSL register bit definitions */
|
||||
#define IGC_FHFTSL_FTSL_SHIFT 0
|
||||
#define IGC_FHFTSL_FTSL_MASK GENMASK(1, 0)
|
||||
|
||||
/* Redirection Table - RW Array */
|
||||
#define IGC_RETA(_i) (0x05C00 + ((_i) * 4))
|
||||
/* RSS Random Key - RW Array */
|
||||
#define IGC_RSSRK(_i) (0x05C80 + ((_i) * 4))
|
||||
|
||||
/* Receive Register Descriptions */
|
||||
#define IGC_RCTL 0x00100 /* Rx Control - RW */
|
||||
#define IGC_SRRCTL(_n) (0x0C00C + ((_n) * 0x40))
|
||||
#define IGC_PSRTYPE(_i) (0x05480 + ((_i) * 4))
|
||||
#define IGC_RDBAL(_n) (0x0C000 + ((_n) * 0x40))
|
||||
#define IGC_RDBAH(_n) (0x0C004 + ((_n) * 0x40))
|
||||
#define IGC_RDLEN(_n) (0x0C008 + ((_n) * 0x40))
|
||||
#define IGC_RDH(_n) (0x0C010 + ((_n) * 0x40))
|
||||
#define IGC_RDT(_n) (0x0C018 + ((_n) * 0x40))
|
||||
#define IGC_RXDCTL(_n) (0x0C028 + ((_n) * 0x40))
|
||||
#define IGC_RQDPC(_n) (0x0C030 + ((_n) * 0x40))
|
||||
#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_UTA 0x0A000 /* Unicast Table Array - RW */
|
||||
#define IGC_RAL(_n) (0x05400 + ((_n) * 0x08))
|
||||
#define IGC_RAH(_n) (0x05404 + ((_n) * 0x08))
|
||||
#define IGC_VLANPQF 0x055B0 /* VLAN Priority Queue Filter - RW */
|
||||
|
||||
/* Transmit Register Descriptions */
|
||||
#define IGC_TCTL 0x00400 /* Tx Control - RW */
|
||||
#define IGC_TIPG 0x00410 /* Tx Inter-packet gap - RW */
|
||||
#define IGC_TDBAL(_n) (0x0E000 + ((_n) * 0x40))
|
||||
#define IGC_TDBAH(_n) (0x0E004 + ((_n) * 0x40))
|
||||
#define IGC_TDLEN(_n) (0x0E008 + ((_n) * 0x40))
|
||||
#define IGC_TDH(_n) (0x0E010 + ((_n) * 0x40))
|
||||
#define IGC_TDT(_n) (0x0E018 + ((_n) * 0x40))
|
||||
#define IGC_TXDCTL(_n) (0x0E028 + ((_n) * 0x40))
|
||||
|
||||
/* MMD Register Descriptions */
|
||||
#define IGC_MMDAC 13 /* MMD Access Control */
|
||||
#define IGC_MMDAAD 14 /* MMD Access Address/Data */
|
||||
|
||||
/* Statistics Register Descriptions */
|
||||
#define IGC_CRCERRS 0x04000 /* CRC Error Count - R/clr */
|
||||
#define IGC_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */
|
||||
#define IGC_RXERRC 0x0400C /* Receive 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_RPTHC 0x04104 /* Rx Packets To Host */
|
||||
#define IGC_TLPIC 0x04148 /* EEE Tx LPI Count */
|
||||
#define IGC_RLPIC 0x0414C /* EEE Rx LPI Count */
|
||||
#define IGC_HGPTC 0x04118 /* Host Good Packets Tx Count */
|
||||
#define IGC_RXDMTC 0x04120 /* Rx Descriptor Minimum Threshold Count */
|
||||
#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 */
|
||||
|
||||
/* Time sync registers */
|
||||
#define IGC_TSICR 0x0B66C /* Time Sync Interrupt Cause */
|
||||
#define IGC_TSIM 0x0B674 /* Time Sync Interrupt Mask Register */
|
||||
#define IGC_TSAUXC 0x0B640 /* Timesync Auxiliary Control register */
|
||||
#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_TSSDP 0x0003C /* Time Sync SDP Configuration Register - RW */
|
||||
#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_AUXSTMPL0 0x0B65C /* Auxiliary Time Stamp 0 Register Low - RO */
|
||||
#define IGC_AUXSTMPH0 0x0B660 /* Auxiliary Time Stamp 0 Register High - RO */
|
||||
#define IGC_AUXSTMPL1 0x0B664 /* Auxiliary Time Stamp 1 Register Low - RO */
|
||||
#define IGC_AUXSTMPH1 0x0B668 /* Auxiliary Time Stamp 1 Register High - RO */
|
||||
|
||||
#define IGC_IMIR(_i) (0x05A80 + ((_i) * 4)) /* Immediate Interrupt */
|
||||
#define IGC_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* Immediate INTR Ext*/
|
||||
|
||||
#define IGC_FTQF(_n) (0x059E0 + (4 * (_n))) /* 5-tuple Queue Fltr */
|
||||
|
||||
/* Transmit Scheduling Registers */
|
||||
#define IGC_TQAVCTRL 0x3570
|
||||
#define IGC_TXQCTL(_n) (0x3344 + 0x4 * (_n))
|
||||
#define IGC_GTXOFFSET 0x3310
|
||||
#define IGC_BASET_L 0x3314
|
||||
#define IGC_BASET_H 0x3318
|
||||
#define IGC_QBVCYCLET 0x331C
|
||||
#define IGC_QBVCYCLET_S 0x3320
|
||||
|
||||
#define IGC_STQT(_n) (0x3324 + 0x4 * (_n))
|
||||
#define IGC_ENDQT(_n) (0x3334 + 0x4 * (_n))
|
||||
#define IGC_DTXMXPKTSZ 0x355C
|
||||
|
||||
#define IGC_TQAVCC(_n) (0x3004 + ((_n) * 0x40))
|
||||
#define IGC_TQAVHC(_n) (0x300C + ((_n) * 0x40))
|
||||
|
||||
/* System Time Registers */
|
||||
#define IGC_SYSTIML 0x0B600 /* System time register Low - RO */
|
||||
#define IGC_SYSTIMH 0x0B604 /* System time register High - RO */
|
||||
#define IGC_SYSTIMR 0x0B6F8 /* System time register Residue */
|
||||
#define IGC_TIMINCA 0x0B608 /* Increment attributes register - RW */
|
||||
|
||||
#define IGC_TXSTMPL 0x0B618 /* Tx timestamp value Low - RO */
|
||||
#define IGC_TXSTMPH 0x0B61C /* Tx timestamp value High - RO */
|
||||
|
||||
#define IGC_TIMADJ 0x0B60C /* Time Adjustment Offset Register */
|
||||
|
||||
/* PCIe Registers */
|
||||
#define IGC_PTM_CTRL 0x12540 /* PTM Control */
|
||||
#define IGC_PTM_STAT 0x12544 /* PTM Status */
|
||||
#define IGC_PTM_CYCLE_CTRL 0x1254C /* PTM Cycle Control */
|
||||
|
||||
/* PTM Time registers */
|
||||
#define IGC_PTM_T1_TIM0_L 0x12558 /* T1 on Timer 0 Low */
|
||||
#define IGC_PTM_T1_TIM0_H 0x1255C /* T1 on Timer 0 High */
|
||||
|
||||
#define IGC_PTM_CURR_T2_L 0x1258C /* Current T2 Low */
|
||||
#define IGC_PTM_CURR_T2_H 0x12590 /* Current T2 High */
|
||||
#define IGC_PTM_PREV_T2_L 0x12584 /* Previous T2 Low */
|
||||
#define IGC_PTM_PREV_T2_H 0x12588 /* Previous T2 High */
|
||||
#define IGC_PTM_PREV_T4M1 0x12578 /* T4 Minus T1 on previous PTM Cycle */
|
||||
#define IGC_PTM_CURR_T4M1 0x1257C /* T4 Minus T1 on this PTM Cycle */
|
||||
#define IGC_PTM_PREV_T3M2 0x12580 /* T3 Minus T2 on previous PTM Cycle */
|
||||
#define IGC_PTM_TDELAY 0x12594 /* PTM PCIe Link Delay */
|
||||
|
||||
#define IGC_PCIE_DIG_DELAY 0x12550 /* PCIe Digital Delay */
|
||||
#define IGC_PCIE_PHY_DELAY 0x12554 /* PCIe PHY Delay */
|
||||
|
||||
/* Management registers */
|
||||
#define IGC_MANC 0x05820 /* Management Control - RW */
|
||||
|
||||
/* Shadow Ram Write Register - RW */
|
||||
#define IGC_SRWR 0x12018
|
||||
|
||||
/* Wake Up registers */
|
||||
#define IGC_WUC 0x05800 /* Wakeup Control - RW */
|
||||
#define IGC_WUFC 0x05808 /* Wakeup Filter Control - RW */
|
||||
#define IGC_WUS 0x05810 /* Wakeup Status - R/W1C */
|
||||
#define IGC_WUPL 0x05900 /* Wakeup Packet Length - RW */
|
||||
#define IGC_WUFC_EXT 0x0580C /* Wakeup Filter Control Register Extended - RW */
|
||||
|
||||
/* Wake Up packet memory */
|
||||
#define IGC_WUPM_REG(_i) (0x05A00 + ((_i) * 4))
|
||||
|
||||
/* Energy Efficient Ethernet "EEE" registers */
|
||||
#define IGC_EEER 0x0E30 /* Energy Efficient Ethernet "EEE"*/
|
||||
#define IGC_IPCNFG 0x0E38 /* Internal PHY Configuration */
|
||||
#define IGC_EEE_SU 0x0E34 /* EEE Setup */
|
||||
|
||||
/* LTR registers */
|
||||
#define IGC_LTRC 0x01A0 /* Latency Tolerance Reporting Control */
|
||||
#define IGC_LTRMINV 0x5BB0 /* LTR Minimum Value */
|
||||
#define IGC_LTRMAXV 0x5BB4 /* LTR Maximum Value */
|
||||
|
||||
/* forward declaration */
|
||||
struct igc_hw;
|
||||
u32 igc_rd32(struct igc_hw *hw, u32 reg);
|
||||
|
||||
/* write operations, indexed using DWORDS */
|
||||
#define wr32(reg, val) \
|
||||
do { \
|
||||
u8 __iomem *hw_addr = READ_ONCE((hw)->hw_addr); \
|
||||
if (!IGC_REMOVED(hw_addr)) \
|
||||
writel((val), &hw_addr[(reg)]); \
|
||||
} while (0)
|
||||
|
||||
#define rd32(reg) (igc_rd32(hw, reg))
|
||||
|
||||
#define wrfl() ((void)rd32(IGC_STATUS))
|
||||
|
||||
#define array_wr32(reg, offset, value) \
|
||||
wr32((reg) + ((offset) << 2), (value))
|
||||
|
||||
#define array_rd32(reg, offset) (igc_rd32(hw, (reg) + ((offset) << 2)))
|
||||
|
||||
#define IGC_REMOVED(h) unlikely(!(h))
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#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 */
|
||||
#define IGC_CTRL_EXT 0x00018 /* Extended Device Control - RW */
|
||||
#define IGC_MDIC 0x00020 /* MDI Control - RW */
|
||||
#define IGC_CONNSW 0x00034 /* Copper/Fiber switch control - RW */
|
||||
#define IGC_VET 0x00038 /* VLAN Ether Type - RW */
|
||||
#define IGC_I225_PHPM 0x00E14 /* I225 PHY Power Management */
|
||||
#define IGC_GPHY_VERSION 0x0001E /* I225 gPHY Firmware Version */
|
||||
|
||||
/* Internal Packet Buffer Size Registers */
|
||||
#define IGC_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */
|
||||
#define IGC_TXPBS 0x03404 /* Tx Packet Buffer Size - RW */
|
||||
|
||||
/* NVM Register Descriptions */
|
||||
#define IGC_EERD 0x12014 /* EEprom mode read - RW */
|
||||
#define IGC_EEWR 0x12018 /* EEprom mode write - RW */
|
||||
|
||||
/* Flow Control Register Descriptions */
|
||||
#define IGC_FCAL 0x00028 /* FC Address Low - RW */
|
||||
#define IGC_FCAH 0x0002C /* FC Address High - RW */
|
||||
#define IGC_FCT 0x00030 /* FC Type - RW */
|
||||
#define IGC_FCTTV 0x00170 /* FC Transmit Timer - RW */
|
||||
#define IGC_FCRTL 0x02160 /* FC Receive Threshold Low - RW */
|
||||
#define IGC_FCRTH 0x02168 /* FC Receive Threshold High - RW */
|
||||
#define IGC_FCRTV 0x02460 /* FC Refresh Timer Value - RW */
|
||||
|
||||
/* Semaphore registers */
|
||||
#define IGC_SW_FW_SYNC 0x05B5C /* SW-FW Synchronization - RW */
|
||||
#define IGC_SWSM 0x05B50 /* SW Semaphore */
|
||||
#define IGC_FWSM 0x05B54 /* FW Semaphore */
|
||||
|
||||
/* Function Active and Power State to MNG */
|
||||
#define IGC_FACTPS 0x05B30
|
||||
|
||||
/* Interrupt Register Description */
|
||||
#define IGC_EICR 0x01580 /* Ext. Interrupt Cause read - W0 */
|
||||
#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 Auto Mask - RW */
|
||||
#define IGC_ICR 0x01500 /* Intr Cause Read - RC/W1C */
|
||||
#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 */
|
||||
/* Intr Throttle - RW */
|
||||
#define IGC_EITR(_n) (0x01680 + (0x4 * (_n)))
|
||||
/* Interrupt Vector Allocation - RW */
|
||||
#define IGC_IVAR0 0x01700
|
||||
#define IGC_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */
|
||||
#define IGC_GPIE 0x01514 /* General Purpose Intr Enable - RW */
|
||||
|
||||
/* RSS registers */
|
||||
#define IGC_MRQC 0x05818 /* Multiple Receive Control - RW */
|
||||
|
||||
/* Filtering Registers */
|
||||
#define IGC_ETQF(_n) (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */
|
||||
#define IGC_FHFT(_n) (0x09000 + (256 * (_n))) /* Flexible Host Filter */
|
||||
#define IGC_FHFT_EXT(_n) (0x09A00 + (256 * (_n))) /* Flexible Host Filter Extended */
|
||||
#define IGC_FHFTSL 0x05804 /* Flex Filter indirect table select */
|
||||
|
||||
/* ETQF register bit definitions */
|
||||
#define IGC_ETQF_FILTER_ENABLE BIT(26)
|
||||
#define IGC_ETQF_QUEUE_ENABLE BIT(31)
|
||||
#define IGC_ETQF_QUEUE_SHIFT 16
|
||||
#define IGC_ETQF_QUEUE_MASK 0x00070000
|
||||
#define IGC_ETQF_ETYPE_MASK 0x0000FFFF
|
||||
|
||||
/* FHFT register bit definitions */
|
||||
#define IGC_FHFT_LENGTH_MASK GENMASK(7, 0)
|
||||
#define IGC_FHFT_QUEUE_SHIFT 8
|
||||
#define IGC_FHFT_QUEUE_MASK GENMASK(10, 8)
|
||||
#define IGC_FHFT_PRIO_SHIFT 16
|
||||
#define IGC_FHFT_PRIO_MASK GENMASK(18, 16)
|
||||
#define IGC_FHFT_IMM_INT BIT(24)
|
||||
#define IGC_FHFT_DROP BIT(25)
|
||||
|
||||
/* FHFTSL register bit definitions */
|
||||
#define IGC_FHFTSL_FTSL_SHIFT 0
|
||||
#define IGC_FHFTSL_FTSL_MASK GENMASK(1, 0)
|
||||
|
||||
/* Redirection Table - RW Array */
|
||||
#define IGC_RETA(_i) (0x05C00 + ((_i) * 4))
|
||||
/* RSS Random Key - RW Array */
|
||||
#define IGC_RSSRK(_i) (0x05C80 + ((_i) * 4))
|
||||
|
||||
/* Receive Register Descriptions */
|
||||
#define IGC_RCTL 0x00100 /* Rx Control - RW */
|
||||
#define IGC_SRRCTL(_n) (0x0C00C + ((_n) * 0x40))
|
||||
#define IGC_PSRTYPE(_i) (0x05480 + ((_i) * 4))
|
||||
#define IGC_RDBAL(_n) (0x0C000 + ((_n) * 0x40))
|
||||
#define IGC_RDBAH(_n) (0x0C004 + ((_n) * 0x40))
|
||||
#define IGC_RDLEN(_n) (0x0C008 + ((_n) * 0x40))
|
||||
#define IGC_RDH(_n) (0x0C010 + ((_n) * 0x40))
|
||||
#define IGC_RDT(_n) (0x0C018 + ((_n) * 0x40))
|
||||
#define IGC_RXDCTL(_n) (0x0C028 + ((_n) * 0x40))
|
||||
#define IGC_RQDPC(_n) (0x0C030 + ((_n) * 0x40))
|
||||
#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_UTA 0x0A000 /* Unicast Table Array - RW */
|
||||
#define IGC_RAL(_n) (0x05400 + ((_n) * 0x08))
|
||||
#define IGC_RAH(_n) (0x05404 + ((_n) * 0x08))
|
||||
#define IGC_VLANPQF 0x055B0 /* VLAN Priority Queue Filter - RW */
|
||||
|
||||
/* Transmit Register Descriptions */
|
||||
#define IGC_TCTL 0x00400 /* Tx Control - RW */
|
||||
#define IGC_TIPG 0x00410 /* Tx Inter-packet gap - RW */
|
||||
#define IGC_TDBAL(_n) (0x0E000 + ((_n) * 0x40))
|
||||
#define IGC_TDBAH(_n) (0x0E004 + ((_n) * 0x40))
|
||||
#define IGC_TDLEN(_n) (0x0E008 + ((_n) * 0x40))
|
||||
#define IGC_TDH(_n) (0x0E010 + ((_n) * 0x40))
|
||||
#define IGC_TDT(_n) (0x0E018 + ((_n) * 0x40))
|
||||
#define IGC_TXDCTL(_n) (0x0E028 + ((_n) * 0x40))
|
||||
|
||||
/* MMD Register Descriptions */
|
||||
#define IGC_MMDAC 13 /* MMD Access Control */
|
||||
#define IGC_MMDAAD 14 /* MMD Access Address/Data */
|
||||
|
||||
/* Statistics Register Descriptions */
|
||||
#define IGC_CRCERRS 0x04000 /* CRC Error Count - R/clr */
|
||||
#define IGC_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */
|
||||
#define IGC_RXERRC 0x0400C /* Receive 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_RPTHC 0x04104 /* Rx Packets To Host */
|
||||
#define IGC_TLPIC 0x04148 /* EEE Tx LPI Count */
|
||||
#define IGC_RLPIC 0x0414C /* EEE Rx LPI Count */
|
||||
#define IGC_HGPTC 0x04118 /* Host Good Packets Tx Count */
|
||||
#define IGC_RXDMTC 0x04120 /* Rx Descriptor Minimum Threshold Count */
|
||||
#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 */
|
||||
|
||||
/* Time sync registers */
|
||||
#define IGC_TSICR 0x0B66C /* Time Sync Interrupt Cause */
|
||||
#define IGC_TSIM 0x0B674 /* Time Sync Interrupt Mask Register */
|
||||
#define IGC_TSAUXC 0x0B640 /* Timesync Auxiliary Control register */
|
||||
#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_TSSDP 0x0003C /* Time Sync SDP Configuration Register - RW */
|
||||
#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_AUXSTMPL0 0x0B65C /* Auxiliary Time Stamp 0 Register Low - RO */
|
||||
#define IGC_AUXSTMPH0 0x0B660 /* Auxiliary Time Stamp 0 Register High - RO */
|
||||
#define IGC_AUXSTMPL1 0x0B664 /* Auxiliary Time Stamp 1 Register Low - RO */
|
||||
#define IGC_AUXSTMPH1 0x0B668 /* Auxiliary Time Stamp 1 Register High - RO */
|
||||
|
||||
#define IGC_IMIR(_i) (0x05A80 + ((_i) * 4)) /* Immediate Interrupt */
|
||||
#define IGC_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* Immediate INTR Ext*/
|
||||
|
||||
#define IGC_FTQF(_n) (0x059E0 + (4 * (_n))) /* 5-tuple Queue Fltr */
|
||||
|
||||
/* Transmit Scheduling Registers */
|
||||
#define IGC_TQAVCTRL 0x3570
|
||||
#define IGC_TXQCTL(_n) (0x3344 + 0x4 * (_n))
|
||||
#define IGC_GTXOFFSET 0x3310
|
||||
#define IGC_BASET_L 0x3314
|
||||
#define IGC_BASET_H 0x3318
|
||||
#define IGC_QBVCYCLET 0x331C
|
||||
#define IGC_QBVCYCLET_S 0x3320
|
||||
|
||||
#define IGC_STQT(_n) (0x3324 + 0x4 * (_n))
|
||||
#define IGC_ENDQT(_n) (0x3334 + 0x4 * (_n))
|
||||
#define IGC_DTXMXPKTSZ 0x355C
|
||||
|
||||
#define IGC_TQAVCC(_n) (0x3004 + ((_n) * 0x40))
|
||||
#define IGC_TQAVHC(_n) (0x300C + ((_n) * 0x40))
|
||||
|
||||
/* System Time Registers */
|
||||
#define IGC_SYSTIML 0x0B600 /* System time register Low - RO */
|
||||
#define IGC_SYSTIMH 0x0B604 /* System time register High - RO */
|
||||
#define IGC_SYSTIMR 0x0B6F8 /* System time register Residue */
|
||||
#define IGC_TIMINCA 0x0B608 /* Increment attributes register - RW */
|
||||
|
||||
/* TX Timestamp Low */
|
||||
#define IGC_TXSTMPL_0 0x0B618
|
||||
#define IGC_TXSTMPL_1 0x0B698
|
||||
#define IGC_TXSTMPL_2 0x0B6B8
|
||||
#define IGC_TXSTMPL_3 0x0B6D8
|
||||
|
||||
/* TX Timestamp High */
|
||||
#define IGC_TXSTMPH_0 0x0B61C
|
||||
#define IGC_TXSTMPH_1 0x0B69C
|
||||
#define IGC_TXSTMPH_2 0x0B6BC
|
||||
#define IGC_TXSTMPH_3 0x0B6DC
|
||||
|
||||
#define IGC_TXSTMPL 0x0B618 /* Tx timestamp value Low - RO */
|
||||
#define IGC_TXSTMPH 0x0B61C /* Tx timestamp value High - RO */
|
||||
|
||||
#define IGC_TIMADJ 0x0B60C /* Time Adjustment Offset Register */
|
||||
|
||||
/* PCIe Registers */
|
||||
#define IGC_PTM_CTRL 0x12540 /* PTM Control */
|
||||
#define IGC_PTM_STAT 0x12544 /* PTM Status */
|
||||
#define IGC_PTM_CYCLE_CTRL 0x1254C /* PTM Cycle Control */
|
||||
|
||||
/* PTM Time registers */
|
||||
#define IGC_PTM_T1_TIM0_L 0x12558 /* T1 on Timer 0 Low */
|
||||
#define IGC_PTM_T1_TIM0_H 0x1255C /* T1 on Timer 0 High */
|
||||
|
||||
#define IGC_PTM_CURR_T2_L 0x1258C /* Current T2 Low */
|
||||
#define IGC_PTM_CURR_T2_H 0x12590 /* Current T2 High */
|
||||
#define IGC_PTM_PREV_T2_L 0x12584 /* Previous T2 Low */
|
||||
#define IGC_PTM_PREV_T2_H 0x12588 /* Previous T2 High */
|
||||
#define IGC_PTM_PREV_T4M1 0x12578 /* T4 Minus T1 on previous PTM Cycle */
|
||||
#define IGC_PTM_CURR_T4M1 0x1257C /* T4 Minus T1 on this PTM Cycle */
|
||||
#define IGC_PTM_PREV_T3M2 0x12580 /* T3 Minus T2 on previous PTM Cycle */
|
||||
#define IGC_PTM_TDELAY 0x12594 /* PTM PCIe Link Delay */
|
||||
|
||||
#define IGC_PCIE_DIG_DELAY 0x12550 /* PCIe Digital Delay */
|
||||
#define IGC_PCIE_PHY_DELAY 0x12554 /* PCIe PHY Delay */
|
||||
|
||||
/* Management registers */
|
||||
#define IGC_MANC 0x05820 /* Management Control - RW */
|
||||
|
||||
/* Shadow Ram Write Register - RW */
|
||||
#define IGC_SRWR 0x12018
|
||||
|
||||
/* Wake Up registers */
|
||||
#define IGC_WUC 0x05800 /* Wakeup Control - RW */
|
||||
#define IGC_WUFC 0x05808 /* Wakeup Filter Control - RW */
|
||||
#define IGC_WUS 0x05810 /* Wakeup Status - R/W1C */
|
||||
#define IGC_WUPL 0x05900 /* Wakeup Packet Length - RW */
|
||||
#define IGC_WUFC_EXT 0x0580C /* Wakeup Filter Control Register Extended - RW */
|
||||
|
||||
/* Wake Up packet memory */
|
||||
#define IGC_WUPM_REG(_i) (0x05A00 + ((_i) * 4))
|
||||
|
||||
/* Energy Efficient Ethernet "EEE" registers */
|
||||
#define IGC_EEER 0x0E30 /* Energy Efficient Ethernet "EEE"*/
|
||||
#define IGC_IPCNFG 0x0E38 /* Internal PHY Configuration */
|
||||
#define IGC_EEE_SU 0x0E34 /* EEE Setup */
|
||||
|
||||
/* LTR registers */
|
||||
#define IGC_LTRC 0x01A0 /* Latency Tolerance Reporting Control */
|
||||
#define IGC_LTRMINV 0x5BB0 /* LTR Minimum Value */
|
||||
#define IGC_LTRMAXV 0x5BB4 /* LTR Maximum Value */
|
||||
|
||||
/* forward declaration */
|
||||
struct igc_hw;
|
||||
u32 igc_rd32(struct igc_hw *hw, u32 reg);
|
||||
|
||||
/* write operations, indexed using DWORDS */
|
||||
#define wr32(reg, val) \
|
||||
do { \
|
||||
u8 __iomem *hw_addr = READ_ONCE((hw)->hw_addr); \
|
||||
if (!IGC_REMOVED(hw_addr)) \
|
||||
writel((val), &hw_addr[(reg)]); \
|
||||
} while (0)
|
||||
|
||||
#define rd32(reg) (igc_rd32(hw, reg))
|
||||
|
||||
#define wrfl() ((void)rd32(IGC_STATUS))
|
||||
|
||||
#define array_wr32(reg, offset, value) \
|
||||
wr32((reg) + ((offset) << 2), (value))
|
||||
|
||||
#define array_rd32(reg, offset) (igc_rd32(hw, (reg) + ((offset) << 2)))
|
||||
|
||||
#define IGC_REMOVED(h) unlikely(!(h))
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#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 */
|
||||
#define IGC_CTRL_EXT 0x00018 /* Extended Device Control - RW */
|
||||
#define IGC_MDIC 0x00020 /* MDI Control - RW */
|
||||
#define IGC_CONNSW 0x00034 /* Copper/Fiber switch control - RW */
|
||||
#define IGC_VET 0x00038 /* VLAN Ether Type - RW */
|
||||
#define IGC_I225_PHPM 0x00E14 /* I225 PHY Power Management */
|
||||
#define IGC_GPHY_VERSION 0x0001E /* I225 gPHY Firmware Version */
|
||||
|
||||
/* Internal Packet Buffer Size Registers */
|
||||
#define IGC_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */
|
||||
#define IGC_TXPBS 0x03404 /* Tx Packet Buffer Size - RW */
|
||||
|
||||
/* NVM Register Descriptions */
|
||||
#define IGC_EERD 0x12014 /* EEprom mode read - RW */
|
||||
#define IGC_EEWR 0x12018 /* EEprom mode write - RW */
|
||||
|
||||
/* Flow Control Register Descriptions */
|
||||
#define IGC_FCAL 0x00028 /* FC Address Low - RW */
|
||||
#define IGC_FCAH 0x0002C /* FC Address High - RW */
|
||||
#define IGC_FCT 0x00030 /* FC Type - RW */
|
||||
#define IGC_FCTTV 0x00170 /* FC Transmit Timer - RW */
|
||||
#define IGC_FCRTL 0x02160 /* FC Receive Threshold Low - RW */
|
||||
#define IGC_FCRTH 0x02168 /* FC Receive Threshold High - RW */
|
||||
#define IGC_FCRTV 0x02460 /* FC Refresh Timer Value - RW */
|
||||
|
||||
/* Semaphore registers */
|
||||
#define IGC_SW_FW_SYNC 0x05B5C /* SW-FW Synchronization - RW */
|
||||
#define IGC_SWSM 0x05B50 /* SW Semaphore */
|
||||
#define IGC_FWSM 0x05B54 /* FW Semaphore */
|
||||
|
||||
/* Function Active and Power State to MNG */
|
||||
#define IGC_FACTPS 0x05B30
|
||||
|
||||
/* Interrupt Register Description */
|
||||
#define IGC_EICR 0x01580 /* Ext. Interrupt Cause read - W0 */
|
||||
#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 Auto Mask - RW */
|
||||
#define IGC_ICR 0x01500 /* Intr Cause Read - RC/W1C */
|
||||
#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 */
|
||||
/* Intr Throttle - RW */
|
||||
#define IGC_EITR(_n) (0x01680 + (0x4 * (_n)))
|
||||
/* Interrupt Vector Allocation - RW */
|
||||
#define IGC_IVAR0 0x01700
|
||||
#define IGC_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */
|
||||
#define IGC_GPIE 0x01514 /* General Purpose Intr Enable - RW */
|
||||
|
||||
/* RSS registers */
|
||||
#define IGC_MRQC 0x05818 /* Multiple Receive Control - RW */
|
||||
|
||||
/* Filtering Registers */
|
||||
#define IGC_ETQF(_n) (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */
|
||||
#define IGC_FHFT(_n) (0x09000 + (256 * (_n))) /* Flexible Host Filter */
|
||||
#define IGC_FHFT_EXT(_n) (0x09A00 + (256 * (_n))) /* Flexible Host Filter Extended */
|
||||
#define IGC_FHFTSL 0x05804 /* Flex Filter indirect table select */
|
||||
|
||||
/* ETQF register bit definitions */
|
||||
#define IGC_ETQF_FILTER_ENABLE BIT(26)
|
||||
#define IGC_ETQF_QUEUE_ENABLE BIT(31)
|
||||
#define IGC_ETQF_QUEUE_SHIFT 16
|
||||
#define IGC_ETQF_QUEUE_MASK 0x00070000
|
||||
#define IGC_ETQF_ETYPE_MASK 0x0000FFFF
|
||||
|
||||
/* FHFT register bit definitions */
|
||||
#define IGC_FHFT_LENGTH_MASK GENMASK(7, 0)
|
||||
#define IGC_FHFT_QUEUE_SHIFT 8
|
||||
#define IGC_FHFT_QUEUE_MASK GENMASK(10, 8)
|
||||
#define IGC_FHFT_PRIO_SHIFT 16
|
||||
#define IGC_FHFT_PRIO_MASK GENMASK(18, 16)
|
||||
#define IGC_FHFT_IMM_INT BIT(24)
|
||||
#define IGC_FHFT_DROP BIT(25)
|
||||
|
||||
/* FHFTSL register bit definitions */
|
||||
#define IGC_FHFTSL_FTSL_SHIFT 0
|
||||
#define IGC_FHFTSL_FTSL_MASK GENMASK(1, 0)
|
||||
|
||||
/* Redirection Table - RW Array */
|
||||
#define IGC_RETA(_i) (0x05C00 + ((_i) * 4))
|
||||
/* RSS Random Key - RW Array */
|
||||
#define IGC_RSSRK(_i) (0x05C80 + ((_i) * 4))
|
||||
|
||||
/* Receive Register Descriptions */
|
||||
#define IGC_RCTL 0x00100 /* Rx Control - RW */
|
||||
#define IGC_SRRCTL(_n) (0x0C00C + ((_n) * 0x40))
|
||||
#define IGC_PSRTYPE(_i) (0x05480 + ((_i) * 4))
|
||||
#define IGC_RDBAL(_n) (0x0C000 + ((_n) * 0x40))
|
||||
#define IGC_RDBAH(_n) (0x0C004 + ((_n) * 0x40))
|
||||
#define IGC_RDLEN(_n) (0x0C008 + ((_n) * 0x40))
|
||||
#define IGC_RDH(_n) (0x0C010 + ((_n) * 0x40))
|
||||
#define IGC_RDT(_n) (0x0C018 + ((_n) * 0x40))
|
||||
#define IGC_RXDCTL(_n) (0x0C028 + ((_n) * 0x40))
|
||||
#define IGC_RQDPC(_n) (0x0C030 + ((_n) * 0x40))
|
||||
#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_UTA 0x0A000 /* Unicast Table Array - RW */
|
||||
#define IGC_RAL(_n) (0x05400 + ((_n) * 0x08))
|
||||
#define IGC_RAH(_n) (0x05404 + ((_n) * 0x08))
|
||||
#define IGC_VLANPQF 0x055B0 /* VLAN Priority Queue Filter - RW */
|
||||
|
||||
/* Transmit Register Descriptions */
|
||||
#define IGC_TCTL 0x00400 /* Tx Control - RW */
|
||||
#define IGC_TIPG 0x00410 /* Tx Inter-packet gap - RW */
|
||||
#define IGC_TDBAL(_n) (0x0E000 + ((_n) * 0x40))
|
||||
#define IGC_TDBAH(_n) (0x0E004 + ((_n) * 0x40))
|
||||
#define IGC_TDLEN(_n) (0x0E008 + ((_n) * 0x40))
|
||||
#define IGC_TDH(_n) (0x0E010 + ((_n) * 0x40))
|
||||
#define IGC_TDT(_n) (0x0E018 + ((_n) * 0x40))
|
||||
#define IGC_TXDCTL(_n) (0x0E028 + ((_n) * 0x40))
|
||||
|
||||
/* MMD Register Descriptions */
|
||||
#define IGC_MMDAC 13 /* MMD Access Control */
|
||||
#define IGC_MMDAAD 14 /* MMD Access Address/Data */
|
||||
|
||||
/* Statistics Register Descriptions */
|
||||
#define IGC_CRCERRS 0x04000 /* CRC Error Count - R/clr */
|
||||
#define IGC_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */
|
||||
#define IGC_RXERRC 0x0400C /* Receive 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_RPTHC 0x04104 /* Rx Packets To Host */
|
||||
#define IGC_TLPIC 0x04148 /* EEE Tx LPI Count */
|
||||
#define IGC_RLPIC 0x0414C /* EEE Rx LPI Count */
|
||||
#define IGC_HGPTC 0x04118 /* Host Good Packets Tx Count */
|
||||
#define IGC_RXDMTC 0x04120 /* Rx Descriptor Minimum Threshold Count */
|
||||
#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 */
|
||||
|
||||
/* Time sync registers */
|
||||
#define IGC_TSICR 0x0B66C /* Time Sync Interrupt Cause */
|
||||
#define IGC_TSIM 0x0B674 /* Time Sync Interrupt Mask Register */
|
||||
#define IGC_TSAUXC 0x0B640 /* Timesync Auxiliary Control register */
|
||||
#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_TSSDP 0x0003C /* Time Sync SDP Configuration Register - RW */
|
||||
#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_AUXSTMPL0 0x0B65C /* Auxiliary Time Stamp 0 Register Low - RO */
|
||||
#define IGC_AUXSTMPH0 0x0B660 /* Auxiliary Time Stamp 0 Register High - RO */
|
||||
#define IGC_AUXSTMPL1 0x0B664 /* Auxiliary Time Stamp 1 Register Low - RO */
|
||||
#define IGC_AUXSTMPH1 0x0B668 /* Auxiliary Time Stamp 1 Register High - RO */
|
||||
|
||||
#define IGC_IMIR(_i) (0x05A80 + ((_i) * 4)) /* Immediate Interrupt */
|
||||
#define IGC_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* Immediate INTR Ext*/
|
||||
|
||||
#define IGC_FTQF(_n) (0x059E0 + (4 * (_n))) /* 5-tuple Queue Fltr */
|
||||
|
||||
/* Transmit Scheduling Registers */
|
||||
#define IGC_TQAVCTRL 0x3570
|
||||
#define IGC_TXQCTL(_n) (0x3344 + 0x4 * (_n))
|
||||
#define IGC_GTXOFFSET 0x3310
|
||||
#define IGC_BASET_L 0x3314
|
||||
#define IGC_BASET_H 0x3318
|
||||
#define IGC_QBVCYCLET 0x331C
|
||||
#define IGC_QBVCYCLET_S 0x3320
|
||||
|
||||
#define IGC_STQT(_n) (0x3324 + 0x4 * (_n))
|
||||
#define IGC_ENDQT(_n) (0x3334 + 0x4 * (_n))
|
||||
#define IGC_DTXMXPKTSZ 0x355C
|
||||
|
||||
#define IGC_TQAVCC(_n) (0x3004 + ((_n) * 0x40))
|
||||
#define IGC_TQAVHC(_n) (0x300C + ((_n) * 0x40))
|
||||
|
||||
/* System Time Registers */
|
||||
#define IGC_SYSTIML 0x0B600 /* System time register Low - RO */
|
||||
#define IGC_SYSTIMH 0x0B604 /* System time register High - RO */
|
||||
#define IGC_SYSTIMR 0x0B6F8 /* System time register Residue */
|
||||
#define IGC_TIMINCA 0x0B608 /* Increment attributes register - RW */
|
||||
|
||||
/* TX Timestamp Low */
|
||||
#define IGC_TXSTMPL_0 0x0B618
|
||||
#define IGC_TXSTMPL_1 0x0B698
|
||||
#define IGC_TXSTMPL_2 0x0B6B8
|
||||
#define IGC_TXSTMPL_3 0x0B6D8
|
||||
|
||||
/* TX Timestamp High */
|
||||
#define IGC_TXSTMPH_0 0x0B61C
|
||||
#define IGC_TXSTMPH_1 0x0B69C
|
||||
#define IGC_TXSTMPH_2 0x0B6BC
|
||||
#define IGC_TXSTMPH_3 0x0B6DC
|
||||
|
||||
#define IGC_TXSTMPL 0x0B618 /* Tx timestamp value Low - RO */
|
||||
#define IGC_TXSTMPH 0x0B61C /* Tx timestamp value High - RO */
|
||||
|
||||
#define IGC_TIMADJ 0x0B60C /* Time Adjustment Offset Register */
|
||||
|
||||
/* PCIe Registers */
|
||||
#define IGC_PTM_CTRL 0x12540 /* PTM Control */
|
||||
#define IGC_PTM_STAT 0x12544 /* PTM Status */
|
||||
#define IGC_PTM_CYCLE_CTRL 0x1254C /* PTM Cycle Control */
|
||||
|
||||
/* PTM Time registers */
|
||||
#define IGC_PTM_T1_TIM0_L 0x12558 /* T1 on Timer 0 Low */
|
||||
#define IGC_PTM_T1_TIM0_H 0x1255C /* T1 on Timer 0 High */
|
||||
|
||||
#define IGC_PTM_CURR_T2_L 0x1258C /* Current T2 Low */
|
||||
#define IGC_PTM_CURR_T2_H 0x12590 /* Current T2 High */
|
||||
#define IGC_PTM_PREV_T2_L 0x12584 /* Previous T2 Low */
|
||||
#define IGC_PTM_PREV_T2_H 0x12588 /* Previous T2 High */
|
||||
#define IGC_PTM_PREV_T4M1 0x12578 /* T4 Minus T1 on previous PTM Cycle */
|
||||
#define IGC_PTM_CURR_T4M1 0x1257C /* T4 Minus T1 on this PTM Cycle */
|
||||
#define IGC_PTM_PREV_T3M2 0x12580 /* T3 Minus T2 on previous PTM Cycle */
|
||||
#define IGC_PTM_TDELAY 0x12594 /* PTM PCIe Link Delay */
|
||||
|
||||
#define IGC_PCIE_DIG_DELAY 0x12550 /* PCIe Digital Delay */
|
||||
#define IGC_PCIE_PHY_DELAY 0x12554 /* PCIe PHY Delay */
|
||||
|
||||
/* Management registers */
|
||||
#define IGC_MANC 0x05820 /* Management Control - RW */
|
||||
|
||||
/* Shadow Ram Write Register - RW */
|
||||
#define IGC_SRWR 0x12018
|
||||
|
||||
/* Wake Up registers */
|
||||
#define IGC_WUC 0x05800 /* Wakeup Control - RW */
|
||||
#define IGC_WUFC 0x05808 /* Wakeup Filter Control - RW */
|
||||
#define IGC_WUS 0x05810 /* Wakeup Status - R/W1C */
|
||||
#define IGC_WUPL 0x05900 /* Wakeup Packet Length - RW */
|
||||
#define IGC_WUFC_EXT 0x0580C /* Wakeup Filter Control Register Extended - RW */
|
||||
|
||||
/* Wake Up packet memory */
|
||||
#define IGC_WUPM_REG(_i) (0x05A00 + ((_i) * 4))
|
||||
|
||||
/* Energy Efficient Ethernet "EEE" registers */
|
||||
#define IGC_EEER 0x0E30 /* Energy Efficient Ethernet "EEE"*/
|
||||
#define IGC_IPCNFG 0x0E38 /* Internal PHY Configuration */
|
||||
#define IGC_EEE_SU 0x0E34 /* EEE Setup */
|
||||
|
||||
/* LTR registers */
|
||||
#define IGC_LTRC 0x01A0 /* Latency Tolerance Reporting Control */
|
||||
#define IGC_LTRMINV 0x5BB0 /* LTR Minimum Value */
|
||||
#define IGC_LTRMAXV 0x5BB4 /* LTR Maximum Value */
|
||||
|
||||
/* forward declaration */
|
||||
struct igc_hw;
|
||||
u32 igc_rd32(struct igc_hw *hw, u32 reg);
|
||||
|
||||
/* write operations, indexed using DWORDS */
|
||||
#define wr32(reg, val) \
|
||||
do { \
|
||||
u8 __iomem *hw_addr = READ_ONCE((hw)->hw_addr); \
|
||||
if (!IGC_REMOVED(hw_addr)) \
|
||||
writel((val), &hw_addr[(reg)]); \
|
||||
} while (0)
|
||||
|
||||
#define rd32(reg) (igc_rd32(hw, reg))
|
||||
|
||||
#define wrfl() ((void)rd32(IGC_STATUS))
|
||||
|
||||
#define array_wr32(reg, offset, value) \
|
||||
wr32((reg) + ((offset) << 2), (value))
|
||||
|
||||
#define array_rd32(reg, offset) (igc_rd32(hw, (reg) + ((offset) << 2)))
|
||||
|
||||
#define IGC_REMOVED(h) unlikely(!(h))
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,350 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2019 Intel Corporation */
|
||||
|
||||
#include "igc-6.4-ethercat.h"
|
||||
#include "igc_hw-6.4-ethercat.h"
|
||||
#include "igc_tsn-6.4-ethercat.h"
|
||||
|
||||
static bool is_any_launchtime(struct igc_adapter *adapter)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
struct igc_ring *ring = adapter->tx_ring[i];
|
||||
|
||||
if (ring->launchtime_enable)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_cbs_enabled(struct igc_adapter *adapter)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
struct igc_ring *ring = adapter->tx_ring[i];
|
||||
|
||||
if (ring->cbs_enable)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsigned int igc_tsn_new_flags(struct igc_adapter *adapter)
|
||||
{
|
||||
unsigned int new_flags = adapter->flags & ~IGC_FLAG_TSN_ANY_ENABLED;
|
||||
|
||||
if (adapter->taprio_offload_enable)
|
||||
new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
|
||||
|
||||
if (is_any_launchtime(adapter))
|
||||
new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
|
||||
|
||||
if (is_cbs_enabled(adapter))
|
||||
new_flags |= IGC_FLAG_TSN_QAV_ENABLED;
|
||||
|
||||
return new_flags;
|
||||
}
|
||||
|
||||
void igc_tsn_adjust_txtime_offset(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u16 txoffset;
|
||||
|
||||
if (!is_any_launchtime(adapter))
|
||||
return;
|
||||
|
||||
switch (adapter->link_speed) {
|
||||
case SPEED_10:
|
||||
txoffset = IGC_TXOFFSET_SPEED_10;
|
||||
break;
|
||||
case SPEED_100:
|
||||
txoffset = IGC_TXOFFSET_SPEED_100;
|
||||
break;
|
||||
case SPEED_1000:
|
||||
txoffset = IGC_TXOFFSET_SPEED_1000;
|
||||
break;
|
||||
case SPEED_2500:
|
||||
txoffset = IGC_TXOFFSET_SPEED_2500;
|
||||
break;
|
||||
default:
|
||||
txoffset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
wr32(IGC_GTXOFFSET, txoffset);
|
||||
}
|
||||
|
||||
/* Returns the TSN specific registers to their default values after
|
||||
* the adapter is reset.
|
||||
*/
|
||||
static int igc_tsn_disable_offload(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 tqavctrl;
|
||||
int i;
|
||||
|
||||
wr32(IGC_GTXOFFSET, 0);
|
||||
wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT);
|
||||
wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_DEFAULT);
|
||||
|
||||
tqavctrl = rd32(IGC_TQAVCTRL);
|
||||
tqavctrl &= ~(IGC_TQAVCTRL_TRANSMIT_MODE_TSN |
|
||||
IGC_TQAVCTRL_ENHANCED_QAV | IGC_TQAVCTRL_FUTSCDDIS);
|
||||
|
||||
wr32(IGC_TQAVCTRL, tqavctrl);
|
||||
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
wr32(IGC_TXQCTL(i), 0);
|
||||
wr32(IGC_STQT(i), 0);
|
||||
wr32(IGC_ENDQT(i), NSEC_PER_SEC);
|
||||
}
|
||||
|
||||
wr32(IGC_QBVCYCLET_S, 0);
|
||||
wr32(IGC_QBVCYCLET, NSEC_PER_SEC);
|
||||
|
||||
adapter->flags &= ~IGC_FLAG_TSN_QBV_ENABLED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igc_tsn_enable_offload(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 tqavctrl, baset_l, baset_h;
|
||||
u32 sec, nsec, cycle;
|
||||
ktime_t base_time, systim;
|
||||
int i;
|
||||
|
||||
wr32(IGC_TSAUXC, 0);
|
||||
wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_TSN);
|
||||
wr32(IGC_TXPBS, IGC_TXPBSIZE_TSN);
|
||||
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
struct igc_ring *ring = adapter->tx_ring[i];
|
||||
u32 txqctl = 0;
|
||||
u16 cbs_value;
|
||||
u32 tqavcc;
|
||||
|
||||
wr32(IGC_STQT(i), ring->start_time);
|
||||
wr32(IGC_ENDQT(i), ring->end_time);
|
||||
|
||||
if (adapter->taprio_offload_enable) {
|
||||
/* If taprio_offload_enable is set we are in "taprio"
|
||||
* mode and we need to be strict about the
|
||||
* cycles: only transmit a packet if it can be
|
||||
* completed during that cycle.
|
||||
*
|
||||
* If taprio_offload_enable is NOT true when
|
||||
* enabling TSN offload, the cycle should have
|
||||
* no external effects, but is only used internally
|
||||
* to adapt the base time register after a second
|
||||
* has passed.
|
||||
*
|
||||
* Enabling strict mode in this case would
|
||||
* unnecessarily prevent the transmission of
|
||||
* certain packets (i.e. at the boundary of a
|
||||
* second) and thus interfere with the launchtime
|
||||
* feature that promises transmission at a
|
||||
* certain point in time.
|
||||
*/
|
||||
txqctl |= IGC_TXQCTL_STRICT_CYCLE |
|
||||
IGC_TXQCTL_STRICT_END;
|
||||
}
|
||||
|
||||
if (ring->launchtime_enable)
|
||||
txqctl |= IGC_TXQCTL_QUEUE_MODE_LAUNCHT;
|
||||
|
||||
/* Skip configuring CBS for Q2 and Q3 */
|
||||
if (i > 1)
|
||||
goto skip_cbs;
|
||||
|
||||
if (ring->cbs_enable) {
|
||||
if (i == 0)
|
||||
txqctl |= IGC_TXQCTL_QAV_SEL_CBS0;
|
||||
else
|
||||
txqctl |= IGC_TXQCTL_QAV_SEL_CBS1;
|
||||
|
||||
/* According to i225 datasheet section 7.5.2.7, we
|
||||
* should set the 'idleSlope' field from TQAVCC
|
||||
* register following the equation:
|
||||
*
|
||||
* value = link-speed 0x7736 * BW * 0.2
|
||||
* ---------- * ----------------- (E1)
|
||||
* 100Mbps 2.5
|
||||
*
|
||||
* Note that 'link-speed' is in Mbps.
|
||||
*
|
||||
* 'BW' is the percentage bandwidth out of full
|
||||
* link speed which can be found with the
|
||||
* following equation. Note that idleSlope here
|
||||
* is the parameter from this function
|
||||
* which is in kbps.
|
||||
*
|
||||
* BW = idleSlope
|
||||
* ----------------- (E2)
|
||||
* link-speed * 1000
|
||||
*
|
||||
* That said, we can come up with a generic
|
||||
* equation to calculate the value we should set
|
||||
* it TQAVCC register by replacing 'BW' in E1 by E2.
|
||||
* The resulting equation is:
|
||||
*
|
||||
* value = link-speed * 0x7736 * idleSlope * 0.2
|
||||
* ------------------------------------- (E3)
|
||||
* 100 * 2.5 * link-speed * 1000
|
||||
*
|
||||
* 'link-speed' is present in both sides of the
|
||||
* fraction so it is canceled out. The final
|
||||
* equation is the following:
|
||||
*
|
||||
* value = idleSlope * 61036
|
||||
* ----------------- (E4)
|
||||
* 2500000
|
||||
*
|
||||
* NOTE: For i225, given the above, we can see
|
||||
* that idleslope is represented in
|
||||
* 40.959433 kbps units by the value at
|
||||
* the TQAVCC register (2.5Gbps / 61036),
|
||||
* which reduces the granularity for
|
||||
* idleslope increments.
|
||||
*
|
||||
* In i225 controller, the sendSlope and loCredit
|
||||
* parameters from CBS are not configurable
|
||||
* by software so we don't do any
|
||||
* 'controller configuration' in respect to
|
||||
* these parameters.
|
||||
*/
|
||||
cbs_value = DIV_ROUND_UP_ULL(ring->idleslope
|
||||
* 61036ULL, 2500000);
|
||||
|
||||
tqavcc = rd32(IGC_TQAVCC(i));
|
||||
tqavcc &= ~IGC_TQAVCC_IDLESLOPE_MASK;
|
||||
tqavcc |= cbs_value | IGC_TQAVCC_KEEP_CREDITS;
|
||||
wr32(IGC_TQAVCC(i), tqavcc);
|
||||
|
||||
wr32(IGC_TQAVHC(i),
|
||||
0x80000000 + ring->hicredit * 0x7735);
|
||||
} else {
|
||||
/* Disable any CBS for the queue */
|
||||
txqctl &= ~(IGC_TXQCTL_QAV_SEL_MASK);
|
||||
|
||||
/* Set idleSlope to zero. */
|
||||
tqavcc = rd32(IGC_TQAVCC(i));
|
||||
tqavcc &= ~(IGC_TQAVCC_IDLESLOPE_MASK |
|
||||
IGC_TQAVCC_KEEP_CREDITS);
|
||||
wr32(IGC_TQAVCC(i), tqavcc);
|
||||
|
||||
/* Set hiCredit to zero. */
|
||||
wr32(IGC_TQAVHC(i), 0);
|
||||
}
|
||||
skip_cbs:
|
||||
wr32(IGC_TXQCTL(i), txqctl);
|
||||
}
|
||||
|
||||
tqavctrl = rd32(IGC_TQAVCTRL) & ~IGC_TQAVCTRL_FUTSCDDIS;
|
||||
|
||||
tqavctrl |= IGC_TQAVCTRL_TRANSMIT_MODE_TSN | IGC_TQAVCTRL_ENHANCED_QAV;
|
||||
|
||||
adapter->qbv_count++;
|
||||
|
||||
cycle = adapter->cycle_time;
|
||||
base_time = adapter->base_time;
|
||||
|
||||
nsec = rd32(IGC_SYSTIML);
|
||||
sec = rd32(IGC_SYSTIMH);
|
||||
|
||||
systim = ktime_set(sec, nsec);
|
||||
if (ktime_compare(systim, base_time) > 0) {
|
||||
s64 n = div64_s64(ktime_sub_ns(systim, base_time), cycle);
|
||||
|
||||
base_time = ktime_add_ns(base_time, (n + 1) * cycle);
|
||||
|
||||
/* Increase the counter if scheduling into the past while
|
||||
* Gate Control List (GCL) is running.
|
||||
*/
|
||||
if ((rd32(IGC_BASET_H) || rd32(IGC_BASET_L)) &&
|
||||
(adapter->tc_setup_type == TC_SETUP_QDISC_TAPRIO) &&
|
||||
(adapter->qbv_count > 1))
|
||||
adapter->qbv_config_change_errors++;
|
||||
} else {
|
||||
if (igc_is_device_id_i226(hw)) {
|
||||
ktime_t adjust_time, expires_time;
|
||||
|
||||
/* According to datasheet section 7.5.2.9.3.3, FutScdDis bit
|
||||
* has to be configured before the cycle time and base time.
|
||||
* Tx won't hang if a GCL is already running,
|
||||
* so in this case we don't need to set FutScdDis.
|
||||
*/
|
||||
if (!(rd32(IGC_BASET_H) || rd32(IGC_BASET_L)))
|
||||
tqavctrl |= IGC_TQAVCTRL_FUTSCDDIS;
|
||||
|
||||
nsec = rd32(IGC_SYSTIML);
|
||||
sec = rd32(IGC_SYSTIMH);
|
||||
systim = ktime_set(sec, nsec);
|
||||
|
||||
adjust_time = adapter->base_time;
|
||||
expires_time = ktime_sub_ns(adjust_time, systim);
|
||||
hrtimer_start(&adapter->hrtimer, expires_time, HRTIMER_MODE_REL);
|
||||
}
|
||||
}
|
||||
|
||||
wr32(IGC_TQAVCTRL, tqavctrl);
|
||||
|
||||
wr32(IGC_QBVCYCLET_S, cycle);
|
||||
wr32(IGC_QBVCYCLET, cycle);
|
||||
|
||||
baset_h = div_s64_rem(base_time, NSEC_PER_SEC, &baset_l);
|
||||
wr32(IGC_BASET_H, baset_h);
|
||||
|
||||
/* In i226, Future base time is only supported when FutScdDis bit
|
||||
* is enabled and only active for re-configuration.
|
||||
* In this case, initialize the base time with zero to create
|
||||
* "re-configuration" scenario then only set the desired base time.
|
||||
*/
|
||||
if (tqavctrl & IGC_TQAVCTRL_FUTSCDDIS)
|
||||
wr32(IGC_BASET_L, 0);
|
||||
wr32(IGC_BASET_L, baset_l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igc_tsn_reset(struct igc_adapter *adapter)
|
||||
{
|
||||
unsigned int new_flags;
|
||||
int err = 0;
|
||||
|
||||
new_flags = igc_tsn_new_flags(adapter);
|
||||
|
||||
if (!(new_flags & IGC_FLAG_TSN_ANY_ENABLED))
|
||||
return igc_tsn_disable_offload(adapter);
|
||||
|
||||
err = igc_tsn_enable_offload(adapter);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
adapter->flags = new_flags;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int igc_tsn_offload_apply(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
|
||||
/* Per I225/6 HW Design Section 7.5.2.1, transmit mode
|
||||
* cannot be changed dynamically. Require reset the adapter.
|
||||
*/
|
||||
if (netif_running(adapter->netdev) &&
|
||||
(igc_is_device_id_i225(hw) || !adapter->qbv_count)) {
|
||||
schedule_work(&adapter->reset_task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
igc_tsn_reset(adapter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2020 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_TSN_H_
|
||||
#define _IGC_TSN_H_
|
||||
|
||||
int igc_tsn_offload_apply(struct igc_adapter *adapter);
|
||||
int igc_tsn_reset(struct igc_adapter *adapter);
|
||||
void igc_tsn_adjust_txtime_offset(struct igc_adapter *adapter);
|
||||
|
||||
#endif /* _IGC_BASE_H */
|
||||
|
|
@ -0,0 +1,350 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2019 Intel Corporation */
|
||||
|
||||
#include "igc.h"
|
||||
#include "igc_hw.h"
|
||||
#include "igc_tsn.h"
|
||||
|
||||
static bool is_any_launchtime(struct igc_adapter *adapter)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
struct igc_ring *ring = adapter->tx_ring[i];
|
||||
|
||||
if (ring->launchtime_enable)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_cbs_enabled(struct igc_adapter *adapter)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
struct igc_ring *ring = adapter->tx_ring[i];
|
||||
|
||||
if (ring->cbs_enable)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsigned int igc_tsn_new_flags(struct igc_adapter *adapter)
|
||||
{
|
||||
unsigned int new_flags = adapter->flags & ~IGC_FLAG_TSN_ANY_ENABLED;
|
||||
|
||||
if (adapter->taprio_offload_enable)
|
||||
new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
|
||||
|
||||
if (is_any_launchtime(adapter))
|
||||
new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
|
||||
|
||||
if (is_cbs_enabled(adapter))
|
||||
new_flags |= IGC_FLAG_TSN_QAV_ENABLED;
|
||||
|
||||
return new_flags;
|
||||
}
|
||||
|
||||
void igc_tsn_adjust_txtime_offset(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u16 txoffset;
|
||||
|
||||
if (!is_any_launchtime(adapter))
|
||||
return;
|
||||
|
||||
switch (adapter->link_speed) {
|
||||
case SPEED_10:
|
||||
txoffset = IGC_TXOFFSET_SPEED_10;
|
||||
break;
|
||||
case SPEED_100:
|
||||
txoffset = IGC_TXOFFSET_SPEED_100;
|
||||
break;
|
||||
case SPEED_1000:
|
||||
txoffset = IGC_TXOFFSET_SPEED_1000;
|
||||
break;
|
||||
case SPEED_2500:
|
||||
txoffset = IGC_TXOFFSET_SPEED_2500;
|
||||
break;
|
||||
default:
|
||||
txoffset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
wr32(IGC_GTXOFFSET, txoffset);
|
||||
}
|
||||
|
||||
/* Returns the TSN specific registers to their default values after
|
||||
* the adapter is reset.
|
||||
*/
|
||||
static int igc_tsn_disable_offload(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 tqavctrl;
|
||||
int i;
|
||||
|
||||
wr32(IGC_GTXOFFSET, 0);
|
||||
wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT);
|
||||
wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_DEFAULT);
|
||||
|
||||
tqavctrl = rd32(IGC_TQAVCTRL);
|
||||
tqavctrl &= ~(IGC_TQAVCTRL_TRANSMIT_MODE_TSN |
|
||||
IGC_TQAVCTRL_ENHANCED_QAV | IGC_TQAVCTRL_FUTSCDDIS);
|
||||
|
||||
wr32(IGC_TQAVCTRL, tqavctrl);
|
||||
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
wr32(IGC_TXQCTL(i), 0);
|
||||
wr32(IGC_STQT(i), 0);
|
||||
wr32(IGC_ENDQT(i), NSEC_PER_SEC);
|
||||
}
|
||||
|
||||
wr32(IGC_QBVCYCLET_S, 0);
|
||||
wr32(IGC_QBVCYCLET, NSEC_PER_SEC);
|
||||
|
||||
adapter->flags &= ~IGC_FLAG_TSN_QBV_ENABLED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igc_tsn_enable_offload(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 tqavctrl, baset_l, baset_h;
|
||||
u32 sec, nsec, cycle;
|
||||
ktime_t base_time, systim;
|
||||
int i;
|
||||
|
||||
wr32(IGC_TSAUXC, 0);
|
||||
wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_TSN);
|
||||
wr32(IGC_TXPBS, IGC_TXPBSIZE_TSN);
|
||||
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
struct igc_ring *ring = adapter->tx_ring[i];
|
||||
u32 txqctl = 0;
|
||||
u16 cbs_value;
|
||||
u32 tqavcc;
|
||||
|
||||
wr32(IGC_STQT(i), ring->start_time);
|
||||
wr32(IGC_ENDQT(i), ring->end_time);
|
||||
|
||||
if (adapter->taprio_offload_enable) {
|
||||
/* If taprio_offload_enable is set we are in "taprio"
|
||||
* mode and we need to be strict about the
|
||||
* cycles: only transmit a packet if it can be
|
||||
* completed during that cycle.
|
||||
*
|
||||
* If taprio_offload_enable is NOT true when
|
||||
* enabling TSN offload, the cycle should have
|
||||
* no external effects, but is only used internally
|
||||
* to adapt the base time register after a second
|
||||
* has passed.
|
||||
*
|
||||
* Enabling strict mode in this case would
|
||||
* unnecessarily prevent the transmission of
|
||||
* certain packets (i.e. at the boundary of a
|
||||
* second) and thus interfere with the launchtime
|
||||
* feature that promises transmission at a
|
||||
* certain point in time.
|
||||
*/
|
||||
txqctl |= IGC_TXQCTL_STRICT_CYCLE |
|
||||
IGC_TXQCTL_STRICT_END;
|
||||
}
|
||||
|
||||
if (ring->launchtime_enable)
|
||||
txqctl |= IGC_TXQCTL_QUEUE_MODE_LAUNCHT;
|
||||
|
||||
/* Skip configuring CBS for Q2 and Q3 */
|
||||
if (i > 1)
|
||||
goto skip_cbs;
|
||||
|
||||
if (ring->cbs_enable) {
|
||||
if (i == 0)
|
||||
txqctl |= IGC_TXQCTL_QAV_SEL_CBS0;
|
||||
else
|
||||
txqctl |= IGC_TXQCTL_QAV_SEL_CBS1;
|
||||
|
||||
/* According to i225 datasheet section 7.5.2.7, we
|
||||
* should set the 'idleSlope' field from TQAVCC
|
||||
* register following the equation:
|
||||
*
|
||||
* value = link-speed 0x7736 * BW * 0.2
|
||||
* ---------- * ----------------- (E1)
|
||||
* 100Mbps 2.5
|
||||
*
|
||||
* Note that 'link-speed' is in Mbps.
|
||||
*
|
||||
* 'BW' is the percentage bandwidth out of full
|
||||
* link speed which can be found with the
|
||||
* following equation. Note that idleSlope here
|
||||
* is the parameter from this function
|
||||
* which is in kbps.
|
||||
*
|
||||
* BW = idleSlope
|
||||
* ----------------- (E2)
|
||||
* link-speed * 1000
|
||||
*
|
||||
* That said, we can come up with a generic
|
||||
* equation to calculate the value we should set
|
||||
* it TQAVCC register by replacing 'BW' in E1 by E2.
|
||||
* The resulting equation is:
|
||||
*
|
||||
* value = link-speed * 0x7736 * idleSlope * 0.2
|
||||
* ------------------------------------- (E3)
|
||||
* 100 * 2.5 * link-speed * 1000
|
||||
*
|
||||
* 'link-speed' is present in both sides of the
|
||||
* fraction so it is canceled out. The final
|
||||
* equation is the following:
|
||||
*
|
||||
* value = idleSlope * 61036
|
||||
* ----------------- (E4)
|
||||
* 2500000
|
||||
*
|
||||
* NOTE: For i225, given the above, we can see
|
||||
* that idleslope is represented in
|
||||
* 40.959433 kbps units by the value at
|
||||
* the TQAVCC register (2.5Gbps / 61036),
|
||||
* which reduces the granularity for
|
||||
* idleslope increments.
|
||||
*
|
||||
* In i225 controller, the sendSlope and loCredit
|
||||
* parameters from CBS are not configurable
|
||||
* by software so we don't do any
|
||||
* 'controller configuration' in respect to
|
||||
* these parameters.
|
||||
*/
|
||||
cbs_value = DIV_ROUND_UP_ULL(ring->idleslope
|
||||
* 61036ULL, 2500000);
|
||||
|
||||
tqavcc = rd32(IGC_TQAVCC(i));
|
||||
tqavcc &= ~IGC_TQAVCC_IDLESLOPE_MASK;
|
||||
tqavcc |= cbs_value | IGC_TQAVCC_KEEP_CREDITS;
|
||||
wr32(IGC_TQAVCC(i), tqavcc);
|
||||
|
||||
wr32(IGC_TQAVHC(i),
|
||||
0x80000000 + ring->hicredit * 0x7735);
|
||||
} else {
|
||||
/* Disable any CBS for the queue */
|
||||
txqctl &= ~(IGC_TXQCTL_QAV_SEL_MASK);
|
||||
|
||||
/* Set idleSlope to zero. */
|
||||
tqavcc = rd32(IGC_TQAVCC(i));
|
||||
tqavcc &= ~(IGC_TQAVCC_IDLESLOPE_MASK |
|
||||
IGC_TQAVCC_KEEP_CREDITS);
|
||||
wr32(IGC_TQAVCC(i), tqavcc);
|
||||
|
||||
/* Set hiCredit to zero. */
|
||||
wr32(IGC_TQAVHC(i), 0);
|
||||
}
|
||||
skip_cbs:
|
||||
wr32(IGC_TXQCTL(i), txqctl);
|
||||
}
|
||||
|
||||
tqavctrl = rd32(IGC_TQAVCTRL) & ~IGC_TQAVCTRL_FUTSCDDIS;
|
||||
|
||||
tqavctrl |= IGC_TQAVCTRL_TRANSMIT_MODE_TSN | IGC_TQAVCTRL_ENHANCED_QAV;
|
||||
|
||||
adapter->qbv_count++;
|
||||
|
||||
cycle = adapter->cycle_time;
|
||||
base_time = adapter->base_time;
|
||||
|
||||
nsec = rd32(IGC_SYSTIML);
|
||||
sec = rd32(IGC_SYSTIMH);
|
||||
|
||||
systim = ktime_set(sec, nsec);
|
||||
if (ktime_compare(systim, base_time) > 0) {
|
||||
s64 n = div64_s64(ktime_sub_ns(systim, base_time), cycle);
|
||||
|
||||
base_time = ktime_add_ns(base_time, (n + 1) * cycle);
|
||||
|
||||
/* Increase the counter if scheduling into the past while
|
||||
* Gate Control List (GCL) is running.
|
||||
*/
|
||||
if ((rd32(IGC_BASET_H) || rd32(IGC_BASET_L)) &&
|
||||
(adapter->tc_setup_type == TC_SETUP_QDISC_TAPRIO) &&
|
||||
(adapter->qbv_count > 1))
|
||||
adapter->qbv_config_change_errors++;
|
||||
} else {
|
||||
if (igc_is_device_id_i226(hw)) {
|
||||
ktime_t adjust_time, expires_time;
|
||||
|
||||
/* According to datasheet section 7.5.2.9.3.3, FutScdDis bit
|
||||
* has to be configured before the cycle time and base time.
|
||||
* Tx won't hang if a GCL is already running,
|
||||
* so in this case we don't need to set FutScdDis.
|
||||
*/
|
||||
if (!(rd32(IGC_BASET_H) || rd32(IGC_BASET_L)))
|
||||
tqavctrl |= IGC_TQAVCTRL_FUTSCDDIS;
|
||||
|
||||
nsec = rd32(IGC_SYSTIML);
|
||||
sec = rd32(IGC_SYSTIMH);
|
||||
systim = ktime_set(sec, nsec);
|
||||
|
||||
adjust_time = adapter->base_time;
|
||||
expires_time = ktime_sub_ns(adjust_time, systim);
|
||||
hrtimer_start(&adapter->hrtimer, expires_time, HRTIMER_MODE_REL);
|
||||
}
|
||||
}
|
||||
|
||||
wr32(IGC_TQAVCTRL, tqavctrl);
|
||||
|
||||
wr32(IGC_QBVCYCLET_S, cycle);
|
||||
wr32(IGC_QBVCYCLET, cycle);
|
||||
|
||||
baset_h = div_s64_rem(base_time, NSEC_PER_SEC, &baset_l);
|
||||
wr32(IGC_BASET_H, baset_h);
|
||||
|
||||
/* In i226, Future base time is only supported when FutScdDis bit
|
||||
* is enabled and only active for re-configuration.
|
||||
* In this case, initialize the base time with zero to create
|
||||
* "re-configuration" scenario then only set the desired base time.
|
||||
*/
|
||||
if (tqavctrl & IGC_TQAVCTRL_FUTSCDDIS)
|
||||
wr32(IGC_BASET_L, 0);
|
||||
wr32(IGC_BASET_L, baset_l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igc_tsn_reset(struct igc_adapter *adapter)
|
||||
{
|
||||
unsigned int new_flags;
|
||||
int err = 0;
|
||||
|
||||
new_flags = igc_tsn_new_flags(adapter);
|
||||
|
||||
if (!(new_flags & IGC_FLAG_TSN_ANY_ENABLED))
|
||||
return igc_tsn_disable_offload(adapter);
|
||||
|
||||
err = igc_tsn_enable_offload(adapter);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
adapter->flags = new_flags;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int igc_tsn_offload_apply(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
|
||||
/* Per I225/6 HW Design Section 7.5.2.1, transmit mode
|
||||
* cannot be changed dynamically. Require reset the adapter.
|
||||
*/
|
||||
if (netif_running(adapter->netdev) &&
|
||||
(igc_is_device_id_i225(hw) || !adapter->qbv_count)) {
|
||||
schedule_work(&adapter->reset_task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
igc_tsn_reset(adapter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2020 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_TSN_H_
|
||||
#define _IGC_TSN_H_
|
||||
|
||||
int igc_tsn_offload_apply(struct igc_adapter *adapter);
|
||||
int igc_tsn_reset(struct igc_adapter *adapter);
|
||||
void igc_tsn_adjust_txtime_offset(struct igc_adapter *adapter);
|
||||
|
||||
#endif /* _IGC_BASE_H */
|
||||
|
|
@ -0,0 +1,350 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2019 Intel Corporation */
|
||||
|
||||
#include "igc-6.6-ethercat.h"
|
||||
#include "igc_hw-6.6-ethercat.h"
|
||||
#include "igc_tsn-6.6-ethercat.h"
|
||||
|
||||
static bool is_any_launchtime(struct igc_adapter *adapter)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
struct igc_ring *ring = adapter->tx_ring[i];
|
||||
|
||||
if (ring->launchtime_enable)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_cbs_enabled(struct igc_adapter *adapter)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
struct igc_ring *ring = adapter->tx_ring[i];
|
||||
|
||||
if (ring->cbs_enable)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsigned int igc_tsn_new_flags(struct igc_adapter *adapter)
|
||||
{
|
||||
unsigned int new_flags = adapter->flags & ~IGC_FLAG_TSN_ANY_ENABLED;
|
||||
|
||||
if (adapter->taprio_offload_enable)
|
||||
new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
|
||||
|
||||
if (is_any_launchtime(adapter))
|
||||
new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
|
||||
|
||||
if (is_cbs_enabled(adapter))
|
||||
new_flags |= IGC_FLAG_TSN_QAV_ENABLED;
|
||||
|
||||
return new_flags;
|
||||
}
|
||||
|
||||
void igc_tsn_adjust_txtime_offset(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u16 txoffset;
|
||||
|
||||
if (!is_any_launchtime(adapter))
|
||||
return;
|
||||
|
||||
switch (adapter->link_speed) {
|
||||
case SPEED_10:
|
||||
txoffset = IGC_TXOFFSET_SPEED_10;
|
||||
break;
|
||||
case SPEED_100:
|
||||
txoffset = IGC_TXOFFSET_SPEED_100;
|
||||
break;
|
||||
case SPEED_1000:
|
||||
txoffset = IGC_TXOFFSET_SPEED_1000;
|
||||
break;
|
||||
case SPEED_2500:
|
||||
txoffset = IGC_TXOFFSET_SPEED_2500;
|
||||
break;
|
||||
default:
|
||||
txoffset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
wr32(IGC_GTXOFFSET, txoffset);
|
||||
}
|
||||
|
||||
/* Returns the TSN specific registers to their default values after
|
||||
* the adapter is reset.
|
||||
*/
|
||||
static int igc_tsn_disable_offload(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 tqavctrl;
|
||||
int i;
|
||||
|
||||
wr32(IGC_GTXOFFSET, 0);
|
||||
wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT);
|
||||
wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_DEFAULT);
|
||||
|
||||
tqavctrl = rd32(IGC_TQAVCTRL);
|
||||
tqavctrl &= ~(IGC_TQAVCTRL_TRANSMIT_MODE_TSN |
|
||||
IGC_TQAVCTRL_ENHANCED_QAV | IGC_TQAVCTRL_FUTSCDDIS);
|
||||
|
||||
wr32(IGC_TQAVCTRL, tqavctrl);
|
||||
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
wr32(IGC_TXQCTL(i), 0);
|
||||
wr32(IGC_STQT(i), 0);
|
||||
wr32(IGC_ENDQT(i), NSEC_PER_SEC);
|
||||
}
|
||||
|
||||
wr32(IGC_QBVCYCLET_S, 0);
|
||||
wr32(IGC_QBVCYCLET, NSEC_PER_SEC);
|
||||
|
||||
adapter->flags &= ~IGC_FLAG_TSN_QBV_ENABLED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igc_tsn_enable_offload(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 tqavctrl, baset_l, baset_h;
|
||||
u32 sec, nsec, cycle;
|
||||
ktime_t base_time, systim;
|
||||
int i;
|
||||
|
||||
wr32(IGC_TSAUXC, 0);
|
||||
wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_TSN);
|
||||
wr32(IGC_TXPBS, IGC_TXPBSIZE_TSN);
|
||||
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
struct igc_ring *ring = adapter->tx_ring[i];
|
||||
u32 txqctl = 0;
|
||||
u16 cbs_value;
|
||||
u32 tqavcc;
|
||||
|
||||
wr32(IGC_STQT(i), ring->start_time);
|
||||
wr32(IGC_ENDQT(i), ring->end_time);
|
||||
|
||||
if (adapter->taprio_offload_enable) {
|
||||
/* If taprio_offload_enable is set we are in "taprio"
|
||||
* mode and we need to be strict about the
|
||||
* cycles: only transmit a packet if it can be
|
||||
* completed during that cycle.
|
||||
*
|
||||
* If taprio_offload_enable is NOT true when
|
||||
* enabling TSN offload, the cycle should have
|
||||
* no external effects, but is only used internally
|
||||
* to adapt the base time register after a second
|
||||
* has passed.
|
||||
*
|
||||
* Enabling strict mode in this case would
|
||||
* unnecessarily prevent the transmission of
|
||||
* certain packets (i.e. at the boundary of a
|
||||
* second) and thus interfere with the launchtime
|
||||
* feature that promises transmission at a
|
||||
* certain point in time.
|
||||
*/
|
||||
txqctl |= IGC_TXQCTL_STRICT_CYCLE |
|
||||
IGC_TXQCTL_STRICT_END;
|
||||
}
|
||||
|
||||
if (ring->launchtime_enable)
|
||||
txqctl |= IGC_TXQCTL_QUEUE_MODE_LAUNCHT;
|
||||
|
||||
/* Skip configuring CBS for Q2 and Q3 */
|
||||
if (i > 1)
|
||||
goto skip_cbs;
|
||||
|
||||
if (ring->cbs_enable) {
|
||||
if (i == 0)
|
||||
txqctl |= IGC_TXQCTL_QAV_SEL_CBS0;
|
||||
else
|
||||
txqctl |= IGC_TXQCTL_QAV_SEL_CBS1;
|
||||
|
||||
/* According to i225 datasheet section 7.5.2.7, we
|
||||
* should set the 'idleSlope' field from TQAVCC
|
||||
* register following the equation:
|
||||
*
|
||||
* value = link-speed 0x7736 * BW * 0.2
|
||||
* ---------- * ----------------- (E1)
|
||||
* 100Mbps 2.5
|
||||
*
|
||||
* Note that 'link-speed' is in Mbps.
|
||||
*
|
||||
* 'BW' is the percentage bandwidth out of full
|
||||
* link speed which can be found with the
|
||||
* following equation. Note that idleSlope here
|
||||
* is the parameter from this function
|
||||
* which is in kbps.
|
||||
*
|
||||
* BW = idleSlope
|
||||
* ----------------- (E2)
|
||||
* link-speed * 1000
|
||||
*
|
||||
* That said, we can come up with a generic
|
||||
* equation to calculate the value we should set
|
||||
* it TQAVCC register by replacing 'BW' in E1 by E2.
|
||||
* The resulting equation is:
|
||||
*
|
||||
* value = link-speed * 0x7736 * idleSlope * 0.2
|
||||
* ------------------------------------- (E3)
|
||||
* 100 * 2.5 * link-speed * 1000
|
||||
*
|
||||
* 'link-speed' is present in both sides of the
|
||||
* fraction so it is canceled out. The final
|
||||
* equation is the following:
|
||||
*
|
||||
* value = idleSlope * 61036
|
||||
* ----------------- (E4)
|
||||
* 2500000
|
||||
*
|
||||
* NOTE: For i225, given the above, we can see
|
||||
* that idleslope is represented in
|
||||
* 40.959433 kbps units by the value at
|
||||
* the TQAVCC register (2.5Gbps / 61036),
|
||||
* which reduces the granularity for
|
||||
* idleslope increments.
|
||||
*
|
||||
* In i225 controller, the sendSlope and loCredit
|
||||
* parameters from CBS are not configurable
|
||||
* by software so we don't do any
|
||||
* 'controller configuration' in respect to
|
||||
* these parameters.
|
||||
*/
|
||||
cbs_value = DIV_ROUND_UP_ULL(ring->idleslope
|
||||
* 61036ULL, 2500000);
|
||||
|
||||
tqavcc = rd32(IGC_TQAVCC(i));
|
||||
tqavcc &= ~IGC_TQAVCC_IDLESLOPE_MASK;
|
||||
tqavcc |= cbs_value | IGC_TQAVCC_KEEP_CREDITS;
|
||||
wr32(IGC_TQAVCC(i), tqavcc);
|
||||
|
||||
wr32(IGC_TQAVHC(i),
|
||||
0x80000000 + ring->hicredit * 0x7735);
|
||||
} else {
|
||||
/* Disable any CBS for the queue */
|
||||
txqctl &= ~(IGC_TXQCTL_QAV_SEL_MASK);
|
||||
|
||||
/* Set idleSlope to zero. */
|
||||
tqavcc = rd32(IGC_TQAVCC(i));
|
||||
tqavcc &= ~(IGC_TQAVCC_IDLESLOPE_MASK |
|
||||
IGC_TQAVCC_KEEP_CREDITS);
|
||||
wr32(IGC_TQAVCC(i), tqavcc);
|
||||
|
||||
/* Set hiCredit to zero. */
|
||||
wr32(IGC_TQAVHC(i), 0);
|
||||
}
|
||||
skip_cbs:
|
||||
wr32(IGC_TXQCTL(i), txqctl);
|
||||
}
|
||||
|
||||
tqavctrl = rd32(IGC_TQAVCTRL) & ~IGC_TQAVCTRL_FUTSCDDIS;
|
||||
|
||||
tqavctrl |= IGC_TQAVCTRL_TRANSMIT_MODE_TSN | IGC_TQAVCTRL_ENHANCED_QAV;
|
||||
|
||||
adapter->qbv_count++;
|
||||
|
||||
cycle = adapter->cycle_time;
|
||||
base_time = adapter->base_time;
|
||||
|
||||
nsec = rd32(IGC_SYSTIML);
|
||||
sec = rd32(IGC_SYSTIMH);
|
||||
|
||||
systim = ktime_set(sec, nsec);
|
||||
if (ktime_compare(systim, base_time) > 0) {
|
||||
s64 n = div64_s64(ktime_sub_ns(systim, base_time), cycle);
|
||||
|
||||
base_time = ktime_add_ns(base_time, (n + 1) * cycle);
|
||||
|
||||
/* Increase the counter if scheduling into the past while
|
||||
* Gate Control List (GCL) is running.
|
||||
*/
|
||||
if ((rd32(IGC_BASET_H) || rd32(IGC_BASET_L)) &&
|
||||
(adapter->tc_setup_type == TC_SETUP_QDISC_TAPRIO) &&
|
||||
(adapter->qbv_count > 1))
|
||||
adapter->qbv_config_change_errors++;
|
||||
} else {
|
||||
if (igc_is_device_id_i226(hw)) {
|
||||
ktime_t adjust_time, expires_time;
|
||||
|
||||
/* According to datasheet section 7.5.2.9.3.3, FutScdDis bit
|
||||
* has to be configured before the cycle time and base time.
|
||||
* Tx won't hang if a GCL is already running,
|
||||
* so in this case we don't need to set FutScdDis.
|
||||
*/
|
||||
if (!(rd32(IGC_BASET_H) || rd32(IGC_BASET_L)))
|
||||
tqavctrl |= IGC_TQAVCTRL_FUTSCDDIS;
|
||||
|
||||
nsec = rd32(IGC_SYSTIML);
|
||||
sec = rd32(IGC_SYSTIMH);
|
||||
systim = ktime_set(sec, nsec);
|
||||
|
||||
adjust_time = adapter->base_time;
|
||||
expires_time = ktime_sub_ns(adjust_time, systim);
|
||||
hrtimer_start(&adapter->hrtimer, expires_time, HRTIMER_MODE_REL);
|
||||
}
|
||||
}
|
||||
|
||||
wr32(IGC_TQAVCTRL, tqavctrl);
|
||||
|
||||
wr32(IGC_QBVCYCLET_S, cycle);
|
||||
wr32(IGC_QBVCYCLET, cycle);
|
||||
|
||||
baset_h = div_s64_rem(base_time, NSEC_PER_SEC, &baset_l);
|
||||
wr32(IGC_BASET_H, baset_h);
|
||||
|
||||
/* In i226, Future base time is only supported when FutScdDis bit
|
||||
* is enabled and only active for re-configuration.
|
||||
* In this case, initialize the base time with zero to create
|
||||
* "re-configuration" scenario then only set the desired base time.
|
||||
*/
|
||||
if (tqavctrl & IGC_TQAVCTRL_FUTSCDDIS)
|
||||
wr32(IGC_BASET_L, 0);
|
||||
wr32(IGC_BASET_L, baset_l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igc_tsn_reset(struct igc_adapter *adapter)
|
||||
{
|
||||
unsigned int new_flags;
|
||||
int err = 0;
|
||||
|
||||
new_flags = igc_tsn_new_flags(adapter);
|
||||
|
||||
if (!(new_flags & IGC_FLAG_TSN_ANY_ENABLED))
|
||||
return igc_tsn_disable_offload(adapter);
|
||||
|
||||
err = igc_tsn_enable_offload(adapter);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
adapter->flags = new_flags;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int igc_tsn_offload_apply(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
|
||||
/* Per I225/6 HW Design Section 7.5.2.1, transmit mode
|
||||
* cannot be changed dynamically. Require reset the adapter.
|
||||
*/
|
||||
if (netif_running(adapter->netdev) &&
|
||||
(igc_is_device_id_i225(hw) || !adapter->qbv_count)) {
|
||||
schedule_work(&adapter->reset_task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
igc_tsn_reset(adapter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2020 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_TSN_H_
|
||||
#define _IGC_TSN_H_
|
||||
|
||||
int igc_tsn_offload_apply(struct igc_adapter *adapter);
|
||||
int igc_tsn_reset(struct igc_adapter *adapter);
|
||||
void igc_tsn_adjust_txtime_offset(struct igc_adapter *adapter);
|
||||
|
||||
#endif /* _IGC_BASE_H */
|
||||
|
|
@ -0,0 +1,350 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2019 Intel Corporation */
|
||||
|
||||
#include "igc.h"
|
||||
#include "igc_hw.h"
|
||||
#include "igc_tsn.h"
|
||||
|
||||
static bool is_any_launchtime(struct igc_adapter *adapter)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
struct igc_ring *ring = adapter->tx_ring[i];
|
||||
|
||||
if (ring->launchtime_enable)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_cbs_enabled(struct igc_adapter *adapter)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
struct igc_ring *ring = adapter->tx_ring[i];
|
||||
|
||||
if (ring->cbs_enable)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsigned int igc_tsn_new_flags(struct igc_adapter *adapter)
|
||||
{
|
||||
unsigned int new_flags = adapter->flags & ~IGC_FLAG_TSN_ANY_ENABLED;
|
||||
|
||||
if (adapter->taprio_offload_enable)
|
||||
new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
|
||||
|
||||
if (is_any_launchtime(adapter))
|
||||
new_flags |= IGC_FLAG_TSN_QBV_ENABLED;
|
||||
|
||||
if (is_cbs_enabled(adapter))
|
||||
new_flags |= IGC_FLAG_TSN_QAV_ENABLED;
|
||||
|
||||
return new_flags;
|
||||
}
|
||||
|
||||
void igc_tsn_adjust_txtime_offset(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u16 txoffset;
|
||||
|
||||
if (!is_any_launchtime(adapter))
|
||||
return;
|
||||
|
||||
switch (adapter->link_speed) {
|
||||
case SPEED_10:
|
||||
txoffset = IGC_TXOFFSET_SPEED_10;
|
||||
break;
|
||||
case SPEED_100:
|
||||
txoffset = IGC_TXOFFSET_SPEED_100;
|
||||
break;
|
||||
case SPEED_1000:
|
||||
txoffset = IGC_TXOFFSET_SPEED_1000;
|
||||
break;
|
||||
case SPEED_2500:
|
||||
txoffset = IGC_TXOFFSET_SPEED_2500;
|
||||
break;
|
||||
default:
|
||||
txoffset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
wr32(IGC_GTXOFFSET, txoffset);
|
||||
}
|
||||
|
||||
/* Returns the TSN specific registers to their default values after
|
||||
* the adapter is reset.
|
||||
*/
|
||||
static int igc_tsn_disable_offload(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 tqavctrl;
|
||||
int i;
|
||||
|
||||
wr32(IGC_GTXOFFSET, 0);
|
||||
wr32(IGC_TXPBS, I225_TXPBSIZE_DEFAULT);
|
||||
wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_DEFAULT);
|
||||
|
||||
tqavctrl = rd32(IGC_TQAVCTRL);
|
||||
tqavctrl &= ~(IGC_TQAVCTRL_TRANSMIT_MODE_TSN |
|
||||
IGC_TQAVCTRL_ENHANCED_QAV | IGC_TQAVCTRL_FUTSCDDIS);
|
||||
|
||||
wr32(IGC_TQAVCTRL, tqavctrl);
|
||||
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
wr32(IGC_TXQCTL(i), 0);
|
||||
wr32(IGC_STQT(i), 0);
|
||||
wr32(IGC_ENDQT(i), NSEC_PER_SEC);
|
||||
}
|
||||
|
||||
wr32(IGC_QBVCYCLET_S, 0);
|
||||
wr32(IGC_QBVCYCLET, NSEC_PER_SEC);
|
||||
|
||||
adapter->flags &= ~IGC_FLAG_TSN_QBV_ENABLED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igc_tsn_enable_offload(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 tqavctrl, baset_l, baset_h;
|
||||
u32 sec, nsec, cycle;
|
||||
ktime_t base_time, systim;
|
||||
int i;
|
||||
|
||||
wr32(IGC_TSAUXC, 0);
|
||||
wr32(IGC_DTXMXPKTSZ, IGC_DTXMXPKTSZ_TSN);
|
||||
wr32(IGC_TXPBS, IGC_TXPBSIZE_TSN);
|
||||
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
struct igc_ring *ring = adapter->tx_ring[i];
|
||||
u32 txqctl = 0;
|
||||
u16 cbs_value;
|
||||
u32 tqavcc;
|
||||
|
||||
wr32(IGC_STQT(i), ring->start_time);
|
||||
wr32(IGC_ENDQT(i), ring->end_time);
|
||||
|
||||
if (adapter->taprio_offload_enable) {
|
||||
/* If taprio_offload_enable is set we are in "taprio"
|
||||
* mode and we need to be strict about the
|
||||
* cycles: only transmit a packet if it can be
|
||||
* completed during that cycle.
|
||||
*
|
||||
* If taprio_offload_enable is NOT true when
|
||||
* enabling TSN offload, the cycle should have
|
||||
* no external effects, but is only used internally
|
||||
* to adapt the base time register after a second
|
||||
* has passed.
|
||||
*
|
||||
* Enabling strict mode in this case would
|
||||
* unnecessarily prevent the transmission of
|
||||
* certain packets (i.e. at the boundary of a
|
||||
* second) and thus interfere with the launchtime
|
||||
* feature that promises transmission at a
|
||||
* certain point in time.
|
||||
*/
|
||||
txqctl |= IGC_TXQCTL_STRICT_CYCLE |
|
||||
IGC_TXQCTL_STRICT_END;
|
||||
}
|
||||
|
||||
if (ring->launchtime_enable)
|
||||
txqctl |= IGC_TXQCTL_QUEUE_MODE_LAUNCHT;
|
||||
|
||||
/* Skip configuring CBS for Q2 and Q3 */
|
||||
if (i > 1)
|
||||
goto skip_cbs;
|
||||
|
||||
if (ring->cbs_enable) {
|
||||
if (i == 0)
|
||||
txqctl |= IGC_TXQCTL_QAV_SEL_CBS0;
|
||||
else
|
||||
txqctl |= IGC_TXQCTL_QAV_SEL_CBS1;
|
||||
|
||||
/* According to i225 datasheet section 7.5.2.7, we
|
||||
* should set the 'idleSlope' field from TQAVCC
|
||||
* register following the equation:
|
||||
*
|
||||
* value = link-speed 0x7736 * BW * 0.2
|
||||
* ---------- * ----------------- (E1)
|
||||
* 100Mbps 2.5
|
||||
*
|
||||
* Note that 'link-speed' is in Mbps.
|
||||
*
|
||||
* 'BW' is the percentage bandwidth out of full
|
||||
* link speed which can be found with the
|
||||
* following equation. Note that idleSlope here
|
||||
* is the parameter from this function
|
||||
* which is in kbps.
|
||||
*
|
||||
* BW = idleSlope
|
||||
* ----------------- (E2)
|
||||
* link-speed * 1000
|
||||
*
|
||||
* That said, we can come up with a generic
|
||||
* equation to calculate the value we should set
|
||||
* it TQAVCC register by replacing 'BW' in E1 by E2.
|
||||
* The resulting equation is:
|
||||
*
|
||||
* value = link-speed * 0x7736 * idleSlope * 0.2
|
||||
* ------------------------------------- (E3)
|
||||
* 100 * 2.5 * link-speed * 1000
|
||||
*
|
||||
* 'link-speed' is present in both sides of the
|
||||
* fraction so it is canceled out. The final
|
||||
* equation is the following:
|
||||
*
|
||||
* value = idleSlope * 61036
|
||||
* ----------------- (E4)
|
||||
* 2500000
|
||||
*
|
||||
* NOTE: For i225, given the above, we can see
|
||||
* that idleslope is represented in
|
||||
* 40.959433 kbps units by the value at
|
||||
* the TQAVCC register (2.5Gbps / 61036),
|
||||
* which reduces the granularity for
|
||||
* idleslope increments.
|
||||
*
|
||||
* In i225 controller, the sendSlope and loCredit
|
||||
* parameters from CBS are not configurable
|
||||
* by software so we don't do any
|
||||
* 'controller configuration' in respect to
|
||||
* these parameters.
|
||||
*/
|
||||
cbs_value = DIV_ROUND_UP_ULL(ring->idleslope
|
||||
* 61036ULL, 2500000);
|
||||
|
||||
tqavcc = rd32(IGC_TQAVCC(i));
|
||||
tqavcc &= ~IGC_TQAVCC_IDLESLOPE_MASK;
|
||||
tqavcc |= cbs_value | IGC_TQAVCC_KEEP_CREDITS;
|
||||
wr32(IGC_TQAVCC(i), tqavcc);
|
||||
|
||||
wr32(IGC_TQAVHC(i),
|
||||
0x80000000 + ring->hicredit * 0x7735);
|
||||
} else {
|
||||
/* Disable any CBS for the queue */
|
||||
txqctl &= ~(IGC_TXQCTL_QAV_SEL_MASK);
|
||||
|
||||
/* Set idleSlope to zero. */
|
||||
tqavcc = rd32(IGC_TQAVCC(i));
|
||||
tqavcc &= ~(IGC_TQAVCC_IDLESLOPE_MASK |
|
||||
IGC_TQAVCC_KEEP_CREDITS);
|
||||
wr32(IGC_TQAVCC(i), tqavcc);
|
||||
|
||||
/* Set hiCredit to zero. */
|
||||
wr32(IGC_TQAVHC(i), 0);
|
||||
}
|
||||
skip_cbs:
|
||||
wr32(IGC_TXQCTL(i), txqctl);
|
||||
}
|
||||
|
||||
tqavctrl = rd32(IGC_TQAVCTRL) & ~IGC_TQAVCTRL_FUTSCDDIS;
|
||||
|
||||
tqavctrl |= IGC_TQAVCTRL_TRANSMIT_MODE_TSN | IGC_TQAVCTRL_ENHANCED_QAV;
|
||||
|
||||
adapter->qbv_count++;
|
||||
|
||||
cycle = adapter->cycle_time;
|
||||
base_time = adapter->base_time;
|
||||
|
||||
nsec = rd32(IGC_SYSTIML);
|
||||
sec = rd32(IGC_SYSTIMH);
|
||||
|
||||
systim = ktime_set(sec, nsec);
|
||||
if (ktime_compare(systim, base_time) > 0) {
|
||||
s64 n = div64_s64(ktime_sub_ns(systim, base_time), cycle);
|
||||
|
||||
base_time = ktime_add_ns(base_time, (n + 1) * cycle);
|
||||
|
||||
/* Increase the counter if scheduling into the past while
|
||||
* Gate Control List (GCL) is running.
|
||||
*/
|
||||
if ((rd32(IGC_BASET_H) || rd32(IGC_BASET_L)) &&
|
||||
(adapter->tc_setup_type == TC_SETUP_QDISC_TAPRIO) &&
|
||||
(adapter->qbv_count > 1))
|
||||
adapter->qbv_config_change_errors++;
|
||||
} else {
|
||||
if (igc_is_device_id_i226(hw)) {
|
||||
ktime_t adjust_time, expires_time;
|
||||
|
||||
/* According to datasheet section 7.5.2.9.3.3, FutScdDis bit
|
||||
* has to be configured before the cycle time and base time.
|
||||
* Tx won't hang if a GCL is already running,
|
||||
* so in this case we don't need to set FutScdDis.
|
||||
*/
|
||||
if (!(rd32(IGC_BASET_H) || rd32(IGC_BASET_L)))
|
||||
tqavctrl |= IGC_TQAVCTRL_FUTSCDDIS;
|
||||
|
||||
nsec = rd32(IGC_SYSTIML);
|
||||
sec = rd32(IGC_SYSTIMH);
|
||||
systim = ktime_set(sec, nsec);
|
||||
|
||||
adjust_time = adapter->base_time;
|
||||
expires_time = ktime_sub_ns(adjust_time, systim);
|
||||
hrtimer_start(&adapter->hrtimer, expires_time, HRTIMER_MODE_REL);
|
||||
}
|
||||
}
|
||||
|
||||
wr32(IGC_TQAVCTRL, tqavctrl);
|
||||
|
||||
wr32(IGC_QBVCYCLET_S, cycle);
|
||||
wr32(IGC_QBVCYCLET, cycle);
|
||||
|
||||
baset_h = div_s64_rem(base_time, NSEC_PER_SEC, &baset_l);
|
||||
wr32(IGC_BASET_H, baset_h);
|
||||
|
||||
/* In i226, Future base time is only supported when FutScdDis bit
|
||||
* is enabled and only active for re-configuration.
|
||||
* In this case, initialize the base time with zero to create
|
||||
* "re-configuration" scenario then only set the desired base time.
|
||||
*/
|
||||
if (tqavctrl & IGC_TQAVCTRL_FUTSCDDIS)
|
||||
wr32(IGC_BASET_L, 0);
|
||||
wr32(IGC_BASET_L, baset_l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igc_tsn_reset(struct igc_adapter *adapter)
|
||||
{
|
||||
unsigned int new_flags;
|
||||
int err = 0;
|
||||
|
||||
new_flags = igc_tsn_new_flags(adapter);
|
||||
|
||||
if (!(new_flags & IGC_FLAG_TSN_ANY_ENABLED))
|
||||
return igc_tsn_disable_offload(adapter);
|
||||
|
||||
err = igc_tsn_enable_offload(adapter);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
adapter->flags = new_flags;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int igc_tsn_offload_apply(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
|
||||
/* Per I225/6 HW Design Section 7.5.2.1, transmit mode
|
||||
* cannot be changed dynamically. Require reset the adapter.
|
||||
*/
|
||||
if (netif_running(adapter->netdev) &&
|
||||
(igc_is_device_id_i225(hw) || !adapter->qbv_count)) {
|
||||
schedule_work(&adapter->reset_task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
igc_tsn_reset(adapter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2020 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_TSN_H_
|
||||
#define _IGC_TSN_H_
|
||||
|
||||
int igc_tsn_offload_apply(struct igc_adapter *adapter);
|
||||
int igc_tsn_reset(struct igc_adapter *adapter);
|
||||
void igc_tsn_adjust_txtime_offset(struct igc_adapter *adapter);
|
||||
|
||||
#endif /* _IGC_BASE_H */
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2020, Intel Corporation. */
|
||||
|
||||
#include <linux/if_vlan.h>
|
||||
#include <net/xdp_sock_drv.h>
|
||||
|
||||
#include "igc-6.4-ethercat.h"
|
||||
#include "igc_xdp-6.4-ethercat.h"
|
||||
|
||||
int igc_xdp_set_prog(struct igc_adapter *adapter, struct bpf_prog *prog,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct net_device *dev = adapter->netdev;
|
||||
bool if_running = netif_running(dev);
|
||||
struct bpf_prog *old_prog;
|
||||
|
||||
if (dev->mtu > ETH_DATA_LEN) {
|
||||
/* For now, the driver doesn't support XDP functionality with
|
||||
* jumbo frames so we return error.
|
||||
*/
|
||||
NL_SET_ERR_MSG_MOD(extack, "Jumbo frames not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (if_running)
|
||||
igc_close(dev);
|
||||
|
||||
old_prog = xchg(&adapter->xdp_prog, prog);
|
||||
if (old_prog)
|
||||
bpf_prog_put(old_prog);
|
||||
|
||||
if (prog)
|
||||
xdp_features_set_redirect_target(dev, true);
|
||||
else
|
||||
xdp_features_clear_redirect_target(dev);
|
||||
|
||||
if (if_running)
|
||||
igc_open(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igc_xdp_enable_pool(struct igc_adapter *adapter,
|
||||
struct xsk_buff_pool *pool, u16 queue_id)
|
||||
{
|
||||
struct net_device *ndev = adapter->netdev;
|
||||
struct device *dev = &adapter->pdev->dev;
|
||||
struct igc_ring *rx_ring, *tx_ring;
|
||||
struct napi_struct *napi;
|
||||
bool needs_reset;
|
||||
u32 frame_size;
|
||||
int err;
|
||||
|
||||
if (queue_id >= adapter->num_rx_queues ||
|
||||
queue_id >= adapter->num_tx_queues)
|
||||
return -EINVAL;
|
||||
|
||||
frame_size = xsk_pool_get_rx_frame_size(pool);
|
||||
if (frame_size < ETH_FRAME_LEN + VLAN_HLEN * 2) {
|
||||
/* When XDP is enabled, the driver doesn't support frames that
|
||||
* span over multiple buffers. To avoid that, we check if xsk
|
||||
* frame size is big enough to fit the max ethernet frame size
|
||||
* + vlan double tagging.
|
||||
*/
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
err = xsk_pool_dma_map(pool, dev, IGC_RX_DMA_ATTR);
|
||||
if (err) {
|
||||
netdev_err(ndev, "Failed to map xsk pool\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
needs_reset = netif_running(adapter->netdev) && igc_xdp_is_enabled(adapter);
|
||||
|
||||
rx_ring = adapter->rx_ring[queue_id];
|
||||
tx_ring = adapter->tx_ring[queue_id];
|
||||
/* Rx and Tx rings share the same napi context. */
|
||||
napi = &rx_ring->q_vector->napi;
|
||||
|
||||
if (needs_reset) {
|
||||
igc_disable_rx_ring(rx_ring);
|
||||
igc_disable_tx_ring(tx_ring);
|
||||
napi_disable(napi);
|
||||
}
|
||||
|
||||
set_bit(IGC_RING_FLAG_AF_XDP_ZC, &rx_ring->flags);
|
||||
set_bit(IGC_RING_FLAG_AF_XDP_ZC, &tx_ring->flags);
|
||||
|
||||
if (needs_reset) {
|
||||
napi_enable(napi);
|
||||
igc_enable_rx_ring(rx_ring);
|
||||
igc_enable_tx_ring(tx_ring);
|
||||
|
||||
err = igc_xsk_wakeup(ndev, queue_id, XDP_WAKEUP_RX);
|
||||
if (err) {
|
||||
xsk_pool_dma_unmap(pool, IGC_RX_DMA_ATTR);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igc_xdp_disable_pool(struct igc_adapter *adapter, u16 queue_id)
|
||||
{
|
||||
struct igc_ring *rx_ring, *tx_ring;
|
||||
struct xsk_buff_pool *pool;
|
||||
struct napi_struct *napi;
|
||||
bool needs_reset;
|
||||
|
||||
if (queue_id >= adapter->num_rx_queues ||
|
||||
queue_id >= adapter->num_tx_queues)
|
||||
return -EINVAL;
|
||||
|
||||
pool = xsk_get_pool_from_qid(adapter->netdev, queue_id);
|
||||
if (!pool)
|
||||
return -EINVAL;
|
||||
|
||||
needs_reset = netif_running(adapter->netdev) && igc_xdp_is_enabled(adapter);
|
||||
|
||||
rx_ring = adapter->rx_ring[queue_id];
|
||||
tx_ring = adapter->tx_ring[queue_id];
|
||||
/* Rx and Tx rings share the same napi context. */
|
||||
napi = &rx_ring->q_vector->napi;
|
||||
|
||||
if (needs_reset) {
|
||||
igc_disable_rx_ring(rx_ring);
|
||||
igc_disable_tx_ring(tx_ring);
|
||||
napi_disable(napi);
|
||||
}
|
||||
|
||||
xsk_pool_dma_unmap(pool, IGC_RX_DMA_ATTR);
|
||||
clear_bit(IGC_RING_FLAG_AF_XDP_ZC, &rx_ring->flags);
|
||||
clear_bit(IGC_RING_FLAG_AF_XDP_ZC, &tx_ring->flags);
|
||||
|
||||
if (needs_reset) {
|
||||
napi_enable(napi);
|
||||
igc_enable_rx_ring(rx_ring);
|
||||
igc_enable_tx_ring(tx_ring);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igc_xdp_setup_pool(struct igc_adapter *adapter, struct xsk_buff_pool *pool,
|
||||
u16 queue_id)
|
||||
{
|
||||
return pool ? igc_xdp_enable_pool(adapter, pool, queue_id) :
|
||||
igc_xdp_disable_pool(adapter, queue_id);
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2020, Intel Corporation. */
|
||||
|
||||
#ifndef _IGC_XDP_H_
|
||||
#define _IGC_XDP_H_
|
||||
|
||||
int igc_xdp_set_prog(struct igc_adapter *adapter, struct bpf_prog *prog,
|
||||
struct netlink_ext_ack *extack);
|
||||
int igc_xdp_setup_pool(struct igc_adapter *adapter, struct xsk_buff_pool *pool,
|
||||
u16 queue_id);
|
||||
|
||||
static inline bool igc_xdp_is_enabled(struct igc_adapter *adapter)
|
||||
{
|
||||
return !!adapter->xdp_prog;
|
||||
}
|
||||
|
||||
#endif /* _IGC_XDP_H_ */
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2020, Intel Corporation. */
|
||||
|
||||
#include <linux/if_vlan.h>
|
||||
#include <net/xdp_sock_drv.h>
|
||||
|
||||
#include "igc.h"
|
||||
#include "igc_xdp.h"
|
||||
|
||||
int igc_xdp_set_prog(struct igc_adapter *adapter, struct bpf_prog *prog,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct net_device *dev = adapter->netdev;
|
||||
bool if_running = netif_running(dev);
|
||||
struct bpf_prog *old_prog;
|
||||
|
||||
if (dev->mtu > ETH_DATA_LEN) {
|
||||
/* For now, the driver doesn't support XDP functionality with
|
||||
* jumbo frames so we return error.
|
||||
*/
|
||||
NL_SET_ERR_MSG_MOD(extack, "Jumbo frames not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (if_running)
|
||||
igc_close(dev);
|
||||
|
||||
old_prog = xchg(&adapter->xdp_prog, prog);
|
||||
if (old_prog)
|
||||
bpf_prog_put(old_prog);
|
||||
|
||||
if (prog)
|
||||
xdp_features_set_redirect_target(dev, true);
|
||||
else
|
||||
xdp_features_clear_redirect_target(dev);
|
||||
|
||||
if (if_running)
|
||||
igc_open(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igc_xdp_enable_pool(struct igc_adapter *adapter,
|
||||
struct xsk_buff_pool *pool, u16 queue_id)
|
||||
{
|
||||
struct net_device *ndev = adapter->netdev;
|
||||
struct device *dev = &adapter->pdev->dev;
|
||||
struct igc_ring *rx_ring, *tx_ring;
|
||||
struct napi_struct *napi;
|
||||
bool needs_reset;
|
||||
u32 frame_size;
|
||||
int err;
|
||||
|
||||
if (queue_id >= adapter->num_rx_queues ||
|
||||
queue_id >= adapter->num_tx_queues)
|
||||
return -EINVAL;
|
||||
|
||||
frame_size = xsk_pool_get_rx_frame_size(pool);
|
||||
if (frame_size < ETH_FRAME_LEN + VLAN_HLEN * 2) {
|
||||
/* When XDP is enabled, the driver doesn't support frames that
|
||||
* span over multiple buffers. To avoid that, we check if xsk
|
||||
* frame size is big enough to fit the max ethernet frame size
|
||||
* + vlan double tagging.
|
||||
*/
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
err = xsk_pool_dma_map(pool, dev, IGC_RX_DMA_ATTR);
|
||||
if (err) {
|
||||
netdev_err(ndev, "Failed to map xsk pool\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
needs_reset = netif_running(adapter->netdev) && igc_xdp_is_enabled(adapter);
|
||||
|
||||
rx_ring = adapter->rx_ring[queue_id];
|
||||
tx_ring = adapter->tx_ring[queue_id];
|
||||
/* Rx and Tx rings share the same napi context. */
|
||||
napi = &rx_ring->q_vector->napi;
|
||||
|
||||
if (needs_reset) {
|
||||
igc_disable_rx_ring(rx_ring);
|
||||
igc_disable_tx_ring(tx_ring);
|
||||
napi_disable(napi);
|
||||
}
|
||||
|
||||
set_bit(IGC_RING_FLAG_AF_XDP_ZC, &rx_ring->flags);
|
||||
set_bit(IGC_RING_FLAG_AF_XDP_ZC, &tx_ring->flags);
|
||||
|
||||
if (needs_reset) {
|
||||
napi_enable(napi);
|
||||
igc_enable_rx_ring(rx_ring);
|
||||
igc_enable_tx_ring(tx_ring);
|
||||
|
||||
err = igc_xsk_wakeup(ndev, queue_id, XDP_WAKEUP_RX);
|
||||
if (err) {
|
||||
xsk_pool_dma_unmap(pool, IGC_RX_DMA_ATTR);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igc_xdp_disable_pool(struct igc_adapter *adapter, u16 queue_id)
|
||||
{
|
||||
struct igc_ring *rx_ring, *tx_ring;
|
||||
struct xsk_buff_pool *pool;
|
||||
struct napi_struct *napi;
|
||||
bool needs_reset;
|
||||
|
||||
if (queue_id >= adapter->num_rx_queues ||
|
||||
queue_id >= adapter->num_tx_queues)
|
||||
return -EINVAL;
|
||||
|
||||
pool = xsk_get_pool_from_qid(adapter->netdev, queue_id);
|
||||
if (!pool)
|
||||
return -EINVAL;
|
||||
|
||||
needs_reset = netif_running(adapter->netdev) && igc_xdp_is_enabled(adapter);
|
||||
|
||||
rx_ring = adapter->rx_ring[queue_id];
|
||||
tx_ring = adapter->tx_ring[queue_id];
|
||||
/* Rx and Tx rings share the same napi context. */
|
||||
napi = &rx_ring->q_vector->napi;
|
||||
|
||||
if (needs_reset) {
|
||||
igc_disable_rx_ring(rx_ring);
|
||||
igc_disable_tx_ring(tx_ring);
|
||||
napi_disable(napi);
|
||||
}
|
||||
|
||||
xsk_pool_dma_unmap(pool, IGC_RX_DMA_ATTR);
|
||||
clear_bit(IGC_RING_FLAG_AF_XDP_ZC, &rx_ring->flags);
|
||||
clear_bit(IGC_RING_FLAG_AF_XDP_ZC, &tx_ring->flags);
|
||||
|
||||
if (needs_reset) {
|
||||
napi_enable(napi);
|
||||
igc_enable_rx_ring(rx_ring);
|
||||
igc_enable_tx_ring(tx_ring);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igc_xdp_setup_pool(struct igc_adapter *adapter, struct xsk_buff_pool *pool,
|
||||
u16 queue_id)
|
||||
{
|
||||
return pool ? igc_xdp_enable_pool(adapter, pool, queue_id) :
|
||||
igc_xdp_disable_pool(adapter, queue_id);
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2020, Intel Corporation. */
|
||||
|
||||
#ifndef _IGC_XDP_H_
|
||||
#define _IGC_XDP_H_
|
||||
|
||||
int igc_xdp_set_prog(struct igc_adapter *adapter, struct bpf_prog *prog,
|
||||
struct netlink_ext_ack *extack);
|
||||
int igc_xdp_setup_pool(struct igc_adapter *adapter, struct xsk_buff_pool *pool,
|
||||
u16 queue_id);
|
||||
|
||||
static inline bool igc_xdp_is_enabled(struct igc_adapter *adapter)
|
||||
{
|
||||
return !!adapter->xdp_prog;
|
||||
}
|
||||
|
||||
#endif /* _IGC_XDP_H_ */
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2020, Intel Corporation. */
|
||||
|
||||
#include <linux/if_vlan.h>
|
||||
#include <net/xdp_sock_drv.h>
|
||||
|
||||
#include "igc-6.6-ethercat.h"
|
||||
#include "igc_xdp-6.6-ethercat.h"
|
||||
|
||||
int igc_xdp_set_prog(struct igc_adapter *adapter, struct bpf_prog *prog,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct net_device *dev = adapter->netdev;
|
||||
bool if_running = netif_running(dev);
|
||||
struct bpf_prog *old_prog;
|
||||
|
||||
if (dev->mtu > ETH_DATA_LEN) {
|
||||
/* For now, the driver doesn't support XDP functionality with
|
||||
* jumbo frames so we return error.
|
||||
*/
|
||||
NL_SET_ERR_MSG_MOD(extack, "Jumbo frames not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (if_running)
|
||||
igc_close(dev);
|
||||
|
||||
old_prog = xchg(&adapter->xdp_prog, prog);
|
||||
if (old_prog)
|
||||
bpf_prog_put(old_prog);
|
||||
|
||||
if (prog)
|
||||
xdp_features_set_redirect_target(dev, true);
|
||||
else
|
||||
xdp_features_clear_redirect_target(dev);
|
||||
|
||||
if (if_running)
|
||||
igc_open(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igc_xdp_enable_pool(struct igc_adapter *adapter,
|
||||
struct xsk_buff_pool *pool, u16 queue_id)
|
||||
{
|
||||
struct net_device *ndev = adapter->netdev;
|
||||
struct device *dev = &adapter->pdev->dev;
|
||||
struct igc_ring *rx_ring, *tx_ring;
|
||||
struct napi_struct *napi;
|
||||
bool needs_reset;
|
||||
u32 frame_size;
|
||||
int err;
|
||||
|
||||
if (queue_id >= adapter->num_rx_queues ||
|
||||
queue_id >= adapter->num_tx_queues)
|
||||
return -EINVAL;
|
||||
|
||||
frame_size = xsk_pool_get_rx_frame_size(pool);
|
||||
if (frame_size < ETH_FRAME_LEN + VLAN_HLEN * 2) {
|
||||
/* When XDP is enabled, the driver doesn't support frames that
|
||||
* span over multiple buffers. To avoid that, we check if xsk
|
||||
* frame size is big enough to fit the max ethernet frame size
|
||||
* + vlan double tagging.
|
||||
*/
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
err = xsk_pool_dma_map(pool, dev, IGC_RX_DMA_ATTR);
|
||||
if (err) {
|
||||
netdev_err(ndev, "Failed to map xsk pool\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
needs_reset = netif_running(adapter->netdev) && igc_xdp_is_enabled(adapter);
|
||||
|
||||
rx_ring = adapter->rx_ring[queue_id];
|
||||
tx_ring = adapter->tx_ring[queue_id];
|
||||
/* Rx and Tx rings share the same napi context. */
|
||||
napi = &rx_ring->q_vector->napi;
|
||||
|
||||
if (needs_reset) {
|
||||
igc_disable_rx_ring(rx_ring);
|
||||
igc_disable_tx_ring(tx_ring);
|
||||
napi_disable(napi);
|
||||
}
|
||||
|
||||
set_bit(IGC_RING_FLAG_AF_XDP_ZC, &rx_ring->flags);
|
||||
set_bit(IGC_RING_FLAG_AF_XDP_ZC, &tx_ring->flags);
|
||||
|
||||
if (needs_reset) {
|
||||
napi_enable(napi);
|
||||
igc_enable_rx_ring(rx_ring);
|
||||
igc_enable_tx_ring(tx_ring);
|
||||
|
||||
err = igc_xsk_wakeup(ndev, queue_id, XDP_WAKEUP_RX);
|
||||
if (err) {
|
||||
xsk_pool_dma_unmap(pool, IGC_RX_DMA_ATTR);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igc_xdp_disable_pool(struct igc_adapter *adapter, u16 queue_id)
|
||||
{
|
||||
struct igc_ring *rx_ring, *tx_ring;
|
||||
struct xsk_buff_pool *pool;
|
||||
struct napi_struct *napi;
|
||||
bool needs_reset;
|
||||
|
||||
if (queue_id >= adapter->num_rx_queues ||
|
||||
queue_id >= adapter->num_tx_queues)
|
||||
return -EINVAL;
|
||||
|
||||
pool = xsk_get_pool_from_qid(adapter->netdev, queue_id);
|
||||
if (!pool)
|
||||
return -EINVAL;
|
||||
|
||||
needs_reset = netif_running(adapter->netdev) && igc_xdp_is_enabled(adapter);
|
||||
|
||||
rx_ring = adapter->rx_ring[queue_id];
|
||||
tx_ring = adapter->tx_ring[queue_id];
|
||||
/* Rx and Tx rings share the same napi context. */
|
||||
napi = &rx_ring->q_vector->napi;
|
||||
|
||||
if (needs_reset) {
|
||||
igc_disable_rx_ring(rx_ring);
|
||||
igc_disable_tx_ring(tx_ring);
|
||||
napi_disable(napi);
|
||||
}
|
||||
|
||||
xsk_pool_dma_unmap(pool, IGC_RX_DMA_ATTR);
|
||||
clear_bit(IGC_RING_FLAG_AF_XDP_ZC, &rx_ring->flags);
|
||||
clear_bit(IGC_RING_FLAG_AF_XDP_ZC, &tx_ring->flags);
|
||||
|
||||
if (needs_reset) {
|
||||
napi_enable(napi);
|
||||
igc_enable_rx_ring(rx_ring);
|
||||
igc_enable_tx_ring(tx_ring);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igc_xdp_setup_pool(struct igc_adapter *adapter, struct xsk_buff_pool *pool,
|
||||
u16 queue_id)
|
||||
{
|
||||
return pool ? igc_xdp_enable_pool(adapter, pool, queue_id) :
|
||||
igc_xdp_disable_pool(adapter, queue_id);
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2020, Intel Corporation. */
|
||||
|
||||
#ifndef _IGC_XDP_H_
|
||||
#define _IGC_XDP_H_
|
||||
|
||||
int igc_xdp_set_prog(struct igc_adapter *adapter, struct bpf_prog *prog,
|
||||
struct netlink_ext_ack *extack);
|
||||
int igc_xdp_setup_pool(struct igc_adapter *adapter, struct xsk_buff_pool *pool,
|
||||
u16 queue_id);
|
||||
|
||||
static inline bool igc_xdp_is_enabled(struct igc_adapter *adapter)
|
||||
{
|
||||
return !!adapter->xdp_prog;
|
||||
}
|
||||
|
||||
#endif /* _IGC_XDP_H_ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue