aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Joyner <erj@FreeBSD.org>2018-10-12 22:40:54 +0000
committerEric Joyner <erj@FreeBSD.org>2018-10-12 22:40:54 +0000
commit77c1fcec914bae1232762ca0b0462abd6957ff26 (patch)
tree4020a4c92e52f202fe6b8513fd8c95f59db9a225
parent3cf1291d2e64aa741ae520363f8710f2c1e80127 (diff)
downloadsrc-77c1fcec914bae1232762ca0b0462abd6957ff26.tar.gz
src-77c1fcec914bae1232762ca0b0462abd6957ff26.zip
ixl/iavf(4): Change ixlv to iavf and update it to use iflib(9)
Finishes the conversion of the 40Gb Intel Ethernet drivers to iflib(9) for FreeBSD 12.0, and fixes numerous bugs in both ixl(4) and iavf(4). This commit also re-adds the VF driver to GENERIC since it now compiles and functions. The VF driver name was changed from ixlv(4) to iavf(4) because the VF driver is now intended to be used with future products, not just with Fortville/Fort Park VFs. A man page update that documents these drivers is forthcoming in a separate commit. Reviewed by: sbruno@, kbowling@ Tested by: jeffrey.e.pieper@intel.com Approved by: re (gjb@) Relnotes: yes Sponsored by: Intel Corporation Differential Revision: https://reviews.freebsd.org/D16429
Notes
Notes: svn path=/head/; revision=339338
-rw-r--r--sys/amd64/conf/GENERIC5
-rw-r--r--sys/amd64/conf/NOTES7
-rw-r--r--sys/conf/files.amd6424
-rw-r--r--sys/dev/ixl/README410
-rw-r--r--sys/dev/ixl/i40e_osdep.c34
-rw-r--r--sys/dev/ixl/if_ixl.c216
-rw-r--r--sys/dev/ixl/if_ixlv.c2862
-rw-r--r--sys/dev/ixl/ixl.h38
-rw-r--r--sys/dev/ixl/ixl_debug.h23
-rw-r--r--sys/dev/ixl/ixl_pf.h39
-rw-r--r--sys/dev/ixl/ixl_pf_iov.c195
-rw-r--r--sys/dev/ixl/ixl_pf_iov.h12
-rw-r--r--sys/dev/ixl/ixl_pf_main.c554
-rw-r--r--sys/dev/ixl/ixl_pf_qmgr.c20
-rw-r--r--sys/dev/ixl/ixl_pf_qmgr.h16
-rw-r--r--sys/dev/ixl/ixl_txrx.c249
-rw-r--r--sys/dev/ixl/ixlv.h151
-rw-r--r--sys/dev/ixl/ixlv_vc_mgr.h76
-rw-r--r--sys/dev/ixl/ixlvc.c614
-rw-r--r--sys/modules/Makefile3
-rw-r--r--sys/modules/iavf/Makefile (renamed from sys/modules/ixlv/Makefile)6
-rw-r--r--sys/modules/ixl/Makefile10
-rw-r--r--sys/net/iflib.c124
-rw-r--r--sys/net/iflib.h4
-rw-r--r--sys/net/iflib_private.h1
25 files changed, 2158 insertions, 3535 deletions
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC
index da3d200fcec7..32b6db7dec61 100644
--- a/sys/amd64/conf/GENERIC
+++ b/sys/amd64/conf/GENERIC
@@ -240,9 +240,8 @@ device de # DEC/Intel DC21x4x (``Tulip'')
device em # Intel PRO/1000 Gigabit Ethernet Family
device ix # Intel PRO/10GbE PCIE PF Ethernet
device ixv # Intel PRO/10GbE PCIE VF Ethernet
-device ixl # Intel XL710 40Gbe PCIE Ethernet
-#options IXL_IW # Enable iWARP Client Interface in ixl(4)
-#device ixlv # Intel XL710 40Gbe VF PCIE Ethernet
+device ixl # Intel 700 Series Physical Function
+device iavf # Intel Adaptive Virtual Function
device le # AMD Am7900 LANCE and Am79C9xx PCnet
device ti # Alteon Networks Tigon I/II gigabit Ethernet
device txp # 3Com 3cR990 (``Typhoon'')
diff --git a/sys/amd64/conf/NOTES b/sys/amd64/conf/NOTES
index e11120fbdd58..c56b13592a8a 100644
--- a/sys/amd64/conf/NOTES
+++ b/sys/amd64/conf/NOTES
@@ -313,8 +313,6 @@ options DRM_DEBUG # Include debug printfs (slow)
# iwn: Intel Wireless WiFi Link 1000/105/135/2000/4965/5000/6000/6050 abgn
# 802.11 network adapters
# Requires the iwn firmware module
-# ixl: Intel XL710 40Gbe PCIE Ethernet
-# ixlv: Intel XL710 40Gbe VF PCIE Ethernet
# mthca: Mellanox HCA InfiniBand
# mlx4ib: Mellanox ConnectX HCA InfiniBand
# mlx4en: Mellanox ConnectX HCA Ethernet
@@ -332,9 +330,8 @@ options ED_SIC
device ipw # Intel 2100 wireless NICs.
device iwi # Intel 2200BG/2225BG/2915ABG wireless NICs.
device iwn # Intel 4965/1000/5000/6000 wireless NICs.
-device ixl # Intel XL710 40Gbe PCIE Ethernet
-#options IXL_IW # Enable iWARP Client Interface in ixl(4)
-#device ixlv # Intel XL710 40Gbe VF PCIE Ethernet
+device ixl # Intel 700 Series Physical Function
+device iavf # Intel Adaptive Virtual Function
device mthca # Mellanox HCA InfiniBand
device mlx4 # Shared code module between IB and Ethernet
device mlx4ib # Mellanox ConnectX HCA InfiniBand
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
index 0407dd30c7f1..3d0c60487b66 100644
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -271,25 +271,23 @@ dev/ixl/ixl_pf_iov.c optional ixl pci pci_iov \
compile-with "${NORMAL_C} -I$S/dev/ixl"
dev/ixl/ixl_pf_i2c.c optional ixl pci \
compile-with "${NORMAL_C} -I$S/dev/ixl"
-#dev/ixl/ixl_iw.c optional ixl pci \
-# compile-with "${NORMAL_C} -I$S/dev/ixl"
-#dev/ixl/if_ixlv.c optional ixlv pci \
-# compile-with "${NORMAL_C} -I$S/dev/ixl"
-#dev/ixl/ixlvc.c optional ixlv pci \
-# compile-with "${NORMAL_C} -I$S/dev/ixl"
-dev/ixl/ixl_txrx.c optional ixl pci | ixlv pci \
+dev/ixl/if_ixlv.c optional iavf pci \
compile-with "${NORMAL_C} -I$S/dev/ixl"
-dev/ixl/i40e_osdep.c optional ixl pci | ixlv pci \
+dev/ixl/ixlvc.c optional iavf pci \
compile-with "${NORMAL_C} -I$S/dev/ixl"
-dev/ixl/i40e_lan_hmc.c optional ixl pci | ixlv pci \
+dev/ixl/ixl_txrx.c optional ixl pci | iavf pci \
compile-with "${NORMAL_C} -I$S/dev/ixl"
-dev/ixl/i40e_hmc.c optional ixl pci | ixlv pci \
+dev/ixl/i40e_osdep.c optional ixl pci | iavf pci \
compile-with "${NORMAL_C} -I$S/dev/ixl"
-dev/ixl/i40e_common.c optional ixl pci | ixlv pci \
+dev/ixl/i40e_lan_hmc.c optional ixl pci | iavf pci \
compile-with "${NORMAL_C} -I$S/dev/ixl"
-dev/ixl/i40e_nvm.c optional ixl pci | ixlv pci \
+dev/ixl/i40e_hmc.c optional ixl pci | iavf pci \
compile-with "${NORMAL_C} -I$S/dev/ixl"
-dev/ixl/i40e_adminq.c optional ixl pci | ixlv pci \
+dev/ixl/i40e_common.c optional ixl pci | iavf pci \
+ compile-with "${NORMAL_C} -I$S/dev/ixl"
+dev/ixl/i40e_nvm.c optional ixl pci | iavf pci \
+ compile-with "${NORMAL_C} -I$S/dev/ixl"
+dev/ixl/i40e_adminq.c optional ixl pci | iavf pci \
compile-with "${NORMAL_C} -I$S/dev/ixl"
dev/ixl/i40e_dcb.c optional ixl pci \
compile-with "${NORMAL_C} -I$S/dev/ixl"
diff --git a/sys/dev/ixl/README b/sys/dev/ixl/README
deleted file mode 100644
index dc0149ce623f..000000000000
--- a/sys/dev/ixl/README
+++ /dev/null
@@ -1,410 +0,0 @@
- ixl FreeBSD* Base Driver and ixlv VF Driver for the
- Intel XL710 Ethernet Controller Family
-
-/*$FreeBSD$*/
-================================================================
-
-August 26, 2014
-
-
-Contents
-========
-
-- Overview
-- Supported Adapters
-- The VF Driver
-- Building and Installation
-- Additional Configurations
-- Known Limitations
-
-
-Overview
-========
-
-This file describes the IXL FreeBSD* Base driver and the IXLV VF Driver
-for the XL710 Ethernet Family of Adapters. The Driver has been developed
-for use with FreeBSD 10.0 or later, but should be compatible with any
-supported release.
-
-For questions related to hardware requirements, refer to the documentation
-supplied with your Intel XL710 adapter. All hardware requirements listed
-apply for use with FreeBSD.
-
-
-Supported Adapters
-==================
-
-The drivers in this release are compatible with XL710 and X710-based
-Intel Ethernet Network Connections.
-
-
-SFP+ Devices with Pluggable Optics
-----------------------------------
-
-SR Modules
-----------
- Intel DUAL RATE 1G/10G SFP+ SR (bailed) FTLX8571D3BCV-IT
- Intel DUAL RATE 1G/10G SFP+ SR (bailed) AFBR-703SDZ-IN2
-
-LR Modules
-----------
- Intel DUAL RATE 1G/10G SFP+ LR (bailed) FTLX1471D3BCV-IT
- Intel DUAL RATE 1G/10G SFP+ LR (bailed) AFCT-701SDZ-IN2
-
-QSFP+ Modules
--------------
- Intel TRIPLE RATE 1G/10G/40G QSFP+ SR (bailed) E40GQSFPSR
- Intel TRIPLE RATE 1G/10G/40G QSFP+ LR (bailed) E40GQSFPLR
- QSFP+ 1G speed is not supported on XL710 based devices.
-
-X710/XL710 Based SFP+ adapters support all passive and active limiting direct
-attach cables that comply with SFF-8431 v4.1 and SFF-8472 v10.4 specifications.
-
-The VF Driver
-==================
-The VF driver is normally used in a virtualized environment where a host
-driver manages SRIOV, and provides a VF device to the guest. With this
-first release the only host environment tested was using Linux QEMU/KVM.
-Support is planned for Xen and VMWare hosts at a later time.
-
-In the FreeBSD guest the IXLV driver would be loaded and will function
-using the VF device assigned to it.
-
-The VF driver provides most of the same functionality as the CORE driver,
-but is actually a slave to the Host, access to many controls are actually
-accomplished by a request to the Host via what is called the "Admin queue".
-These are startup and initialization events however, once in operation
-the device is self-contained and should achieve near native performance.
-
-Some notable limitations of the VF environment: for security reasons
-the driver is never permitted to be promiscuous, therefore a tcpdump
-will not behave the same with the interface. Second, media info is not
-available from the PF, so it will always appear as auto.
-
-Tarball Building and Installation
-=========================
-
-NOTE: You must have kernel sources installed to compile the driver tarball.
-
-These instructions assume a standalone driver tarball, building the driver
-already in the kernel source is simply a matter of adding the device entry
-to the kernel config file, or building in the ixl or ixlv module directory.
-
-In the instructions below, x.x.x is the driver version
-as indicated in the name of the driver tarball. The example is
-for ixl, the same procedure applies for ixlv.
-
-1. Move the base driver tar file to the directory of your choice.
- For example, use /home/username/ixl or /usr/local/src/ixl.
-
-2. Untar/unzip the archive:
- tar xfz ixl-x.x.x.tar.gz
-
-3. To install man page:
- cd ixl-x.x.x
- gzip -c ixl.4 > /usr/share/man/man4/ixl.4.gz
-
-4. To load the driver onto a running system:
- cd ixl-x.x.x/src
- make load
-
-5. To assign an IP address to the interface, enter the following:
- ifconfig ixl<interface_num> <IP_address>
-
-6. Verify that the interface works. Enter the following, where <IP_address>
- is the IP address for another machine on the same subnet as the interface
- that is being tested:
-
- ping <IP_address>
-
-7. If you want the driver to load automatically when the system is booted:
-
- cd ixl-x.x.x/src
- make
- make install
-
- Edit /boot/loader.conf, and add the following line:
- if_ixl_load="YES"
-
- Edit /etc/rc.conf, and create the appropriate
- ifconfig_ixl<interface_num> entry:
-
- ifconfig_ixl<interface_num>="<ifconfig_settings>"
-
- Example usage:
-
- ifconfig_ixl0="inet 192.168.10.1 netmask 255.255.255.0"
-
- NOTE: For assistance, see the ifconfig man page.
-
-
-
-Configuration and Tuning
-=========================
-
-Both drivers supports Transmit/Receive Checksum Offload for IPv4 and IPv6,
-TSO forIPv4 and IPv6, LRO, and Jumbo Frames on all 40 Gigabit adapters.
-
- Jumbo Frames
- ------------
- To enable Jumbo Frames, use the ifconfig utility to increase
- the MTU beyond 1500 bytes.
-
- - The Jumbo Frames setting on the switch must be set to at least
- 22 byteslarger than that of the adapter.
-
- - The maximum MTU setting for Jumbo Frames is 9706. This value
- coincides with the maximum jumbo frames size of 9728.
- To modify the setting, enter the following:
-
- ifconfig ixl<interface_num> <hostname or IP address> mtu 9000
-
- - To confirm an interface's MTU value, use the ifconfig command.
- To confirm the MTU used between two specific devices, use:
-
- route get <destination_IP_address>
-
- VLANs
- -----
- To create a new VLAN pseudo-interface:
-
- ifconfig <vlan_name> create
-
- To associate the VLAN pseudo-interface with a physical interface
- and assign a VLAN ID, IP address, and netmask:
-
- ifconfig <vlan_name> <ip_address> netmask <subnet_mask> vlan
- <vlan_id> vlandev <physical_interface>
-
- Example:
-
- ifconfig vlan10 10.0.0.1 netmask 255.255.255.0 vlan 10 vlandev ixl0
-
- In this example, all packets will be marked on egress with
- 802.1Q VLAN tags, specifying a VLAN ID of 10.
-
- To remove a VLAN pseudo-interface:
-
- ifconfig <vlan_name> destroy
-
-
- Checksum Offload
- ----------------
-
- Checksum offloading supports IPv4 and IPv6 with TCP and UDP packets
- and is supported for both transmit and receive. Checksum offloading
- for transmit and recieve is enabled by default for both IPv4 and IPv6.
-
- Checksum offloading can be enabled or disabled using ifconfig.
- Transmit and receive offloading for IPv4 and Ipv6 are enabled
- and disabled seperately.
-
- NOTE: TSO requires Tx checksum, so when Tx checksum
- is disabled, TSO will also be disabled.
-
- To enable Tx checksum offloading for ipv4:
-
- ifconfig ixl<interface_num> txcsum4
-
- To disable Tx checksum offloading for ipv4:
-
- ifconfig ixl<interface_num> -txcsum4
- (NOTE: This will disable TSO4)
-
- To enable Rx checksum offloading for ipv6:
-
- ifconfig ixl<interface_num> rxcsum6
-
- To disable Rx checksum offloading for ipv6:
-
- ifconfig ixl<interface_num> -rxcsum6
- (NOTE: This will disable TSO6)
-
-
- To confirm the current settings:
-
- ifconfig ixl<interface_num>
-
-
- TSO
- ---
-
- TSO supports both IPv4 and IPv6 and is enabled by default. TSO can
- be disabled and enabled using the ifconfig utility.
-
- NOTE: TSO requires Tx checksum, so when Tx checksum is
- disabled, TSO will also be disabled.
-
- To disable TSO IPv4:
-
- ifconfig ixl<interface_num> -tso4
-
- To enable TSO IPv4:
-
- ifconfig ixl<interface_num> tso4
-
- To disable TSO IPv6:
-
- ifconfig ixl<interface_num> -tso6
-
- To enable TSO IPv6:
-
- ifconfig ixl<interface_num> tso6
-
- To disable BOTH TSO IPv4 and IPv6:
-
- ifconfig ixl<interface_num> -tso
-
- To enable BOTH TSO IPv4 and IPv6:
-
- ifconfig ixl<interface_num> tso
-
-
- LRO
- ---
-
- Large Receive Offload is enabled by default. It can be enabled
- or disabled by using the ifconfig utility.
-
- NOTE: LRO should be disabled when forwarding packets.
-
- To disable LRO:
-
- ifconfig ixl<interface_num> -lro
-
- To enable LRO:
-
- ifconfig ixl<interface_num> lro
-
-
-Flow Control (IXL only)
-------------
-Flow control is disabled by default. To change flow control settings use sysctl.
-
-To enable flow control to Rx pause frames:
-
- sysctl dev.ixl.<interface_num>.fc=1
-
-To enable flow control to Tx pause frames:
-
- sysctl dev.ixl.<interface_num>.fc=2
-
-To enable flow control to Rx and Tx pause frames:
-
- sysctl dev.ixl.<interface_num>.fc=3
-
-To disable flow control:
-
- sysctl dev.ixl.<interface_num>.fc=0
-
-
-NOTE: You must have a flow control capable link partner.
-
-NOTE: The VF driver does not have access to flow control, it must be
- managed from the host side.
-
-
- Important system configuration changes:
- =======================================
-
--Change the file /etc/sysctl.conf, and add the line:
-
- hw.intr_storm_threshold: 0 (the default is 1000)
-
--Best throughput results are seen with a large MTU; use 9706 if possible.
-
--The default number of descriptors per ring is 1024, increasing this may
-improve performance depending on the use case.
-
--The VF driver uses a relatively large buf ring, this was found to eliminate
- UDP transmit errors, it is a tuneable, and if no UDP traffic is used it can
- be reduced. It is memory used per queue.
-
-
-Known Limitations
-=================
-
-Network Memory Buffer allocation
---------------------------------
- FreeBSD may have a low number of network memory buffers (mbufs) by default.
-If your mbuf value is too low, it may cause the driver to fail to initialize
-and/or cause the system to become unresponsive. You can check to see if the
-system is mbuf-starved by running 'netstat -m'. Increase the number of mbufs
-by editing the lines below in /etc/sysctl.conf:
-
- kern.ipc.nmbclusters
- kern.ipc.nmbjumbop
- kern.ipc.nmbjumbo9
- kern.ipc.nmbjumbo16
- kern.ipc.nmbufs
-
-The amount of memory that you allocate is system specific, and may
-require some trial and error.
-
-Also, increasing the follwing in /etc/sysctl.conf could help increase
-network performance:
-
- kern.ipc.maxsockbuf
- net.inet.tcp.sendspace
- net.inet.tcp.recvspace
- net.inet.udp.maxdgram
- net.inet.udp.recvspace
-
-
-UDP Stress Test Dropped Packet Issue
-------------------------------------
-Under small packet UDP stress test with the ixl driver, the FreeBSD system
-may drop UDP packets due to the fullness of socket buffers. You may want to
-change the driver's Flow Control variables to the minimum value for
-controlling packet reception.
-
-
-Disable LRO when routing/bridging
----------------------------------
-LRO must be turned off when forwarding traffic.
-
-
-Lower than expected performance
--------------------------------
-Some PCIe x8 slots are actually configured as x4 slots. These slots have
-insufficient bandwidth for full line rate with dual port and quad port
-devices.
-
-In addition, if you put a PCIe Generation 3-capable adapter into a PCIe
-Generation 2 slot, you cannot get full bandwidth. The driver detects this
-situation and writes the following message in the system log:
-
- "PCI-Express bandwidth available for this card is not sufficient for
- optimal performance. For optimal performance a x8 PCI-Express slot
- is required."
-
-If this error occurs, moving your adapter to a true PCIe Generation 3 x8
-slot will resolve the issue.
-
-
-Support
-=======
-
-For general information and support, go to the Intel support website at:
-
- http://support.intel.com
-
-If an issue is identified with the released source code on the supported kernel
-with a supported adapter, email the specific information related to the issue
-to freebsdnic@mailbox.intel.com.
-
-
-License
-=======
-
-This software program is released under the terms of a license agreement
-between you ('Licensee') and Intel. Do not use or load this software or any
-associated materials (collectively, the 'Software') until you have carefully
-read the full terms and conditions of the LICENSE located in this software
-package. By loadingor using the Software, you agree to the terms of this
-Agreement. If you do not agree with the terms of this Agreement, do not
-install or use the Software.
-
-* Other names and brands may be claimed as the property of others.
-
-
diff --git a/sys/dev/ixl/i40e_osdep.c b/sys/dev/ixl/i40e_osdep.c
index 3dad1f76ce40..ee8ca26c5d7a 100644
--- a/sys/dev/ixl/i40e_osdep.c
+++ b/sys/dev/ixl/i40e_osdep.c
@@ -161,27 +161,25 @@ i40e_destroy_spinlock(struct i40e_spinlock *lock)
mtx_destroy(&lock->mutex);
}
+static inline int
+ixl_ms_scale(int x)
+{
+ if (hz == 1000)
+ return (x);
+ else if (hz > 1000)
+ return (x*(hz/1000));
+ else
+ return (max(1, x/(1000/hz)));
+}
+
void
i40e_msec_pause(int msecs)
{
- int ticks_to_pause = (msecs * hz) / 1000;
- int start_ticks = ticks;
-
- if (cold || SCHEDULER_STOPPED()) {
+ if (cold || SCHEDULER_STOPPED())
i40e_msec_delay(msecs);
- return;
- }
-
- while (1) {
- kern_yield(PRI_USER);
- int yielded_ticks = ticks - start_ticks;
- if (yielded_ticks > ticks_to_pause)
- break;
- else if (yielded_ticks < 0
- && (yielded_ticks + INT_MAX + 1 > ticks_to_pause)) {
- break;
- }
- }
+ else
+ // ERJ: (msecs * hz) could overflow
+ pause("ixl", ixl_ms_scale(msecs));
}
/*
@@ -272,7 +270,5 @@ i40e_write_pci_cfg(struct i40e_hw *hw, u32 reg, u16 value)
{
pci_write_config(((struct i40e_osdep *)hw->back)->dev,
reg, value, 2);
-
- return;
}
diff --git a/sys/dev/ixl/if_ixl.c b/sys/dev/ixl/if_ixl.c
index 23c9d13c695d..99b14b52e782 100644
--- a/sys/dev/ixl/if_ixl.c
+++ b/sys/dev/ixl/if_ixl.c
@@ -48,7 +48,7 @@
* Driver version
*********************************************************************/
#define IXL_DRIVER_VERSION_MAJOR 2
-#define IXL_DRIVER_VERSION_MINOR 0
+#define IXL_DRIVER_VERSION_MINOR 1
#define IXL_DRIVER_VERSION_BUILD 0
#define IXL_DRIVER_VERSION_STRING \
@@ -115,10 +115,11 @@ static void ixl_if_timer(if_ctx_t ctx, uint16_t qid);
static void ixl_if_vlan_register(if_ctx_t ctx, u16 vtag);
static void ixl_if_vlan_unregister(if_ctx_t ctx, u16 vtag);
static uint64_t ixl_if_get_counter(if_ctx_t ctx, ift_counter cnt);
-static void ixl_if_vflr_handle(if_ctx_t ctx);
-// static void ixl_if_link_intr_enable(if_ctx_t ctx);
static int ixl_if_i2c_req(if_ctx_t ctx, struct ifi2creq *req);
static int ixl_if_priv_ioctl(if_ctx_t ctx, u_long command, caddr_t data);
+#ifdef PCI_IOV
+static void ixl_if_vflr_handle(if_ctx_t ctx);
+#endif
/*** Other ***/
static int ixl_mc_filter_apply(void *arg, struct ifmultiaddr *ifma, int);
@@ -137,9 +138,9 @@ static device_method_t ixl_methods[] = {
DEVMETHOD(device_detach, iflib_device_detach),
DEVMETHOD(device_shutdown, iflib_device_shutdown),
#ifdef PCI_IOV
- DEVMETHOD(pci_iov_init, ixl_iov_init),
- DEVMETHOD(pci_iov_uninit, ixl_iov_uninit),
- DEVMETHOD(pci_iov_add_vf, ixl_add_vf),
+ DEVMETHOD(pci_iov_init, iflib_device_iov_init),
+ DEVMETHOD(pci_iov_uninit, iflib_device_iov_uninit),
+ DEVMETHOD(pci_iov_add_vf, iflib_device_iov_add_vf),
#endif
DEVMETHOD_END
};
@@ -169,7 +170,6 @@ static device_method_t ixl_if_methods[] = {
DEVMETHOD(ifdi_msix_intr_assign, ixl_if_msix_intr_assign),
DEVMETHOD(ifdi_intr_enable, ixl_if_enable_intr),
DEVMETHOD(ifdi_intr_disable, ixl_if_disable_intr),
- //DEVMETHOD(ifdi_link_intr_enable, ixl_if_link_intr_enable),
DEVMETHOD(ifdi_rx_queue_intr_enable, ixl_if_rx_queue_intr_enable),
DEVMETHOD(ifdi_tx_queue_intr_enable, ixl_if_tx_queue_intr_enable),
DEVMETHOD(ifdi_tx_queues_alloc, ixl_if_tx_queues_alloc),
@@ -185,9 +185,14 @@ static device_method_t ixl_if_methods[] = {
DEVMETHOD(ifdi_vlan_register, ixl_if_vlan_register),
DEVMETHOD(ifdi_vlan_unregister, ixl_if_vlan_unregister),
DEVMETHOD(ifdi_get_counter, ixl_if_get_counter),
- DEVMETHOD(ifdi_vflr_handle, ixl_if_vflr_handle),
DEVMETHOD(ifdi_i2c_req, ixl_if_i2c_req),
DEVMETHOD(ifdi_priv_ioctl, ixl_if_priv_ioctl),
+#ifdef PCI_IOV
+ DEVMETHOD(ifdi_iov_init, ixl_if_iov_init),
+ DEVMETHOD(ifdi_iov_uninit, ixl_if_iov_uninit),
+ DEVMETHOD(ifdi_iov_vf_add, ixl_if_iov_vf_add),
+ DEVMETHOD(ifdi_vflr_handle, ixl_if_vflr_handle),
+#endif
// ifdi_led_func
// ifdi_debug
DEVMETHOD_END
@@ -202,7 +207,7 @@ static driver_t ixl_if_driver = {
*/
static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0,
- "IXL driver parameters");
+ "ixl driver parameters");
/*
* Leave this on unless you need to send flow control
@@ -222,6 +227,13 @@ SYSCTL_INT(_hw_ixl, OID_AUTO, i2c_access_method, CTLFLAG_RDTUN,
&ixl_i2c_access_method, 0,
IXL_SYSCTL_HELP_I2C_METHOD);
+static int ixl_enable_vf_loopback = 1;
+TUNABLE_INT("hw.ixl.enable_vf_loopback",
+ &ixl_enable_vf_loopback);
+SYSCTL_INT(_hw_ixl, OID_AUTO, enable_vf_loopback, CTLFLAG_RDTUN,
+ &ixl_enable_vf_loopback, 0,
+ IXL_SYSCTL_HELP_VF_LOOPBACK);
+
/*
* Different method for processing TX descriptor
* completion.
@@ -333,9 +345,9 @@ ixl_register(device_t dev)
static int
ixl_allocate_pci_resources(struct ixl_pf *pf)
{
- int rid;
- struct i40e_hw *hw = &pf->hw;
device_t dev = iflib_get_dev(pf->vsi.ctx);
+ struct i40e_hw *hw = &pf->hw;
+ int rid;
/* Map BAR0 */
rid = PCIR_BAR(0);
@@ -386,21 +398,17 @@ ixl_if_attach_pre(if_ctx_t ctx)
enum i40e_status_code status;
int error = 0;
- INIT_DEBUGOUT("ixl_if_attach_pre: begin");
+ INIT_DBG_DEV(dev, "begin");
- /* Allocate, clear, and link in our primary soft structure */
dev = iflib_get_dev(ctx);
pf = iflib_get_softc(ctx);
+
vsi = &pf->vsi;
vsi->back = pf;
pf->dev = dev;
hw = &pf->hw;
- /*
- ** Note this assumes we have a single embedded VSI,
- ** this could be enhanced later to allocate multiple
- */
- //vsi->dev = pf->dev;
+ vsi->dev = dev;
vsi->hw = &pf->hw;
vsi->id = 0;
vsi->num_vlans = 0;
@@ -545,6 +553,7 @@ ixl_if_attach_pre(if_ctx_t ctx)
* sizeof(struct i40e_tx_desc), DBA_ALIGN);
scctx->isc_txrx = &ixl_txrx_dwb;
}
+ scctx->isc_txrx->ift_legacy_intr = ixl_intr;
scctx->isc_rxqsizes[0] = roundup2(scctx->isc_nrxd[0]
* sizeof(union i40e_32byte_rx_desc), DBA_ALIGN);
scctx->isc_msix_bar = PCIR_BAR(IXL_MSIX_BAR);
@@ -556,7 +565,7 @@ ixl_if_attach_pre(if_ctx_t ctx)
scctx->isc_tx_csum_flags = CSUM_OFFLOAD;
scctx->isc_capabilities = scctx->isc_capenable = IXL_CAPS;
- INIT_DEBUGOUT("ixl_if_attach_pre: end");
+ INIT_DBG_DEV(dev, "end");
return (0);
err_mac_hmc:
@@ -579,7 +588,7 @@ ixl_if_attach_post(if_ctx_t ctx)
int error = 0;
enum i40e_status_code status;
- INIT_DEBUGOUT("ixl_if_attach_post: begin");
+ INIT_DBG_DEV(dev, "begin");
dev = iflib_get_dev(ctx);
pf = iflib_get_softc(ctx);
@@ -587,6 +596,10 @@ ixl_if_attach_post(if_ctx_t ctx)
vsi->ifp = iflib_get_ifp(ctx);
hw = &pf->hw;
+ /* Save off determined number of queues for interface */
+ vsi->num_rx_queues = vsi->shared->isc_nrxqsets;
+ vsi->num_tx_queues = vsi->shared->isc_ntxqsets;
+
/* Setup OS network interface / ifnet */
if (ixl_setup_interface(dev, pf)) {
device_printf(dev, "interface setup failed!\n");
@@ -694,6 +707,10 @@ err:
return (error);
}
+/**
+ * XXX: iflib always ignores the return value of detach()
+ * -> This means that this isn't allowed to fail
+ */
static int
ixl_if_detach(if_ctx_t ctx)
{
@@ -702,7 +719,7 @@ ixl_if_detach(if_ctx_t ctx)
struct i40e_hw *hw = &pf->hw;
device_t dev = pf->dev;
enum i40e_status_code status;
-#if defined(PCI_IOV) || defined(IXL_IW)
+#ifdef IXL_IW
int error;
#endif
@@ -713,17 +730,10 @@ ixl_if_detach(if_ctx_t ctx)
error = ixl_iw_pf_detach(pf);
if (error == EBUSY) {
device_printf(dev, "iwarp in use; stop it first.\n");
- return (error);
+ //return (error);
}
}
#endif
-#ifdef PCI_IOV
- error = pci_iov_detach(dev);
- if (error != 0) {
- device_printf(dev, "SR-IOV in use; detach first.\n");
- return (error);
- }
-#endif
/* Remove all previously allocated media types */
ifmedia_removeall(vsi->media);
@@ -751,7 +761,6 @@ ixl_if_detach(if_ctx_t ctx)
return (0);
}
-/* TODO: Do shutdown-specific stuff here */
static int
ixl_if_shutdown(if_ctx_t ctx)
{
@@ -796,43 +805,13 @@ ixl_if_resume(if_ctx_t ctx)
return (0);
}
-/* Set Report Status queue fields to 0 */
-static void
-ixl_init_tx_rsqs(struct ixl_vsi *vsi)
-{
- if_softc_ctx_t scctx = vsi->shared;
- struct ixl_tx_queue *tx_que;
- int i, j;
-
- for (i = 0, tx_que = vsi->tx_queues; i < vsi->num_tx_queues; i++, tx_que++) {
- struct tx_ring *txr = &tx_que->txr;
-
- txr->tx_rs_cidx = txr->tx_rs_pidx = txr->tx_cidx_processed = 0;
-
- for (j = 0; j < scctx->isc_ntxd[0]; j++)
- txr->tx_rsq[j] = QIDX_INVALID;
- }
-}
-
-static void
-ixl_init_tx_cidx(struct ixl_vsi *vsi)
-{
- struct ixl_tx_queue *tx_que;
- int i;
-
- for (i = 0, tx_que = vsi->tx_queues; i < vsi->num_tx_queues; i++, tx_que++) {
- struct tx_ring *txr = &tx_que->txr;
-
- txr->tx_cidx_processed = 0;
- }
-}
-
void
ixl_if_init(if_ctx_t ctx)
{
struct ixl_pf *pf = iflib_get_softc(ctx);
struct ixl_vsi *vsi = &pf->vsi;
struct i40e_hw *hw = &pf->hw;
+ struct ifnet *ifp = iflib_get_ifp(ctx);
device_t dev = iflib_get_dev(ctx);
u8 tmpaddr[ETHER_ADDR_LEN];
int ret;
@@ -840,12 +819,12 @@ ixl_if_init(if_ctx_t ctx)
/*
* If the aq is dead here, it probably means something outside of the driver
* did something to the adapter, like a PF reset.
- * So rebuild the driver's state here if that occurs.
+ * So, rebuild the driver's state here if that occurs.
*/
if (!i40e_check_asq_alive(&pf->hw)) {
device_printf(dev, "Admin Queue is down; resetting...\n");
ixl_teardown_hw_structs(pf);
- ixl_reset(pf);
+ ixl_rebuild_hw_structs_after_reset(pf);
}
/* Get the latest mac address... User might use a LAA */
@@ -872,8 +851,7 @@ ixl_if_init(if_ctx_t ctx)
return;
}
- // TODO: Call iflib setup multicast filters here?
- // It's called in ixgbe in D5213
+ /* Reconfigure multicast filters in HW */
ixl_if_multi_set(ctx);
/* Set up RSS */
@@ -895,8 +873,12 @@ ixl_if_init(if_ctx_t ctx)
i40e_aq_set_default_vsi(hw, vsi->seid, NULL);
+ /* Re-add configure filters to HW */
ixl_reconfigure_filters(vsi);
+ /* Configure promiscuous mode */
+ ixl_if_promisc_set(ctx, if_getflags(ifp));
+
#ifdef IXL_IW
if (ixl_enable_iwarp && pf->iw_enabled) {
ret = ixl_iw_pf_init(pf);
@@ -923,7 +905,7 @@ ixl_if_stop(if_ctx_t ctx)
#endif
ixl_disable_rings_intr(vsi);
- ixl_disable_rings(vsi);
+ ixl_disable_rings(pf, vsi, &pf->qtag);
}
static int
@@ -936,6 +918,9 @@ ixl_if_msix_intr_assign(if_ctx_t ctx, int msix)
int err, i, rid, vector = 0;
char buf[16];
+ MPASS(vsi->shared->isc_nrxqsets > 0);
+ MPASS(vsi->shared->isc_ntxqsets > 0);
+
/* Admin Que must use vector 0*/
rid = vector + 1;
err = iflib_irq_alloc_generic(ctx, &vsi->irq, rid, IFLIB_INTR_ADMIN,
@@ -943,14 +928,14 @@ ixl_if_msix_intr_assign(if_ctx_t ctx, int msix)
if (err) {
iflib_irq_free(ctx, &vsi->irq);
device_printf(iflib_get_dev(ctx),
- "Failed to register Admin que handler");
+ "Failed to register Admin Que handler");
return (err);
}
- // TODO: Re-enable this at some point
- // iflib_softirq_alloc_generic(ctx, rid, IFLIB_INTR_IOV, pf, 0, "ixl_iov");
+ /* Create soft IRQ for handling VFLRs */
+ iflib_softirq_alloc_generic(ctx, &pf->iov_irq, IFLIB_INTR_IOV, pf, 0, "iov");
/* Now set up the stations */
- for (i = 0, vector = 1; i < vsi->num_rx_queues; i++, vector++, rx_que++) {
+ for (i = 0, vector = 1; i < vsi->shared->isc_nrxqsets; i++, vector++, rx_que++) {
rid = vector + 1;
snprintf(buf, sizeof(buf), "rxq%d", i);
@@ -960,7 +945,7 @@ ixl_if_msix_intr_assign(if_ctx_t ctx, int msix)
* what's expected in the iflib context? */
if (err) {
device_printf(iflib_get_dev(ctx),
- "Failed to allocate q int %d err: %d", i, err);
+ "Failed to allocate queue RX int vector %d, err: %d\n", i, err);
vsi->num_rx_queues = i + 1;
goto fail;
}
@@ -969,16 +954,16 @@ ixl_if_msix_intr_assign(if_ctx_t ctx, int msix)
bzero(buf, sizeof(buf));
- for (i = 0; i < vsi->num_tx_queues; i++, tx_que++) {
+ for (i = 0; i < vsi->shared->isc_ntxqsets; i++, tx_que++) {
snprintf(buf, sizeof(buf), "txq%d", i);
iflib_softirq_alloc_generic(ctx,
- &vsi->rx_queues[i % vsi->num_rx_queues].que_irq,
+ &vsi->rx_queues[i % vsi->shared->isc_nrxqsets].que_irq,
IFLIB_INTR_TX, tx_que, tx_que->txr.me, buf);
/* TODO: Maybe call a strategy function for this to figure out which
* interrupts to map Tx queues to. I don't know if there's an immediately
* better way than this other than a user-supplied map, though. */
- tx_que->msix = (i % vsi->num_rx_queues) + 1;
+ tx_que->msix = (i % vsi->shared->isc_nrxqsets) + 1;
}
return (0);
@@ -1051,11 +1036,10 @@ ixl_if_tx_queue_intr_enable(if_ctx_t ctx, uint16_t txqid)
{
struct ixl_pf *pf = iflib_get_softc(ctx);
struct ixl_vsi *vsi = &pf->vsi;
- struct i40e_hw *hw = vsi->hw;
- struct ixl_tx_queue *tx_que = &vsi->tx_queues[txqid];
+ struct i40e_hw *hw = vsi->hw;
+ struct ixl_tx_queue *tx_que = &vsi->tx_queues[txqid];
ixl_enable_queue(hw, tx_que->msix - 1);
-
return (0);
}
@@ -1066,12 +1050,11 @@ ixl_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntxq
struct ixl_vsi *vsi = &pf->vsi;
if_softc_ctx_t scctx = vsi->shared;
struct ixl_tx_queue *que;
- // int i;
int i, j, error = 0;
- MPASS(vsi->num_tx_queues > 0);
+ MPASS(scctx->isc_ntxqsets > 0);
MPASS(ntxqs == 1);
- MPASS(vsi->num_tx_queues == ntxqsets);
+ MPASS(scctx->isc_ntxqsets == ntxqsets);
/* Allocate queue structure memory */
if (!(vsi->tx_queues =
@@ -1118,9 +1101,12 @@ ixl_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nrxq
struct ixl_rx_queue *que;
int i, error = 0;
- MPASS(vsi->num_rx_queues > 0);
+#ifdef INVARIANTS
+ if_softc_ctx_t scctx = vsi->shared;
+ MPASS(scctx->isc_nrxqsets > 0);
MPASS(nrxqs == 1);
- MPASS(vsi->num_rx_queues == nrxqsets);
+ MPASS(scctx->isc_nrxqsets == nrxqsets);
+#endif
/* Allocate queue structure memory */
if (!(vsi->rx_queues =
@@ -1156,7 +1142,7 @@ ixl_if_queues_free(if_ctx_t ctx)
struct ixl_pf *pf = iflib_get_softc(ctx);
struct ixl_vsi *vsi = &pf->vsi;
- if (vsi->enable_head_writeback) {
+ if (!vsi->enable_head_writeback) {
struct ixl_tx_queue *que;
int i = 0;
@@ -1208,6 +1194,20 @@ ixl_update_link_status(struct ixl_pf *pf)
}
}
+static void
+ixl_handle_lan_overflow_event(struct ixl_pf *pf, struct i40e_arq_event_info *e)
+{
+ device_t dev = pf->dev;
+ u32 rxq_idx, qtx_ctl;
+
+ rxq_idx = (e->desc.params.external.param0 & I40E_PRTDCB_RUPTQ_RXQNUM_MASK) >>
+ I40E_PRTDCB_RUPTQ_RXQNUM_SHIFT;
+ qtx_ctl = e->desc.params.external.param1;
+
+ device_printf(dev, "LAN overflow event: global rxq_idx %d\n", rxq_idx);
+ device_printf(dev, "LAN overflow event: QTX_CTL 0x%08x\n", qtx_ctl);
+}
+
static int
ixl_process_adminq(struct ixl_pf *pf, u16 *pending)
{
@@ -1248,7 +1248,7 @@ ixl_process_adminq(struct ixl_pf *pf, u16 *pending)
* aren't currently configured.
*/
case i40e_aqc_opc_event_lan_overflow:
- device_printf(dev, "LAN overflow event\n");
+ ixl_handle_lan_overflow_event(pf, &event);
break;
default:
break;
@@ -1278,13 +1278,9 @@ ixl_if_update_admin_status(if_ctx_t ctx)
if (pf->state & IXL_PF_STATE_MDD_PENDING)
ixl_handle_mdd_event(pf);
-#ifdef PCI_IOV
- if (pf->state & IXL_PF_STATE_VF_RESET_REQ)
- iflib_iov_intr_deferred(ctx);
-#endif
-
ixl_process_adminq(pf, &pending);
ixl_update_link_status(pf);
+ ixl_update_stats_counters(pf);
/*
* If there are still messages to process, reschedule ourselves.
@@ -1301,14 +1297,16 @@ ixl_if_multi_set(if_ctx_t ctx)
{
struct ixl_pf *pf = iflib_get_softc(ctx);
struct ixl_vsi *vsi = &pf->vsi;
- struct i40e_hw *hw = vsi->hw;
- int mcnt = 0, flags;
+ struct i40e_hw *hw = vsi->hw;
+ int mcnt = 0, flags;
+ int del_mcnt;
IOCTL_DEBUGOUT("ixl_if_multi_set: begin");
mcnt = if_multiaddr_count(iflib_get_ifp(ctx), MAX_MULTICAST_ADDR);
- /* delete existing MC filters */
- ixl_del_multi(vsi);
+ /* Delete filters for removed multicast addresses */
+ del_mcnt = ixl_del_multi(vsi);
+ vsi->num_macs -= del_mcnt;
if (__predict_false(mcnt == MAX_MULTICAST_ADDR)) {
i40e_aq_set_vsi_multicast_promiscuous(hw,
@@ -1316,13 +1314,17 @@ ixl_if_multi_set(if_ctx_t ctx)
return;
}
/* (re-)install filters for all mcast addresses */
+ /* XXX: This bypasses filter count tracking code! */
mcnt = if_multi_apply(iflib_get_ifp(ctx), ixl_mc_filter_apply, vsi);
if (mcnt > 0) {
+ vsi->num_macs += mcnt;
flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC);
ixl_add_hw_filters(vsi, flags, mcnt);
}
+ ixl_dbg_filter(pf, "%s: filter mac total: %d\n",
+ __func__, vsi->num_macs);
IOCTL_DEBUGOUT("ixl_if_multi_set: end");
}
@@ -1518,32 +1520,11 @@ ixl_if_promisc_set(if_ctx_t ctx, int flags)
static void
ixl_if_timer(if_ctx_t ctx, uint16_t qid)
{
- struct ixl_pf *pf = iflib_get_softc(ctx);
- //struct i40e_hw *hw = &pf->hw;
- //struct ixl_tx_queue *que = &vsi->tx_queues[qid];
- #if 0
- u32 mask;
-
- /*
- ** Check status of the queues
- */
- mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK |
- I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK);
-
- /* If queue param has outstanding work, trigger sw irq */
- // TODO: TX queues in iflib don't use HW interrupts; does this do anything?
- if (que->busy)
- wr32(hw, I40E_PFINT_DYN_CTLN(que->txr.me), mask);
-#endif
-
if (qid != 0)
return;
/* Fire off the adminq task */
iflib_admin_intr_deferred(ctx);
-
- /* Update stats */
- ixl_update_stats_counters(pf);
}
static void
@@ -1612,13 +1593,15 @@ ixl_if_get_counter(if_ctx_t ctx, ift_counter cnt)
}
}
+#ifdef PCI_IOV
static void
ixl_if_vflr_handle(if_ctx_t ctx)
{
- IXL_DEV_ERR(iflib_get_dev(ctx), "");
+ struct ixl_pf *pf = iflib_get_softc(ctx);
- // TODO: call ixl_handle_vflr()
+ ixl_handle_vflr(pf);
}
+#endif
static int
ixl_if_i2c_req(if_ctx_t ctx, struct ifi2creq *req)
@@ -1676,6 +1659,7 @@ ixl_save_pf_tunables(struct ixl_pf *pf)
pf->dbg_mask = ixl_core_debug_mask;
pf->hw.debug_mask = ixl_shared_debug_mask;
pf->vsi.enable_head_writeback = !!(ixl_enable_head_writeback);
+ pf->enable_vf_loopback = !!(ixl_enable_vf_loopback);
#if 0
pf->dynamic_rx_itr = ixl_dynamic_rx_itr;
pf->dynamic_tx_itr = ixl_dynamic_tx_itr;
diff --git a/sys/dev/ixl/if_ixlv.c b/sys/dev/ixl/if_ixlv.c
index dd72d52ab187..9d3495e3b1ed 100644
--- a/sys/dev/ixl/if_ixlv.c
+++ b/sys/dev/ixl/if_ixlv.c
@@ -32,19 +32,19 @@
******************************************************************************/
/*$FreeBSD$*/
-#include "ixl.h"
#include "ixlv.h"
/*********************************************************************
* Driver version
*********************************************************************/
-#define IXLV_DRIVER_VERSION_MAJOR 1
-#define IXLV_DRIVER_VERSION_MINOR 5
-#define IXLV_DRIVER_VERSION_BUILD 4
+#define IAVF_DRIVER_VERSION_MAJOR 2
+#define IAVF_DRIVER_VERSION_MINOR 0
+#define IAVF_DRIVER_VERSION_BUILD 0
-char ixlv_driver_version[] = __XSTRING(IXLV_DRIVER_VERSION_MAJOR) "."
- __XSTRING(IXLV_DRIVER_VERSION_MINOR) "."
- __XSTRING(IXLV_DRIVER_VERSION_BUILD) "-iflib-k";
+#define IAVF_DRIVER_VERSION_STRING \
+ __XSTRING(IAVF_DRIVER_VERSION_MAJOR) "." \
+ __XSTRING(IAVF_DRIVER_VERSION_MINOR) "." \
+ __XSTRING(IAVF_DRIVER_VERSION_BUILD) "-k"
/*********************************************************************
* PCI Device ID Table
@@ -56,9 +56,9 @@ char ixlv_driver_version[] = __XSTRING(IXLV_DRIVER_VERSION_MAJOR) "."
static pci_vendor_info_t ixlv_vendor_info_array[] =
{
- {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_VF, 0, 0, 0},
- {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_X722_VF, 0, 0, 0},
- {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_ADAPTIVE_VF, 0, 0, 0},
+ PVID(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_VF, "Intel(R) Ethernet Virtual Function 700 Series"),
+ PVID(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_X722_VF, "Intel(R) Ethernet Virtual Function 700 Series (X722)"),
+ PVID(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_ADAPTIVE_VF, "Intel(R) Ethernet Adaptive Virtual Function"),
/* required last entry */
PVID_END
};
@@ -66,7 +66,7 @@ static pci_vendor_info_t ixlv_vendor_info_array[] =
/*********************************************************************
* Function prototypes
*********************************************************************/
-static void *ixlv_register(device_t dev);
+static void *ixlv_register(device_t dev);
static int ixlv_if_attach_pre(if_ctx_t ctx);
static int ixlv_if_attach_post(if_ctx_t ctx);
static int ixlv_if_detach(if_ctx_t ctx);
@@ -76,7 +76,8 @@ static int ixlv_if_resume(if_ctx_t ctx);
static int ixlv_if_msix_intr_assign(if_ctx_t ctx, int msix);
static void ixlv_if_enable_intr(if_ctx_t ctx);
static void ixlv_if_disable_intr(if_ctx_t ctx);
-static int ixlv_if_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid);
+static int ixlv_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid);
+static int ixlv_if_tx_queue_intr_enable(if_ctx_t ctx, uint16_t txqid);
static int ixlv_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntxqs, int ntxqsets);
static int ixlv_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nqs, int nqsets);
static void ixlv_if_queues_free(if_ctx_t ctx);
@@ -100,8 +101,8 @@ static int ixlv_vf_config(struct ixlv_sc *);
static void ixlv_init_filters(struct ixlv_sc *);
static void ixlv_free_pci_resources(struct ixlv_sc *);
static void ixlv_free_filters(struct ixlv_sc *);
-static void ixlv_setup_interface(device_t, struct ixl_vsi *);
-static void ixlv_add_sysctls(struct ixlv_sc *);
+static void ixlv_setup_interface(device_t, struct ixlv_sc *);
+static void ixlv_add_device_sysctls(struct ixlv_sc *);
static void ixlv_enable_adminq_irq(struct i40e_hw *);
static void ixlv_disable_adminq_irq(struct i40e_hw *);
static void ixlv_enable_queue_irq(struct i40e_hw *, int);
@@ -113,21 +114,24 @@ static int ixlv_add_mac_filter(struct ixlv_sc *, u8 *, u16);
static int ixlv_del_mac_filter(struct ixlv_sc *sc, u8 *macaddr);
static int ixlv_msix_que(void *);
static int ixlv_msix_adminq(void *);
-static void ixlv_do_adminq_locked(struct ixlv_sc *sc);
-static void ixl_init_cmd_complete(struct ixl_vc_cmd *, void *,
- enum i40e_status_code);
-static void ixlv_configure_itr(struct ixlv_sc *);
-
-static void ixlv_setup_vlan_filters(struct ixlv_sc *);
-
-static char *ixlv_vc_speed_to_string(enum virtchnl_link_speed link_speed);
-static int ixlv_sysctl_current_speed(SYSCTL_HANDLER_ARGS);
-
-// static void ixlv_add_sysctls(struct ixlv_sc *);
-#ifdef IXL_DEBUG
-static int ixlv_sysctl_qtx_tail_handler(SYSCTL_HANDLER_ARGS);
-static int ixlv_sysctl_qrx_tail_handler(SYSCTL_HANDLER_ARGS);
-#endif
+//static void ixlv_del_multi(struct ixlv_sc *sc);
+static void ixlv_init_multi(struct ixlv_sc *sc);
+static void ixlv_configure_itr(struct ixlv_sc *sc);
+
+static int ixlv_sysctl_rx_itr(SYSCTL_HANDLER_ARGS);
+static int ixlv_sysctl_tx_itr(SYSCTL_HANDLER_ARGS);
+static int ixlv_sysctl_current_speed(SYSCTL_HANDLER_ARGS);
+static int ixlv_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS);
+static int ixlv_sysctl_queue_interrupt_table(SYSCTL_HANDLER_ARGS);
+static int ixlv_sysctl_vf_reset(SYSCTL_HANDLER_ARGS);
+static int ixlv_sysctl_vflr_reset(SYSCTL_HANDLER_ARGS);
+
+char *ixlv_vc_speed_to_string(enum virtchnl_link_speed link_speed);
+static void ixlv_save_tunables(struct ixlv_sc *);
+static enum i40e_status_code
+ ixlv_process_adminq(struct ixlv_sc *, u16 *);
+static int ixlv_send_vc_msg(struct ixlv_sc *sc, u32 op);
+static int ixlv_send_vc_msg_sleep(struct ixlv_sc *sc, u32 op);
/*********************************************************************
* FreeBSD Device Interface Entry Points
@@ -144,17 +148,21 @@ static device_method_t ixlv_methods[] = {
};
static driver_t ixlv_driver = {
- "ixlv", ixlv_methods, sizeof(struct ixlv_sc),
+ "iavf", ixlv_methods, sizeof(struct ixlv_sc),
};
devclass_t ixlv_devclass;
-DRIVER_MODULE(ixlv, pci, ixlv_driver, ixlv_devclass, 0, 0);
+DRIVER_MODULE(iavf, pci, ixlv_driver, ixlv_devclass, 0, 0);
MODULE_PNP_INFO("U32:vendor;U32:device;U32:subvendor;U32:subdevice;U32:revision",
- pci, ixlv, ixlv_vendor_info_array,
+ pci, iavf, ixlv_vendor_info_array,
nitems(ixlv_vendor_info_array) - 1);
-MODULE_DEPEND(ixlv, pci, 1, 1, 1);
-MODULE_DEPEND(ixlv, ether, 1, 1, 1);
-MODULE_DEPEND(ixlv, iflib, 1, 1, 1);
+MODULE_VERSION(iavf, 1);
+
+MODULE_DEPEND(iavf, pci, 1, 1, 1);
+MODULE_DEPEND(iavf, ether, 1, 1, 1);
+MODULE_DEPEND(iavf, iflib, 1, 1, 1);
+
+MALLOC_DEFINE(M_IXLV, "iavf", "iavf driver allocations");
static device_method_t ixlv_if_methods[] = {
DEVMETHOD(ifdi_attach_pre, ixlv_if_attach_pre),
@@ -168,14 +176,14 @@ static device_method_t ixlv_if_methods[] = {
DEVMETHOD(ifdi_msix_intr_assign, ixlv_if_msix_intr_assign),
DEVMETHOD(ifdi_intr_enable, ixlv_if_enable_intr),
DEVMETHOD(ifdi_intr_disable, ixlv_if_disable_intr),
- DEVMETHOD(ifdi_queue_intr_enable, ixlv_if_queue_intr_enable),
+ DEVMETHOD(ifdi_rx_queue_intr_enable, ixlv_if_rx_queue_intr_enable),
+ DEVMETHOD(ifdi_tx_queue_intr_enable, ixlv_if_tx_queue_intr_enable),
DEVMETHOD(ifdi_tx_queues_alloc, ixlv_if_tx_queues_alloc),
DEVMETHOD(ifdi_rx_queues_alloc, ixlv_if_rx_queues_alloc),
DEVMETHOD(ifdi_queues_free, ixlv_if_queues_free),
DEVMETHOD(ifdi_update_admin_status, ixlv_if_update_admin_status),
DEVMETHOD(ifdi_multi_set, ixlv_if_multi_set),
DEVMETHOD(ifdi_mtu_set, ixlv_if_mtu_set),
- // DEVMETHOD(ifdi_crcstrip_set, ixlv_if_crcstrip_set),
DEVMETHOD(ifdi_media_status, ixlv_if_media_status),
DEVMETHOD(ifdi_media_change, ixlv_if_media_change),
DEVMETHOD(ifdi_promisc_set, ixlv_if_promisc_set),
@@ -187,95 +195,73 @@ static device_method_t ixlv_if_methods[] = {
};
static driver_t ixlv_if_driver = {
- "ixlv_if", ixlv_if_methods, sizeof(struct ixlv_sc)
+ "iavf_if", ixlv_if_methods, sizeof(struct ixlv_sc)
};
/*
** TUNEABLE PARAMETERS:
*/
-static SYSCTL_NODE(_hw, OID_AUTO, ixlv, CTLFLAG_RD, 0,
- "IXLV driver parameters");
-
-/*
-** Number of descriptors per ring:
-** - TX and RX sizes are independently configurable
-*/
-static int ixlv_tx_ring_size = IXL_DEFAULT_RING;
-TUNABLE_INT("hw.ixlv.tx_ring_size", &ixlv_tx_ring_size);
-SYSCTL_INT(_hw_ixlv, OID_AUTO, tx_ring_size, CTLFLAG_RDTUN,
- &ixlv_tx_ring_size, 0, "TX Descriptor Ring Size");
-
-static int ixlv_rx_ring_size = IXL_DEFAULT_RING;
-TUNABLE_INT("hw.ixlv.rx_ring_size", &ixlv_rx_ring_size);
-SYSCTL_INT(_hw_ixlv, OID_AUTO, rx_ring_size, CTLFLAG_RDTUN,
- &ixlv_rx_ring_size, 0, "TX Descriptor Ring Size");
-
-/* Set to zero to auto calculate */
-int ixlv_max_queues = 0;
-TUNABLE_INT("hw.ixlv.max_queues", &ixlv_max_queues);
-SYSCTL_INT(_hw_ixlv, OID_AUTO, max_queues, CTLFLAG_RDTUN,
- &ixlv_max_queues, 0, "Number of Queues");
+static SYSCTL_NODE(_hw, OID_AUTO, iavf, CTLFLAG_RD, 0,
+ "iavf driver parameters");
/*
* Different method for processing TX descriptor
* completion.
*/
static int ixlv_enable_head_writeback = 0;
-TUNABLE_INT("hw.ixlv.enable_head_writeback",
+TUNABLE_INT("hw.iavf.enable_head_writeback",
&ixlv_enable_head_writeback);
-SYSCTL_INT(_hw_ixlv, OID_AUTO, enable_head_writeback, CTLFLAG_RDTUN,
+SYSCTL_INT(_hw_iavf, OID_AUTO, enable_head_writeback, CTLFLAG_RDTUN,
&ixlv_enable_head_writeback, 0,
"For detecting last completed TX descriptor by hardware, use value written by HW instead of checking descriptors");
-/*
-** Controls for Interrupt Throttling
-** - true/false for dynamic adjustment
-** - default values for static ITR
-*/
-int ixlv_dynamic_rx_itr = 0;
-TUNABLE_INT("hw.ixlv.dynamic_rx_itr", &ixlv_dynamic_rx_itr);
-SYSCTL_INT(_hw_ixlv, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN,
- &ixlv_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate");
+static int ixlv_core_debug_mask = 0;
+TUNABLE_INT("hw.iavf.core_debug_mask",
+ &ixlv_core_debug_mask);
+SYSCTL_INT(_hw_iavf, OID_AUTO, core_debug_mask, CTLFLAG_RDTUN,
+ &ixlv_core_debug_mask, 0,
+ "Display debug statements that are printed in non-shared code");
-int ixlv_dynamic_tx_itr = 0;
-TUNABLE_INT("hw.ixlv.dynamic_tx_itr", &ixlv_dynamic_tx_itr);
-SYSCTL_INT(_hw_ixlv, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN,
- &ixlv_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate");
+static int ixlv_shared_debug_mask = 0;
+TUNABLE_INT("hw.iavf.shared_debug_mask",
+ &ixlv_shared_debug_mask);
+SYSCTL_INT(_hw_iavf, OID_AUTO, shared_debug_mask, CTLFLAG_RDTUN,
+ &ixlv_shared_debug_mask, 0,
+ "Display debug statements that are printed in shared code");
int ixlv_rx_itr = IXL_ITR_8K;
-TUNABLE_INT("hw.ixlv.rx_itr", &ixlv_rx_itr);
-SYSCTL_INT(_hw_ixlv, OID_AUTO, rx_itr, CTLFLAG_RDTUN,
+TUNABLE_INT("hw.iavf.rx_itr", &ixlv_rx_itr);
+SYSCTL_INT(_hw_iavf, OID_AUTO, rx_itr, CTLFLAG_RDTUN,
&ixlv_rx_itr, 0, "RX Interrupt Rate");
int ixlv_tx_itr = IXL_ITR_4K;
-TUNABLE_INT("hw.ixlv.tx_itr", &ixlv_tx_itr);
-SYSCTL_INT(_hw_ixlv, OID_AUTO, tx_itr, CTLFLAG_RDTUN,
+TUNABLE_INT("hw.iavf.tx_itr", &ixlv_tx_itr);
+SYSCTL_INT(_hw_iavf, OID_AUTO, tx_itr, CTLFLAG_RDTUN,
&ixlv_tx_itr, 0, "TX Interrupt Rate");
-extern struct if_txrx ixl_txrx;
+extern struct if_txrx ixl_txrx_hwb;
+extern struct if_txrx ixl_txrx_dwb;
static struct if_shared_ctx ixlv_sctx_init = {
.isc_magic = IFLIB_MAGIC,
.isc_q_align = PAGE_SIZE,/* max(DBA_ALIGN, PAGE_SIZE) */
.isc_tx_maxsize = IXL_TSO_SIZE + sizeof(struct ether_vlan_header),
- .isc_tx_maxsegsize = PAGE_SIZE,
+ .isc_tx_maxsegsize = IXL_MAX_DMA_SEG_SIZE,
.isc_tso_maxsize = IXL_TSO_SIZE + sizeof(struct ether_vlan_header),
- .isc_tso_maxsegsize = PAGE_SIZE,
- // TODO: Review the rx_maxsize and rx_maxsegsize params
- // Where are they used in iflib?
+ .isc_tso_maxsegsize = IXL_MAX_DMA_SEG_SIZE,
.isc_rx_maxsize = 16384,
- .isc_rx_nsegments = 1,
- .isc_rx_maxsegsize = 16384,
- // TODO: What is isc_nfl for?
+ .isc_rx_nsegments = IXL_MAX_RX_SEGS,
+ .isc_rx_maxsegsize = IXL_MAX_DMA_SEG_SIZE,
.isc_nfl = 1,
.isc_ntxqs = 1,
.isc_nrxqs = 1,
.isc_admin_intrcnt = 1,
.isc_vendor_info = ixlv_vendor_info_array,
- .isc_driver_version = ixlv_driver_version,
+ .isc_driver_version = IAVF_DRIVER_VERSION_STRING,
.isc_driver = &ixlv_if_driver,
+ .isc_flags = IFLIB_NEED_SCRATCH | IFLIB_NEED_ZERO_CSUM | IFLIB_IS_VF,
.isc_nrxd_min = {IXL_MIN_RING},
.isc_ntxd_min = {IXL_MIN_RING},
@@ -288,64 +274,82 @@ static struct if_shared_ctx ixlv_sctx_init = {
if_shared_ctx_t ixlv_sctx = &ixlv_sctx_init;
/*** Functions ***/
-
static void *
ixlv_register(device_t dev)
{
return (ixlv_sctx);
- }
+}
+
+static int
+ixlv_allocate_pci_resources(struct ixlv_sc *sc)
+{
+ struct i40e_hw *hw = &sc->hw;
+ device_t dev = iflib_get_dev(sc->vsi.ctx);
+ int rid;
+
+ /* Map BAR0 */
+ rid = PCIR_BAR(0);
+ sc->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &rid, RF_ACTIVE);
+
+ if (!(sc->pci_mem)) {
+ device_printf(dev, "Unable to allocate bus resource: PCI memory\n");
+ return (ENXIO);
+ }
+
+ /* Save off the PCI information */
+ hw->vendor_id = pci_get_vendor(dev);
+ hw->device_id = pci_get_device(dev);
+ hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
+ hw->subsystem_vendor_id =
+ pci_read_config(dev, PCIR_SUBVEND_0, 2);
+ hw->subsystem_device_id =
+ pci_read_config(dev, PCIR_SUBDEV_0, 2);
+
+ hw->bus.device = pci_get_slot(dev);
+ hw->bus.func = pci_get_function(dev);
+
+ /* Save off register access information */
+ sc->osdep.mem_bus_space_tag =
+ rman_get_bustag(sc->pci_mem);
+ sc->osdep.mem_bus_space_handle =
+ rman_get_bushandle(sc->pci_mem);
+ sc->osdep.mem_bus_space_size = rman_get_size(sc->pci_mem);
+ sc->osdep.flush_reg = I40E_VFGEN_RSTAT;
+ sc->osdep.dev = dev;
+
+ sc->hw.hw_addr = (u8 *) &sc->osdep.mem_bus_space_handle;
+ sc->hw.back = &sc->osdep;
+
+ return (0);
+}
static int
ixlv_if_attach_pre(if_ctx_t ctx)
{
device_t dev;
- struct ixlv_sc *sc;
- struct i40e_hw *hw;
- struct ixl_vsi *vsi;
+ struct ixlv_sc *sc;
+ struct i40e_hw *hw;
+ struct ixl_vsi *vsi;
if_softc_ctx_t scctx;
int error = 0;
- INIT_DBG_DEV(dev, "begin");
-
dev = iflib_get_dev(ctx);
sc = iflib_get_softc(ctx);
- hw = &sc->hw;
- /*
- ** Note this assumes we have a single embedded VSI,
- ** this could be enhanced later to allocate multiple
- */
+
vsi = &sc->vsi;
- vsi->dev = dev;
vsi->back = sc;
+ sc->dev = dev;
+ hw = &sc->hw;
+
+ vsi->dev = dev;
vsi->hw = &sc->hw;
- // vsi->id = 0;
vsi->num_vlans = 0;
vsi->ctx = ctx;
vsi->media = iflib_get_media(ctx);
vsi->shared = scctx = iflib_get_softc_ctx(ctx);
- sc->dev = dev;
- /* Initialize hw struct */
- ixlv_init_hw(sc);
- /*
- * These are the same across all current ixl models
- */
- vsi->shared->isc_tx_nsegments = IXL_MAX_TX_SEGS;
- vsi->shared->isc_msix_bar = PCIR_BAR(IXL_MSIX_BAR);
- vsi->shared->isc_tx_tso_segments_max = IXL_MAX_TSO_SEGS;
- vsi->shared->isc_tx_tso_size_max = IXL_TSO_SIZE;
- vsi->shared->isc_tx_tso_segsize_max = PAGE_SIZE;
-
- /* Save this tunable */
- vsi->enable_head_writeback = ixlv_enable_head_writeback;
-
- scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0]
- * sizeof(struct i40e_tx_desc) + sizeof(u32), DBA_ALIGN);
- scctx->isc_rxqsizes[0] = roundup2(scctx->isc_nrxd[0]
- * sizeof(union i40e_32byte_rx_desc), DBA_ALIGN);
- /* XXX: No idea what this does */
- /* TODO: This value may depend on resources received */
- scctx->isc_max_txqsets = scctx->isc_max_rxqsets = 16;
+ ixlv_save_tunables(sc);
/* Do PCI setup - map BAR0, etc */
if (ixlv_allocate_pci_resources(sc)) {
@@ -355,9 +359,12 @@ ixlv_if_attach_pre(if_ctx_t ctx)
goto err_early;
}
- INIT_DBG_DEV(dev, "Allocated PCI resources and MSIX vectors");
+ ixlv_dbg_init(sc, "Allocated PCI resources and MSIX vectors\n");
- /* XXX: This is called by init_shared_code in the PF driver */
+ /*
+ * XXX: This is called by init_shared_code in the PF driver,
+ * but the rest of that function does not support VFs.
+ */
error = i40e_set_mac_type(hw);
if (error) {
device_printf(dev, "%s: set_mac_type failed: %d\n",
@@ -372,7 +379,7 @@ ixlv_if_attach_pre(if_ctx_t ctx)
goto err_pci_res;
}
- INIT_DBG_DEV(dev, "VF Device is ready for configuration");
+ ixlv_dbg_init(sc, "VF Device is ready for configuration\n");
/* Sets up Admin Queue */
error = ixlv_setup_vc(sc);
@@ -382,7 +389,7 @@ ixlv_if_attach_pre(if_ctx_t ctx)
goto err_pci_res;
}
- INIT_DBG_DEV(dev, "PF API version verified");
+ ixlv_dbg_init(sc, "PF API version verified\n");
/* Need API version before sending reset message */
error = ixlv_reset(sc);
@@ -391,7 +398,7 @@ ixlv_if_attach_pre(if_ctx_t ctx)
goto err_aq;
}
- INIT_DBG_DEV(dev, "VF reset complete");
+ ixlv_dbg_init(sc, "VF reset complete\n");
/* Ask for VF config from PF */
error = ixlv_vf_config(sc);
@@ -407,13 +414,12 @@ ixlv_if_attach_pre(if_ctx_t ctx)
sc->vf_res->max_vectors,
sc->vf_res->rss_key_size,
sc->vf_res->rss_lut_size);
-#ifdef IXL_DEBUG
- device_printf(dev, "Offload flags: 0x%b\n",
- sc->vf_res->vf_offload_flags, IXLV_PRINTF_VF_OFFLOAD_FLAGS);
-#endif
+ ixlv_dbg_info(sc, "Capabilities=%b\n",
+ sc->vf_res->vf_cap_flags, IXLV_PRINTF_VF_OFFLOAD_FLAGS);
/* got VF config message back from PF, now we can parse it */
for (int i = 0; i < sc->vf_res->num_vsis; i++) {
+ /* XXX: We only use the first VSI we find */
if (sc->vf_res->vsi_res[i].vsi_type == I40E_VSI_SRIOV)
sc->vsi_res = &sc->vf_res->vsi_res[i];
}
@@ -424,7 +430,7 @@ ixlv_if_attach_pre(if_ctx_t ctx)
}
vsi->id = sc->vsi_res->vsi_id;
- INIT_DBG_DEV(dev, "Resource Acquisition complete");
+ ixlv_dbg_init(sc, "Resource Acquisition complete\n");
/* If no mac address was assigned just make a random one */
if (!ixlv_check_ether_addr(hw->mac.addr)) {
@@ -437,30 +443,41 @@ ixlv_if_attach_pre(if_ctx_t ctx)
bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
iflib_set_mac(ctx, hw->mac.addr);
- // TODO: Is this still safe to call?
- // ixl_vsi_setup_rings_size(vsi, ixlv_tx_ring_size, ixlv_rx_ring_size);
-
/* Allocate filter lists */
ixlv_init_filters(sc);
/* Fill out more iflib parameters */
- scctx->isc_txrx = &ixl_txrx;
- // TODO: Probably needs changing
- vsi->shared->isc_rss_table_size = sc->hw.func_caps.rss_table_size;
+ scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max =
+ sc->vsi_res->num_queue_pairs;
+ if (vsi->enable_head_writeback) {
+ scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0]
+ * sizeof(struct i40e_tx_desc) + sizeof(u32), DBA_ALIGN);
+ scctx->isc_txrx = &ixl_txrx_hwb;
+ } else {
+ scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0]
+ * sizeof(struct i40e_tx_desc), DBA_ALIGN);
+ scctx->isc_txrx = &ixl_txrx_dwb;
+ }
+ scctx->isc_rxqsizes[0] = roundup2(scctx->isc_nrxd[0]
+ * sizeof(union i40e_32byte_rx_desc), DBA_ALIGN);
+ scctx->isc_msix_bar = PCIR_BAR(IXL_MSIX_BAR);
+ scctx->isc_tx_nsegments = IXL_MAX_TX_SEGS;
+ scctx->isc_tx_tso_segments_max = IXL_MAX_TSO_SEGS;
+ scctx->isc_tx_tso_size_max = IXL_TSO_SIZE;
+ scctx->isc_tx_tso_segsize_max = IXL_MAX_DMA_SEG_SIZE;
+ scctx->isc_rss_table_size = IXL_RSS_VSI_LUT_SIZE;
scctx->isc_tx_csum_flags = CSUM_OFFLOAD;
scctx->isc_capabilities = scctx->isc_capenable = IXL_CAPS;
- INIT_DBG_DEV(dev, "end");
return (0);
+
err_res_buf:
- free(sc->vf_res, M_DEVBUF);
+ free(sc->vf_res, M_IXLV);
err_aq:
i40e_shutdown_adminq(hw);
err_pci_res:
ixlv_free_pci_resources(sc);
err_early:
- ixlv_free_filters(sc);
- INIT_DBG_DEV(dev, "end: error %d", error);
return (error);
}
@@ -476,57 +493,52 @@ ixlv_if_attach_post(if_ctx_t ctx)
INIT_DBG_DEV(dev, "begin");
dev = iflib_get_dev(ctx);
- vsi = iflib_get_softc(ctx);
+ sc = iflib_get_softc(ctx);
+ vsi = &sc->vsi;
vsi->ifp = iflib_get_ifp(ctx);
- sc = (struct ixlv_sc *)vsi->back;
hw = &sc->hw;
+ /* Save off determined number of queues for interface */
+ vsi->num_rx_queues = vsi->shared->isc_nrxqsets;
+ vsi->num_tx_queues = vsi->shared->isc_ntxqsets;
+
/* Setup the stack interface */
- if (ixlv_setup_interface(dev, sc) != 0) {
- device_printf(dev, "%s: setup interface failed!\n",
- __func__);
- error = EIO;
- goto out;
- }
+ ixlv_setup_interface(dev, sc);
INIT_DBG_DEV(dev, "Interface setup complete");
/* Initialize statistics & add sysctls */
bzero(&sc->vsi.eth_stats, sizeof(struct i40e_eth_stats));
- ixlv_add_sysctls(sc);
+ ixlv_add_device_sysctls(sc);
+
+ sc->init_state = IXLV_INIT_READY;
+ atomic_store_rel_32(&sc->queues_enabled, 0);
- /* We want AQ enabled early */
+ /* We want AQ enabled early for init */
ixlv_enable_adminq_irq(hw);
+
INIT_DBG_DEV(dev, "end");
+
return (error);
-// TODO: Check if any failures can happen above
-#if 0
-out:
- free(sc->vf_res, M_DEVBUF);
- i40e_shutdown_adminq(hw);
- ixlv_free_pci_resources(sc);
- ixlv_free_filters(sc);
- INIT_DBG_DEV(dev, "end: error %d", error);
- return (error);
-#endif
}
+/**
+ * XXX: iflib always ignores the return value of detach()
+ * -> This means that this isn't allowed to fail
+ */
static int
ixlv_if_detach(if_ctx_t ctx)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
- struct ixlv_sc *sc = vsi->back;
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ struct ixl_vsi *vsi = &sc->vsi;
struct i40e_hw *hw = &sc->hw;
- device_t dev = sc->dev;
+ device_t dev = sc->dev;
enum i40e_status_code status;
INIT_DBG_DEV(dev, "begin");
/* Remove all the media and link information */
- ifmedia_removeall(&sc->media);
-
- /* Drain VC mgr */
- callout_drain(&sc->vc_mgr.callout);
+ ifmedia_removeall(vsi->media);
ixlv_disable_adminq_irq(hw);
status = i40e_shutdown_adminq(&sc->hw);
@@ -536,7 +548,7 @@ ixlv_if_detach(if_ctx_t ctx)
i40e_stat_str(hw, status));
}
- free(sc->vf_res, M_DEVBUF);
+ free(sc->vf_res, M_IXLV);
ixlv_free_pci_resources(sc);
ixlv_free_filters(sc);
@@ -544,411 +556,157 @@ ixlv_if_detach(if_ctx_t ctx)
return (0);
}
-/* TODO: Do shutdown-specific stuff here */
static int
ixlv_if_shutdown(if_ctx_t ctx)
{
- int error = 0;
-
- INIT_DBG_DEV(dev, "begin");
-
- /* TODO: Call ixl_if_stop()? */
-
- return (error);
+ return (0);
}
-/* TODO: What is a VF supposed to do in suspend/resume? */
static int
ixlv_if_suspend(if_ctx_t ctx)
{
- int error = 0;
-
- INIT_DBG_DEV(dev, "begin");
-
- /* TODO: Call ixl_if_stop()? */
-
- return (error);
+ return (0);
}
static int
ixlv_if_resume(if_ctx_t ctx)
{
- struct ifnet *ifp = iflib_get_ifp(ctx);
-
- INIT_DBG_DEV(dev, "begin");
-
- /* Read & clear wake-up registers */
-
- /* Required after D3->D0 transition */
- if (ifp->if_flags & IFF_UP)
- ixlv_if_init(ctx);
-
return (0);
}
-#if 0
static int
-ixlv_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
-{
- struct ixl_vsi *vsi = ifp->if_softc;
- struct ixlv_sc *sc = vsi->back;
- struct ifreq *ifr = (struct ifreq *)data;
-#if defined(INET) || defined(INET6)
- struct ifaddr *ifa = (struct ifaddr *)data;
- bool avoid_reset = FALSE;
-#endif
- int error = 0;
-
-
- switch (command) {
-
- case SIOCSIFADDR:
-#ifdef INET
- if (ifa->ifa_addr->sa_family == AF_INET)
- avoid_reset = TRUE;
-#endif
-#ifdef INET6
- if (ifa->ifa_addr->sa_family == AF_INET6)
- avoid_reset = TRUE;
-#endif
-#if defined(INET) || defined(INET6)
- /*
- ** Calling init results in link renegotiation,
- ** so we avoid doing it when possible.
- */
- if (avoid_reset) {
- ifp->if_flags |= IFF_UP;
- if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
- ixlv_init(vsi);
-#ifdef INET
- if (!(ifp->if_flags & IFF_NOARP))
- arp_ifinit(ifp, ifa);
-#endif
- } else
- error = ether_ioctl(ifp, command, data);
- break;
-#endif
- case SIOCSIFMTU:
- IOCTL_DBG_IF2(ifp, "SIOCSIFMTU (Set Interface MTU)");
- mtx_lock(&sc->mtx);
- if (ifr->ifr_mtu > IXL_MAX_FRAME -
- ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) {
- error = EINVAL;
- IOCTL_DBG_IF(ifp, "mtu too large");
- } else {
- IOCTL_DBG_IF2(ifp, "mtu: %lu -> %d", (u_long)ifp->if_mtu, ifr->ifr_mtu);
- // ERJ: Interestingly enough, these types don't match
- ifp->if_mtu = (u_long)ifr->ifr_mtu;
- vsi->max_frame_size =
- ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
- + ETHER_VLAN_ENCAP_LEN;
- if (ifp->if_drv_flags & IFF_DRV_RUNNING)
- ixlv_init_locked(sc);
- }
- mtx_unlock(&sc->mtx);
- break;
- case SIOCSIFFLAGS:
- IOCTL_DBG_IF2(ifp, "SIOCSIFFLAGS (Set Interface Flags)");
- mtx_lock(&sc->mtx);
- if (ifp->if_flags & IFF_UP) {
- if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
- ixlv_init_locked(sc);
- } else
- if (ifp->if_drv_flags & IFF_DRV_RUNNING)
- ixlv_stop(sc);
- sc->if_flags = ifp->if_flags;
- mtx_unlock(&sc->mtx);
- break;
- case SIOCADDMULTI:
- IOCTL_DBG_IF2(ifp, "SIOCADDMULTI");
- if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
- mtx_lock(&sc->mtx);
- ixlv_disable_intr(vsi);
- ixlv_add_multi(vsi);
- ixlv_enable_intr(vsi);
- mtx_unlock(&sc->mtx);
- }
- break;
- case SIOCDELMULTI:
- IOCTL_DBG_IF2(ifp, "SIOCDELMULTI");
- if (sc->init_state == IXLV_RUNNING) {
- mtx_lock(&sc->mtx);
- ixlv_disable_intr(vsi);
- ixlv_del_multi(vsi);
- ixlv_enable_intr(vsi);
- mtx_unlock(&sc->mtx);
- }
- break;
- case SIOCSIFMEDIA:
- case SIOCGIFMEDIA:
- IOCTL_DBG_IF2(ifp, "SIOCxIFMEDIA (Get/Set Interface Media)");
- error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
- break;
- case SIOCSIFCAP:
- {
- int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
- IOCTL_DBG_IF2(ifp, "SIOCSIFCAP (Set Capabilities)");
-
- ixlv_cap_txcsum_tso(vsi, ifp, mask);
-
- if (mask & IFCAP_RXCSUM)
- ifp->if_capenable ^= IFCAP_RXCSUM;
- if (mask & IFCAP_RXCSUM_IPV6)
- ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
- if (mask & IFCAP_LRO)
- ifp->if_capenable ^= IFCAP_LRO;
- if (mask & IFCAP_VLAN_HWTAGGING)
- ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
- if (mask & IFCAP_VLAN_HWFILTER)
- ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
- if (mask & IFCAP_VLAN_HWTSO)
- ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
- if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
- ixlv_init(vsi);
- }
- VLAN_CAPABILITIES(ifp);
+ixlv_send_vc_msg_sleep(struct ixlv_sc *sc, u32 op)
+{
+ int error = 0;
+ if_ctx_t ctx = sc->vsi.ctx;
- break;
+ error = ixl_vc_send_cmd(sc, op);
+ if (error != 0) {
+ ixlv_dbg_vc(sc, "Error sending %b: %d\n", op, IXLV_FLAGS, error);
+ return (error);
}
- default:
- IOCTL_DBG_IF2(ifp, "UNKNOWN (0x%X)", (int)command);
- error = ether_ioctl(ifp, command, data);
- break;
+ /* Don't wait for a response if the device is being detached. */
+ if (!iflib_in_detach(ctx)) {
+ ixlv_dbg_vc(sc, "Sleeping for op %b\n", op, IXLV_FLAGS);
+ error = sx_sleep(ixl_vc_get_op_chan(sc, op),
+ iflib_ctx_lock_get(ctx), PRI_MAX, "ixlvc", IXLV_AQ_TIMEOUT);
+
+ if (error == EWOULDBLOCK)
+ device_printf(sc->dev, "%b timed out\n", op, IXLV_FLAGS);
}
return (error);
}
-#endif
-/*
-** To do a reinit on the VF is unfortunately more complicated
-** than a physical device, we must have the PF more or less
-** completely recreate our memory, so many things that were
-** done only once at attach in traditional drivers now must be
-** redone at each reinitialization. This function does that
-** 'prelude' so we can then call the normal locked init code.
-*/
-int
-ixlv_reinit_locked(struct ixlv_sc *sc)
+static int
+ixlv_send_vc_msg(struct ixlv_sc *sc, u32 op)
{
- struct i40e_hw *hw = &sc->hw;
- struct ixl_vsi *vsi = &sc->vsi;
- struct ifnet *ifp = vsi->ifp;
- struct ixlv_mac_filter *mf, *mf_temp;
- struct ixlv_vlan_filter *vf;
- int error = 0;
-
- INIT_DBG_IF(ifp, "begin");
-
- if (ifp->if_drv_flags & IFF_DRV_RUNNING)
- ixlv_stop(sc);
-
- error = ixlv_reset(sc);
-
- INIT_DBG_IF(ifp, "VF was reset");
-
- /* set the state in case we went thru RESET */
- sc->init_state = IXLV_RUNNING;
-
- /*
- ** Resetting the VF drops all filters from hardware;
- ** we need to mark them to be re-added in init.
- */
- SLIST_FOREACH_SAFE(mf, sc->mac_filters, next, mf_temp) {
- if (mf->flags & IXL_FILTER_DEL) {
- SLIST_REMOVE(sc->mac_filters, mf,
- ixlv_mac_filter, next);
- free(mf, M_DEVBUF);
- } else
- mf->flags |= IXL_FILTER_ADD;
- }
- if (vsi->num_vlans != 0)
- SLIST_FOREACH(vf, sc->vlan_filters, next)
- vf->flags = IXL_FILTER_ADD;
- else { /* clean any stale filters */
- while (!SLIST_EMPTY(sc->vlan_filters)) {
- vf = SLIST_FIRST(sc->vlan_filters);
- SLIST_REMOVE_HEAD(sc->vlan_filters, next);
- free(vf, M_DEVBUF);
- }
- }
+ int error = 0;
- ixlv_enable_adminq_irq(hw);
- ixl_vc_flush(&sc->vc_mgr);
+ error = ixl_vc_send_cmd(sc, op);
+ if (error != 0)
+ ixlv_dbg_vc(sc, "Error sending %b: %d\n", op, IXLV_FLAGS, error);
- INIT_DBG_IF(ifp, "end");
return (error);
}
static void
-ixl_init_cmd_complete(struct ixl_vc_cmd *cmd, void *arg,
- enum i40e_status_code code)
+ixlv_init_queues(struct ixl_vsi *vsi)
{
- struct ixlv_sc *sc;
+ if_softc_ctx_t scctx = vsi->shared;
+ struct ixl_tx_queue *tx_que = vsi->tx_queues;
+ struct ixl_rx_queue *rx_que = vsi->rx_queues;
+ struct rx_ring *rxr;
- sc = arg;
+ for (int i = 0; i < vsi->num_tx_queues; i++, tx_que++)
+ ixl_init_tx_ring(vsi, tx_que);
- /*
- * Ignore "Adapter Stopped" message as that happens if an ifconfig down
- * happens while a command is in progress, so we don't print an error
- * in that case.
- */
- if (code != I40E_SUCCESS && code != I40E_ERR_ADAPTER_STOPPED) {
- if_printf(sc->vsi.ifp,
- "Error %s waiting for PF to complete operation %d\n",
- i40e_stat_str(&sc->hw, code), cmd->request);
+ for (int i = 0; i < vsi->num_rx_queues; i++, rx_que++) {
+ rxr = &rx_que->rxr;
+
+ if (scctx->isc_max_frame_size <= MCLBYTES)
+ rxr->mbuf_sz = MCLBYTES;
+ else
+ rxr->mbuf_sz = MJUMPAGESIZE;
+
+ wr32(vsi->hw, rxr->tail, 0);
}
}
void
ixlv_if_init(if_ctx_t ctx)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
- if_softc_ctx_t scctx = vsi->shared;
- struct ixlv_sc *sc = vsi->back;
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ struct ixl_vsi *vsi = &sc->vsi;
struct i40e_hw *hw = &sc->hw;
struct ifnet *ifp = iflib_get_ifp(ctx);
- struct ixl_tx_queue *tx_que = vsi->tx_queues;
- struct ixl_rx_queue *rx_que = vsi->rx_queues;
-
+ u8 tmpaddr[ETHER_ADDR_LEN];
int error = 0;
INIT_DBG_IF(ifp, "begin");
- IXLV_CORE_LOCK_ASSERT(sc);
+ MPASS(sx_xlocked(iflib_ctx_lock_get(ctx)));
- /* Do a reinit first if an init has already been done */
- if ((sc->init_state == IXLV_RUNNING) ||
- (sc->init_state == IXLV_RESET_REQUIRED) ||
- (sc->init_state == IXLV_RESET_PENDING))
- error = ixlv_reinit_locked(sc);
- /* Don't bother with init if we failed reinit */
- if (error)
- goto init_done;
+ error = ixlv_reset_complete(hw);
+ if (error) {
+ device_printf(sc->dev, "%s: VF reset failed\n",
+ __func__);
+ }
- /* Remove existing MAC filter if new MAC addr is set */
- if (bcmp(IF_LLADDR(ifp), hw->mac.addr, ETHER_ADDR_LEN) != 0) {
- error = ixlv_del_mac_filter(sc, hw->mac.addr);
- if (error == 0)
- ixl_vc_enqueue(&sc->vc_mgr, &sc->del_mac_cmd,
- IXLV_FLAG_AQ_DEL_MAC_FILTER, ixl_init_cmd_complete,
- sc);
+ if (!i40e_check_asq_alive(hw)) {
+ ixlv_dbg_info(sc, "ASQ is not alive, re-initializing AQ\n");
+ pci_enable_busmaster(sc->dev);
+ i40e_shutdown_adminq(hw);
+ i40e_init_adminq(hw);
}
- /* Check for an LAA mac address... */
- bcopy(IF_LLADDR(ifp), hw->mac.addr, ETHER_ADDR_LEN);
+ /* Make sure queues are disabled */
+ ixlv_send_vc_msg(sc, IXLV_FLAG_AQ_DISABLE_QUEUES);
- /* Add mac filter for this VF to PF */
- if (i40e_validate_mac_addr(hw->mac.addr) == I40E_SUCCESS) {
- error = ixlv_add_mac_filter(sc, hw->mac.addr, 0);
- if (!error || error == EEXIST)
- ixl_vc_enqueue(&sc->vc_mgr, &sc->add_mac_cmd,
- IXLV_FLAG_AQ_ADD_MAC_FILTER, ixl_init_cmd_complete,
- sc);
+ bcopy(IF_LLADDR(ifp), tmpaddr, ETHER_ADDR_LEN);
+ if (!cmp_etheraddr(hw->mac.addr, tmpaddr) &&
+ (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) {
+ error = ixlv_del_mac_filter(sc, hw->mac.addr);
+ if (error == 0)
+ ixlv_send_vc_msg(sc, IXLV_FLAG_AQ_DEL_MAC_FILTER);
+
+ bcopy(tmpaddr, hw->mac.addr, ETH_ALEN);
}
- /* Setup vlan's if needed */
- ixlv_setup_vlan_filters(sc);
+ error = ixlv_add_mac_filter(sc, hw->mac.addr, 0);
+ if (!error || error == EEXIST)
+ ixlv_send_vc_msg(sc, IXLV_FLAG_AQ_ADD_MAC_FILTER);
+ iflib_set_mac(ctx, hw->mac.addr);
- // TODO: Functionize
/* Prepare the queues for operation */
- for (int i = 0; i < vsi->num_tx_queues; i++, tx_que++) {
- // TODO: Necessary? Correct?
- ixl_init_tx_ring(vsi, tx_que);
- }
- for (int i = 0; i < vsi->num_rx_queues; i++, rx_que++) {
- struct rx_ring *rxr = &rx_que->rxr;
-
- if (scctx->isc_max_frame_size <= MCLBYTES)
- rxr->mbuf_sz = MCLBYTES;
- else
- rxr->mbuf_sz = MJUMPAGESIZE;
- }
+ ixlv_init_queues(vsi);
/* Set initial ITR values */
ixlv_configure_itr(sc);
- /* Configure queues */
- ixl_vc_enqueue(&sc->vc_mgr, &sc->config_queues_cmd,
- IXLV_FLAG_AQ_CONFIGURE_QUEUES, ixl_init_cmd_complete, sc);
+ ixlv_send_vc_msg(sc, IXLV_FLAG_AQ_CONFIGURE_QUEUES);
/* Set up RSS */
ixlv_config_rss(sc);
/* Map vectors */
- ixl_vc_enqueue(&sc->vc_mgr, &sc->map_vectors_cmd,
- IXLV_FLAG_AQ_MAP_VECTORS, ixl_init_cmd_complete, sc);
-
- /* Enable queues */
- ixl_vc_enqueue(&sc->vc_mgr, &sc->enable_queues_cmd,
- IXLV_FLAG_AQ_ENABLE_QUEUES, ixl_init_cmd_complete, sc);
-
- sc->init_state = IXLV_RUNNING;
+ ixlv_send_vc_msg(sc, IXLV_FLAG_AQ_MAP_VECTORS);
-init_done:
- INIT_DBG_IF(ifp, "end");
- return;
-}
-
-#if 0
-void
-ixlv_init(void *arg)
-{
- struct ixl_vsi *vsi = (struct ixl_vsi *)arg;
- struct ixlv_sc *sc = vsi->back;
- int retries = 0;
-
- /* Prevent init from running again while waiting for AQ calls
- * made in init_locked() to complete. */
- mtx_lock(&sc->mtx);
- if (sc->init_in_progress) {
- mtx_unlock(&sc->mtx);
- return;
- } else
- sc->init_in_progress = true;
-
- ixlv_init_locked(sc);
- mtx_unlock(&sc->mtx);
-
- /* Wait for init_locked to finish */
- while (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)
- && ++retries < IXLV_MAX_INIT_WAIT) {
- i40e_msec_pause(25);
- }
- if (retries >= IXLV_MAX_INIT_WAIT) {
- if_printf(vsi->ifp,
- "Init failed to complete in allotted time!\n");
- }
+ /* Init SW TX ring indices */
+ if (vsi->enable_head_writeback)
+ ixl_init_tx_cidx(vsi);
+ else
+ ixl_init_tx_rsqs(vsi);
- mtx_lock(&sc->mtx);
- sc->init_in_progress = false;
- mtx_unlock(&sc->mtx);
-}
+ /* Configure promiscuous mode */
+ ixlv_if_promisc_set(ctx, if_getflags(ifp));
-/*
- * ixlv_attach() helper function; gathers information about
- * the (virtual) hardware for use elsewhere in the driver.
- */
-static void
-ixlv_init_hw(struct ixlv_sc *sc)
-{
- struct i40e_hw *hw = &sc->hw;
- device_t dev = sc->dev;
-
- /* Save off the information about this board */
- hw->vendor_id = pci_get_vendor(dev);
- hw->device_id = pci_get_device(dev);
- hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
- hw->subsystem_vendor_id =
- pci_read_config(dev, PCIR_SUBVEND_0, 2);
- hw->subsystem_device_id =
- pci_read_config(dev, PCIR_SUBDEV_0, 2);
+ /* Enable queues */
+ ixlv_send_vc_msg_sleep(sc, IXLV_FLAG_AQ_ENABLE_QUEUES);
- hw->bus.device = pci_get_slot(dev);
- hw->bus.func = pci_get_function(dev);
+ sc->init_state = IXLV_RUNNING;
}
-#endif
/*
* ixlv_attach() helper function; initalizes the admin queue
@@ -980,7 +738,7 @@ ixlv_setup_vc(struct ixlv_sc *sc)
continue;
}
- INIT_DBG_DEV(dev, "Initialized Admin Queue; starting"
+ ixlv_dbg_init(sc, "Initialized Admin Queue; starting"
" send_api_ver attempt %d", i+1);
retry_send:
@@ -1009,7 +767,7 @@ retry_send:
if (asq_retries > IXLV_AQ_MAX_ERR)
continue;
- INIT_DBG_DEV(dev, "Sent API version message to PF");
+ ixlv_dbg_init(sc, "Sent API version message to PF");
/* Verify that the VF accepts the PF's API version */
error = ixlv_verify_api_ver(sc);
@@ -1076,13 +834,13 @@ retry_config:
i40e_msec_pause(10);
}
- INIT_DBG_DEV(dev, "Sent VF config message to PF, attempt %d",
+ ixlv_dbg_init(sc, "Sent VF config message to PF, attempt %d\n",
retried + 1);
if (!sc->vf_res) {
bufsz = sizeof(struct virtchnl_vf_resource) +
(I40E_MAX_VF_VSI * sizeof(struct virtchnl_vsi_resource));
- sc->vf_res = malloc(bufsz, M_DEVBUF, M_NOWAIT);
+ sc->vf_res = malloc(bufsz, M_IXLV, M_NOWAIT);
if (!sc->vf_res) {
device_printf(dev,
"%s: Unable to allocate memory for VF configuration"
@@ -1113,7 +871,7 @@ retry_config:
goto done;
fail:
- free(sc->vf_res, M_DEVBUF);
+ free(sc->vf_res, M_IXLV);
done:
return (ret_error);
}
@@ -1121,53 +879,65 @@ done:
static int
ixlv_if_msix_intr_assign(if_ctx_t ctx, int msix)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
- struct ixlv_sc *sc = vsi->back;
- struct ixl_rx_queue *que = vsi->rx_queues;
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ struct ixl_vsi *vsi = &sc->vsi;
+ struct ixl_rx_queue *rx_que = vsi->rx_queues;
struct ixl_tx_queue *tx_que = vsi->tx_queues;
int err, i, rid, vector = 0;
char buf[16];
+ MPASS(vsi->shared->isc_nrxqsets > 0);
+ MPASS(vsi->shared->isc_ntxqsets > 0);
+
/* Admin Que is vector 0*/
rid = vector + 1;
-
err = iflib_irq_alloc_generic(ctx, &vsi->irq, rid, IFLIB_INTR_ADMIN,
- ixlv_msix_adminq, sc, 0, "aq");
+ ixlv_msix_adminq, sc, 0, "aq");
if (err) {
iflib_irq_free(ctx, &vsi->irq);
- device_printf(iflib_get_dev(ctx), "Failed to register Admin que handler");
+ device_printf(iflib_get_dev(ctx),
+ "Failed to register Admin Que handler");
return (err);
}
- sc->admvec = vector;
- ++vector;
/* Now set up the stations */
- for (i = 0; i < vsi->num_rx_queues; i++, vector++, que++) {
+ for (i = 0, vector = 1; i < vsi->shared->isc_nrxqsets; i++, vector++, rx_que++) {
rid = vector + 1;
snprintf(buf, sizeof(buf), "rxq%d", i);
- err = iflib_irq_alloc_generic(ctx, &que->que_irq, rid, IFLIB_INTR_RX,
- ixlv_msix_que, que, que->rxr.me, buf);
+ err = iflib_irq_alloc_generic(ctx, &rx_que->que_irq, rid,
+ IFLIB_INTR_RX, ixlv_msix_que, rx_que, rx_que->rxr.me, buf);
+ /* XXX: Does the driver work as expected if there are fewer num_rx_queues than
+ * what's expected in the iflib context? */
if (err) {
- device_printf(iflib_get_dev(ctx), "Failed to allocate q int %d err: %d", i, err);
+ device_printf(iflib_get_dev(ctx),
+ "Failed to allocate queue RX int vector %d, err: %d\n", i, err);
vsi->num_rx_queues = i + 1;
goto fail;
}
- que->msix = vector;
+ rx_que->msix = vector;
}
- for (i = 0, tx_que = vsi->tx_queues; i < vsi->num_tx_queues; i++, tx_que++) {
+ bzero(buf, sizeof(buf));
+
+ for (i = 0; i < vsi->shared->isc_ntxqsets; i++, tx_que++) {
snprintf(buf, sizeof(buf), "txq%d", i);
- rid = que->msix + 1;
- iflib_softirq_alloc_generic(ctx, rid, IFLIB_INTR_TX, tx_que, tx_que->txr.me, buf);
+ iflib_softirq_alloc_generic(ctx,
+ &vsi->rx_queues[i % vsi->shared->isc_nrxqsets].que_irq,
+ IFLIB_INTR_TX, tx_que, tx_que->txr.me, buf);
+
+ /* TODO: Maybe call a strategy function for this to figure out which
+ * interrupts to map Tx queues to. I don't know if there's an immediately
+ * better way than this other than a user-supplied map, though. */
+ tx_que->msix = (i % vsi->shared->isc_nrxqsets) + 1;
}
return (0);
fail:
iflib_irq_free(ctx, &vsi->irq);
- que = vsi->rx_queues;
- for (int i = 0; i < vsi->num_rx_queues; i++, que++)
- iflib_irq_free(ctx, &que->que_irq);
+ rx_que = vsi->rx_queues;
+ for (int i = 0; i < vsi->num_rx_queues; i++, rx_que++)
+ iflib_irq_free(ctx, &rx_que->que_irq);
return (err);
}
@@ -1175,7 +945,8 @@ fail:
static void
ixlv_if_enable_intr(if_ctx_t ctx)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ struct ixl_vsi *vsi = &sc->vsi;
ixlv_enable_intr(vsi);
}
@@ -1184,34 +955,48 @@ ixlv_if_enable_intr(if_ctx_t ctx)
static void
ixlv_if_disable_intr(if_ctx_t ctx)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ struct ixl_vsi *vsi = &sc->vsi;
ixlv_disable_intr(vsi);
}
-/* Enable queue interrupt */
static int
-ixlv_if_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid)
+ixlv_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
- struct i40e_hw *hw = vsi->hw;
- struct ixl_rx_queue *que = &vsi->rx_queues[rxqid];
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ struct ixl_vsi *vsi = &sc->vsi;
+ struct i40e_hw *hw = vsi->hw;
+ struct ixl_rx_queue *rx_que = &vsi->rx_queues[rxqid];
+
+ ixlv_enable_queue_irq(hw, rx_que->msix - 1);
+ return (0);
+}
- ixlv_enable_queue_irq(hw, que->rxr.me);
+static int
+ixlv_if_tx_queue_intr_enable(if_ctx_t ctx, uint16_t txqid)
+{
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ struct ixl_vsi *vsi = &sc->vsi;
+ struct i40e_hw *hw = vsi->hw;
+ struct ixl_tx_queue *tx_que = &vsi->tx_queues[txqid];
+ ixlv_enable_queue_irq(hw, tx_que->msix - 1);
return (0);
}
static int
ixlv_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntxqs, int ntxqsets)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ struct ixl_vsi *vsi = &sc->vsi;
+ if_softc_ctx_t scctx = vsi->shared;
struct ixl_tx_queue *que;
- int i;
+ int i, j, error = 0;
- MPASS(vsi->num_tx_queues > 0);
+ MPASS(scctx->isc_ntxqsets > 0);
MPASS(ntxqs == 1);
- MPASS(vsi->num_tx_queues == ntxqsets);
+ MPASS(scctx->isc_ntxqsets == ntxqsets);
/* Allocate queue structure memory */
if (!(vsi->tx_queues =
@@ -1222,40 +1007,56 @@ ixlv_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntx
for (i = 0, que = vsi->tx_queues; i < ntxqsets; i++, que++) {
struct tx_ring *txr = &que->txr;
+
txr->me = i;
que->vsi = vsi;
+ if (!vsi->enable_head_writeback) {
+ /* Allocate report status array */
+ if (!(txr->tx_rsq = malloc(sizeof(qidx_t) * scctx->isc_ntxd[0], M_IXLV, M_NOWAIT))) {
+ device_printf(iflib_get_dev(ctx), "failed to allocate tx_rsq memory\n");
+ error = ENOMEM;
+ goto fail;
+ }
+ /* Init report status array */
+ for (j = 0; j < scctx->isc_ntxd[0]; j++)
+ txr->tx_rsq[j] = QIDX_INVALID;
+ }
/* get the virtual and physical address of the hardware queues */
txr->tail = I40E_QTX_TAIL1(txr->me);
- txr->tx_base = (struct i40e_tx_desc *)vaddrs[i];
- txr->tx_paddr = paddrs[i];
+ txr->tx_base = (struct i40e_tx_desc *)vaddrs[i * ntxqs];
+ txr->tx_paddr = paddrs[i * ntxqs];
txr->que = que;
}
-
- // TODO: Do a config_gtask_init for admin queue here?
- // iflib_config_gtask_init(ctx, &adapter->mod_task, ixgbe_handle_mod, "mod_task");
- device_printf(iflib_get_dev(ctx), "%s: allocated for %d txqs\n", __func__, vsi->num_tx_queues);
return (0);
+fail:
+ ixlv_if_queues_free(ctx);
+ return (error);
}
static int
ixlv_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nrxqs, int nrxqsets)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ struct ixl_vsi *vsi = &sc->vsi;
struct ixl_rx_queue *que;
- int i;
+ int i, error = 0;
- MPASS(vsi->num_rx_queues > 0);
+#ifdef INVARIANTS
+ if_softc_ctx_t scctx = vsi->shared;
+ MPASS(scctx->isc_nrxqsets > 0);
MPASS(nrxqs == 1);
- MPASS(vsi->num_rx_queues == nrxqsets);
+ MPASS(scctx->isc_nrxqsets == nrxqsets);
+#endif
/* Allocate queue structure memory */
if (!(vsi->rx_queues =
(struct ixl_rx_queue *) malloc(sizeof(struct ixl_rx_queue) *
nrxqsets, M_IXLV, M_NOWAIT | M_ZERO))) {
device_printf(iflib_get_dev(ctx), "Unable to allocate RX ring memory\n");
- return (ENOMEM);
+ error = ENOMEM;
+ goto fail;
}
for (i = 0, que = vsi->rx_queues; i < nrxqsets; i++, que++) {
@@ -1266,19 +1067,35 @@ ixlv_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nrx
/* get the virtual and physical address of the hardware queues */
rxr->tail = I40E_QRX_TAIL1(rxr->me);
- rxr->rx_base = (union i40e_rx_desc *)vaddrs[i];
- rxr->rx_paddr = paddrs[i];
+ rxr->rx_base = (union i40e_rx_desc *)vaddrs[i * nrxqs];
+ rxr->rx_paddr = paddrs[i * nrxqs];
rxr->que = que;
}
- device_printf(iflib_get_dev(ctx), "%s: allocated for %d rxqs\n", __func__, vsi->num_rx_queues);
return (0);
+fail:
+ ixlv_if_queues_free(ctx);
+ return (error);
}
static void
ixlv_if_queues_free(if_ctx_t ctx)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ struct ixl_vsi *vsi = &sc->vsi;
+
+ if (!vsi->enable_head_writeback) {
+ struct ixl_tx_queue *que;
+ int i = 0;
+
+ for (i = 0, que = vsi->tx_queues; i < vsi->shared->isc_ntxqsets; i++, que++) {
+ struct tx_ring *txr = &que->txr;
+ if (txr->tx_rsq != NULL) {
+ free(txr->tx_rsq, M_IXLV);
+ txr->tx_rsq = NULL;
+ }
+ }
+ }
if (vsi->tx_queues != NULL) {
free(vsi->tx_queues, M_IXLV);
@@ -1290,274 +1107,237 @@ ixlv_if_queues_free(if_ctx_t ctx)
}
}
-// TODO: Implement
-static void
-ixlv_if_update_admin_status(if_ctx_t ctx)
+static int
+ixlv_check_aq_errors(struct ixlv_sc *sc)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
- //struct ixlv_sc *sc = vsi->back;
- //struct i40e_hw *hw = &sc->hw;
- //struct i40e_arq_event_info event;
- //i40e_status ret;
- //u32 loop = 0;
- //u16 opcode
- u16 result = 0;
- //u64 baudrate;
-
- /* TODO: Split up
- * - Update admin queue stuff
- * - Update link status
- * - Enqueue aq task
- * - Re-enable admin intr
- */
+ struct i40e_hw *hw = &sc->hw;
+ device_t dev = sc->dev;
+ u32 reg, oldreg;
+ u8 aq_error = false;
-/* TODO: Does VF reset need to be handled here? */
-#if 0
- if (pf->state & IXL_PF_STATE_EMPR_RESETTING) {
- /* Flag cleared at end of this function */
- ixl_handle_empr_reset(pf);
- return;
+ /* check for Admin queue errors */
+ oldreg = reg = rd32(hw, hw->aq.arq.len);
+ if (reg & I40E_VF_ARQLEN1_ARQVFE_MASK) {
+ device_printf(dev, "ARQ VF Error detected\n");
+ reg &= ~I40E_VF_ARQLEN1_ARQVFE_MASK;
+ aq_error = true;
}
-#endif
+ if (reg & I40E_VF_ARQLEN1_ARQOVFL_MASK) {
+ device_printf(dev, "ARQ Overflow Error detected\n");
+ reg &= ~I40E_VF_ARQLEN1_ARQOVFL_MASK;
+ aq_error = true;
+ }
+ if (reg & I40E_VF_ARQLEN1_ARQCRIT_MASK) {
+ device_printf(dev, "ARQ Critical Error detected\n");
+ reg &= ~I40E_VF_ARQLEN1_ARQCRIT_MASK;
+ aq_error = true;
+ }
+ if (oldreg != reg)
+ wr32(hw, hw->aq.arq.len, reg);
-#if 0
- event.buf_len = IXL_AQ_BUF_SZ;
- event.msg_buf = malloc(event.buf_len,
- M_IXLV, M_NOWAIT | M_ZERO);
- if (!event.msg_buf) {
- device_printf(pf->dev, "%s: Unable to allocate memory for Admin"
- " Queue event!\n", __func__);
- return;
+ oldreg = reg = rd32(hw, hw->aq.asq.len);
+ if (reg & I40E_VF_ATQLEN1_ATQVFE_MASK) {
+ device_printf(dev, "ASQ VF Error detected\n");
+ reg &= ~I40E_VF_ATQLEN1_ATQVFE_MASK;
+ aq_error = true;
+ }
+ if (reg & I40E_VF_ATQLEN1_ATQOVFL_MASK) {
+ device_printf(dev, "ASQ Overflow Error detected\n");
+ reg &= ~I40E_VF_ATQLEN1_ATQOVFL_MASK;
+ aq_error = true;
+ }
+ if (reg & I40E_VF_ATQLEN1_ATQCRIT_MASK) {
+ device_printf(dev, "ASQ Critical Error detected\n");
+ reg &= ~I40E_VF_ATQLEN1_ATQCRIT_MASK;
+ aq_error = true;
+ }
+ if (oldreg != reg)
+ wr32(hw, hw->aq.asq.len, reg);
+
+ if (aq_error) {
+ device_printf(dev, "WARNING: Stopping VF!\n");
+ /*
+ * A VF reset might not be enough to fix a problem here;
+ * a PF reset could be required.
+ */
+ sc->init_state = IXLV_RESET_REQUIRED;
+ ixlv_stop(sc);
+ ixlv_request_reset(sc);
}
+ return (aq_error ? EIO : 0);
+}
+
+static enum i40e_status_code
+ixlv_process_adminq(struct ixlv_sc *sc, u16 *pending)
+{
+ enum i40e_status_code status = I40E_SUCCESS;
+ struct i40e_arq_event_info event;
+ struct i40e_hw *hw = &sc->hw;
+ struct virtchnl_msg *v_msg;
+ int error = 0, loop = 0;
+ u32 reg;
+
+ error = ixlv_check_aq_errors(sc);
+ if (error)
+ return (I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR);
+
+ event.buf_len = IXL_AQ_BUF_SZ;
+ event.msg_buf = sc->aq_buffer;
+ bzero(event.msg_buf, IXL_AQ_BUF_SZ);
+ v_msg = (struct virtchnl_msg *)&event.desc;
+
/* clean and process any events */
do {
- ret = i40e_clean_arq_element(hw, &event, &result);
- if (ret)
- break;
- opcode = LE16_TO_CPU(event.desc.opcode);
- ixl_dbg(pf, IXL_DBG_AQ,
- "Admin Queue event: %#06x\n", opcode);
- switch (opcode) {
- case i40e_aqc_opc_get_link_status:
- ixl_link_event(pf, &event);
- break;
- case i40e_aqc_opc_send_msg_to_pf:
-#ifdef PCI_IOV
- ixl_handle_vf_msg(pf, &event);
-#endif
- break;
- case i40e_aqc_opc_event_lan_overflow:
- break;
- default:
-#ifdef IXL_DEBUG
- printf("AdminQ unknown event %x\n", opcode);
-#endif
+ status = i40e_clean_arq_element(hw, &event, pending);
+ /*
+ * Also covers normal case when i40e_clean_arq_element()
+ * returns "I40E_ERR_ADMIN_QUEUE_NO_WORK"
+ */
+ if (status)
break;
- }
+ ixlv_vc_completion(sc, v_msg->v_opcode,
+ v_msg->v_retval, event.msg_buf, event.msg_len);
+ bzero(event.msg_buf, IXL_AQ_BUF_SZ);
+ } while (*pending && (loop++ < IXL_ADM_LIMIT));
- } while (result && (loop++ < IXL_ADM_LIMIT));
+ /* Re-enable admin queue interrupt cause */
+ reg = rd32(hw, I40E_VFINT_ICR0_ENA1);
+ reg |= I40E_VFINT_ICR0_ENA1_ADMINQ_MASK;
+ wr32(hw, I40E_VFINT_ICR0_ENA1, reg);
- free(event.msg_buf, M_IXLV);
-#endif
+ return (status);
+}
-#if 0
- /* XXX: This updates the link status */
- if (pf->link_up) {
- if (vsi->link_active == FALSE) {
- vsi->link_active = TRUE;
- baudrate = ixl_max_aq_speed_to_value(pf->link_speed);
- iflib_link_state_change(ctx, LINK_STATE_UP, baudrate);
- ixl_link_up_msg(pf);
- // ixl_ping_all_vfs(adapter);
- }
- } else { /* Link down */
- if (vsi->link_active == TRUE) {
- vsi->link_active = FALSE;
- iflib_link_state_change(ctx, LINK_STATE_DOWN, 0);
- // ixl_ping_all_vfs(adapter);
- }
- }
-#endif
+static void
+ixlv_if_update_admin_status(if_ctx_t ctx)
+{
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ struct i40e_hw *hw = &sc->hw;
+ u16 pending;
+
+ ixlv_process_adminq(sc, &pending);
+ ixlv_update_link_status(sc);
/*
- * If there are still messages to process, reschedule ourselves.
- * Otherwise, re-enable our interrupt and go to sleep.
+ * If there are still messages to process, reschedule.
+ * Otherwise, re-enable the Admin Queue interrupt.
*/
- if (result > 0)
+ if (pending > 0)
iflib_admin_intr_deferred(ctx);
else
- /* TODO: Link/adminq interrupt should be re-enabled in IFDI_LINK_INTR_ENABLE */
- ixlv_enable_intr(vsi);
+ ixlv_enable_adminq_irq(hw);
+}
+
+static int
+ixlv_mc_filter_apply(void *arg, struct ifmultiaddr *ifma, int count __unused)
+{
+ struct ixlv_sc *sc = arg;
+ int error = 0;
+
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ return (0);
+ error = ixlv_add_mac_filter(sc,
+ (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr),
+ IXL_FILTER_MC);
+
+ return (!error);
}
static void
ixlv_if_multi_set(if_ctx_t ctx)
{
- // struct ixl_vsi *vsi = iflib_get_softc(ctx);
- // struct i40e_hw *hw = vsi->hw;
- // struct ixlv_sc *sc = vsi->back;
- // int mcnt = 0, flags;
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ int mcnt = 0;
- IOCTL_DEBUGOUT("ixl_if_multi_set: begin");
+ IOCTL_DEBUGOUT("ixlv_if_multi_set: begin");
- // TODO: Implement
-#if 0
mcnt = if_multiaddr_count(iflib_get_ifp(ctx), MAX_MULTICAST_ADDR);
- /* delete existing MC filters */
- ixlv_del_multi(vsi);
-
if (__predict_false(mcnt == MAX_MULTICAST_ADDR)) {
- // Set promiscuous mode (multicast)
- // TODO: This needs to get handled somehow
-#if 0
- ixl_vc_enqueue(&sc->vc_mgr, &sc->add_vlan_cmd,
- IXLV_FLAG_AQ_CONFIGURE_PROMISC, ixl_init_cmd_complete, sc);
-#endif
+ /* Delete MC filters and enable mulitcast promisc instead */
+ ixlv_init_multi(sc);
+ sc->promisc_flags |= FLAG_VF_MULTICAST_PROMISC;
+ ixlv_send_vc_msg(sc, IXLV_FLAG_AQ_CONFIGURE_PROMISC);
return;
}
- /* (re-)install filters for all mcast addresses */
- mcnt = if_multi_apply(iflib_get_ifp(ctx), ixl_mc_filter_apply, vsi);
-
- if (mcnt > 0) {
- flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC);
- ixlv_add_hw_filters(vsi, flags, mcnt);
- }
-#endif
- IOCTL_DEBUGOUT("ixl_if_multi_set: end");
+ /* If there aren't too many filters, delete existing MC filters */
+ ixlv_init_multi(sc);
+
+ /* And (re-)install filters for all mcast addresses */
+ mcnt = if_multi_apply(iflib_get_ifp(ctx), ixlv_mc_filter_apply, sc);
+
+ if (mcnt > 0)
+ ixlv_send_vc_msg(sc, IXLV_FLAG_AQ_ADD_MAC_FILTER);
+}
+
+static int
+ixlv_if_mtu_set(if_ctx_t ctx, uint32_t mtu)
+{
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ struct ixl_vsi *vsi = &sc->vsi;
+
+ IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)");
+ if (mtu > IXL_MAX_FRAME - ETHER_HDR_LEN - ETHER_CRC_LEN -
+ ETHER_VLAN_ENCAP_LEN)
+ return (EINVAL);
+
+ vsi->shared->isc_max_frame_size = mtu + ETHER_HDR_LEN + ETHER_CRC_LEN +
+ ETHER_VLAN_ENCAP_LEN;
+
+ return (0);
}
static void
ixlv_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
- struct ixlv_sc *sc = (struct ixlv_sc *)vsi->back;
- struct i40e_hw *hw = &sc->hw;
+#ifdef IXL_DEBUG
+ struct ifnet *ifp = iflib_get_ifp(ctx);
+#endif
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
- INIT_DEBUGOUT("ixl_media_status: begin");
+ INIT_DBG_IF(ifp, "begin");
- hw->phy.get_link_info = TRUE;
- i40e_get_link_status(hw, &sc->link_up);
+ ixlv_update_link_status(sc);
ifmr->ifm_status = IFM_AVALID;
ifmr->ifm_active = IFM_ETHER;
- if (!sc->link_up) {
+ if (!sc->link_up)
return;
- }
ifmr->ifm_status |= IFM_ACTIVE;
/* Hardware is always full-duplex */
ifmr->ifm_active |= IFM_FDX;
- // TODO: Check another variable to get link speed
-#if 0
- switch (hw->phy.link_info.phy_type) {
- /* 100 M */
- case I40E_PHY_TYPE_100BASE_TX:
- ifmr->ifm_active |= IFM_100_TX;
- break;
- /* 1 G */
- case I40E_PHY_TYPE_1000BASE_T:
- ifmr->ifm_active |= IFM_1000_T;
- break;
- case I40E_PHY_TYPE_1000BASE_SX:
- ifmr->ifm_active |= IFM_1000_SX;
- break;
- case I40E_PHY_TYPE_1000BASE_LX:
- ifmr->ifm_active |= IFM_1000_LX;
- break;
- case I40E_PHY_TYPE_1000BASE_T_OPTICAL:
- ifmr->ifm_active |= IFM_OTHER;
- break;
- /* 10 G */
- case I40E_PHY_TYPE_10GBASE_SFPP_CU:
- ifmr->ifm_active |= IFM_10G_TWINAX;
- break;
- case I40E_PHY_TYPE_10GBASE_SR:
- ifmr->ifm_active |= IFM_10G_SR;
- break;
- case I40E_PHY_TYPE_10GBASE_LR:
- ifmr->ifm_active |= IFM_10G_LR;
- break;
- case I40E_PHY_TYPE_10GBASE_T:
- ifmr->ifm_active |= IFM_10G_T;
- break;
- case I40E_PHY_TYPE_XAUI:
- case I40E_PHY_TYPE_XFI:
- case I40E_PHY_TYPE_10GBASE_AOC:
- ifmr->ifm_active |= IFM_OTHER;
- break;
- /* 25 G */
- case I40E_PHY_TYPE_25GBASE_KR:
- ifmr->ifm_active |= IFM_25G_KR;
- break;
- case I40E_PHY_TYPE_25GBASE_CR:
- ifmr->ifm_active |= IFM_25G_CR;
- break;
- case I40E_PHY_TYPE_25GBASE_SR:
- ifmr->ifm_active |= IFM_25G_SR;
- break;
- case I40E_PHY_TYPE_25GBASE_LR:
- ifmr->ifm_active |= IFM_UNKNOWN;
- break;
- /* 40 G */
- case I40E_PHY_TYPE_40GBASE_CR4:
- case I40E_PHY_TYPE_40GBASE_CR4_CU:
- ifmr->ifm_active |= IFM_40G_CR4;
- break;
- case I40E_PHY_TYPE_40GBASE_SR4:
- ifmr->ifm_active |= IFM_40G_SR4;
- break;
- case I40E_PHY_TYPE_40GBASE_LR4:
- ifmr->ifm_active |= IFM_40G_LR4;
- break;
- case I40E_PHY_TYPE_XLAUI:
- ifmr->ifm_active |= IFM_OTHER;
- break;
- case I40E_PHY_TYPE_1000BASE_KX:
- ifmr->ifm_active |= IFM_1000_KX;
- break;
- case I40E_PHY_TYPE_SGMII:
- ifmr->ifm_active |= IFM_1000_SGMII;
- break;
- /* ERJ: What's the difference between these? */
- case I40E_PHY_TYPE_10GBASE_CR1_CU:
- case I40E_PHY_TYPE_10GBASE_CR1:
- ifmr->ifm_active |= IFM_10G_CR1;
- break;
- case I40E_PHY_TYPE_10GBASE_KX4:
- ifmr->ifm_active |= IFM_10G_KX4;
- break;
- case I40E_PHY_TYPE_10GBASE_KR:
- ifmr->ifm_active |= IFM_10G_KR;
- break;
- case I40E_PHY_TYPE_SFI:
- ifmr->ifm_active |= IFM_10G_SFI;
- break;
- /* Our single 20G media type */
- case I40E_PHY_TYPE_20GBASE_KR2:
- ifmr->ifm_active |= IFM_20G_KR2;
- break;
- case I40E_PHY_TYPE_40GBASE_KR4:
- ifmr->ifm_active |= IFM_40G_KR4;
- break;
- case I40E_PHY_TYPE_XLPPI:
- case I40E_PHY_TYPE_40GBASE_AOC:
- ifmr->ifm_active |= IFM_40G_XLPPI;
- break;
- /* Unknown to driver */
- default:
- ifmr->ifm_active |= IFM_UNKNOWN;
- break;
+ /* Based on the link speed reported by the PF over the AdminQ, choose a
+ * PHY type to report. This isn't 100% correct since we don't really
+ * know the underlying PHY type of the PF, but at least we can report
+ * a valid link speed...
+ */
+ switch (sc->link_speed) {
+ case VIRTCHNL_LINK_SPEED_100MB:
+ ifmr->ifm_active |= IFM_100_TX;
+ break;
+ case VIRTCHNL_LINK_SPEED_1GB:
+ ifmr->ifm_active |= IFM_1000_T;
+ break;
+ case VIRTCHNL_LINK_SPEED_10GB:
+ ifmr->ifm_active |= IFM_10G_SR;
+ break;
+ case VIRTCHNL_LINK_SPEED_20GB:
+ case VIRTCHNL_LINK_SPEED_25GB:
+ ifmr->ifm_active |= IFM_25G_SR;
+ break;
+ case VIRTCHNL_LINK_SPEED_40GB:
+ ifmr->ifm_active |= IFM_40G_SR4;
+ break;
+ default:
+ ifmr->ifm_active |= IFM_UNKNOWN;
+ break;
}
- /* Report flow control status as well */
- if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX)
- ifmr->ifm_active |= IFM_ETH_TXPAUSE;
- if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)
- ifmr->ifm_active |= IFM_ETH_RXPAUSE;
- #endif
+
+ INIT_DBG_IF(ifp, "end");
}
static int
@@ -1574,57 +1354,44 @@ ixlv_if_media_change(if_ctx_t ctx)
return (ENODEV);
}
-// TODO: Rework
static int
ixlv_if_promisc_set(if_ctx_t ctx, int flags)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
struct ifnet *ifp = iflib_get_ifp(ctx);
- struct i40e_hw *hw = vsi->hw;
- int err;
- bool uni = FALSE, multi = FALSE;
+
+ sc->promisc_flags = 0;
if (flags & IFF_ALLMULTI ||
if_multiaddr_count(ifp, MAX_MULTICAST_ADDR) == MAX_MULTICAST_ADDR)
- multi = TRUE;
+ sc->promisc_flags |= FLAG_VF_MULTICAST_PROMISC;
if (flags & IFF_PROMISC)
- uni = TRUE;
+ sc->promisc_flags |= FLAG_VF_UNICAST_PROMISC;
- err = i40e_aq_set_vsi_unicast_promiscuous(hw,
- vsi->seid, uni, NULL, false);
- if (err)
- return (err);
- err = i40e_aq_set_vsi_multicast_promiscuous(hw,
- vsi->seid, multi, NULL);
- return (err);
+ ixlv_send_vc_msg(sc, IXLV_FLAG_AQ_CONFIGURE_PROMISC);
+
+ return (0);
}
static void
ixlv_if_timer(if_ctx_t ctx, uint16_t qid)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
- struct ixlv_sc *sc = vsi->back;
- //struct i40e_hw *hw = &sc->hw;
- //struct ixl_tx_queue *que = &vsi->tx_queues[qid];
- //u32 mask;
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ struct i40e_hw *hw = &sc->hw;
+ u32 val;
-#if 0
- /*
- ** Check status of the queues
- */
- mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK |
- I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK);
-
- /* If queue param has outstanding work, trigger sw irq */
- // TODO: TX queues in iflib don't use HW interrupts; does this do anything?
- if (que->busy)
- wr32(hw, I40E_PFINT_DYN_CTLN(que->txr.me), mask);
- #endif
-
- // XXX: Is this timer per-queue?
if (qid != 0)
return;
+ /* Check for when PF triggers a VF reset */
+ val = rd32(hw, I40E_VFGEN_RSTAT) &
+ I40E_VFGEN_RSTAT_VFR_STATE_MASK;
+ if (val != VIRTCHNL_VFR_VFACTIVE
+ && val != VIRTCHNL_VFR_COMPLETED) {
+ ixlv_dbg_info(sc, "reset in progress! (%d)\n", val);
+ return;
+ }
+
/* Fire off the adminq task */
iflib_admin_intr_deferred(ctx);
@@ -1635,35 +1402,49 @@ ixlv_if_timer(if_ctx_t ctx, uint16_t qid)
static void
ixlv_if_vlan_register(if_ctx_t ctx, u16 vtag)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
- //struct i40e_hw *hw = vsi->hw;
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ struct ixl_vsi *vsi = &sc->vsi;
+ struct ixlv_vlan_filter *v;
if ((vtag == 0) || (vtag > 4095)) /* Invalid */
return;
++vsi->num_vlans;
- // TODO: Redo
- // ixlv_add_filter(vsi, hw->mac.addr, vtag);
+ v = malloc(sizeof(struct ixlv_vlan_filter), M_IXLV, M_WAITOK | M_ZERO);
+ SLIST_INSERT_HEAD(sc->vlan_filters, v, next);
+ v->vlan = vtag;
+ v->flags = IXL_FILTER_ADD;
+
+ ixlv_send_vc_msg(sc, IXLV_FLAG_AQ_ADD_VLAN_FILTER);
}
static void
ixlv_if_vlan_unregister(if_ctx_t ctx, u16 vtag)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
- //struct i40e_hw *hw = vsi->hw;
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ struct ixl_vsi *vsi = &sc->vsi;
+ struct ixlv_vlan_filter *v;
+ int i = 0;
if ((vtag == 0) || (vtag > 4095)) /* Invalid */
return;
- --vsi->num_vlans;
- // TODO: Redo
- // ixlv_del_filter(vsi, hw->mac.addr, vtag);
+ SLIST_FOREACH(v, sc->vlan_filters, next) {
+ if (v->vlan == vtag) {
+ v->flags = IXL_FILTER_DEL;
+ ++i;
+ --vsi->num_vlans;
+ }
+ }
+ if (i)
+ ixlv_send_vc_msg(sc, IXLV_FLAG_AQ_DEL_VLAN_FILTER);
}
static uint64_t
ixlv_if_get_counter(if_ctx_t ctx, ift_counter cnt)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
+ struct ixl_vsi *vsi = &sc->vsi;
if_t ifp = iflib_get_ifp(ctx);
switch (cnt) {
@@ -1697,53 +1478,6 @@ ixlv_if_get_counter(if_ctx_t ctx, ift_counter cnt)
}
}
-static int
-ixlv_allocate_pci_resources(struct ixlv_sc *sc)
-{
- struct i40e_hw *hw = &sc->hw;
- device_t dev = iflib_get_dev(sc->vsi.ctx);
- int rid;
-
- /* Map BAR0 */
- rid = PCIR_BAR(0);
- sc->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
- &rid, RF_ACTIVE);
-
- if (!(sc->pci_mem)) {
- device_printf(dev, "Unable to allocate bus resource: PCI memory\n");
- return (ENXIO);
- }
-
- /* Save off the PCI information */
- hw->vendor_id = pci_get_vendor(dev);
- hw->device_id = pci_get_device(dev);
- hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
- hw->subsystem_vendor_id =
- pci_read_config(dev, PCIR_SUBVEND_0, 2);
- hw->subsystem_device_id =
- pci_read_config(dev, PCIR_SUBDEV_0, 2);
-
- hw->bus.device = pci_get_slot(dev);
- hw->bus.func = pci_get_function(dev);
-
- /* Save off register access information */
- sc->osdep.mem_bus_space_tag =
- rman_get_bustag(sc->pci_mem);
- sc->osdep.mem_bus_space_handle =
- rman_get_bushandle(sc->pci_mem);
- sc->osdep.mem_bus_space_size = rman_get_size(sc->pci_mem);
- sc->osdep.flush_reg = I40E_VFGEN_RSTAT;
- sc->osdep.dev = dev;
-
- sc->hw.hw_addr = (u8 *) &sc->osdep.mem_bus_space_handle;
- sc->hw.back = &sc->osdep;
-
- /* Disable adminq interrupts (just in case) */
- /* TODO: Probably not necessary */
- // ixlv_disable_adminq_irq(&sc->hw);
-
- return (0);
- }
static void
ixlv_free_pci_resources(struct ixlv_sc *sc)
@@ -1753,13 +1487,10 @@ ixlv_free_pci_resources(struct ixlv_sc *sc)
device_t dev = sc->dev;
/* We may get here before stations are setup */
- // TODO: Check if we can still check against sc->msix
- if ((sc->msix > 0) || (rx_que == NULL))
+ if (rx_que == NULL)
goto early;
- /*
- ** Release all msix VSI resources:
- */
+ /* Release all interrupts */
iflib_irq_free(vsi->ctx, &vsi->irq);
for (int i = 0; i < vsi->num_rx_queues; i++, rx_que++)
@@ -1795,6 +1526,7 @@ ixlv_reset(struct ixlv_sc *sc)
__func__);
return (error);
}
+ pci_enable_busmaster(dev);
error = i40e_shutdown_adminq(hw);
if (error) {
@@ -1807,9 +1539,10 @@ ixlv_reset(struct ixlv_sc *sc)
if (error) {
device_printf(dev, "%s: init_adminq failed: %d\n",
__func__, error);
- return(error);
+ return (error);
}
+ ixlv_enable_adminq_irq(hw);
return (0);
}
@@ -1833,17 +1566,14 @@ ixlv_reset_complete(struct i40e_hw *hw)
}
static void
-ixlv_setup_interface(device_t dev, struct ixl_vsi *vsi)
+ixlv_setup_interface(device_t dev, struct ixlv_sc *sc)
{
+ struct ixl_vsi *vsi = &sc->vsi;
if_ctx_t ctx = vsi->ctx;
- struct ixlv_sc *sc = vsi->back;
struct ifnet *ifp = iflib_get_ifp(ctx);
- uint64_t cap;
- //struct ixl_queue *que = vsi->queues;
INIT_DBG_DEV(dev, "begin");
- /* TODO: Remove VLAN_ENCAP_LEN? */
vsi->shared->isc_max_frame_size =
ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
+ ETHER_VLAN_ENCAP_LEN;
@@ -1853,255 +1583,9 @@ ixlv_setup_interface(device_t dev, struct ixl_vsi *vsi)
if_initbaudrate(ifp, IF_Gbps(40));
#endif
- /* Media types based on reported link speed over AdminQ */
- ifmedia_add(&sc->media, IFM_ETHER | IFM_100_TX, 0, NULL);
- ifmedia_add(&sc->media, IFM_ETHER | IFM_1000_T, 0, NULL);
- ifmedia_add(&sc->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
- ifmedia_add(&sc->media, IFM_ETHER | IFM_25G_SR, 0, NULL);
- ifmedia_add(&sc->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
-
- ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
- ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO);
-
- INIT_DBG_DEV(dev, "end");
- return (0);
-}
-#if 0
-
-/*
-** Allocate and setup a single queue
-*/
-static int
-ixlv_setup_queue(struct ixlv_sc *sc, struct ixl_queue *que)
-{
- device_t dev = sc->dev;
- struct tx_ring *txr;
- struct rx_ring *rxr;
- int rsize, tsize;
- int error = I40E_SUCCESS;
-
- txr = &que->txr;
- txr->que = que;
- txr->tail = I40E_QTX_TAIL1(que->me);
- /* Initialize the TX lock */
- snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)",
- device_get_nameunit(dev), que->me);
- mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF);
- /*
- * Create the TX descriptor ring
- *
- * In Head Writeback mode, the descriptor ring is one bigger
- * than the number of descriptors for space for the HW to
- * write back index of last completed descriptor.
- */
- if (sc->vsi.enable_head_writeback) {
- tsize = roundup2((que->num_tx_desc *
- sizeof(struct i40e_tx_desc)) +
- sizeof(u32), DBA_ALIGN);
- } else {
- tsize = roundup2((que->num_tx_desc *
- sizeof(struct i40e_tx_desc)), DBA_ALIGN);
- }
- if (i40e_allocate_dma_mem(&sc->hw,
- &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) {
- device_printf(dev,
- "Unable to allocate TX Descriptor memory\n");
- error = ENOMEM;
- goto err_destroy_tx_mtx;
- }
- txr->base = (struct i40e_tx_desc *)txr->dma.va;
- bzero((void *)txr->base, tsize);
- /* Now allocate transmit soft structs for the ring */
- if (ixl_allocate_tx_data(que)) {
- device_printf(dev,
- "Critical Failure setting up TX structures\n");
- error = ENOMEM;
- goto err_free_tx_dma;
- }
- /* Allocate a buf ring */
- txr->br = buf_ring_alloc(ixlv_txbrsz, M_DEVBUF,
- M_WAITOK, &txr->mtx);
- if (txr->br == NULL) {
- device_printf(dev,
- "Critical Failure setting up TX buf ring\n");
- error = ENOMEM;
- goto err_free_tx_data;
- }
-
- /*
- * Next the RX queues...
- */
- rsize = roundup2(que->num_rx_desc *
- sizeof(union i40e_rx_desc), DBA_ALIGN);
- rxr = &que->rxr;
- rxr->que = que;
- rxr->tail = I40E_QRX_TAIL1(que->me);
-
- /* Initialize the RX side lock */
- snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)",
- device_get_nameunit(dev), que->me);
- mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF);
-
- if (i40e_allocate_dma_mem(&sc->hw,
- &rxr->dma, i40e_mem_reserved, rsize, 4096)) { //JFV - should this be DBA?
- device_printf(dev,
- "Unable to allocate RX Descriptor memory\n");
- error = ENOMEM;
- goto err_destroy_rx_mtx;
- }
- rxr->base = (union i40e_rx_desc *)rxr->dma.va;
- bzero((void *)rxr->base, rsize);
-
- /* Allocate receive soft structs for the ring */
- if (ixl_allocate_rx_data(que)) {
- device_printf(dev,
- "Critical Failure setting up receive structs\n");
- error = ENOMEM;
- goto err_free_rx_dma;
- }
-
- return (0);
-
-err_free_rx_dma:
- i40e_free_dma_mem(&sc->hw, &rxr->dma);
-err_destroy_rx_mtx:
- mtx_destroy(&rxr->mtx);
- /* err_free_tx_buf_ring */
- buf_ring_free(txr->br, M_DEVBUF);
-err_free_tx_data:
- ixl_free_que_tx(que);
-err_free_tx_dma:
- i40e_free_dma_mem(&sc->hw, &txr->dma);
-err_destroy_tx_mtx:
- mtx_destroy(&txr->mtx);
-
- return (error);
-}
-#endif
-
-/*
-** Allocate and setup the interface queues
-*/
-static int
-ixlv_setup_queues(struct ixlv_sc *sc)
-{
- device_t dev = sc->dev;
- struct ixl_vsi *vsi;
- struct ixl_queue *que;
- int i;
- int error = I40E_SUCCESS;
-
- vsi = &sc->vsi;
- vsi->back = (void *)sc;
- vsi->hw = &sc->hw;
- vsi->num_vlans = 0;
-
- /* Get memory for the station queues */
- if (!(vsi->queues =
- (struct ixl_queue *) malloc(sizeof(struct ixl_queue) *
- vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) {
- device_printf(dev, "Unable to allocate queue memory\n");
- return ENOMEM;
- }
-
- for (i = 0; i < vsi->num_queues; i++) {
- que = &vsi->queues[i];
- que->num_tx_desc = vsi->num_tx_desc;
- que->num_rx_desc = vsi->num_rx_desc;
- que->me = i;
- que->vsi = vsi;
-
- if (ixlv_setup_queue(sc, que)) {
- error = ENOMEM;
- goto err_free_queues;
- }
- }
-
- return (0);
-
-err_free_queues:
- while (i--)
- ixlv_free_queue(sc, &vsi->queues[i]);
-
- free(vsi->queues, M_DEVBUF);
-
- return (error);
-}
-
-#if 0
-/*
-** This routine is run via an vlan config EVENT,
-** it enables us to use the HW Filter table since
-** we can get the vlan id. This just creates the
-** entry in the soft version of the VFTA, init will
-** repopulate the real table.
-*/
-static void
-ixlv_register_vlan(void *arg, struct ifnet *ifp, u16 vtag)
-{
- struct ixl_vsi *vsi = arg;
- struct ixlv_sc *sc = vsi->back;
- struct ixlv_vlan_filter *v;
-
-
- if (ifp->if_softc != arg) /* Not our event */
- return;
-
- if ((vtag == 0) || (vtag > 4095)) /* Invalid */
- return;
-
- /* Sanity check - make sure it doesn't already exist */
- SLIST_FOREACH(v, sc->vlan_filters, next) {
- if (v->vlan == vtag)
- return;
- }
-
- mtx_lock(&sc->mtx);
- ++vsi->num_vlans;
- v = malloc(sizeof(struct ixlv_vlan_filter), M_DEVBUF, M_NOWAIT | M_ZERO);
- SLIST_INSERT_HEAD(sc->vlan_filters, v, next);
- v->vlan = vtag;
- v->flags = IXL_FILTER_ADD;
- ixl_vc_enqueue(&sc->vc_mgr, &sc->add_vlan_cmd,
- IXLV_FLAG_AQ_ADD_VLAN_FILTER, ixl_init_cmd_complete, sc);
- mtx_unlock(&sc->mtx);
- return;
-}
-
-/*
-** This routine is run via an vlan
-** unconfig EVENT, remove our entry
-** in the soft vfta.
-*/
-static void
-ixlv_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag)
-{
- struct ixl_vsi *vsi = arg;
- struct ixlv_sc *sc = vsi->back;
- struct ixlv_vlan_filter *v;
- int i = 0;
-
- if (ifp->if_softc != arg)
- return;
-
- if ((vtag == 0) || (vtag > 4095)) /* Invalid */
- return;
-
- mtx_lock(&sc->mtx);
- SLIST_FOREACH(v, sc->vlan_filters, next) {
- if (v->vlan == vtag) {
- v->flags = IXL_FILTER_DEL;
- ++i;
- --vsi->num_vlans;
- }
- }
- if (i)
- ixl_vc_enqueue(&sc->vc_mgr, &sc->del_vlan_cmd,
- IXLV_FLAG_AQ_DEL_VLAN_FILTER, ixl_init_cmd_complete, sc);
- mtx_unlock(&sc->mtx);
- return;
+ ifmedia_add(vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL);
+ ifmedia_set(vsi->media, IFM_ETHER | IFM_AUTO);
}
-#endif
/*
** Get a new filter and add it to the mac filter list.
@@ -2112,7 +1596,7 @@ ixlv_get_mac_filter(struct ixlv_sc *sc)
struct ixlv_mac_filter *f;
f = malloc(sizeof(struct ixlv_mac_filter),
- M_DEVBUF, M_NOWAIT | M_ZERO);
+ M_IXLV, M_NOWAIT | M_ZERO);
if (f)
SLIST_INSERT_HEAD(sc->mac_filters, f, next);
@@ -2126,7 +1610,7 @@ static struct ixlv_mac_filter *
ixlv_find_mac_filter(struct ixlv_sc *sc, u8 *macaddr)
{
struct ixlv_mac_filter *f;
- bool match = FALSE;
+ bool match = FALSE;
SLIST_FOREACH(f, sc->mac_filters, next) {
if (cmp_etheraddr(f->macaddr, macaddr)) {
@@ -2148,36 +1632,38 @@ ixlv_msix_adminq(void *arg)
{
struct ixlv_sc *sc = arg;
struct i40e_hw *hw = &sc->hw;
- // device_t dev = sc->dev;
- u32 reg;
+ u32 reg, mask;
bool do_task = FALSE;
++sc->admin_irq;
reg = rd32(hw, I40E_VFINT_ICR01);
+ /*
+ * For masking off interrupt causes that need to be handled before
+ * they can be re-enabled
+ */
mask = rd32(hw, I40E_VFINT_ICR0_ENA1);
- reg = rd32(hw, I40E_VFINT_DYN_CTL01);
- reg |= I40E_VFINT_DYN_CTL01_CLEARPBA_MASK;
- wr32(hw, I40E_VFINT_DYN_CTL01, reg);
-
/* Check on the cause */
- if (reg & I40E_VFINT_ICR0_ADMINQ_MASK)
+ if (reg & I40E_VFINT_ICR0_ADMINQ_MASK) {
+ mask &= ~I40E_VFINT_ICR0_ENA_ADMINQ_MASK;
do_task = TRUE;
+ }
+
+ wr32(hw, I40E_VFINT_ICR0_ENA1, mask);
+ ixlv_enable_adminq_irq(hw);
if (do_task)
- iflib_admin_intr_deferred(sc->vsi.ctx);
+ return (FILTER_SCHEDULE_THREAD);
else
- ixlv_enable_adminq_irq(hw);
-
- return (FILTER_HANDLED);
+ return (FILTER_HANDLED);
}
void
ixlv_enable_intr(struct ixl_vsi *vsi)
{
- struct i40e_hw *hw = vsi->hw;
- struct ixl_rx_queue *que = vsi->rx_queues;
+ struct i40e_hw *hw = vsi->hw;
+ struct ixl_rx_queue *que = vsi->rx_queues;
ixlv_enable_adminq_irq(hw);
for (int i = 0; i < vsi->num_rx_queues; i++, que++)
@@ -2187,10 +1673,9 @@ ixlv_enable_intr(struct ixl_vsi *vsi)
void
ixlv_disable_intr(struct ixl_vsi *vsi)
{
- struct i40e_hw *hw = vsi->hw;
- struct ixl_rx_queue *que = vsi->rx_queues;
+ struct i40e_hw *hw = vsi->hw;
+ struct ixl_rx_queue *que = vsi->rx_queues;
- ixlv_disable_adminq_irq(hw);
for (int i = 0; i < vsi->num_rx_queues; i++, que++)
ixlv_disable_queue_irq(hw, que->rxr.me);
}
@@ -2232,344 +1717,103 @@ ixlv_disable_queue_irq(struct i40e_hw *hw, int id)
wr32(hw, I40E_VFINT_DYN_CTLN1(id),
I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK);
rd32(hw, I40E_VFGEN_RSTAT);
- return;
}
-/*
- * Get initial ITR values from tunable values.
- */
static void
-ixlv_configure_itr(struct ixlv_sc *sc)
+ixlv_configure_tx_itr(struct ixlv_sc *sc)
{
struct i40e_hw *hw = &sc->hw;
struct ixl_vsi *vsi = &sc->vsi;
- struct ixl_rx_queue *rx_que = vsi->rx_queues;
+ struct ixl_tx_queue *que = vsi->tx_queues;
- vsi->rx_itr_setting = ixlv_rx_itr;
- //vsi->tx_itr_setting = ixlv_tx_itr;
+ vsi->tx_itr_setting = sc->tx_itr;
- for (int i = 0; i < vsi->num_rx_queues; i++, rx_que++) {
- struct rx_ring *rxr = &rx_que->rxr;
-
- wr32(hw, I40E_VFINT_ITRN1(IXL_RX_ITR, i),
- vsi->rx_itr_setting);
- rxr->itr = vsi->rx_itr_setting;
- rxr->latency = IXL_AVE_LATENCY;
-
-#if 0
+ for (int i = 0; i < vsi->num_tx_queues; i++, que++) {
struct tx_ring *txr = &que->txr;
+
wr32(hw, I40E_VFINT_ITRN1(IXL_TX_ITR, i),
vsi->tx_itr_setting);
txr->itr = vsi->tx_itr_setting;
txr->latency = IXL_AVE_LATENCY;
-#endif
}
}
-/*
-** Provide a update to the queue RX
-** interrupt moderation value.
-*/
static void
-ixlv_set_queue_rx_itr(struct ixl_rx_queue *que)
+ixlv_configure_rx_itr(struct ixlv_sc *sc)
{
- struct ixl_vsi *vsi = que->vsi;
- struct i40e_hw *hw = vsi->hw;
- struct rx_ring *rxr = &que->rxr;
- u16 rx_itr;
- u16 rx_latency = 0;
- int rx_bytes;
-
-
- /* Idle, do nothing */
- if (rxr->bytes == 0)
- return;
-
- if (ixlv_dynamic_rx_itr) {
- rx_bytes = rxr->bytes/rxr->itr;
- rx_itr = rxr->itr;
+ struct i40e_hw *hw = &sc->hw;
+ struct ixl_vsi *vsi = &sc->vsi;
+ struct ixl_rx_queue *que = vsi->rx_queues;
- /* Adjust latency range */
- switch (rxr->latency) {
- case IXL_LOW_LATENCY:
- if (rx_bytes > 10) {
- rx_latency = IXL_AVE_LATENCY;
- rx_itr = IXL_ITR_20K;
- }
- break;
- case IXL_AVE_LATENCY:
- if (rx_bytes > 20) {
- rx_latency = IXL_BULK_LATENCY;
- rx_itr = IXL_ITR_8K;
- } else if (rx_bytes <= 10) {
- rx_latency = IXL_LOW_LATENCY;
- rx_itr = IXL_ITR_100K;
- }
- break;
- case IXL_BULK_LATENCY:
- if (rx_bytes <= 20) {
- rx_latency = IXL_AVE_LATENCY;
- rx_itr = IXL_ITR_20K;
- }
- break;
- }
+ vsi->rx_itr_setting = sc->rx_itr;
- rxr->latency = rx_latency;
+ for (int i = 0; i < vsi->num_rx_queues; i++, que++) {
+ struct rx_ring *rxr = &que->rxr;
- if (rx_itr != rxr->itr) {
- /* do an exponential smoothing */
- rx_itr = (10 * rx_itr * rxr->itr) /
- ((9 * rx_itr) + rxr->itr);
- rxr->itr = min(rx_itr, IXL_MAX_ITR);
- wr32(hw, I40E_VFINT_ITRN1(IXL_RX_ITR,
- que->rxr.me), rxr->itr);
- }
- } else { /* We may have have toggled to non-dynamic */
- if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC)
- vsi->rx_itr_setting = ixlv_rx_itr;
- /* Update the hardware if needed */
- if (rxr->itr != vsi->rx_itr_setting) {
- rxr->itr = vsi->rx_itr_setting;
- wr32(hw, I40E_VFINT_ITRN1(IXL_RX_ITR,
- que->rxr.me), rxr->itr);
- }
+ wr32(hw, I40E_VFINT_ITRN1(IXL_RX_ITR, i),
+ vsi->rx_itr_setting);
+ rxr->itr = vsi->rx_itr_setting;
+ rxr->latency = IXL_AVE_LATENCY;
}
- rxr->bytes = 0;
- rxr->packets = 0;
- return;
}
+/*
+ * Get initial ITR values from tunable values.
+ */
+static void
+ixlv_configure_itr(struct ixlv_sc *sc)
+{
+ ixlv_configure_tx_itr(sc);
+ ixlv_configure_rx_itr(sc);
+}
/*
-** Provide a update to the queue TX
+** Provide a update to the queue RX
** interrupt moderation value.
*/
static void
-ixlv_set_queue_tx_itr(struct ixl_tx_queue *que)
+ixlv_set_queue_rx_itr(struct ixl_rx_queue *que)
{
struct ixl_vsi *vsi = que->vsi;
struct i40e_hw *hw = vsi->hw;
- struct tx_ring *txr = &que->txr;
- u16 tx_itr;
- u16 tx_latency = 0;
- int tx_bytes;
-
+ struct rx_ring *rxr = &que->rxr;
/* Idle, do nothing */
- if (txr->bytes == 0)
+ if (rxr->bytes == 0)
return;
- if (ixlv_dynamic_tx_itr) {
- tx_bytes = txr->bytes/txr->itr;
- tx_itr = txr->itr;
-
- switch (txr->latency) {
- case IXL_LOW_LATENCY:
- if (tx_bytes > 10) {
- tx_latency = IXL_AVE_LATENCY;
- tx_itr = IXL_ITR_20K;
- }
- break;
- case IXL_AVE_LATENCY:
- if (tx_bytes > 20) {
- tx_latency = IXL_BULK_LATENCY;
- tx_itr = IXL_ITR_8K;
- } else if (tx_bytes <= 10) {
- tx_latency = IXL_LOW_LATENCY;
- tx_itr = IXL_ITR_100K;
- }
- break;
- case IXL_BULK_LATENCY:
- if (tx_bytes <= 20) {
- tx_latency = IXL_AVE_LATENCY;
- tx_itr = IXL_ITR_20K;
- }
- break;
- }
-
- txr->latency = tx_latency;
-
- if (tx_itr != txr->itr) {
- /* do an exponential smoothing */
- tx_itr = (10 * tx_itr * txr->itr) /
- ((9 * tx_itr) + txr->itr);
- txr->itr = min(tx_itr, IXL_MAX_ITR);
- wr32(hw, I40E_VFINT_ITRN1(IXL_TX_ITR,
- que->txr.me), txr->itr);
- }
-
- } else { /* We may have have toggled to non-dynamic */
- if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC)
- vsi->tx_itr_setting = ixlv_tx_itr;
- /* Update the hardware if needed */
- if (txr->itr != vsi->tx_itr_setting) {
- txr->itr = vsi->tx_itr_setting;
- wr32(hw, I40E_VFINT_ITRN1(IXL_TX_ITR,
- que->txr.me), txr->itr);
- }
- }
- txr->bytes = 0;
- txr->packets = 0;
- return;
-}
-
-#if 0
-/*
-**
-** MSIX Interrupt Handlers and Tasklets
-**
-*/
-static void
-ixlv_handle_que(void *context, int pending)
-{
- struct ixl_queue *que = context;
- struct ixl_vsi *vsi = que->vsi;
- struct i40e_hw *hw = vsi->hw;
- struct tx_ring *txr = &que->txr;
- struct ifnet *ifp = vsi->ifp;
- bool more;
-
- if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
- more = ixl_rxeof(que, IXL_RX_LIMIT);
- mtx_lock(&txr->mtx);
- ixl_txeof(que);
- if (!drbr_empty(ifp, txr->br))
- ixl_mq_start_locked(ifp, txr);
- mtx_unlock(&txr->mtx);
- if (more) {
- taskqueue_enqueue(que->tq, &que->task);
- return;
- }
+ /* Update the hardware if needed */
+ if (rxr->itr != vsi->rx_itr_setting) {
+ rxr->itr = vsi->rx_itr_setting;
+ wr32(hw, I40E_VFINT_ITRN1(IXL_RX_ITR,
+ que->rxr.me), rxr->itr);
}
-
- /* Reenable this interrupt - hmmm */
- ixlv_enable_queue_irq(hw, que->me);
- return;
}
-#endif
-
static int
ixlv_msix_que(void *arg)
{
- struct ixl_rx_queue *que = arg;
+ struct ixl_rx_queue *rx_que = arg;
- ++que->irqs;
+ ++rx_que->irqs;
- ixlv_set_queue_rx_itr(que);
- ixlv_set_queue_tx_itr(que);
+ ixlv_set_queue_rx_itr(rx_que);
+ // ixlv_set_queue_tx_itr(que);
return (FILTER_SCHEDULE_THREAD);
}
-
-/*********************************************************************
- *
- * Media Ioctl callback
- *
- * This routine is called whenever the user queries the status of
- * the interface using ifconfig.
- *
- **********************************************************************/
-static void
-ixlv_media_status(struct ifnet * ifp, struct ifmediareq * ifmr)
-{
- struct ixl_vsi *vsi = ifp->if_softc;
- struct ixlv_sc *sc = vsi->back;
-
- INIT_DBG_IF(ifp, "begin");
-
- mtx_lock(&sc->mtx);
-
- ixlv_update_link_status(sc);
-
- ifmr->ifm_status = IFM_AVALID;
- ifmr->ifm_active = IFM_ETHER;
-
- if (!sc->link_up) {
- mtx_unlock(&sc->mtx);
- INIT_DBG_IF(ifp, "end: link not up");
- return;
- }
-
- ifmr->ifm_status |= IFM_ACTIVE;
- /* Hardware is always full-duplex */
- ifmr->ifm_active |= IFM_FDX;
-
- /* Based on the link speed reported by the PF over the AdminQ, choose a
- * PHY type to report. This isn't 100% correct since we don't really
- * know the underlying PHY type of the PF, but at least we can report
- * a valid link speed...
- */
- switch (sc->link_speed) {
- case VIRTCHNL_LINK_SPEED_100MB:
- ifmr->ifm_active |= IFM_100_TX;
- break;
- case VIRTCHNL_LINK_SPEED_1GB:
- ifmr->ifm_active |= IFM_1000_T;
- break;
- case VIRTCHNL_LINK_SPEED_10GB:
- ifmr->ifm_active |= IFM_10G_SR;
- break;
- case VIRTCHNL_LINK_SPEED_20GB:
- case VIRTCHNL_LINK_SPEED_25GB:
- ifmr->ifm_active |= IFM_25G_SR;
- break;
- case VIRTCHNL_LINK_SPEED_40GB:
- ifmr->ifm_active |= IFM_40G_SR4;
- break;
- default:
- ifmr->ifm_active |= IFM_UNKNOWN;
- break;
- }
-
- mtx_unlock(&sc->mtx);
- INIT_DBG_IF(ifp, "end");
- return;
-}
-
-/*********************************************************************
- *
- * Media Ioctl callback
- *
- * This routine is called when the user changes speed/duplex using
- * media/mediopt option with ifconfig.
- *
- **********************************************************************/
-static int
-ixlv_media_change(struct ifnet * ifp)
-{
- struct ixl_vsi *vsi = ifp->if_softc;
- struct ifmedia *ifm = &vsi->media;
-
- INIT_DBG_IF(ifp, "begin");
-
- if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
- return (EINVAL);
-
- if_printf(ifp, "Changing speed is not supported\n");
-
- INIT_DBG_IF(ifp, "end");
- return (ENODEV);
-}
-
-
-#if 0
/*********************************************************************
* Multicast Initialization
*
* This routine is called by init to reset a fresh state.
*
**********************************************************************/
-
static void
-ixlv_init_multi(struct ixl_vsi *vsi)
+ixlv_init_multi(struct ixlv_sc *sc)
{
struct ixlv_mac_filter *f;
- struct ixlv_sc *sc = vsi->back;
- int mcnt = 0;
-
- IOCTL_DBG_IF(vsi->ifp, "begin");
+ int mcnt = 0;
/* First clear any multicast filters */
SLIST_FOREACH(f, sc->mac_filters, next) {
@@ -2580,155 +1824,7 @@ ixlv_init_multi(struct ixl_vsi *vsi)
}
}
if (mcnt > 0)
- ixl_vc_enqueue(&sc->vc_mgr, &sc->del_multi_cmd,
- IXLV_FLAG_AQ_DEL_MAC_FILTER, ixl_init_cmd_complete,
- sc);
-
- IOCTL_DBG_IF(vsi->ifp, "end");
-}
-
-static void
-ixlv_add_multi(struct ixl_vsi *vsi)
-{
- struct ifmultiaddr *ifma;
- struct ifnet *ifp = vsi->ifp;
- struct ixlv_sc *sc = vsi->back;
- int mcnt = 0;
-
- IOCTL_DBG_IF(ifp, "begin");
-
- if_maddr_rlock(ifp);
- /*
- ** Get a count, to decide if we
- ** simply use multicast promiscuous.
- */
- CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
- if (ifma->ifma_addr->sa_family != AF_LINK)
- continue;
- mcnt++;
- }
- if_maddr_runlock(ifp);
-
- /* TODO: Remove -- cannot set promiscuous mode in a VF */
- if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) {
- /* delete all multicast filters */
- ixlv_init_multi(vsi);
- sc->promiscuous_flags |= FLAG_VF_MULTICAST_PROMISC;
- ixl_vc_enqueue(&sc->vc_mgr, &sc->add_multi_cmd,
- IXLV_FLAG_AQ_CONFIGURE_PROMISC, ixl_init_cmd_complete,
- sc);
- IOCTL_DEBUGOUT("%s: end: too many filters", __func__);
- return;
- }
-
- mcnt = 0;
- if_maddr_rlock(ifp);
- CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
- if (ifma->ifma_addr->sa_family != AF_LINK)
- continue;
- if (!ixlv_add_mac_filter(sc,
- (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr),
- IXL_FILTER_MC))
- mcnt++;
- }
- if_maddr_runlock(ifp);
- /*
- ** Notify AQ task that sw filters need to be
- ** added to hw list
- */
- if (mcnt > 0)
- ixl_vc_enqueue(&sc->vc_mgr, &sc->add_multi_cmd,
- IXLV_FLAG_AQ_ADD_MAC_FILTER, ixl_init_cmd_complete,
- sc);
-
- IOCTL_DBG_IF(ifp, "end");
-}
-
-static void
-ixlv_del_multi(struct ixl_vsi *vsi)
-{
- struct ixlv_mac_filter *f;
- struct ifmultiaddr *ifma;
- struct ifnet *ifp = vsi->ifp;
- struct ixlv_sc *sc = vsi->back;
- int mcnt = 0;
- bool match = FALSE;
-
- IOCTL_DBG_IF(ifp, "begin");
-
- /* Search for removed multicast addresses */
- if_maddr_rlock(ifp);
- SLIST_FOREACH(f, sc->mac_filters, next) {
- if ((f->flags & IXL_FILTER_USED)
- && (f->flags & IXL_FILTER_MC)) {
- /* check if mac address in filter is in sc's list */
- match = FALSE;
- CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
- if (ifma->ifma_addr->sa_family != AF_LINK)
- continue;
- u8 *mc_addr =
- (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
- if (cmp_etheraddr(f->macaddr, mc_addr)) {
- match = TRUE;
- break;
- }
- }
- /* if this filter is not in the sc's list, remove it */
- if (match == FALSE && !(f->flags & IXL_FILTER_DEL)) {
- f->flags |= IXL_FILTER_DEL;
- mcnt++;
- IOCTL_DBG_IF(ifp, "marked: " MAC_FORMAT,
- MAC_FORMAT_ARGS(f->macaddr));
- }
- else if (match == FALSE)
- IOCTL_DBG_IF(ifp, "exists: " MAC_FORMAT,
- MAC_FORMAT_ARGS(f->macaddr));
- }
- }
- if_maddr_runlock(ifp);
-
- if (mcnt > 0)
- ixl_vc_enqueue(&sc->vc_mgr, &sc->del_multi_cmd,
- IXLV_FLAG_AQ_DEL_MAC_FILTER, ixl_init_cmd_complete,
- sc);
-
- IOCTL_DBG_IF(ifp, "end");
-}
-
-static void
-ixlv_local_timer(void *arg)
-{
- struct ixlv_sc *sc = arg;
- struct i40e_hw *hw = &sc->hw;
- struct ixl_vsi *vsi = &sc->vsi;
- u32 val;
-
- IXLV_CORE_LOCK_ASSERT(sc);
-
- /* If Reset is in progress just bail */
- if (sc->init_state == IXLV_RESET_PENDING)
- return;
-
- /* Check for when PF triggers a VF reset */
- val = rd32(hw, I40E_VFGEN_RSTAT) &
- I40E_VFGEN_RSTAT_VFR_STATE_MASK;
-
- if (val != VIRTCHNL_VFR_VFACTIVE
- && val != VIRTCHNL_VFR_COMPLETED) {
- DDPRINTF(sc->dev, "reset in progress! (%d)", val);
- return;
- }
-
- ixlv_request_stats(sc);
-
- /* clean and process any events */
- taskqueue_enqueue(sc->tq, &sc->aq_irq);
-
- /* Increment stat when a queue shows hung */
- if (ixl_queue_hang_check(vsi))
- sc->watchdog_events++;
-
- callout_reset(&sc->timer, hz, ixlv_local_timer, sc);
+ ixlv_send_vc_msg(sc, IXLV_FLAG_AQ_DEL_MAC_FILTER);
}
/*
@@ -2739,29 +1835,23 @@ ixlv_local_timer(void *arg)
void
ixlv_update_link_status(struct ixlv_sc *sc)
{
- struct ixl_vsi *vsi = &sc->vsi;
- struct ifnet *ifp = vsi->ifp;
+ struct ixl_vsi *vsi = &sc->vsi;
+ u64 baudrate;
if (sc->link_up){
if (vsi->link_active == FALSE) {
- if (bootverbose)
- if_printf(ifp,"Link is Up, %s\n",
- ixlv_vc_speed_to_string(sc->link_speed));
vsi->link_active = TRUE;
- if_link_state_change(ifp, LINK_STATE_UP);
+ baudrate = ixl_max_vc_speed_to_value(sc->link_speed);
+ ixlv_dbg_info(sc, "baudrate: %lu\n", baudrate);
+ iflib_link_state_change(vsi->ctx, LINK_STATE_UP, baudrate);
}
} else { /* Link down */
if (vsi->link_active == TRUE) {
- if (bootverbose)
- if_printf(ifp,"Link is Down\n");
- if_link_state_change(ifp, LINK_STATE_DOWN);
vsi->link_active = FALSE;
+ iflib_link_state_change(vsi->ctx, LINK_STATE_DOWN, 0);
}
}
-
- return;
}
-#endif
/*********************************************************************
*
@@ -2774,29 +1864,19 @@ static void
ixlv_stop(struct ixlv_sc *sc)
{
struct ifnet *ifp;
- int start;
ifp = sc->vsi.ifp;
- INIT_DBG_IF(ifp, "begin");
-
- ixl_vc_flush(&sc->vc_mgr);
- ixlv_disable_queues(sc);
- start = ticks;
- while ((ifp->if_drv_flags & IFF_DRV_RUNNING) &&
- ((ticks - start) < hz/10))
- ixlv_do_adminq_locked(sc);
+ ixlv_disable_intr(&sc->vsi);
- /* Stop the local timer */
- callout_stop(&sc->timer);
-
- INIT_DBG_IF(ifp, "end");
+ if (atomic_load_acq_32(&sc->queues_enabled))
+ ixlv_send_vc_msg_sleep(sc, IXLV_FLAG_AQ_DISABLE_QUEUES);
}
static void
ixlv_if_stop(if_ctx_t ctx)
{
- struct ixl_vsi *vsi = iflib_get_softc(ctx);
+ struct ixlv_sc *sc = iflib_get_softc(ctx);
ixlv_stop(sc);
}
@@ -2888,14 +1968,11 @@ ixlv_config_rss_reg(struct ixlv_sc *sc)
static void
ixlv_config_rss_pf(struct ixlv_sc *sc)
{
- ixl_vc_enqueue(&sc->vc_mgr, &sc->config_rss_key_cmd,
- IXLV_FLAG_AQ_CONFIG_RSS_KEY, ixl_init_cmd_complete, sc);
+ ixlv_send_vc_msg(sc, IXLV_FLAG_AQ_CONFIG_RSS_KEY);
- ixl_vc_enqueue(&sc->vc_mgr, &sc->set_rss_hena_cmd,
- IXLV_FLAG_AQ_SET_RSS_HENA, ixl_init_cmd_complete, sc);
+ ixlv_send_vc_msg(sc, IXLV_FLAG_AQ_SET_RSS_HENA);
- ixl_vc_enqueue(&sc->vc_mgr, &sc->config_rss_lut_cmd,
- IXLV_FLAG_AQ_CONFIG_RSS_LUT, ixl_init_cmd_complete, sc);
+ ixlv_send_vc_msg(sc, IXLV_FLAG_AQ_CONFIG_RSS_LUT);
}
/*
@@ -2907,42 +1984,16 @@ static void
ixlv_config_rss(struct ixlv_sc *sc)
{
if (sc->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_REG) {
- DDPRINTF(sc->dev, "Setting up RSS using VF registers...");
+ ixlv_dbg_info(sc, "Setting up RSS using VF registers...");
ixlv_config_rss_reg(sc);
} else if (sc->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
- DDPRINTF(sc->dev, "Setting up RSS using messages to PF...");
+ ixlv_dbg_info(sc, "Setting up RSS using messages to PF...");
ixlv_config_rss_pf(sc);
} else
device_printf(sc->dev, "VF does not support RSS capability sent by PF.\n");
}
/*
-** This routine refreshes vlan filters, called by init
-** it scans the filter table and then updates the AQ
-*/
-static void
-ixlv_setup_vlan_filters(struct ixlv_sc *sc)
-{
- struct ixl_vsi *vsi = &sc->vsi;
- struct ixlv_vlan_filter *f;
- int cnt = 0;
-
- if (vsi->num_vlans == 0)
- return;
- /*
- ** Scan the filter table for vlan entries,
- ** and if found call for the AQ update.
- */
- SLIST_FOREACH(f, sc->vlan_filters, next)
- if (f->flags & IXL_FILTER_ADD)
- cnt++;
- if (cnt > 0)
- ixl_vc_enqueue(&sc->vc_mgr, &sc->add_vlan_cmd,
- IXLV_FLAG_AQ_ADD_VLAN_FILTER, ixl_init_cmd_complete, sc);
-}
-
-
-/*
** This routine adds new MAC filters to the sc's list;
** these are later added in hardware by sending a virtual
** channel message.
@@ -2955,7 +2006,7 @@ ixlv_add_mac_filter(struct ixlv_sc *sc, u8 *macaddr, u16 flags)
/* Does one already exist? */
f = ixlv_find_mac_filter(sc, macaddr);
if (f != NULL) {
- IDPRINTF(sc->vsi.ifp, "exists: " MAC_FORMAT,
+ ixlv_dbg_filter(sc, "exists: " MAC_FORMAT "\n",
MAC_FORMAT_ARGS(macaddr));
return (EEXIST);
}
@@ -2963,12 +2014,12 @@ ixlv_add_mac_filter(struct ixlv_sc *sc, u8 *macaddr, u16 flags)
/* If not, get a new empty filter */
f = ixlv_get_mac_filter(sc);
if (f == NULL) {
- if_printf(sc->vsi.ifp, "%s: no filters available!!\n",
+ device_printf(sc->dev, "%s: no filters available!!\n",
__func__);
return (ENOMEM);
}
- IDPRINTF(sc->vsi.ifp, "marked: " MAC_FORMAT,
+ ixlv_dbg_filter(sc, "marked: " MAC_FORMAT "\n",
MAC_FORMAT_ARGS(macaddr));
bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN);
@@ -2993,236 +2044,79 @@ ixlv_del_mac_filter(struct ixlv_sc *sc, u8 *macaddr)
return (0);
}
+/*
+ * Re-uses the name from the PF driver.
+ */
static void
-ixlv_do_adminq_locked(struct ixlv_sc *sc)
+ixlv_add_device_sysctls(struct ixlv_sc *sc)
{
- struct i40e_hw *hw = &sc->hw;
- struct i40e_arq_event_info event;
- struct virtchnl_msg *v_msg;
- device_t dev = sc->dev;
- u16 result = 0;
- u32 reg, oldreg;
- i40e_status ret;
- bool aq_error = false;
+ struct ixl_vsi *vsi = &sc->vsi;
+ device_t dev = sc->dev;
- event.buf_len = IXL_AQ_BUF_SZ;
- event.msg_buf = sc->aq_buffer;
- v_msg = (struct virtchnl_msg *)&event.desc;
+ struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
+ struct sysctl_oid_list *ctx_list =
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
+ struct sysctl_oid *debug_node;
+ struct sysctl_oid_list *debug_list;
- do {
- ret = i40e_clean_arq_element(hw, &event, &result);
- if (ret)
- break;
- ixlv_vc_completion(sc, v_msg->v_opcode,
- v_msg->v_retval, event.msg_buf, event.msg_len);
- if (result != 0)
- bzero(event.msg_buf, IXL_AQ_BUF_SZ);
- } while (result);
+ SYSCTL_ADD_PROC(ctx, ctx_list,
+ OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD,
+ sc, 0, ixlv_sysctl_current_speed, "A", "Current Port Speed");
- /* check for Admin queue errors */
- oldreg = reg = rd32(hw, hw->aq.arq.len);
- if (reg & I40E_VF_ARQLEN1_ARQVFE_MASK) {
- device_printf(dev, "ARQ VF Error detected\n");
- reg &= ~I40E_VF_ARQLEN1_ARQVFE_MASK;
- aq_error = true;
- }
- if (reg & I40E_VF_ARQLEN1_ARQOVFL_MASK) {
- device_printf(dev, "ARQ Overflow Error detected\n");
- reg &= ~I40E_VF_ARQLEN1_ARQOVFL_MASK;
- aq_error = true;
- }
- if (reg & I40E_VF_ARQLEN1_ARQCRIT_MASK) {
- device_printf(dev, "ARQ Critical Error detected\n");
- reg &= ~I40E_VF_ARQLEN1_ARQCRIT_MASK;
- aq_error = true;
- }
- if (oldreg != reg)
- wr32(hw, hw->aq.arq.len, reg);
+ SYSCTL_ADD_PROC(ctx, ctx_list,
+ OID_AUTO, "tx_itr", CTLTYPE_INT | CTLFLAG_RW,
+ sc, 0, ixlv_sysctl_tx_itr, "I",
+ "Immediately set TX ITR value for all queues");
- oldreg = reg = rd32(hw, hw->aq.asq.len);
- if (reg & I40E_VF_ATQLEN1_ATQVFE_MASK) {
- device_printf(dev, "ASQ VF Error detected\n");
- reg &= ~I40E_VF_ATQLEN1_ATQVFE_MASK;
- aq_error = true;
- }
- if (reg & I40E_VF_ATQLEN1_ATQOVFL_MASK) {
- device_printf(dev, "ASQ Overflow Error detected\n");
- reg &= ~I40E_VF_ATQLEN1_ATQOVFL_MASK;
- aq_error = true;
- }
- if (reg & I40E_VF_ATQLEN1_ATQCRIT_MASK) {
- device_printf(dev, "ASQ Critical Error detected\n");
- reg &= ~I40E_VF_ATQLEN1_ATQCRIT_MASK;
- aq_error = true;
- }
- if (oldreg != reg)
- wr32(hw, hw->aq.asq.len, reg);
+ SYSCTL_ADD_PROC(ctx, ctx_list,
+ OID_AUTO, "rx_itr", CTLTYPE_INT | CTLFLAG_RW,
+ sc, 0, ixlv_sysctl_rx_itr, "I",
+ "Immediately set RX ITR value for all queues");
- if (aq_error) {
- /* Need to reset adapter */
- device_printf(dev, "WARNING: Resetting!\n");
- sc->init_state = IXLV_RESET_REQUIRED;
- ixlv_stop(sc);
- // TODO: Make stop/init calls match
- ixlv_if_init(sc->vsi.ctx);
- }
- ixlv_enable_adminq_irq(hw);
-}
+ /* Add sysctls meant to print debug information, but don't list them
+ * in "sysctl -a" output. */
+ debug_node = SYSCTL_ADD_NODE(ctx, ctx_list,
+ OID_AUTO, "debug", CTLFLAG_RD | CTLFLAG_SKIP, NULL, "Debug Sysctls");
+ debug_list = SYSCTL_CHILDREN(debug_node);
-static void
-ixlv_add_sysctls(struct ixlv_sc *sc)
-{
- device_t dev = sc->dev;
- struct ixl_vsi *vsi = &sc->vsi;
- struct i40e_eth_stats *es = &vsi->eth_stats;
+ SYSCTL_ADD_UINT(ctx, debug_list,
+ OID_AUTO, "shared_debug_mask", CTLFLAG_RW,
+ &sc->hw.debug_mask, 0, "Shared code debug message level");
- struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
- struct sysctl_oid *tree = device_get_sysctl_tree(dev);
- struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
+ SYSCTL_ADD_UINT(ctx, debug_list,
+ OID_AUTO, "core_debug_mask", CTLFLAG_RW,
+ &sc->dbg_mask, 0, "Non-shared code debug message level");
- struct sysctl_oid *vsi_node; // *queue_node;
- struct sysctl_oid_list *vsi_list; // *queue_list;
+ SYSCTL_ADD_PROC(ctx, debug_list,
+ OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD,
+ sc, 0, ixlv_sysctl_sw_filter_list, "A", "SW Filter List");
-#define QUEUE_NAME_LEN 32
- //char queue_namebuf[QUEUE_NAME_LEN];
+ SYSCTL_ADD_PROC(ctx, debug_list,
+ OID_AUTO, "queue_interrupt_table", CTLTYPE_STRING | CTLFLAG_RD,
+ sc, 0, ixlv_sysctl_queue_interrupt_table, "A", "View MSI-X indices for TX/RX queues");
-#if 0
- struct ixl_queue *queues = vsi->queues;
- struct tX_ring *txr;
- struct rx_ring *rxr;
-#endif
+ SYSCTL_ADD_PROC(ctx, debug_list,
+ OID_AUTO, "do_vf_reset", CTLTYPE_INT | CTLFLAG_WR,
+ sc, 0, ixlv_sysctl_vf_reset, "A", "Request a VF reset from PF");
- /* Driver statistics sysctls */
- SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "watchdog_events",
- CTLFLAG_RD, &sc->watchdog_events,
- "Watchdog timeouts");
- SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "admin_irq",
- CTLFLAG_RD, &sc->admin_irq,
- "Admin Queue IRQ Handled");
-
- SYSCTL_ADD_INT(ctx, child, OID_AUTO, "tx_ring_size",
- CTLFLAG_RD, &vsi->num_tx_desc, 0,
- "TX ring size");
- SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rx_ring_size",
- CTLFLAG_RD, &vsi->num_rx_desc, 0,
- "RX ring size");
-
- SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "current_speed",
- CTLTYPE_STRING | CTLFLAG_RD,
- sc, 0, ixlv_sysctl_current_speed,
- "A", "Current Port Speed");
-
- /* VSI statistics sysctls */
- vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "vsi",
- CTLFLAG_RD, NULL, "VSI-specific statistics");
- vsi_list = SYSCTL_CHILDREN(vsi_node);
-
- struct ixl_sysctl_info ctls[] =
- {
- {&es->rx_bytes, "good_octets_rcvd", "Good Octets Received"},
- {&es->rx_unicast, "ucast_pkts_rcvd",
- "Unicast Packets Received"},
- {&es->rx_multicast, "mcast_pkts_rcvd",
- "Multicast Packets Received"},
- {&es->rx_broadcast, "bcast_pkts_rcvd",
- "Broadcast Packets Received"},
- {&es->rx_discards, "rx_discards", "Discarded RX packets"},
- {&es->rx_unknown_protocol, "rx_unknown_proto", "RX unknown protocol packets"},
- {&es->tx_bytes, "good_octets_txd", "Good Octets Transmitted"},
- {&es->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"},
- {&es->tx_multicast, "mcast_pkts_txd",
- "Multicast Packets Transmitted"},
- {&es->tx_broadcast, "bcast_pkts_txd",
- "Broadcast Packets Transmitted"},
- {&es->tx_errors, "tx_errors", "TX packet errors"},
- // end
- {0,0,0}
- };
- struct ixl_sysctl_info *entry = ctls;
- while (entry->stat != NULL)
- {
- SYSCTL_ADD_QUAD(ctx, child, OID_AUTO, entry->name,
- CTLFLAG_RD, entry->stat,
- entry->description);
- entry++;
- }
-
-#if 0
- /* Queue sysctls */
- for (int q = 0; q < vsi->num_queues; q++) {
- snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q);
- queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, OID_AUTO, queue_namebuf,
- CTLFLAG_RD, NULL, "Queue Name");
- queue_list = SYSCTL_CHILDREN(queue_node);
-
- txr = &(queues[q].txr);
- rxr = &(queues[q].rxr);
-
- SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed",
- CTLFLAG_RD, &(queues[q].mbuf_defrag_failed),
- "m_defrag() failed");
- SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "dropped",
- CTLFLAG_RD, &(queues[q].dropped_pkts),
- "Driver dropped packets");
- SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "irqs",
- CTLFLAG_RD, &(queues[q].irqs),
- "irqs on this queue");
- SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "tso_tx",
- CTLFLAG_RD, &(queues[q].tso),
- "TSO");
- SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "tx_dmamap_failed",
- CTLFLAG_RD, &(queues[q].tx_dmamap_failed),
- "Driver tx dma failure in xmit");
- SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "no_desc_avail",
- CTLFLAG_RD, &(txr->no_desc),
- "Queue No Descriptor Available");
- SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "tx_packets",
- CTLFLAG_RD, &(txr->total_packets),
- "Queue Packets Transmitted");
- SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "tx_bytes",
- CTLFLAG_RD, &(txr->tx_bytes),
- "Queue Bytes Transmitted");
- SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "rx_packets",
- CTLFLAG_RD, &(rxr->rx_packets),
- "Queue Packets Received");
- SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "rx_bytes",
- CTLFLAG_RD, &(rxr->rx_bytes),
- "Queue Bytes Received");
- SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_itr",
- CTLFLAG_RD, &(rxr->itr), 0,
- "Queue Rx ITR Interval");
- SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "tx_itr",
- CTLFLAG_RD, &(txr->itr), 0,
- "Queue Tx ITR Interval");
+ SYSCTL_ADD_PROC(ctx, debug_list,
+ OID_AUTO, "do_vflr_reset", CTLTYPE_INT | CTLFLAG_WR,
+ sc, 0, ixlv_sysctl_vflr_reset, "A", "Request a VFLR reset from HW");
+
+ /* Add stats sysctls */
+ ixl_add_vsi_sysctls(dev, vsi, ctx, "vsi");
+ ixl_add_queues_sysctls(dev, vsi);
-#ifdef IXL_DEBUG
- /* Examine queue state */
- SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qtx_head",
- CTLTYPE_UINT | CTLFLAG_RD, &queues[q],
- sizeof(struct ixl_queue),
- ixlv_sysctl_qtx_tail_handler, "IU",
- "Queue Transmit Descriptor Tail");
- SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qrx_head",
- CTLTYPE_UINT | CTLFLAG_RD, &queues[q],
- sizeof(struct ixl_queue),
- ixlv_sysctl_qrx_tail_handler, "IU",
- "Queue Receive Descriptor Tail");
- SYSCTL_ADD_INT(ctx, queue_list, OID_AUTO, "watchdog_timer",
- CTLFLAG_RD, &(txr.watchdog_timer), 0,
- "Ticks before watchdog event is triggered");
-#endif
- }
-#endif
}
static void
ixlv_init_filters(struct ixlv_sc *sc)
{
- sc->mac_filters = malloc(sizeof(struct ixlv_mac_filter),
- M_DEVBUF, M_NOWAIT | M_ZERO);
+ sc->mac_filters = malloc(sizeof(struct mac_list),
+ M_IXLV, M_WAITOK | M_ZERO);
SLIST_INIT(sc->mac_filters);
- sc->vlan_filters = malloc(sizeof(struct ixlv_vlan_filter),
- M_DEVBUF, M_NOWAIT | M_ZERO);
+ sc->vlan_filters = malloc(sizeof(struct vlan_list),
+ M_IXLV, M_WAITOK | M_ZERO);
SLIST_INIT(sc->vlan_filters);
}
@@ -3235,18 +2129,18 @@ ixlv_free_filters(struct ixlv_sc *sc)
while (!SLIST_EMPTY(sc->mac_filters)) {
f = SLIST_FIRST(sc->mac_filters);
SLIST_REMOVE_HEAD(sc->mac_filters, next);
- free(f, M_DEVBUF);
+ free(f, M_IXLV);
}
- free(sc->mac_filters, M_DEVBUF);
+ free(sc->mac_filters, M_IXLV);
while (!SLIST_EMPTY(sc->vlan_filters)) {
v = SLIST_FIRST(sc->vlan_filters);
SLIST_REMOVE_HEAD(sc->vlan_filters, next);
- free(v, M_DEVBUF);
+ free(v, M_IXLV);
}
- free(sc->vlan_filters, M_DEVBUF);
+ free(sc->vlan_filters, M_IXLV);
}
-static char *
+char *
ixlv_vc_speed_to_string(enum virtchnl_link_speed link_speed)
{
int index;
@@ -3301,49 +2195,241 @@ ixlv_sysctl_current_speed(SYSCTL_HANDLER_ARGS)
return (error);
}
-#ifdef IXL_DEBUG
-/**
- * ixlv_sysctl_qtx_tail_handler
- * Retrieves I40E_QTX_TAIL1 value from hardware
- * for a sysctl.
+/*
+ * Sanity check and save off tunable values.
*/
-static int
-ixlv_sysctl_qtx_tail_handler(SYSCTL_HANDLER_ARGS)
+static void
+ixlv_save_tunables(struct ixlv_sc *sc)
{
- struct ixl_queue *que;
- int error;
- u32 val;
+ device_t dev = sc->dev;
- que = ((struct ixl_queue *)oidp->oid_arg1);
- if (!que) return 0;
+ /* Save tunable information */
+ sc->dbg_mask = ixlv_core_debug_mask;
+ sc->hw.debug_mask = ixlv_shared_debug_mask;
+ sc->vsi.enable_head_writeback = !!(ixlv_enable_head_writeback);
+
+ if (ixlv_tx_itr < 0 || ixlv_tx_itr > IXL_MAX_ITR) {
+ device_printf(dev, "Invalid tx_itr value of %d set!\n",
+ ixlv_tx_itr);
+ device_printf(dev, "tx_itr must be between %d and %d, "
+ "inclusive\n",
+ 0, IXL_MAX_ITR);
+ device_printf(dev, "Using default value of %d instead\n",
+ IXL_ITR_4K);
+ sc->tx_itr = IXL_ITR_4K;
+ } else
+ sc->tx_itr = ixlv_tx_itr;
+
+ if (ixlv_rx_itr < 0 || ixlv_rx_itr > IXL_MAX_ITR) {
+ device_printf(dev, "Invalid rx_itr value of %d set!\n",
+ ixlv_rx_itr);
+ device_printf(dev, "rx_itr must be between %d and %d, "
+ "inclusive\n",
+ 0, IXL_MAX_ITR);
+ device_printf(dev, "Using default value of %d instead\n",
+ IXL_ITR_8K);
+ sc->rx_itr = IXL_ITR_8K;
+ } else
+ sc->rx_itr = ixlv_rx_itr;
+}
- val = rd32(que->vsi->hw, que->txr.tail);
- error = sysctl_handle_int(oidp, &val, 0, req);
- if (error || !req->newptr)
- return error;
- return (0);
+/*
+ * Used to set the Tx ITR value for all of the VF's queues.
+ * Writes to the ITR registers immediately.
+ */
+static int
+ixlv_sysctl_tx_itr(SYSCTL_HANDLER_ARGS)
+{
+ struct ixlv_sc *sc = (struct ixlv_sc *)arg1;
+ device_t dev = sc->dev;
+ int requested_tx_itr;
+ int error = 0;
+
+ requested_tx_itr = sc->tx_itr;
+ error = sysctl_handle_int(oidp, &requested_tx_itr, 0, req);
+ if ((error) || (req->newptr == NULL))
+ return (error);
+ if (requested_tx_itr < 0 || requested_tx_itr > IXL_MAX_ITR) {
+ device_printf(dev,
+ "Invalid TX itr value; value must be between 0 and %d\n",
+ IXL_MAX_ITR);
+ return (EINVAL);
+ }
+
+ sc->tx_itr = requested_tx_itr;
+ ixlv_configure_tx_itr(sc);
+
+ return (error);
}
-/**
- * ixlv_sysctl_qrx_tail_handler
- * Retrieves I40E_QRX_TAIL1 value from hardware
- * for a sysctl.
+/*
+ * Used to set the Rx ITR value for all of the VF's queues.
+ * Writes to the ITR registers immediately.
*/
-static int
-ixlv_sysctl_qrx_tail_handler(SYSCTL_HANDLER_ARGS)
+static int
+ixlv_sysctl_rx_itr(SYSCTL_HANDLER_ARGS)
{
- struct ixl_queue *que;
- int error;
- u32 val;
+ struct ixlv_sc *sc = (struct ixlv_sc *)arg1;
+ device_t dev = sc->dev;
+ int requested_rx_itr;
+ int error = 0;
+
+ requested_rx_itr = sc->rx_itr;
+ error = sysctl_handle_int(oidp, &requested_rx_itr, 0, req);
+ if ((error) || (req->newptr == NULL))
+ return (error);
+ if (requested_rx_itr < 0 || requested_rx_itr > IXL_MAX_ITR) {
+ device_printf(dev,
+ "Invalid RX itr value; value must be between 0 and %d\n",
+ IXL_MAX_ITR);
+ return (EINVAL);
+ }
- que = ((struct ixl_queue *)oidp->oid_arg1);
- if (!que) return 0;
+ sc->rx_itr = requested_rx_itr;
+ ixlv_configure_rx_itr(sc);
- val = rd32(que->vsi->hw, que->rxr.tail);
- error = sysctl_handle_int(oidp, &val, 0, req);
- if (error || !req->newptr)
- return error;
- return (0);
+ return (error);
}
-#endif
+static int
+ixlv_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS)
+{
+ struct ixlv_sc *sc = (struct ixlv_sc *)arg1;
+ struct ixlv_mac_filter *f;
+ struct ixlv_vlan_filter *v;
+ device_t dev = sc->dev;
+ int ftl_len, ftl_counter = 0, error = 0;
+ struct sbuf *buf;
+
+ buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
+ if (!buf) {
+ device_printf(dev, "Could not allocate sbuf for output.\n");
+ return (ENOMEM);
+ }
+
+ sbuf_printf(buf, "\n");
+
+ /* Print MAC filters */
+ sbuf_printf(buf, "MAC Filters:\n");
+ ftl_len = 0;
+ SLIST_FOREACH(f, sc->mac_filters, next)
+ ftl_len++;
+ if (ftl_len < 1)
+ sbuf_printf(buf, "(none)\n");
+ else {
+ SLIST_FOREACH(f, sc->mac_filters, next) {
+ sbuf_printf(buf,
+ MAC_FORMAT ", flags %#06x\n",
+ MAC_FORMAT_ARGS(f->macaddr), f->flags);
+ }
+ }
+
+ /* Print VLAN filters */
+ sbuf_printf(buf, "VLAN Filters:\n");
+ ftl_len = 0;
+ SLIST_FOREACH(v, sc->vlan_filters, next)
+ ftl_len++;
+ if (ftl_len < 1)
+ sbuf_printf(buf, "(none)");
+ else {
+ SLIST_FOREACH(v, sc->vlan_filters, next) {
+ sbuf_printf(buf,
+ "%d, flags %#06x",
+ v->vlan, v->flags);
+ /* don't print '\n' for last entry */
+ if (++ftl_counter != ftl_len)
+ sbuf_printf(buf, "\n");
+ }
+ }
+
+ error = sbuf_finish(buf);
+ if (error)
+ device_printf(dev, "Error finishing sbuf: %d\n", error);
+
+ sbuf_delete(buf);
+ return (error);
+}
+
+/*
+ * Print out mapping of TX queue indexes and Rx queue indexes
+ * to MSI-X vectors.
+ */
+static int
+ixlv_sysctl_queue_interrupt_table(SYSCTL_HANDLER_ARGS)
+{
+ struct ixlv_sc *sc = (struct ixlv_sc *)arg1;
+ struct ixl_vsi *vsi = &sc->vsi;
+ device_t dev = sc->dev;
+ struct sbuf *buf;
+ int error = 0;
+
+ struct ixl_rx_queue *rx_que = vsi->rx_queues;
+ struct ixl_tx_queue *tx_que = vsi->tx_queues;
+
+ buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
+ if (!buf) {
+ device_printf(dev, "Could not allocate sbuf for output.\n");
+ return (ENOMEM);
+ }
+
+ sbuf_cat(buf, "\n");
+ for (int i = 0; i < vsi->num_rx_queues; i++) {
+ rx_que = &vsi->rx_queues[i];
+ sbuf_printf(buf, "(rxq %3d): %d\n", i, rx_que->msix);
+ }
+ for (int i = 0; i < vsi->num_tx_queues; i++) {
+ tx_que = &vsi->tx_queues[i];
+ sbuf_printf(buf, "(txq %3d): %d\n", i, tx_que->msix);
+ }
+
+ error = sbuf_finish(buf);
+ if (error)
+ device_printf(dev, "Error finishing sbuf: %d\n", error);
+ sbuf_delete(buf);
+
+ return (error);
+}
+
+#define CTX_ACTIVE(ctx) ((if_getdrvflags(iflib_get_ifp(ctx)) & IFF_DRV_RUNNING))
+static int
+ixlv_sysctl_vf_reset(SYSCTL_HANDLER_ARGS)
+{
+ struct ixlv_sc *sc = (struct ixlv_sc *)arg1;
+ int do_reset = 0, error = 0;
+
+ error = sysctl_handle_int(oidp, &do_reset, 0, req);
+ if ((error) || (req->newptr == NULL))
+ return (error);
+
+ if (do_reset == 1) {
+ ixlv_reset(sc);
+ if (CTX_ACTIVE(sc->vsi.ctx))
+ iflib_request_reset(sc->vsi.ctx);
+ }
+
+ return (error);
+}
+
+static int
+ixlv_sysctl_vflr_reset(SYSCTL_HANDLER_ARGS)
+{
+ struct ixlv_sc *sc = (struct ixlv_sc *)arg1;
+ device_t dev = sc->dev;
+ int do_reset = 0, error = 0;
+
+ error = sysctl_handle_int(oidp, &do_reset, 0, req);
+ if ((error) || (req->newptr == NULL))
+ return (error);
+
+ if (do_reset == 1) {
+ if (!pcie_flr(dev, max(pcie_get_max_completion_timeout(dev) / 1000, 10), true)) {
+ device_printf(dev, "PCIE FLR failed\n");
+ error = EIO;
+ }
+ else if (CTX_ACTIVE(sc->vsi.ctx))
+ iflib_request_reset(sc->vsi.ctx);
+ }
+
+ return (error);
+}
+#undef CTX_ACTIVE
diff --git a/sys/dev/ixl/ixl.h b/sys/dev/ixl/ixl.h
index 90edfa2e4cba..e3147fc8939d 100644
--- a/sys/dev/ixl/ixl.h
+++ b/sys/dev/ixl/ixl.h
@@ -32,7 +32,6 @@
******************************************************************************/
/*$FreeBSD$*/
-
#ifndef _IXL_H_
#define _IXL_H_
@@ -136,8 +135,6 @@
#define IXL_MSIX_BAR 3
#define IXL_ADM_LIMIT 2
-// TODO: Find out which TSO_SIZE to use
-//#define IXL_TSO_SIZE 65535
#define IXL_TSO_SIZE ((255*1024)-1)
#define IXL_TX_BUF_SZ ((u32) 1514)
#define IXL_AQ_BUF_SZ ((u32) 4096)
@@ -145,12 +142,14 @@
#define IXL_TX_ITR 1
#define IXL_ITR_NONE 3
#define IXL_QUEUE_EOL 0x7FF
+#define IXL_MIN_FRAME 17
#define IXL_MAX_FRAME 9728
#define IXL_MAX_TX_SEGS 8
#define IXL_MAX_RX_SEGS 5
#define IXL_MAX_TSO_SEGS 128
#define IXL_SPARSE_CHAIN 7
#define IXL_MIN_TSO_MSS 64
+#define IXL_MAX_TSO_MSS 9668
#define IXL_MAX_DMA_SEG_SIZE ((16 * 1024) - 1)
#define IXL_RSS_KEY_SIZE_REG 13
@@ -210,16 +209,6 @@
#define IXL_RX_CTX_BASE_UNITS 128
#define IXL_TX_CTX_BASE_UNITS 128
-#if 0
-#define IXL_VPINT_LNKLSTN_REG(hw, vector, vf_num) \
- I40E_VPINT_LNKLSTN(((vector) - 1) + \
- (((hw)->func_caps.num_msix_vectors_vf - 1) * (vf_num)))
-
-#define IXL_VFINT_DYN_CTLN_REG(hw, vector, vf_num) \
- I40E_VFINT_DYN_CTLN(((vector) - 1) + \
- (((hw)->func_caps.num_msix_vectors_vf - 1) * (vf_num)))
-#endif
-
#define IXL_PF_PCI_CIAA_VF_DEVICE_STATUS 0xAA
#define IXL_PF_PCI_CIAD_VF_TRANS_PENDING_MASK 0x20
@@ -299,6 +288,9 @@
#define IXL_SET_NOPROTO(vsi, count) (vsi)->noproto = (count)
#endif
+/* For stats sysctl naming */
+#define QUEUE_NAME_LEN 32
+
#define IXL_DEV_ERR(_dev, _format, ...) \
device_printf(_dev, "%s: " _format " (%s:%d)\n", __func__, ##__VA_ARGS__, __FILE__, __LINE__)
@@ -415,16 +407,15 @@ struct ixl_vsi {
if_ctx_t ctx;
if_softc_ctx_t shared;
struct ifnet *ifp;
- //device_t dev;
+ device_t dev;
struct i40e_hw *hw;
struct ifmedia *media;
-#define num_rx_queues shared->isc_nrxqsets
-#define num_tx_queues shared->isc_ntxqsets
+
+ int num_rx_queues;
+ int num_tx_queues;
void *back;
enum i40e_vsi_type type;
- // TODO: Remove?
- u64 que_mask;
int id;
u32 rx_itr_setting;
u32 tx_itr_setting;
@@ -541,9 +532,18 @@ struct ixl_sysctl_info {
extern const uint8_t ixl_bcast_addr[ETHER_ADDR_LEN];
/* Common function prototypes between PF/VF driver */
+void ixl_debug_core(device_t dev, u32 enabled_mask, u32 mask, char *fmt, ...);
void ixl_init_tx_ring(struct ixl_vsi *vsi, struct ixl_tx_queue *que);
void ixl_get_default_rss_key(u32 *);
const char * i40e_vc_stat_str(struct i40e_hw *hw,
enum virtchnl_status_code stat_err);
-u64 ixl_max_aq_speed_to_value(u8);
+void ixl_init_tx_rsqs(struct ixl_vsi *vsi);
+void ixl_init_tx_cidx(struct ixl_vsi *vsi);
+u64 ixl_max_vc_speed_to_value(u8 link_speeds);
+void ixl_add_vsi_sysctls(device_t dev, struct ixl_vsi *vsi,
+ struct sysctl_ctx_list *ctx, const char *sysctl_name);
+void ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx,
+ struct sysctl_oid_list *child,
+ struct i40e_eth_stats *eth_stats);
+void ixl_add_queues_sysctls(device_t dev, struct ixl_vsi *vsi);
#endif /* _IXL_H_ */
diff --git a/sys/dev/ixl/ixl_debug.h b/sys/dev/ixl/ixl_debug.h
index c003a9a60a3e..b97f2b87372d 100644
--- a/sys/dev/ixl/ixl_debug.h
+++ b/sys/dev/ixl/ixl_debug.h
@@ -91,12 +91,9 @@ enum ixl_dbg_mask {
IXL_DBG_EN_DIS = 0x00000002,
IXL_DBG_AQ = 0x00000004,
IXL_DBG_NVMUPD = 0x00000008,
+ IXL_DBG_FILTER = 0x00000010,
- IXL_DBG_IOCTL_KNOWN = 0x00000010,
- IXL_DBG_IOCTL_UNKNOWN = 0x00000020,
- IXL_DBG_IOCTL_ALL = 0x00000030,
-
- I40E_DEBUG_RSS = 0x00000100,
+ IXL_DEBUG_RSS = 0x00000100,
IXL_DBG_IOV = 0x00001000,
IXL_DBG_IOV_VC = 0x00002000,
@@ -107,4 +104,20 @@ enum ixl_dbg_mask {
IXL_DBG_ALL = 0xFFFFFFFF
};
+enum ixlv_dbg_mask {
+ IXLV_DBG_INFO = 0x00000001,
+ IXLV_DBG_EN_DIS = 0x00000002,
+ IXLV_DBG_AQ = 0x00000004,
+ IXLV_DBG_INIT = 0x00000008,
+ IXLV_DBG_FILTER = 0x00000010,
+
+ IXLV_DEBUG_RSS = 0x00000100,
+
+ IXLV_DBG_VC = 0x00001000,
+
+ IXLV_DBG_SWITCH_INFO = 0x00010000,
+
+ IXLV_DBG_ALL = 0xFFFFFFFF
+};
+
#endif /* _IXL_DEBUG_H_ */
diff --git a/sys/dev/ixl/ixl_pf.h b/sys/dev/ixl/ixl_pf.h
index d2f74dd424a0..35d1cf4679fa 100644
--- a/sys/dev/ixl/ixl_pf.h
+++ b/sys/dev/ixl/ixl_pf.h
@@ -87,10 +87,6 @@ struct ixl_vf {
/* Physical controller structure */
struct ixl_pf {
- /*
- * This is first so that iflib_get_softc can return
- * either the VSI or the PF structures.
- */
struct ixl_vsi vsi;
struct i40e_hw hw;
@@ -103,7 +99,6 @@ struct ixl_pf {
int iw_msix;
bool iw_enabled;
#endif
- int if_flags;
u32 state;
u8 supported_speeds;
@@ -111,13 +106,12 @@ struct ixl_pf {
struct ixl_pf_qtag qtag;
/* Tunable values */
- bool enable_msix;
- int max_queues;
bool enable_tx_fc_filter;
int dynamic_rx_itr;
int dynamic_tx_itr;
int tx_itr;
int rx_itr;
+ int enable_vf_loopback;
bool link_up;
int advertised_speed;
@@ -126,7 +120,6 @@ struct ixl_pf {
bool has_i2c;
/* Misc stats maintained by the driver */
- u64 watchdog_events;
u64 admin_irq;
/* Statistics from hw */
@@ -145,8 +138,7 @@ struct ixl_pf {
struct ixl_vf *vfs;
int num_vfs;
uint16_t veb_seid;
- struct task vflr_task;
- int vc_debug_lvl;
+ struct if_irq iov_irq;
};
/*
@@ -226,6 +218,12 @@ struct ixl_pf {
"\t3 - Use Admin Queue command (best)\n" \
"Using the Admin Queue is only supported on 710 devices with FW version 1.7 or higher"
+#define IXL_SYSCTL_HELP_VF_LOOPBACK \
+"\nDetermines mode that embedded device switch will use when SR-IOV is initialized:\n" \
+"\t0 - Disable (VEPA)\n" \
+"\t1 - Enable (VEB)\n" \
+"Enabling this will allow VFs in separate VMs to communicate over the hardware bridge."
+
extern const char * const ixl_fc_string[6];
MALLOC_DECLARE(M_IXL);
@@ -242,14 +240,10 @@ MALLOC_DECLARE(M_IXL);
ixl_send_vf_nack_msg((pf), (vf), (op), (st), __FILE__, __LINE__)
/* Debug printing */
-#define ixl_dbg(p, m, s, ...) ixl_debug_core(p, m, s, ##__VA_ARGS__)
-void ixl_debug_core(struct ixl_pf *, enum ixl_dbg_mask, char *, ...);
-
-/* For stats sysctl naming */
-#define QUEUE_NAME_LEN 32
-
-/* For netmap(4) compatibility */
-#define ixl_disable_intr(vsi) ixl_disable_rings_intr(vsi)
+#define ixl_dbg(pf, m, s, ...) ixl_debug_core(pf->dev, pf->dbg_mask, m, s, ##__VA_ARGS__)
+#define ixl_dbg_info(pf, s, ...) ixl_debug_core(pf->dev, pf->dbg_mask, IXL_DBG_INFO, s, ##__VA_ARGS__)
+#define ixl_dbg_filter(pf, s, ...) ixl_debug_core(pf->dev, pf->dbg_mask, IXL_DBG_FILTER, s, ##__VA_ARGS__)
+#define ixl_dbg_iov(pf, s, ...) ixl_debug_core(pf->dev, pf->dbg_mask, IXL_DBG_IOV, s, ##__VA_ARGS__)
/* PF-only function declarations */
int ixl_setup_interface(device_t, struct ixl_pf *);
@@ -292,7 +286,6 @@ void ixl_stat_update32(struct i40e_hw *, u32, bool,
u64 *, u64 *);
void ixl_stop(struct ixl_pf *);
-void ixl_add_vsi_sysctls(struct ixl_pf *pf, struct ixl_vsi *vsi, struct sysctl_ctx_list *ctx, const char *sysctl_name);
int ixl_get_hw_capabilities(struct ixl_pf *);
void ixl_link_up_msg(struct ixl_pf *);
void ixl_update_link_status(struct ixl_pf *);
@@ -333,7 +326,7 @@ int ixl_aq_get_link_status(struct ixl_pf *,
int ixl_handle_nvmupd_cmd(struct ixl_pf *, struct ifdrv *);
void ixl_handle_empr_reset(struct ixl_pf *);
int ixl_prepare_for_reset(struct ixl_pf *pf, bool is_up);
-int ixl_rebuild_hw_structs_after_reset(struct ixl_pf *, bool is_up);
+int ixl_rebuild_hw_structs_after_reset(struct ixl_pf *);
void ixl_set_queue_rx_itr(struct ixl_rx_queue *);
void ixl_set_queue_tx_itr(struct ixl_tx_queue *);
@@ -342,7 +335,7 @@ void ixl_add_filter(struct ixl_vsi *, const u8 *, s16 vlan);
void ixl_del_filter(struct ixl_vsi *, const u8 *, s16 vlan);
void ixl_reconfigure_filters(struct ixl_vsi *vsi);
-int ixl_disable_rings(struct ixl_vsi *);
+int ixl_disable_rings(struct ixl_pf *, struct ixl_vsi *, struct ixl_pf_qtag *);
int ixl_disable_tx_ring(struct ixl_pf *, struct ixl_pf_qtag *, u16);
int ixl_disable_rx_ring(struct ixl_pf *, struct ixl_pf_qtag *, u16);
int ixl_disable_ring(struct ixl_pf *pf, struct ixl_pf_qtag *, u16);
@@ -364,11 +357,12 @@ void ixl_enable_intr(struct ixl_vsi *);
void ixl_disable_rings_intr(struct ixl_vsi *);
void ixl_set_promisc(struct ixl_vsi *);
void ixl_add_multi(struct ixl_vsi *);
-void ixl_del_multi(struct ixl_vsi *);
+int ixl_del_multi(struct ixl_vsi *);
void ixl_setup_vlan_filters(struct ixl_vsi *);
void ixl_init_filters(struct ixl_vsi *);
void ixl_add_hw_filters(struct ixl_vsi *, int, int);
void ixl_del_hw_filters(struct ixl_vsi *, int);
+void ixl_del_default_hw_filters(struct ixl_vsi *);
struct ixl_mac_filter *
ixl_find_filter(struct ixl_vsi *, const u8 *, s16);
void ixl_add_mc_filter(struct ixl_vsi *, u8 *);
@@ -400,5 +394,6 @@ s32 ixl_write_i2c_byte_aq(struct ixl_pf *pf, u8 byte_offset,
int ixl_get_fw_lldp_status(struct ixl_pf *pf);
int ixl_attach_get_link_status(struct ixl_pf *);
+u64 ixl_max_aq_speed_to_value(u8);
#endif /* _IXL_PF_H_ */
diff --git a/sys/dev/ixl/ixl_pf_iov.c b/sys/dev/ixl/ixl_pf_iov.c
index b7ae4cc8e17c..4353545a1a5d 100644
--- a/sys/dev/ixl/ixl_pf_iov.c
+++ b/sys/dev/ixl/ixl_pf_iov.c
@@ -77,14 +77,21 @@ static void ixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
static void ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size);
static void ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size);
static int ixl_vf_reserve_queues(struct ixl_pf *pf, struct ixl_vf *vf, int num_queues);
+static int ixl_config_pf_vsi_loopback(struct ixl_pf *pf, bool enable);
static int ixl_adminq_err_to_errno(enum i40e_admin_queue_err err);
+/*
+ * TODO: Move pieces of this into iflib and call the rest in a handler?
+ *
+ * e.g. ixl_if_iov_set_schema
+ *
+ * It's odd to do pci_iov_detach() there while doing pci_iov_attach()
+ * in the driver.
+ */
void
ixl_initialize_sriov(struct ixl_pf *pf)
{
- return;
-#if 0
device_t dev = pf->dev;
struct i40e_hw *hw = &pf->hw;
nvlist_t *pf_schema, *vf_schema;
@@ -101,7 +108,7 @@ ixl_initialize_sriov(struct ixl_pf *pf)
IOV_SCHEMA_HASDEFAULT, FALSE);
pci_iov_schema_add_uint16(vf_schema, "num-queues",
IOV_SCHEMA_HASDEFAULT,
- max(1, hw->func_caps.num_msix_vectors_vf - 1) % IXLV_MAX_QUEUES);
+ max(1, min(hw->func_caps.num_msix_vectors_vf - 1, IXLV_MAX_QUEUES)));
iov_error = pci_iov_attach(dev, pf_schema, vf_schema);
if (iov_error != 0) {
@@ -110,9 +117,6 @@ ixl_initialize_sriov(struct ixl_pf *pf)
iov_error);
} else
device_printf(dev, "SR-IOV ready\n");
-
- pf->vc_debug_lvl = 1;
-#endif
}
@@ -142,7 +146,9 @@ ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
bzero(&vsi_ctx.info, sizeof(vsi_ctx.info));
vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID);
- vsi_ctx.info.switch_id = htole16(0);
+ if (pf->enable_vf_loopback)
+ vsi_ctx.info.switch_id =
+ htole16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_SECURITY_VALID);
vsi_ctx.info.sec_flags = 0;
@@ -157,7 +163,7 @@ ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
htole16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID);
vsi_ctx.info.mapping_flags = htole16(I40E_AQ_VSI_QUE_MAP_NONCONTIG);
- /* ERJ: Only scattered allocation is supported for VFs right now */
+ /* XXX: Only scattered allocation is supported for VFs right now */
for (i = 0; i < vf->qtag.num_active; i++)
vsi_ctx.info.queue_mapping[i] = vf->qtag.qidx[i];
for (; i < nitems(vsi_ctx.info.queue_mapping); i++)
@@ -172,8 +178,6 @@ ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
vf->vsi.seid = vsi_ctx.seid;
vf->vsi.vsi_num = vsi_ctx.vsi_number;
- // TODO: How to deal with num tx queues / num rx queues split?
- // I don't think just assigning this variable is going to work
vf->vsi.num_rx_queues = vf->qtag.num_active;
vf->vsi.num_tx_queues = vf->qtag.num_active;
@@ -204,10 +208,15 @@ ixl_vf_setup_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
if (error != 0)
return (error);
+ /* Let VF receive broadcast Ethernet frames */
+ error = i40e_aq_set_vsi_broadcast(hw, vf->vsi.seid, TRUE, NULL);
+ if (error)
+ device_printf(pf->dev, "Error configuring VF VSI for broadcast promiscuous\n");
+ /* Re-add VF's MAC/VLAN filters to its VSI */
+ ixl_reconfigure_filters(&vf->vsi);
+ /* Reset stats? */
vf->vsi.hw_filters_add = 0;
vf->vsi.hw_filters_del = 0;
- // ixl_add_filter(&vf->vsi, ixl_bcast_addr, IXL_VLAN_ANY);
- ixl_reconfigure_filters(&vf->vsi);
return (0);
}
@@ -372,12 +381,16 @@ ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf)
hw = &pf->hw;
+ ixl_dbg_iov(pf, "Resetting VF-%d\n", vf->vf_num);
+
vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num));
vfrtrig |= I40E_VPGEN_VFRTRIG_VFSWR_MASK;
wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
ixl_flush(hw);
ixl_reinit_vf(pf, vf);
+
+ ixl_dbg_iov(pf, "Resetting VF-%d done.\n", vf->vf_num);
}
static void
@@ -413,7 +426,8 @@ ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf)
wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
if (vf->vsi.seid != 0)
- ixl_disable_rings(&vf->vsi);
+ ixl_disable_rings(pf, &vf->vsi, &vf->qtag);
+ ixl_pf_qmgr_clear_queue_flags(&vf->qtag);
ixl_vf_release_resources(pf, vf);
ixl_vf_setup_vsi(pf, vf);
@@ -649,7 +663,7 @@ ixl_vf_config_rx_queue(struct ixl_pf *pf, struct ixl_vf *vf,
rxq.tphwdesc_ena = 1;
rxq.tphdata_ena = 1;
rxq.tphhead_ena = 1;
- rxq.lrxqthresh = 2;
+ rxq.lrxqthresh = 1;
rxq.prefena = 1;
status = i40e_set_lan_rx_queue_context(hw, global_queue_num, &rxq);
@@ -924,7 +938,7 @@ ixl_vf_enable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
continue;
/* Warn if this queue is already marked as enabled */
if (ixl_pf_qmgr_is_queue_enabled(&vf->qtag, i, true))
- device_printf(pf->dev, "VF %d: TX ring %d is already enabled!\n",
+ ixl_dbg_iov(pf, "VF %d: TX ring %d is already enabled!\n",
vf->vf_num, i);
error = ixl_enable_tx_ring(pf, &vf->qtag, i);
@@ -949,7 +963,7 @@ ixl_vf_enable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
continue;
/* Warn if this queue is already marked as enabled */
if (ixl_pf_qmgr_is_queue_enabled(&vf->qtag, i, false))
- device_printf(pf->dev, "VF %d: RX ring %d is already enabled!\n",
+ ixl_dbg_iov(pf, "VF %d: RX ring %d is already enabled!\n",
vf->vf_num, i);
error = ixl_enable_rx_ring(pf, &vf->qtag, i);
if (error)
@@ -1003,7 +1017,7 @@ ixl_vf_disable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf,
continue;
/* Warn if this queue is already marked as disabled */
if (!ixl_pf_qmgr_is_queue_enabled(&vf->qtag, i, true)) {
- device_printf(pf->dev, "VF %d: TX ring %d is already disabled!\n",
+ ixl_dbg_iov(pf, "VF %d: TX ring %d is already disabled!\n",
vf->vf_num, i);
continue;
}
@@ -1029,7 +1043,7 @@ ixl_vf_disable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf,
continue;
/* Warn if this queue is already marked as disabled */
if (!ixl_pf_qmgr_is_queue_enabled(&vf->qtag, i, false)) {
- device_printf(pf->dev, "VF %d: RX ring %d is already disabled!\n",
+ ixl_dbg_iov(pf, "VF %d: RX ring %d is already disabled!\n",
vf->vf_num, i);
continue;
}
@@ -1292,6 +1306,7 @@ ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf,
void *msg, uint16_t msg_size)
{
struct virtchnl_promisc_info *info;
+ struct i40e_hw *hw = &pf->hw;
enum i40e_status_code code;
if (msg_size != sizeof(*info)) {
@@ -1301,8 +1316,11 @@ ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf,
}
if (!(vf->vf_flags & VF_FLAG_PROMISC_CAP)) {
- i40e_send_vf_nack(pf, vf,
- VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
+ /*
+ * Do the same thing as the Linux PF driver -- lie to the VF
+ */
+ ixl_send_vf_ack(pf, vf,
+ VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE);
return;
}
@@ -1313,19 +1331,25 @@ ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf,
return;
}
- code = i40e_aq_set_vsi_unicast_promiscuous(&pf->hw, info->vsi_id,
+ code = i40e_aq_set_vsi_unicast_promiscuous(hw, vf->vsi.seid,
info->flags & FLAG_VF_UNICAST_PROMISC, NULL, TRUE);
if (code != I40E_SUCCESS) {
+ device_printf(pf->dev, "i40e_aq_set_vsi_unicast_promiscuous (seid %d) failed: status %s,"
+ " error %s\n", vf->vsi.seid, i40e_stat_str(hw, code),
+ i40e_aq_str(hw, hw->aq.asq_last_status));
i40e_send_vf_nack(pf, vf,
- VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code);
+ VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
return;
}
- code = i40e_aq_set_vsi_multicast_promiscuous(&pf->hw, info->vsi_id,
+ code = i40e_aq_set_vsi_multicast_promiscuous(hw, vf->vsi.seid,
info->flags & FLAG_VF_MULTICAST_PROMISC, NULL);
if (code != I40E_SUCCESS) {
+ device_printf(pf->dev, "i40e_aq_set_vsi_multicast_promiscuous (seid %d) failed: status %s,"
+ " error %s\n", vf->vsi.seid, i40e_stat_str(hw, code),
+ i40e_aq_str(hw, hw->aq.asq_last_status));
i40e_send_vf_nack(pf, vf,
- VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code);
+ VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
return;
}
@@ -1627,19 +1651,25 @@ ixl_handle_vf_msg(struct ixl_pf *pf, struct i40e_arq_event_info *event)
/* Handle any VFs that have reset themselves via a Function Level Reset(FLR). */
void
-ixl_handle_vflr(void *arg, int pending)
+ixl_handle_vflr(struct ixl_pf *pf)
{
- struct ixl_pf *pf;
struct ixl_vf *vf;
struct i40e_hw *hw;
uint16_t global_vf_num;
uint32_t vflrstat_index, vflrstat_mask, vflrstat, icr0;
int i;
- pf = arg;
hw = &pf->hw;
- /* TODO: May need to lock this */
+ ixl_dbg_iov(pf, "%s: begin\n", __func__);
+
+ /* Re-enable VFLR interrupt cause so driver doesn't miss a
+ * reset interrupt for another VF */
+ icr0 = rd32(hw, I40E_PFINT_ICR0_ENA);
+ icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK;
+ wr32(hw, I40E_PFINT_ICR0_ENA, icr0);
+ ixl_flush(hw);
+
for (i = 0; i < pf->num_vfs; i++) {
global_vf_num = hw->func_caps.vf_base_id + i;
@@ -1654,17 +1684,12 @@ ixl_handle_vflr(void *arg, int pending)
wr32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index),
vflrstat_mask);
+ ixl_dbg_iov(pf, "Reinitializing VF-%d\n", i);
ixl_reinit_vf(pf, vf);
+ ixl_dbg_iov(pf, "Reinitializing VF-%d done\n", i);
}
}
- atomic_clear_32(&pf->state, IXL_PF_STATE_VF_RESET_REQ);
- icr0 = rd32(hw, I40E_PFINT_ICR0_ENA);
- icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK;
- wr32(hw, I40E_PFINT_ICR0_ENA, icr0);
- ixl_flush(hw);
-
- // IXL_PF_UNLOCK()
}
static int
@@ -1721,23 +1746,52 @@ ixl_adminq_err_to_errno(enum i40e_admin_queue_err err)
}
}
+static int
+ixl_config_pf_vsi_loopback(struct ixl_pf *pf, bool enable)
+{
+ struct i40e_hw *hw = &pf->hw;
+ device_t dev = pf->dev;
+ struct ixl_vsi *vsi = &pf->vsi;
+ struct i40e_vsi_context ctxt;
+ int error;
+
+ memset(&ctxt, 0, sizeof(ctxt));
+
+ ctxt.seid = vsi->seid;
+ if (pf->veb_seid != 0)
+ ctxt.uplink_seid = pf->veb_seid;
+ ctxt.pf_num = hw->pf_id;
+ ctxt.connection_type = IXL_VSI_DATA_PORT;
+
+ ctxt.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID);
+ ctxt.info.switch_id = (enable) ?
+ htole16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB) : 0;
+
+ /* error is set to 0 on success */
+ error = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
+ if (error) {
+ device_printf(dev, "i40e_aq_update_vsi_params() failed, error %d,"
+ " aq_error %d\n", error, hw->aq.asq_last_status);
+ }
+
+ return (error);
+}
+
int
-ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
+ixl_if_iov_init(if_ctx_t ctx, uint16_t num_vfs, const nvlist_t *params)
{
- struct ixl_pf *pf;
+ struct ixl_pf *pf = iflib_get_softc(ctx);
+ device_t dev = iflib_get_dev(ctx);
struct i40e_hw *hw;
struct ixl_vsi *pf_vsi;
enum i40e_status_code ret;
int i, error;
- pf = device_get_softc(dev);
hw = &pf->hw;
pf_vsi = &pf->vsi;
- //IXL_PF_LOCK(pf);
pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT |
M_ZERO);
-
if (pf->vfs == NULL) {
error = ENOMEM;
goto fail;
@@ -1746,65 +1800,77 @@ ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
for (i = 0; i < num_vfs; i++)
sysctl_ctx_init(&pf->vfs[i].ctx);
+ /*
+ * Add the VEB and ...
+ * - do nothing: VEPA mode
+ * - enable loopback mode on connected VSIs: VEB mode
+ */
ret = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid,
1, FALSE, &pf->veb_seid, FALSE, NULL);
if (ret != I40E_SUCCESS) {
- error = ixl_adminq_err_to_errno(hw->aq.asq_last_status);
- device_printf(dev, "add_veb failed; code=%d error=%d", ret,
- error);
+ error = hw->aq.asq_last_status;
+ device_printf(dev, "i40e_aq_add_veb failed; status %s error %s",
+ i40e_stat_str(hw, ret), i40e_aq_str(hw, error));
goto fail;
}
+ if (pf->enable_vf_loopback)
+ ixl_config_pf_vsi_loopback(pf, true);
+
+ /*
+ * Adding a VEB brings back the default MAC filter(s). Remove them,
+ * and let the driver add the proper filters back.
+ */
+ ixl_del_default_hw_filters(pf_vsi);
+ ixl_reconfigure_filters(pf_vsi);
pf->num_vfs = num_vfs;
- //IXL_PF_UNLOCK(pf);
return (0);
fail:
free(pf->vfs, M_IXL);
pf->vfs = NULL;
- //IXL_PF_UNLOCK(pf);
return (error);
}
void
-ixl_iov_uninit(device_t dev)
+ixl_if_iov_uninit(if_ctx_t ctx)
{
- struct ixl_pf *pf;
+ struct ixl_pf *pf = iflib_get_softc(ctx);
struct i40e_hw *hw;
struct ixl_vsi *vsi;
struct ifnet *ifp;
struct ixl_vf *vfs;
int i, num_vfs;
- pf = device_get_softc(dev);
hw = &pf->hw;
vsi = &pf->vsi;
ifp = vsi->ifp;
- //IXL_PF_LOCK(pf);
for (i = 0; i < pf->num_vfs; i++) {
if (pf->vfs[i].vsi.seid != 0)
i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL);
ixl_pf_qmgr_release(&pf->qmgr, &pf->vfs[i].qtag);
ixl_free_mac_filters(&pf->vfs[i].vsi);
- DDPRINTF(dev, "VF %d: %d released\n",
+ ixl_dbg_iov(pf, "VF %d: %d released\n",
i, pf->vfs[i].qtag.num_allocated);
- DDPRINTF(dev, "Unallocated total: %d\n", ixl_pf_qmgr_get_num_free(&pf->qmgr));
+ ixl_dbg_iov(pf, "Unallocated total: %d\n", ixl_pf_qmgr_get_num_free(&pf->qmgr));
}
if (pf->veb_seid != 0) {
i40e_aq_delete_element(hw, pf->veb_seid, NULL);
pf->veb_seid = 0;
}
+ /* Reset PF VSI loopback mode */
+ if (pf->enable_vf_loopback)
+ ixl_config_pf_vsi_loopback(pf, false);
vfs = pf->vfs;
num_vfs = pf->num_vfs;
pf->vfs = NULL;
pf->num_vfs = 0;
- //IXL_PF_UNLOCK(pf);
- /* Do this after the unlock as sysctl_ctx_free might sleep. */
+ /* sysctl_ctx_free might sleep, but this func is called w/ an sx lock */
for (i = 0; i < num_vfs; i++)
sysctl_ctx_free(&vfs[i].ctx);
free(vfs, M_IXL);
@@ -1823,9 +1889,9 @@ ixl_vf_reserve_queues(struct ixl_pf *pf, struct ixl_vf *vf, int num_queues)
if (num_queues < 1) {
device_printf(dev, "Setting VF %d num-queues to 1\n", vf->vf_num);
num_queues = 1;
- } else if (num_queues > 16) {
- device_printf(dev, "Setting VF %d num-queues to 16\n", vf->vf_num);
- num_queues = 16;
+ } else if (num_queues > IXLV_MAX_QUEUES) {
+ device_printf(dev, "Setting VF %d num-queues to %d\n", vf->vf_num, IXLV_MAX_QUEUES);
+ num_queues = IXLV_MAX_QUEUES;
}
error = ixl_pf_qmgr_alloc_scattered(&pf->qmgr, num_queues, &vf->qtag);
if (error) {
@@ -1834,30 +1900,27 @@ ixl_vf_reserve_queues(struct ixl_pf *pf, struct ixl_vf *vf, int num_queues)
return (ENOSPC);
}
- DDPRINTF(dev, "VF %d: %d allocated, %d active",
+ ixl_dbg_iov(pf, "VF %d: %d allocated, %d active\n",
vf->vf_num, vf->qtag.num_allocated, vf->qtag.num_active);
- DDPRINTF(dev, "Unallocated total: %d", ixl_pf_qmgr_get_num_free(&pf->qmgr));
+ ixl_dbg_iov(pf, "Unallocated total: %d\n", ixl_pf_qmgr_get_num_free(&pf->qmgr));
return (0);
}
int
-ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
+ixl_if_iov_vf_add(if_ctx_t ctx, uint16_t vfnum, const nvlist_t *params)
{
+ struct ixl_pf *pf = iflib_get_softc(ctx);
+ device_t dev = pf->dev;
char sysctl_name[QUEUE_NAME_LEN];
- struct ixl_pf *pf;
struct ixl_vf *vf;
const void *mac;
size_t size;
int error;
int vf_num_queues;
- pf = device_get_softc(dev);
vf = &pf->vfs[vfnum];
-
- //IXL_PF_LOCK(pf);
vf->vf_num = vfnum;
-
vf->vsi.back = pf;
vf->vf_flags = VF_FLAG_ENABLED;
SLIST_INIT(&vf->vsi.ftl);
@@ -1893,12 +1956,12 @@ ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
vf->vf_flags |= VF_FLAG_VLAN_CAP;
+ /* VF needs to be reset before it can be used */
ixl_reset_vf(pf, vf);
out:
- //IXL_PF_UNLOCK(pf);
if (error == 0) {
snprintf(sysctl_name, sizeof(sysctl_name), "vf%d", vfnum);
- ixl_add_vsi_sysctls(pf, &vf->vsi, &vf->ctx, sysctl_name);
+ ixl_add_vsi_sysctls(dev, &vf->vsi, &vf->ctx, sysctl_name);
}
return (error);
diff --git a/sys/dev/ixl/ixl_pf_iov.h b/sys/dev/ixl/ixl_pf_iov.h
index edc4ae44676b..e412df86ae6b 100644
--- a/sys/dev/ixl/ixl_pf_iov.h
+++ b/sys/dev/ixl/ixl_pf_iov.h
@@ -45,19 +45,19 @@
/* Public functions */
/*
- * These three are DEVMETHODs required for SR-IOV PF support.
+ * These three are DEVMETHODs required for SR-IOV PF support in iflib.
*/
-int ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params);
-void ixl_iov_uninit(device_t dev);
-int ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params);
+int ixl_if_iov_init(if_ctx_t ctx, uint16_t num_vfs, const nvlist_t *params);
+void ixl_if_iov_uninit(if_ctx_t ctx);
+int ixl_if_iov_vf_add(if_ctx_t ctx, uint16_t vfnum, const nvlist_t *params);
/*
- * The standard PF driver needs to call these during normal execution when
+ * The base PF driver needs to call these during normal execution when
* SR-IOV mode is active.
*/
void ixl_initialize_sriov(struct ixl_pf *pf);
void ixl_handle_vf_msg(struct ixl_pf *pf, struct i40e_arq_event_info *event);
-void ixl_handle_vflr(void *arg, int pending);
+void ixl_handle_vflr(struct ixl_pf *pf);
void ixl_broadcast_link_state(struct ixl_pf *pf);
#endif /* _IXL_PF_IOV_H_ */
diff --git a/sys/dev/ixl/ixl_pf_main.c b/sys/dev/ixl/ixl_pf_main.c
index 77ab5b7043d3..f775947fdc4c 100644
--- a/sys/dev/ixl/ixl_pf_main.c
+++ b/sys/dev/ixl/ixl_pf_main.c
@@ -46,7 +46,6 @@
static u8 ixl_convert_sysctl_aq_link_speed(u8, bool);
static void ixl_sbuf_print_bytes(struct sbuf *, u8 *, int, int, bool);
-static void ixl_del_default_hw_filters(struct ixl_vsi *);
/* Sysctls */
static int ixl_sysctl_set_flowcntl(SYSCTL_HANDLER_ARGS);
@@ -113,21 +112,6 @@ static char *ixl_fec_string[3] = {
MALLOC_DEFINE(M_IXL, "ixl", "ixl driver allocations");
-void
-ixl_debug_core(struct ixl_pf *pf, enum ixl_dbg_mask mask, char *fmt, ...)
-{
- va_list args;
-
- if (!(mask & pf->dbg_mask))
- return;
-
- /* Re-implement device_printf() */
- device_print_prettyname(pf->dev);
- va_start(args, fmt);
- vprintf(fmt, args);
- va_end(args);
-}
-
/*
** Put the FW, API, NVM, EEtrackID, and OEM version information into a string
*/
@@ -354,6 +338,7 @@ ixl_teardown_hw_structs(struct ixl_pf *pf)
"init: Admin Queue shutdown failure; status %s\n",
i40e_stat_str(hw, status));
+ ixl_pf_qmgr_release(&pf->qmgr, &pf->qtag);
err_out:
return (status);
}
@@ -458,8 +443,7 @@ ixl_reset(struct ixl_pf *pf)
err_out:
return (error);
#endif
- // TODO: Fix second parameter
- ixl_rebuild_hw_structs_after_reset(pf, false);
+ ixl_rebuild_hw_structs_after_reset(pf);
/* The PF reset should have cleared any critical errors */
atomic_clear_32(&pf->state, IXL_PF_STATE_PF_CRIT_ERR);
@@ -527,11 +511,11 @@ ixl_intr(void *arg)
int
ixl_msix_que(void *arg)
{
- struct ixl_rx_queue *que = arg;
+ struct ixl_rx_queue *rx_que = arg;
- ++que->irqs;
+ ++rx_que->irqs;
- ixl_set_queue_rx_itr(que);
+ ixl_set_queue_rx_itr(rx_que);
// ixl_set_queue_tx_itr(que);
return (FILTER_SCHEDULE_THREAD);
@@ -557,8 +541,10 @@ ixl_msix_adminq(void *arg)
++pf->admin_irq;
reg = rd32(hw, I40E_PFINT_ICR0);
- // For masking off interrupt causes that need to be handled before
- // they can be re-enabled
+ /*
+ * For masking off interrupt causes that need to be handled before
+ * they can be re-enabled
+ */
mask = rd32(hw, I40E_PFINT_ICR0_ENA);
/* Check on the cause */
@@ -637,11 +623,12 @@ ixl_msix_adminq(void *arg)
#ifdef PCI_IOV
if (reg & I40E_PFINT_ICR0_VFLR_MASK) {
mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
- atomic_set_32(&pf->state, IXL_PF_STATE_VF_RESET_REQ);
- do_task = TRUE;
+ iflib_iov_intr_deferred(pf->vsi.ctx);
}
#endif
+
wr32(hw, I40E_PFINT_ICR0_ENA, mask);
+ ixl_enable_intr0(hw);
if (do_task)
return (FILTER_SCHEDULE_THREAD);
@@ -703,7 +690,7 @@ ixl_add_multi(struct ixl_vsi *vsi)
IOCTL_DEBUGOUT("ixl_add_multi: end");
}
-void
+int
ixl_del_multi(struct ixl_vsi *vsi)
{
struct ifnet *ifp = vsi->ifp;
@@ -738,6 +725,8 @@ ixl_del_multi(struct ixl_vsi *vsi)
if (mcnt > 0)
ixl_del_hw_filters(vsi, mcnt);
+
+ return (mcnt);
}
void
@@ -1028,7 +1017,6 @@ ixl_setup_interface(device_t dev, struct ixl_pf *pf)
INIT_DBG_DEV(dev, "begin");
- /* TODO: Remove VLAN_ENCAP_LEN? */
vsi->shared->isc_max_frame_size =
ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
+ ETHER_VLAN_ENCAP_LEN;
@@ -1068,6 +1056,29 @@ ixl_setup_interface(device_t dev, struct ixl_pf *pf)
}
/*
+ * Input: bitmap of enum i40e_aq_link_speed
+ */
+u64
+ixl_max_aq_speed_to_value(u8 link_speeds)
+{
+ if (link_speeds & I40E_LINK_SPEED_40GB)
+ return IF_Gbps(40);
+ if (link_speeds & I40E_LINK_SPEED_25GB)
+ return IF_Gbps(25);
+ if (link_speeds & I40E_LINK_SPEED_20GB)
+ return IF_Gbps(20);
+ if (link_speeds & I40E_LINK_SPEED_10GB)
+ return IF_Gbps(10);
+ if (link_speeds & I40E_LINK_SPEED_1GB)
+ return IF_Gbps(1);
+ if (link_speeds & I40E_LINK_SPEED_100MB)
+ return IF_Mbps(100);
+ else
+ /* Minimum supported link speed */
+ return IF_Mbps(100);
+}
+
+/*
** Run when the Admin Queue gets a link state change interrupt.
*/
void
@@ -1194,7 +1205,7 @@ ixl_initialize_vsi(struct ixl_vsi *vsi)
* the driver may not use all of them).
*/
tc_queues = fls(pf->qtag.num_allocated) - 1;
- ctxt.info.tc_mapping[0] = ((0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT)
+ ctxt.info.tc_mapping[0] = ((pf->qtag.first_qidx << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT)
& I40E_AQ_VSI_TC_QUE_OFFSET_MASK) |
((tc_queues << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)
& I40E_AQ_VSI_TC_QUE_NUMBER_MASK);
@@ -1493,23 +1504,6 @@ ixl_set_queue_tx_itr(struct ixl_tx_queue *que)
return;
}
-void
-ixl_add_vsi_sysctls(struct ixl_pf *pf, struct ixl_vsi *vsi,
- struct sysctl_ctx_list *ctx, const char *sysctl_name)
-{
- struct sysctl_oid *tree;
- struct sysctl_oid_list *child;
- struct sysctl_oid_list *vsi_list;
-
- tree = device_get_sysctl_tree(pf->dev);
- child = SYSCTL_CHILDREN(tree);
- vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name,
- CTLFLAG_RD, NULL, "VSI Number");
- vsi_list = SYSCTL_CHILDREN(vsi->vsi_node);
-
- ixl_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats);
-}
-
#ifdef IXL_DEBUG
/**
* ixl_sysctl_qtx_tail_handler
@@ -1634,131 +1628,17 @@ ixl_add_hw_stats(struct ixl_pf *pf)
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
struct sysctl_oid *tree = device_get_sysctl_tree(dev);
struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
- struct sysctl_oid_list *vsi_list, *queue_list;
- struct sysctl_oid *queue_node;
- char queue_namebuf[32];
-
- struct ixl_rx_queue *rx_que;
- struct ixl_tx_queue *tx_que;
- struct tx_ring *txr;
- struct rx_ring *rxr;
/* Driver statistics */
- SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "watchdog_events",
- CTLFLAG_RD, &pf->watchdog_events,
- "Watchdog timeouts");
SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "admin_irq",
CTLFLAG_RD, &pf->admin_irq,
- "Admin Queue IRQ Handled");
-
- ixl_add_vsi_sysctls(pf, &pf->vsi, ctx, "pf");
- vsi_list = SYSCTL_CHILDREN(pf->vsi.vsi_node);
-
- /* Queue statistics */
- for (int q = 0; q < vsi->num_rx_queues; q++) {
- snprintf(queue_namebuf, QUEUE_NAME_LEN, "rxq%02d", q);
- queue_node = SYSCTL_ADD_NODE(ctx, vsi_list,
- OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "RX Queue #");
- queue_list = SYSCTL_CHILDREN(queue_node);
-
- rx_que = &(vsi->rx_queues[q]);
- rxr = &(rx_que->rxr);
-
-
- SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
- CTLFLAG_RD, &(rx_que->irqs),
- "irqs on this queue (both Tx and Rx)");
-
- SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "packets",
- CTLFLAG_RD, &(rxr->rx_packets),
- "Queue Packets Received");
- SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "bytes",
- CTLFLAG_RD, &(rxr->rx_bytes),
- "Queue Bytes Received");
- SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "desc_err",
- CTLFLAG_RD, &(rxr->desc_errs),
- "Queue Rx Descriptor Errors");
- SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "itr",
- CTLFLAG_RD, &(rxr->itr), 0,
- "Queue Rx ITR Interval");
-#ifdef IXL_DEBUG
- SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qrx_tail",
- CTLTYPE_UINT | CTLFLAG_RD, rx_que,
- sizeof(struct ixl_rx_queue),
- ixl_sysctl_qrx_tail_handler, "IU",
- "Queue Receive Descriptor Tail");
-#endif
- }
- for (int q = 0; q < vsi->num_tx_queues; q++) {
- snprintf(queue_namebuf, QUEUE_NAME_LEN, "txq%02d", q);
- queue_node = SYSCTL_ADD_NODE(ctx, vsi_list,
- OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "TX Queue #");
- queue_list = SYSCTL_CHILDREN(queue_node);
-
- tx_que = &(vsi->tx_queues[q]);
- txr = &(tx_que->txr);
-
- SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso",
- CTLFLAG_RD, &(tx_que->tso),
- "TSO");
- SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mss_too_small",
- CTLFLAG_RD, &(txr->mss_too_small),
- "TSO sends with an MSS less than 64");
- SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "packets",
- CTLFLAG_RD, &(txr->tx_packets),
- "Queue Packets Transmitted");
- SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "bytes",
- CTLFLAG_RD, &(txr->tx_bytes),
- "Queue Bytes Transmitted");
- SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "itr",
- CTLFLAG_RD, &(txr->itr), 0,
- "Queue Tx ITR Interval");
-#ifdef IXL_DEBUG
- SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qtx_tail",
- CTLTYPE_UINT | CTLFLAG_RD, tx_que,
- sizeof(struct ixl_tx_queue),
- ixl_sysctl_qtx_tail_handler, "IU",
- "Queue Transmit Descriptor Tail");
-#endif
- }
+ "Admin Queue IRQs received");
- /* MAC stats */
- ixl_add_sysctls_mac_stats(ctx, child, pf_stats);
-}
+ ixl_add_vsi_sysctls(dev, vsi, ctx, "pf");
-void
-ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx,
- struct sysctl_oid_list *child,
- struct i40e_eth_stats *eth_stats)
-{
- struct ixl_sysctl_info ctls[] =
- {
- {&eth_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"},
- {&eth_stats->rx_unicast, "ucast_pkts_rcvd",
- "Unicast Packets Received"},
- {&eth_stats->rx_multicast, "mcast_pkts_rcvd",
- "Multicast Packets Received"},
- {&eth_stats->rx_broadcast, "bcast_pkts_rcvd",
- "Broadcast Packets Received"},
- {&eth_stats->rx_discards, "rx_discards", "Discarded RX packets"},
- {&eth_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"},
- {&eth_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"},
- {&eth_stats->tx_multicast, "mcast_pkts_txd",
- "Multicast Packets Transmitted"},
- {&eth_stats->tx_broadcast, "bcast_pkts_txd",
- "Broadcast Packets Transmitted"},
- // end
- {0,0,0}
- };
+ ixl_add_queues_sysctls(dev, vsi);
- struct ixl_sysctl_info *entry = ctls;
- while (entry->stat != 0)
- {
- SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name,
- CTLFLAG_RD, entry->stat,
- entry->description);
- entry++;
- }
+ ixl_add_sysctls_mac_stats(ctx, child, pf_stats);
}
void
@@ -1986,7 +1866,7 @@ ixl_setup_vlan_filters(struct ixl_vsi *vsi)
* configured which interferes with filters managed by driver.
* Make sure it's removed.
*/
-static void
+void
ixl_del_default_hw_filters(struct ixl_vsi *vsi)
{
struct i40e_aqc_remove_macvlan_element_data e;
@@ -2052,8 +1932,6 @@ ixl_add_mc_filter(struct ixl_vsi *vsi, u8 *macaddr)
f->flags |= IXL_FILTER_MC;
else
printf("WARNING: no filter available!!\n");
-
- return;
}
void
@@ -2063,8 +1941,10 @@ ixl_reconfigure_filters(struct ixl_vsi *vsi)
}
/*
-** This routine adds macvlan filters
-*/
+ * This routine adds a MAC/VLAN filter to the software filter
+ * list, then adds that new filter to the HW if it doesn't already
+ * exist in the SW filter list.
+ */
void
ixl_add_filter(struct ixl_vsi *vsi, const u8 *macaddr, s16 vlan)
{
@@ -2104,8 +1984,8 @@ ixl_add_filter(struct ixl_vsi *vsi, const u8 *macaddr, s16 vlan)
else
vsi->num_macs++;
+ f->flags |= IXL_FILTER_USED;
ixl_add_hw_filters(vsi, f->flags, 1);
- return;
}
void
@@ -2165,12 +2045,15 @@ ixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt)
enum i40e_status_code status;
int j = 0;
- MPASS(cnt > 0);
-
pf = vsi->back;
- dev = iflib_get_dev(vsi->ctx);
+ dev = vsi->dev;
hw = &pf->hw;
+ if (cnt < 1) {
+ ixl_dbg_info(pf, "ixl_add_hw_filters: cnt == 0\n");
+ return;
+ }
+
a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt,
M_DEVBUF, M_NOWAIT | M_ZERO);
if (a == NULL) {
@@ -2197,6 +2080,9 @@ ixl_add_hw_filters(struct ixl_vsi *vsi, int flags, int cnt)
b->flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;
f->flags &= ~IXL_FILTER_ADD;
j++;
+
+ ixl_dbg_filter(pf, "ADD: " MAC_FORMAT "\n",
+ MAC_FORMAT_ARGS(f->macaddr));
}
if (j == cnt)
break;
@@ -2232,7 +2118,7 @@ ixl_del_hw_filters(struct ixl_vsi *vsi, int cnt)
pf = vsi->back;
hw = &pf->hw;
- dev = iflib_get_dev(vsi->ctx);
+ dev = vsi->dev;
d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt,
M_DEVBUF, M_NOWAIT | M_ZERO);
@@ -2252,6 +2138,10 @@ ixl_del_hw_filters(struct ixl_vsi *vsi, int cnt)
} else {
e->vlan_tag = f->vlan;
}
+
+ ixl_dbg_filter(pf, "DEL: " MAC_FORMAT "\n",
+ MAC_FORMAT_ARGS(f->macaddr));
+
/* delete entry from vsi list */
SLIST_REMOVE(&vsi->ftl, f, ixl_mac_filter, next);
free(f, M_DEVBUF);
@@ -2456,30 +2346,22 @@ ixl_disable_ring(struct ixl_pf *pf, struct ixl_pf_qtag *qtag, u16 vsi_qidx)
return (error);
}
-/* For PF VSI only */
int
-ixl_disable_rings(struct ixl_vsi *vsi)
+ixl_disable_rings(struct ixl_pf *pf, struct ixl_vsi *vsi, struct ixl_pf_qtag *qtag)
{
- struct ixl_pf *pf = vsi->back;
- int error = 0;
+ int error = 0;
for (int i = 0; i < vsi->num_tx_queues; i++)
- error = ixl_disable_tx_ring(pf, &pf->qtag, i);
+ error = ixl_disable_tx_ring(pf, qtag, i);
for (int i = 0; i < vsi->num_rx_queues; i++)
- error = ixl_disable_rx_ring(pf, &pf->qtag, i);
+ error = ixl_disable_rx_ring(pf, qtag, i);
return (error);
}
-/**
- * ixl_handle_mdd_event
- *
- * Called from interrupt handler to identify possibly malicious vfs
- * (But also detects events from the PF, as well)
- **/
-void
-ixl_handle_mdd_event(struct ixl_pf *pf)
+static void
+ixl_handle_tx_mdd_event(struct ixl_pf *pf)
{
struct i40e_hw *hw = &pf->hw;
device_t dev = pf->dev;
@@ -2487,88 +2369,163 @@ ixl_handle_mdd_event(struct ixl_pf *pf)
bool mdd_detected = false;
bool pf_mdd_detected = false;
bool vf_mdd_detected = false;
+ u16 vf_num, queue;
+ u8 pf_num, event;
+ u8 pf_mdet_num, vp_mdet_num;
u32 reg;
/* find what triggered the MDD event */
reg = rd32(hw, I40E_GL_MDET_TX);
if (reg & I40E_GL_MDET_TX_VALID_MASK) {
- u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >>
- I40E_GL_MDET_TX_PF_NUM_SHIFT;
- u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >>
- I40E_GL_MDET_TX_EVENT_SHIFT;
- u16 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
- I40E_GL_MDET_TX_QUEUE_SHIFT;
- device_printf(dev,
- "Malicious Driver Detection event %d"
- " on TX queue %d, pf number %d\n",
- event, queue, pf_num);
+ pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >>
+ I40E_GL_MDET_TX_PF_NUM_SHIFT;
+ vf_num = (reg & I40E_GL_MDET_TX_VF_NUM_MASK) >>
+ I40E_GL_MDET_TX_VF_NUM_SHIFT;
+ event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >>
+ I40E_GL_MDET_TX_EVENT_SHIFT;
+ queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
+ I40E_GL_MDET_TX_QUEUE_SHIFT;
wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
mdd_detected = true;
}
- reg = rd32(hw, I40E_GL_MDET_RX);
- if (reg & I40E_GL_MDET_RX_VALID_MASK) {
- u8 pf_num = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >>
- I40E_GL_MDET_RX_FUNCTION_SHIFT;
- u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >>
- I40E_GL_MDET_RX_EVENT_SHIFT;
- u16 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
- I40E_GL_MDET_RX_QUEUE_SHIFT;
- device_printf(dev,
- "Malicious Driver Detection event %d"
- " on RX queue %d, pf number %d\n",
- event, queue, pf_num);
- wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
- mdd_detected = true;
- }
- if (mdd_detected) {
- reg = rd32(hw, I40E_PF_MDET_TX);
- if (reg & I40E_PF_MDET_TX_VALID_MASK) {
- wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
- device_printf(dev,
- "MDD TX event is for this function!\n");
- pf_mdd_detected = true;
- }
- reg = rd32(hw, I40E_PF_MDET_RX);
- if (reg & I40E_PF_MDET_RX_VALID_MASK) {
- wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
- device_printf(dev,
- "MDD RX event is for this function!\n");
- pf_mdd_detected = true;
- }
- }
+ if (!mdd_detected)
+ return;
- if (pf_mdd_detected) {
- atomic_set_32(&pf->state, IXL_PF_STATE_PF_RESET_REQ);
- goto end;
+ reg = rd32(hw, I40E_PF_MDET_TX);
+ if (reg & I40E_PF_MDET_TX_VALID_MASK) {
+ wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
+ pf_mdet_num = hw->pf_id;
+ pf_mdd_detected = true;
}
- // Handle VF detection
- for (int i = 0; i < pf->num_vfs && mdd_detected; i++) {
+ /* Check if MDD was caused by a VF */
+ for (int i = 0; i < pf->num_vfs; i++) {
vf = &(pf->vfs[i]);
reg = rd32(hw, I40E_VP_MDET_TX(i));
if (reg & I40E_VP_MDET_TX_VALID_MASK) {
wr32(hw, I40E_VP_MDET_TX(i), 0xFFFF);
+ vp_mdet_num = i;
vf->num_mdd_events++;
- device_printf(dev, "MDD TX event is for VF %d\n", i);
vf_mdd_detected = true;
}
+ }
+
+ /* Print out an error message */
+ if (vf_mdd_detected && pf_mdd_detected)
+ device_printf(dev,
+ "Malicious Driver Detection event %d"
+ " on TX queue %d, pf number %d (PF-%d), vf number %d (VF-%d)\n",
+ event, queue, pf_num, pf_mdet_num, vf_num, vp_mdet_num);
+ else if (vf_mdd_detected && !pf_mdd_detected)
+ device_printf(dev,
+ "Malicious Driver Detection event %d"
+ " on TX queue %d, pf number %d, vf number %d (VF-%d)\n",
+ event, queue, pf_num, vf_num, vp_mdet_num);
+ else if (!vf_mdd_detected && pf_mdd_detected)
+ device_printf(dev,
+ "Malicious Driver Detection event %d"
+ " on TX queue %d, pf number %d (PF-%d)\n",
+ event, queue, pf_num, pf_mdet_num);
+ /* Theoretically shouldn't happen */
+ else
+ device_printf(dev,
+ "TX Malicious Driver Detection event (unknown)\n");
+}
+
+static void
+ixl_handle_rx_mdd_event(struct ixl_pf *pf)
+{
+ struct i40e_hw *hw = &pf->hw;
+ device_t dev = pf->dev;
+ struct ixl_vf *vf;
+ bool mdd_detected = false;
+ bool pf_mdd_detected = false;
+ bool vf_mdd_detected = false;
+ u16 queue;
+ u8 pf_num, event;
+ u8 pf_mdet_num, vp_mdet_num;
+ u32 reg;
+
+ /*
+ * GL_MDET_RX doesn't contain VF number information, unlike
+ * GL_MDET_TX.
+ */
+ reg = rd32(hw, I40E_GL_MDET_RX);
+ if (reg & I40E_GL_MDET_RX_VALID_MASK) {
+ pf_num = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >>
+ I40E_GL_MDET_RX_FUNCTION_SHIFT;
+ event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >>
+ I40E_GL_MDET_RX_EVENT_SHIFT;
+ queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
+ I40E_GL_MDET_RX_QUEUE_SHIFT;
+ wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
+ mdd_detected = true;
+ }
+
+ if (!mdd_detected)
+ return;
+
+ reg = rd32(hw, I40E_PF_MDET_RX);
+ if (reg & I40E_PF_MDET_RX_VALID_MASK) {
+ wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
+ pf_mdet_num = hw->pf_id;
+ pf_mdd_detected = true;
+ }
+ /* Check if MDD was caused by a VF */
+ for (int i = 0; i < pf->num_vfs; i++) {
+ vf = &(pf->vfs[i]);
reg = rd32(hw, I40E_VP_MDET_RX(i));
if (reg & I40E_VP_MDET_RX_VALID_MASK) {
wr32(hw, I40E_VP_MDET_RX(i), 0xFFFF);
+ vp_mdet_num = i;
vf->num_mdd_events++;
- device_printf(dev, "MDD RX event is for VF %d\n", i);
vf_mdd_detected = true;
}
-
- // TODO: Disable VF if there are too many MDD events from it
}
- if (vf_mdd_detected)
- atomic_set_32(&pf->state, IXL_PF_STATE_VF_RESET_REQ);
+ /* Print out an error message */
+ if (vf_mdd_detected && pf_mdd_detected)
+ device_printf(dev,
+ "Malicious Driver Detection event %d"
+ " on RX queue %d, pf number %d (PF-%d), (VF-%d)\n",
+ event, queue, pf_num, pf_mdet_num, vp_mdet_num);
+ else if (vf_mdd_detected && !pf_mdd_detected)
+ device_printf(dev,
+ "Malicious Driver Detection event %d"
+ " on RX queue %d, pf number %d, (VF-%d)\n",
+ event, queue, pf_num, vp_mdet_num);
+ else if (!vf_mdd_detected && pf_mdd_detected)
+ device_printf(dev,
+ "Malicious Driver Detection event %d"
+ " on RX queue %d, pf number %d (PF-%d)\n",
+ event, queue, pf_num, pf_mdet_num);
+ /* Theoretically shouldn't happen */
+ else
+ device_printf(dev,
+ "RX Malicious Driver Detection event (unknown)\n");
+}
+
+/**
+ * ixl_handle_mdd_event
+ *
+ * Called from interrupt handler to identify possibly malicious vfs
+ * (But also detects events from the PF, as well)
+ **/
+void
+ixl_handle_mdd_event(struct ixl_pf *pf)
+{
+ struct i40e_hw *hw = &pf->hw;
+ u32 reg;
+
+ /*
+ * Handle both TX/RX because it's possible they could
+ * both trigger in the same interrupt.
+ */
+ ixl_handle_tx_mdd_event(pf);
+ ixl_handle_rx_mdd_event(pf);
-end:
atomic_clear_32(&pf->state, IXL_PF_STATE_MDD_PENDING);
/* re-enable mdd interrupt cause */
@@ -2578,14 +2535,12 @@ end:
ixl_flush(hw);
}
-/* This only enables HW interrupts for the RX queues */
void
ixl_enable_intr(struct ixl_vsi *vsi)
{
struct i40e_hw *hw = vsi->hw;
struct ixl_rx_queue *que = vsi->rx_queues;
- // TODO: Check iflib interrupt mode instead?
if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) {
for (int i = 0; i < vsi->num_rx_queues; i++, que++)
ixl_enable_queue(hw, que->rxr.me);
@@ -2845,7 +2800,7 @@ ixl_prepare_for_reset(struct ixl_pf *pf, bool is_up)
}
int
-ixl_rebuild_hw_structs_after_reset(struct ixl_pf *pf, bool is_up)
+ixl_rebuild_hw_structs_after_reset(struct ixl_pf *pf)
{
struct i40e_hw *hw = &pf->hw;
struct ixl_vsi *vsi = &pf->vsi;
@@ -2902,6 +2857,25 @@ ixl_rebuild_hw_structs_after_reset(struct ixl_pf *pf, bool is_up)
if (error) {
device_printf(dev, "ixl_rebuild_hw_structs_after_reset: ixl_switch_config() failed: %d\n",
error);
+ error = EIO;
+ goto ixl_rebuild_hw_structs_after_reset_err;
+ }
+
+ error = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK,
+ NULL);
+ if (error) {
+ device_printf(dev, "init: i40e_aq_set_phy_mask() failed: err %d,"
+ " aq_err %d\n", error, hw->aq.asq_last_status);
+ error = EIO;
+ goto ixl_rebuild_hw_structs_after_reset_err;
+ }
+
+ u8 set_fc_err_mask;
+ error = i40e_set_fc(hw, &set_fc_err_mask, true);
+ if (error) {
+ device_printf(dev, "init: setting link flow control failed; retcode %d,"
+ " fc_err_mask 0x%02x\n", error, set_fc_err_mask);
+ error = EIO;
goto ixl_rebuild_hw_structs_after_reset_err;
}
@@ -2954,7 +2928,7 @@ ixl_handle_empr_reset(struct ixl_pf *pf)
ixl_dbg(pf, IXL_DBG_INFO,
"Reset wait count: %d\n", count);
- ixl_rebuild_hw_structs_after_reset(pf, is_up);
+ ixl_rebuild_hw_structs_after_reset(pf);
atomic_clear_int(&pf->state, IXL_PF_STATE_ADAPTER_RESETTING);
}
@@ -3314,12 +3288,6 @@ ixl_add_device_sysctls(struct ixl_pf *pf)
OID_AUTO, "read_i2c_diag_data", CTLTYPE_STRING | CTLFLAG_RD,
pf, 0, ixl_sysctl_read_i2c_diag_data, "A", "Dump selected diagnostic data from FW");
}
-
-#ifdef PCI_IOV
- SYSCTL_ADD_UINT(ctx, debug_list,
- OID_AUTO, "vc_debug_level", CTLFLAG_RW, &pf->vc_debug_lvl,
- 0, "PF/VF Virtual Channel debug level");
-#endif
}
/*
@@ -3332,9 +3300,7 @@ ixl_sysctl_unallocated_queues(SYSCTL_HANDLER_ARGS)
struct ixl_pf *pf = (struct ixl_pf *)arg1;
int queues;
- //IXL_PF_LOCK(pf);
queues = (int)ixl_pf_qmgr_get_num_free(&pf->qmgr);
- //IXL_PF_UNLOCK(pf);
return sysctl_handle_int(oidp, NULL, queues, req);
}
@@ -3998,44 +3964,72 @@ ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS)
struct ixl_pf *pf = (struct ixl_pf *)arg1;
struct ixl_vsi *vsi = &pf->vsi;
struct ixl_mac_filter *f;
- char *buf, *buf_i;
+ device_t dev = pf->dev;
+ int error = 0, ftl_len = 0, ftl_counter = 0;
- int error = 0;
- int ftl_len = 0;
- int ftl_counter = 0;
- int buf_len = 0;
- int entry_len = 42;
+ struct sbuf *buf;
- SLIST_FOREACH(f, &vsi->ftl, next) {
- ftl_len++;
+ buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
+ if (!buf) {
+ device_printf(dev, "Could not allocate sbuf for output.\n");
+ return (ENOMEM);
}
- if (ftl_len < 1) {
- sysctl_handle_string(oidp, "(none)", 6, req);
- return (0);
- }
+ sbuf_printf(buf, "\n");
- buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2;
- buf = buf_i = malloc(buf_len, M_DEVBUF, M_WAITOK);
+ /* Print MAC filters */
+ sbuf_printf(buf, "PF Filters:\n");
+ SLIST_FOREACH(f, &vsi->ftl, next)
+ ftl_len++;
- sprintf(buf_i++, "\n");
- SLIST_FOREACH(f, &vsi->ftl, next) {
- sprintf(buf_i,
- MAC_FORMAT ", vlan %4d, flags %#06x",
- MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags);
- buf_i += entry_len;
- /* don't print '\n' for last entry */
- if (++ftl_counter != ftl_len) {
- sprintf(buf_i, "\n");
- buf_i++;
+ if (ftl_len < 1)
+ sbuf_printf(buf, "(none)\n");
+ else {
+ SLIST_FOREACH(f, &vsi->ftl, next) {
+ sbuf_printf(buf,
+ MAC_FORMAT ", vlan %4d, flags %#06x",
+ MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags);
+ /* don't print '\n' for last entry */
+ if (++ftl_counter != ftl_len)
+ sbuf_printf(buf, "\n");
}
}
- error = sysctl_handle_string(oidp, buf, strlen(buf), req);
+#ifdef PCI_IOV
+ /* TODO: Give each VF its own filter list sysctl */
+ struct ixl_vf *vf;
+ if (pf->num_vfs > 0) {
+ sbuf_printf(buf, "\n\n");
+ for (int i = 0; i < pf->num_vfs; i++) {
+ vf = &pf->vfs[i];
+ if (!(vf->vf_flags & VF_FLAG_ENABLED))
+ continue;
+
+ vsi = &vf->vsi;
+ ftl_len = 0, ftl_counter = 0;
+ sbuf_printf(buf, "VF-%d Filters:\n", vf->vf_num);
+ SLIST_FOREACH(f, &vsi->ftl, next)
+ ftl_len++;
+
+ if (ftl_len < 1)
+ sbuf_printf(buf, "(none)\n");
+ else {
+ SLIST_FOREACH(f, &vsi->ftl, next) {
+ sbuf_printf(buf,
+ MAC_FORMAT ", vlan %4d, flags %#06x\n",
+ MAC_FORMAT_ARGS(f->macaddr), f->vlan, f->flags);
+ }
+ }
+ }
+ }
+#endif
+
+ error = sbuf_finish(buf);
if (error)
- printf("sysctl error: %d\n", error);
- free(buf, M_DEVBUF);
- return error;
+ device_printf(dev, "Error finishing sbuf: %d\n", error);
+ sbuf_delete(buf);
+
+ return (error);
}
#define IXL_SW_RES_SIZE 0x14
diff --git a/sys/dev/ixl/ixl_pf_qmgr.c b/sys/dev/ixl/ixl_pf_qmgr.c
index 1871a99e3252..92ce8d61bd13 100644
--- a/sys/dev/ixl/ixl_pf_qmgr.c
+++ b/sys/dev/ixl/ixl_pf_qmgr.c
@@ -45,7 +45,7 @@ ixl_pf_qmgr_init(struct ixl_pf_qmgr *qmgr, u16 num_queues)
qmgr->num_queues = num_queues;
qmgr->qinfo = malloc(num_queues * sizeof(struct ixl_pf_qmgr_qinfo),
- M_IXL, M_ZERO | M_WAITOK);
+ M_IXL, M_ZERO | M_NOWAIT);
if (qmgr->qinfo == NULL)
return ENOMEM;
@@ -266,13 +266,29 @@ ixl_pf_qmgr_is_queue_configured(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx)
return (qmgr->qinfo[pf_qidx].rx_configured);
}
+void
+ixl_pf_qmgr_clear_queue_flags(struct ixl_pf_qtag *qtag)
+{
+ MPASS(qtag != NULL);
+
+ struct ixl_pf_qmgr *qmgr = qtag->qmgr;
+ for (u16 i = 0; i < qtag->num_allocated; i++) {
+ u16 pf_qidx = ixl_pf_qidx_from_vsi_qidx(qtag, i);
+
+ qmgr->qinfo[pf_qidx].tx_configured = 0;
+ qmgr->qinfo[pf_qidx].rx_configured = 0;
+ qmgr->qinfo[pf_qidx].rx_enabled = 0;
+ qmgr->qinfo[pf_qidx].tx_enabled = 0;
+ }
+}
+
u16
ixl_pf_qidx_from_vsi_qidx(struct ixl_pf_qtag *qtag, u16 index)
{
MPASS(index < qtag->num_allocated);
if (qtag->type == IXL_PF_QALLOC_CONTIGUOUS)
- return qtag->qidx[0] + index;
+ return qtag->first_qidx + index;
else
return qtag->qidx[index];
}
diff --git a/sys/dev/ixl/ixl_pf_qmgr.h b/sys/dev/ixl/ixl_pf_qmgr.h
index e399afc76105..670a277ff6a5 100644
--- a/sys/dev/ixl/ixl_pf_qmgr.h
+++ b/sys/dev/ixl/ixl_pf_qmgr.h
@@ -53,11 +53,11 @@
/* Manager */
struct ixl_pf_qmgr_qinfo {
- bool allocated;
- bool tx_enabled;
- bool rx_enabled;
- bool tx_configured;
- bool rx_configured;
+ u8 allocated;
+ u8 tx_enabled;
+ u8 rx_enabled;
+ u8 tx_configured;
+ u8 rx_configured;
};
struct ixl_pf_qmgr {
@@ -74,7 +74,10 @@ enum ixl_pf_qmgr_qalloc_type {
struct ixl_pf_qtag {
struct ixl_pf_qmgr *qmgr;
enum ixl_pf_qmgr_qalloc_type type;
- u16 qidx[IXL_MAX_SCATTERED_QUEUES];
+ union {
+ u16 qidx[IXL_MAX_SCATTERED_QUEUES];
+ u16 first_qidx;
+ };
u16 num_allocated;
u16 num_active;
};
@@ -101,6 +104,7 @@ void ixl_pf_qmgr_mark_queue_disabled(struct ixl_pf_qtag *qtag, u16 vsi_qidx, boo
void ixl_pf_qmgr_mark_queue_configured(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx);
bool ixl_pf_qmgr_is_queue_enabled(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx);
bool ixl_pf_qmgr_is_queue_configured(struct ixl_pf_qtag *qtag, u16 vsi_qidx, bool tx);
+void ixl_pf_qmgr_clear_queue_flags(struct ixl_pf_qtag *qtag);
/* Public tag functions */
u16 ixl_pf_qidx_from_vsi_qidx(struct ixl_pf_qtag *qtag, u16 index);
diff --git a/sys/dev/ixl/ixl_txrx.c b/sys/dev/ixl/ixl_txrx.c
index 3994e16a3d16..4966725426de 100644
--- a/sys/dev/ixl/ixl_txrx.c
+++ b/sys/dev/ixl/ixl_txrx.c
@@ -65,8 +65,6 @@ static int ixl_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx,
qidx_t budget);
static int ixl_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri);
-extern int ixl_intr(void *arg);
-
struct if_txrx ixl_txrx_hwb = {
ixl_isc_txd_encap,
ixl_isc_txd_flush,
@@ -75,7 +73,7 @@ struct if_txrx ixl_txrx_hwb = {
ixl_isc_rxd_pkt_get,
ixl_isc_rxd_refill,
ixl_isc_rxd_flush,
- ixl_intr
+ NULL
};
struct if_txrx ixl_txrx_dwb = {
@@ -86,7 +84,7 @@ struct if_txrx ixl_txrx_dwb = {
ixl_isc_rxd_pkt_get,
ixl_isc_rxd_refill,
ixl_isc_rxd_flush,
- ixl_intr
+ NULL
};
/*
@@ -133,6 +131,21 @@ i40e_vc_stat_str(struct i40e_hw *hw, enum virtchnl_status_code stat_err)
return hw->err_str;
}
+void
+ixl_debug_core(device_t dev, u32 enabled_mask, u32 mask, char *fmt, ...)
+{
+ va_list args;
+
+ if (!(mask & enabled_mask))
+ return;
+
+ /* Re-implement device_printf() */
+ device_print_prettyname(dev);
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+}
+
static bool
ixl_is_tx_desc_done(struct tx_ring *txr, int idx)
{
@@ -236,6 +249,8 @@ ixl_tx_setup_offload(struct ixl_tx_queue *que,
*cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP;
*off |= (pi->ipi_tcp_hlen >> 2) <<
I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+ /* Check for NO_HEAD MDD event */
+ MPASS(pi->ipi_tcp_hlen != 0);
}
break;
case IPPROTO_UDP:
@@ -268,23 +283,37 @@ ixl_tso_setup(struct tx_ring *txr, if_pkt_info_t pi)
if_softc_ctx_t scctx;
struct i40e_tx_context_desc *TXD;
u32 cmd, mss, type, tsolen;
- int idx;
+ int idx, total_hdr_len;
u64 type_cmd_tso_mss;
idx = pi->ipi_pidx;
TXD = (struct i40e_tx_context_desc *) &txr->tx_base[idx];
- tsolen = pi->ipi_len - (pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen);
+ total_hdr_len = pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen;
+ tsolen = pi->ipi_len - total_hdr_len;
scctx = txr->que->vsi->shared;
type = I40E_TX_DESC_DTYPE_CONTEXT;
cmd = I40E_TX_CTX_DESC_TSO;
- /* TSO MSS must not be less than 64 */
+ /*
+ * TSO MSS must not be less than 64; this prevents a
+ * BAD_LSO_MSS MDD event when the MSS is too small.
+ */
if (pi->ipi_tso_segsz < IXL_MIN_TSO_MSS) {
txr->mss_too_small++;
pi->ipi_tso_segsz = IXL_MIN_TSO_MSS;
}
mss = pi->ipi_tso_segsz;
+ /* Check for BAD_LS0_MSS MDD event (mss too large) */
+ MPASS(mss <= IXL_MAX_TSO_MSS);
+ /* Check for NO_HEAD MDD event (header lengths are 0) */
+ MPASS(pi->ipi_ehdrlen != 0);
+ MPASS(pi->ipi_ip_hlen != 0);
+ /* Partial check for BAD_LSO_LEN MDD event */
+ MPASS(tsolen != 0);
+ /* Partial check for WRONG_SIZE MDD event (during TSO) */
+ MPASS(total_hdr_len + mss <= IXL_MAX_FRAME);
+
type_cmd_tso_mss = ((u64)type << I40E_TXD_CTX_QW1_DTYPE_SHIFT) |
((u64)cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) |
((u64)tsolen << I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) |
@@ -319,20 +348,16 @@ ixl_isc_txd_encap(void *arg, if_pkt_info_t pi)
int i, j, mask, pidx_last;
u32 cmd, off, tx_intr;
- // device_printf(iflib_get_dev(vsi->ctx), "%s: begin\n", __func__);
-
cmd = off = 0;
i = pi->ipi_pidx;
tx_intr = (pi->ipi_flags & IPI_TX_INTR);
-#if 0
- device_printf(iflib_get_dev(vsi->ctx), "%s: tx_intr %d\n", __func__, tx_intr);
-#endif
/* Set up the TSO/CSUM offload */
if (pi->ipi_csum_flags & CSUM_OFFLOAD) {
/* Set up the TSO context descriptor if required */
if (pi->ipi_csum_flags & CSUM_TSO) {
+ /* Prevent MAX_BUFF MDD event (for TSO) */
if (ixl_tso_detect_sparse(segs, nsegs, pi))
return (EFBIG);
i = ixl_tso_setup(txr, pi);
@@ -344,12 +369,21 @@ ixl_isc_txd_encap(void *arg, if_pkt_info_t pi)
cmd |= I40E_TX_DESC_CMD_ICRC;
mask = scctx->isc_ntxd[0] - 1;
+ /* Check for WRONG_SIZE MDD event */
+ MPASS(pi->ipi_len >= IXL_MIN_FRAME);
+#ifdef INVARIANTS
+ if (!(pi->ipi_csum_flags & CSUM_TSO))
+ MPASS(pi->ipi_len <= IXL_MAX_FRAME);
+#endif
for (j = 0; j < nsegs; j++) {
bus_size_t seglen;
txd = &txr->tx_base[i];
seglen = segs[j].ds_len;
+ /* Check for ZERO_BSIZE MDD event */
+ MPASS(seglen != 0);
+
txd->buffer_addr = htole64(segs[j].ds_addr);
txd->cmd_type_offset_bsz =
htole64(I40E_TX_DESC_DTYPE_DATA
@@ -387,6 +421,8 @@ ixl_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx)
* Advance the Transmit Descriptor Tail (Tdt), this tells the
* hardware that this frame is available to transmit.
*/
+ /* Check for ENDLESS_TX MDD event */
+ MPASS(pidx < vsi->shared->isc_ntxd[0]);
wr32(vsi->hw, txr->tail, pidx);
}
@@ -406,9 +442,7 @@ ixl_init_tx_ring(struct ixl_vsi *vsi, struct ixl_tx_queue *que)
(sizeof(struct i40e_tx_desc)) *
(vsi->shared->isc_ntxd[0] + (vsi->enable_head_writeback ? 1 : 0)));
- // TODO: Write max descriptor index instead of 0?
wr32(vsi->hw, txr->tail, 0);
- wr32(vsi->hw, I40E_QTX_HEAD(txr->me), 0);
}
/*
@@ -470,9 +504,14 @@ ixl_isc_txd_credits_update_dwb(void *arg, uint16_t txqid, bool clear)
MPASS(cur != QIDX_INVALID);
is_done = ixl_is_tx_desc_done(txr, cur);
- if (clear == false || !is_done)
+ if (!is_done)
return (0);
+ /* If clear is false just let caller know that there
+ * are descriptors to reclaim */
+ if (!clear)
+ return (1);
+
prev = txr->tx_cidx_processed;
ntxd = scctx->isc_ntxd[0];
do {
@@ -547,14 +586,6 @@ ixl_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx, qidx_t budget)
nrxd = vsi->shared->isc_nrxd[0];
- if (budget == 1) {
- rxd = &rxr->rx_base[idx];
- qword = le64toh(rxd->wb.qword1.status_error_len);
- status = (qword & I40E_RXD_QW1_STATUS_MASK)
- >> I40E_RXD_QW1_STATUS_SHIFT;
- return !!(status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT));
- }
-
for (cnt = 0, i = idx; cnt < nrxd - 1 && cnt <= budget;) {
rxd = &rxr->rx_base[i];
qword = le64toh(rxd->wb.qword1.status_error_len);
@@ -657,7 +688,7 @@ ixl_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
MPASS((status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) != 0);
ri->iri_len += plen;
- rxr->bytes += plen;
+ rxr->rx_bytes += plen;
cur->wb.qword1.status_error_len = 0;
eop = (status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT));
@@ -745,25 +776,179 @@ ixl_rx_checksum(if_rxd_info_t ri, u32 status, u32 error, u8 ptype)
ri->iri_csum_data |= htons(0xffff);
}
+/* Set Report Status queue fields to 0 */
+void
+ixl_init_tx_rsqs(struct ixl_vsi *vsi)
+{
+ if_softc_ctx_t scctx = vsi->shared;
+ struct ixl_tx_queue *tx_que;
+ int i, j;
+
+ for (i = 0, tx_que = vsi->tx_queues; i < vsi->num_tx_queues; i++, tx_que++) {
+ struct tx_ring *txr = &tx_que->txr;
+
+ txr->tx_rs_cidx = txr->tx_rs_pidx = txr->tx_cidx_processed = 0;
+
+ for (j = 0; j < scctx->isc_ntxd[0]; j++)
+ txr->tx_rsq[j] = QIDX_INVALID;
+ }
+}
+
+void
+ixl_init_tx_cidx(struct ixl_vsi *vsi)
+{
+ struct ixl_tx_queue *tx_que;
+ int i;
+
+ for (i = 0, tx_que = vsi->tx_queues; i < vsi->num_tx_queues; i++, tx_que++) {
+ struct tx_ring *txr = &tx_que->txr;
+
+ txr->tx_cidx_processed = 0;
+ }
+}
+
/*
- * Input: bitmap of enum i40e_aq_link_speed
+ * Input: bitmap of enum virtchnl_link_speed
*/
u64
-ixl_max_aq_speed_to_value(u8 link_speeds)
+ixl_max_vc_speed_to_value(u8 link_speeds)
{
- if (link_speeds & I40E_LINK_SPEED_40GB)
+ if (link_speeds & VIRTCHNL_LINK_SPEED_40GB)
return IF_Gbps(40);
- if (link_speeds & I40E_LINK_SPEED_25GB)
+ if (link_speeds & VIRTCHNL_LINK_SPEED_25GB)
return IF_Gbps(25);
- if (link_speeds & I40E_LINK_SPEED_20GB)
+ if (link_speeds & VIRTCHNL_LINK_SPEED_20GB)
return IF_Gbps(20);
- if (link_speeds & I40E_LINK_SPEED_10GB)
+ if (link_speeds & VIRTCHNL_LINK_SPEED_10GB)
return IF_Gbps(10);
- if (link_speeds & I40E_LINK_SPEED_1GB)
+ if (link_speeds & VIRTCHNL_LINK_SPEED_1GB)
return IF_Gbps(1);
- if (link_speeds & I40E_LINK_SPEED_100MB)
+ if (link_speeds & VIRTCHNL_LINK_SPEED_100MB)
return IF_Mbps(100);
else
/* Minimum supported link speed */
return IF_Mbps(100);
}
+
+void
+ixl_add_vsi_sysctls(device_t dev, struct ixl_vsi *vsi,
+ struct sysctl_ctx_list *ctx, const char *sysctl_name)
+{
+ struct sysctl_oid *tree;
+ struct sysctl_oid_list *child;
+ struct sysctl_oid_list *vsi_list;
+
+ tree = device_get_sysctl_tree(dev);
+ child = SYSCTL_CHILDREN(tree);
+ vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name,
+ CTLFLAG_RD, NULL, "VSI Number");
+ vsi_list = SYSCTL_CHILDREN(vsi->vsi_node);
+
+ ixl_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats);
+}
+
+void
+ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx,
+ struct sysctl_oid_list *child,
+ struct i40e_eth_stats *eth_stats)
+{
+ struct ixl_sysctl_info ctls[] =
+ {
+ {&eth_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"},
+ {&eth_stats->rx_unicast, "ucast_pkts_rcvd",
+ "Unicast Packets Received"},
+ {&eth_stats->rx_multicast, "mcast_pkts_rcvd",
+ "Multicast Packets Received"},
+ {&eth_stats->rx_broadcast, "bcast_pkts_rcvd",
+ "Broadcast Packets Received"},
+ {&eth_stats->rx_discards, "rx_discards", "Discarded RX packets"},
+ {&eth_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"},
+ {&eth_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"},
+ {&eth_stats->tx_multicast, "mcast_pkts_txd",
+ "Multicast Packets Transmitted"},
+ {&eth_stats->tx_broadcast, "bcast_pkts_txd",
+ "Broadcast Packets Transmitted"},
+ // end
+ {0,0,0}
+ };
+
+ struct ixl_sysctl_info *entry = ctls;
+ while (entry->stat != 0)
+ {
+ SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name,
+ CTLFLAG_RD, entry->stat,
+ entry->description);
+ entry++;
+ }
+}
+
+void
+ixl_add_queues_sysctls(device_t dev, struct ixl_vsi *vsi)
+{
+ struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
+ struct sysctl_oid_list *vsi_list, *queue_list;
+ struct sysctl_oid *queue_node;
+ char queue_namebuf[32];
+
+ struct ixl_rx_queue *rx_que;
+ struct ixl_tx_queue *tx_que;
+ struct tx_ring *txr;
+ struct rx_ring *rxr;
+
+ vsi_list = SYSCTL_CHILDREN(vsi->vsi_node);
+
+ /* Queue statistics */
+ for (int q = 0; q < vsi->num_rx_queues; q++) {
+ bzero(queue_namebuf, sizeof(queue_namebuf));
+ snprintf(queue_namebuf, QUEUE_NAME_LEN, "rxq%02d", q);
+ queue_node = SYSCTL_ADD_NODE(ctx, vsi_list,
+ OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "RX Queue #");
+ queue_list = SYSCTL_CHILDREN(queue_node);
+
+ rx_que = &(vsi->rx_queues[q]);
+ rxr = &(rx_que->rxr);
+
+ SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs",
+ CTLFLAG_RD, &(rx_que->irqs),
+ "irqs on this queue (both Tx and Rx)");
+
+ SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "packets",
+ CTLFLAG_RD, &(rxr->rx_packets),
+ "Queue Packets Received");
+ SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "bytes",
+ CTLFLAG_RD, &(rxr->rx_bytes),
+ "Queue Bytes Received");
+ SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "desc_err",
+ CTLFLAG_RD, &(rxr->desc_errs),
+ "Queue Rx Descriptor Errors");
+ SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "itr",
+ CTLFLAG_RD, &(rxr->itr), 0,
+ "Queue Rx ITR Interval");
+ }
+ for (int q = 0; q < vsi->num_tx_queues; q++) {
+ bzero(queue_namebuf, sizeof(queue_namebuf));
+ snprintf(queue_namebuf, QUEUE_NAME_LEN, "txq%02d", q);
+ queue_node = SYSCTL_ADD_NODE(ctx, vsi_list,
+ OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "TX Queue #");
+ queue_list = SYSCTL_CHILDREN(queue_node);
+
+ tx_que = &(vsi->tx_queues[q]);
+ txr = &(tx_que->txr);
+
+ SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso",
+ CTLFLAG_RD, &(tx_que->tso),
+ "TSO");
+ SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mss_too_small",
+ CTLFLAG_RD, &(txr->mss_too_small),
+ "TSO sends with an MSS less than 64");
+ SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "packets",
+ CTLFLAG_RD, &(txr->tx_packets),
+ "Queue Packets Transmitted");
+ SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "bytes",
+ CTLFLAG_RD, &(txr->tx_bytes),
+ "Queue Bytes Transmitted");
+ SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "itr",
+ CTLFLAG_RD, &(txr->itr), 0,
+ "Queue Tx ITR Interval");
+ }
+}
diff --git a/sys/dev/ixl/ixlv.h b/sys/dev/ixl/ixlv.h
index 916b887e87d0..9f6f1cb8eefb 100644
--- a/sys/dev/ixl/ixlv.h
+++ b/sys/dev/ixl/ixlv.h
@@ -36,13 +36,12 @@
#ifndef _IXLV_H_
#define _IXLV_H_
-#include "ixlv_vc_mgr.h"
+#include "ixl.h"
#define IXLV_AQ_MAX_ERR 200
#define IXLV_MAX_FILTERS 128
#define IXLV_MAX_QUEUES 16
#define IXLV_AQ_TIMEOUT (1 * hz)
-#define IXLV_CALLOUT_TIMO (hz / 50) /* 20 msec */
#define IXLV_FLAG_AQ_ENABLE_QUEUES (u32)(1 << 0)
#define IXLV_FLAG_AQ_DISABLE_QUEUES (u32)(1 << 1)
@@ -58,42 +57,38 @@
#define IXLV_FLAG_AQ_CONFIG_RSS_KEY (u32)(1 << 11)
#define IXLV_FLAG_AQ_SET_RSS_HENA (u32)(1 << 12)
#define IXLV_FLAG_AQ_GET_RSS_HENA_CAPS (u32)(1 << 13)
-#define IXLV_FLAG_AQ_CONFIG_RSS_LUT (u32)(1 << 14)
+#define IXLV_FLAG_AQ_CONFIG_RSS_LUT (u32)(1 << 14)
-/* printf %b arg */
+/* printf %b flag args */
#define IXLV_FLAGS \
"\20\1ENABLE_QUEUES\2DISABLE_QUEUES\3ADD_MAC_FILTER" \
"\4ADD_VLAN_FILTER\5DEL_MAC_FILTER\6DEL_VLAN_FILTER" \
"\7CONFIGURE_QUEUES\10MAP_VECTORS\11HANDLE_RESET" \
- "\12CONFIGURE_PROMISC\13GET_STATS"
+ "\12CONFIGURE_PROMISC\13GET_STATS\14CONFIG_RSS_KEY" \
+ "\15SET_RSS_HENA\16GET_RSS_HENA_CAPS\17CONFIG_RSS_LUT"
#define IXLV_PRINTF_VF_OFFLOAD_FLAGS \
- "\20\1I40E_VIRTCHNL_VF_OFFLOAD_L2" \
- "\2I40E_VIRTCHNL_VF_OFFLOAD_IWARP" \
- "\3I40E_VIRTCHNL_VF_OFFLOAD_FCOE" \
- "\4I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ" \
- "\5I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG" \
- "\6I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR" \
- "\21I40E_VIRTCHNL_VF_OFFLOAD_VLAN" \
- "\22I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING" \
- "\23I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2" \
- "\24I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF"
-
-static MALLOC_DEFINE(M_IXLV, "ixlv", "ixlv driver allocations");
+ "\20\1L2" \
+ "\2IWARP" \
+ "\3RSVD" \
+ "\4RSS_AQ" \
+ "\5RSS_REG" \
+ "\6WB_ON_ITR" \
+ "\7REQ_QUEUES" \
+ "\21VLAN" \
+ "\22RX_POLLING" \
+ "\23RSS_PCTYPE_V2" \
+ "\24RSS_PF" \
+ "\25ENCAP" \
+ "\26ENCAP_CSUM" \
+ "\27RX_ENCAP_CSUM"
+
+MALLOC_DECLARE(M_IXLV);
/* Driver state */
enum ixlv_state_t {
- IXLV_START,
- IXLV_FAILED,
IXLV_RESET_REQUIRED,
IXLV_RESET_PENDING,
- IXLV_VERSION_CHECK,
- IXLV_GET_RESOURCES,
IXLV_INIT_READY,
- IXLV_INIT_START,
- IXLV_INIT_CONFIG,
- IXLV_INIT_MAPPING,
- IXLV_INIT_ENABLE,
- IXLV_INIT_COMPLETE,
IXLV_RUNNING,
};
@@ -115,77 +110,48 @@ SLIST_HEAD(vlan_list, ixlv_vlan_filter);
/* Software controller structure */
struct ixlv_sc {
+ struct ixl_vsi vsi;
+
struct i40e_hw hw;
struct i40e_osdep osdep;
device_t dev;
struct resource *pci_mem;
- struct resource *msix_mem;
enum ixlv_state_t init_state;
- int init_in_progress;
-
- /*
- * Interrupt resources
- */
- void *tag;
- struct resource *res; /* For the AQ */
struct ifmedia media;
- struct callout timer;
- int msix;
- int pf_version;
- int if_flags;
+ struct virtchnl_version_info version;
+ enum ixl_dbg_mask dbg_mask;
+ u16 promisc_flags;
bool link_up;
enum virtchnl_link_speed link_speed;
- struct mtx mtx;
-
- u32 qbase;
- u32 admvec;
- struct timeout_task timeout;
-#ifdef notyet
- struct task aq_irq;
- struct task aq_sched;
-#endif
-
- struct ixl_vsi vsi;
+ /* Tunable settings */
+ int tx_itr;
+ int rx_itr;
+ int dynamic_tx_itr;
+ int dynamic_rx_itr;
/* Filter lists */
struct mac_list *mac_filters;
struct vlan_list *vlan_filters;
- /* Promiscuous mode */
- u32 promiscuous_flags;
-
- /* Admin queue task flags */
- u32 aq_wait_count;
-
- struct ixl_vc_mgr vc_mgr;
- struct ixl_vc_cmd add_mac_cmd;
- struct ixl_vc_cmd del_mac_cmd;
- struct ixl_vc_cmd config_queues_cmd;
- struct ixl_vc_cmd map_vectors_cmd;
- struct ixl_vc_cmd enable_queues_cmd;
- struct ixl_vc_cmd add_vlan_cmd;
- struct ixl_vc_cmd del_vlan_cmd;
- struct ixl_vc_cmd add_multi_cmd;
- struct ixl_vc_cmd del_multi_cmd;
- struct ixl_vc_cmd config_rss_key_cmd;
- struct ixl_vc_cmd get_rss_hena_caps_cmd;
- struct ixl_vc_cmd set_rss_hena_cmd;
- struct ixl_vc_cmd config_rss_lut_cmd;
-
/* Virtual comm channel */
struct virtchnl_vf_resource *vf_res;
struct virtchnl_vsi_resource *vsi_res;
/* Misc stats maintained by the driver */
- u64 watchdog_events;
u64 admin_irq;
+ /* Buffer used for reading AQ responses */
u8 aq_buffer[IXL_AQ_BUF_SZ];
+
+ /* State flag used in init/stop */
+ u32 queues_enabled;
+ u8 enable_queues_chan;
+ u8 disable_queues_chan;
};
/*
@@ -203,6 +169,13 @@ ixlv_check_ether_addr(u8 *addr)
return (status);
}
+/* Debug printing */
+#define ixlv_dbg(sc, m, s, ...) ixl_debug_core(sc->dev, sc->dbg_mask, m, s, ##__VA_ARGS__)
+#define ixlv_dbg_init(sc, s, ...) ixl_debug_core(sc->dev, sc->dbg_mask, IXLV_DBG_INIT, s, ##__VA_ARGS__)
+#define ixlv_dbg_info(sc, s, ...) ixl_debug_core(sc->dev, sc->dbg_mask, IXLV_DBG_INFO, s, ##__VA_ARGS__)
+#define ixlv_dbg_vc(sc, s, ...) ixl_debug_core(sc->dev, sc->dbg_mask, IXLV_DBG_VC, s, ##__VA_ARGS__)
+#define ixlv_dbg_filter(sc, s, ...) ixl_debug_core(sc->dev, sc->dbg_mask, IXLV_DBG_FILTER, s, ##__VA_ARGS__)
+
/*
** VF Common function prototypes
*/
@@ -214,28 +187,32 @@ int ixlv_send_vf_config_msg(struct ixlv_sc *);
int ixlv_get_vf_config(struct ixlv_sc *);
void ixlv_init(void *);
int ixlv_reinit_locked(struct ixlv_sc *);
-void ixlv_configure_queues(struct ixlv_sc *);
-void ixlv_enable_queues(struct ixlv_sc *);
-void ixlv_disable_queues(struct ixlv_sc *);
-void ixlv_map_queues(struct ixlv_sc *);
+int ixlv_configure_queues(struct ixlv_sc *);
+int ixlv_enable_queues(struct ixlv_sc *);
+int ixlv_disable_queues(struct ixlv_sc *);
+int ixlv_map_queues(struct ixlv_sc *);
void ixlv_enable_intr(struct ixl_vsi *);
void ixlv_disable_intr(struct ixl_vsi *);
-void ixlv_add_ether_filters(struct ixlv_sc *);
-void ixlv_del_ether_filters(struct ixlv_sc *);
-void ixlv_request_stats(struct ixlv_sc *);
-void ixlv_request_reset(struct ixlv_sc *);
+int ixlv_add_ether_filters(struct ixlv_sc *);
+int ixlv_del_ether_filters(struct ixlv_sc *);
+int ixlv_request_stats(struct ixlv_sc *);
+int ixlv_request_reset(struct ixlv_sc *);
void ixlv_vc_completion(struct ixlv_sc *,
enum virtchnl_ops, enum virtchnl_status_code,
u8 *, u16);
-void ixlv_add_ether_filter(struct ixlv_sc *);
-void ixlv_add_vlans(struct ixlv_sc *);
-void ixlv_del_vlans(struct ixlv_sc *);
+int ixlv_add_ether_filter(struct ixlv_sc *);
+int ixlv_add_vlans(struct ixlv_sc *);
+int ixlv_del_vlans(struct ixlv_sc *);
void ixlv_update_stats_counters(struct ixlv_sc *,
struct i40e_eth_stats *);
void ixlv_update_link_status(struct ixlv_sc *);
-void ixlv_get_default_rss_key(u32 *, bool);
-void ixlv_config_rss_key(struct ixlv_sc *);
-void ixlv_set_rss_hena(struct ixlv_sc *);
-void ixlv_config_rss_lut(struct ixlv_sc *);
-
+int ixlv_get_default_rss_key(u32 *, bool);
+int ixlv_config_rss_key(struct ixlv_sc *);
+int ixlv_set_rss_hena(struct ixlv_sc *);
+int ixlv_config_rss_lut(struct ixlv_sc *);
+int ixlv_config_promisc_mode(struct ixlv_sc *);
+
+int ixl_vc_send_cmd(struct ixlv_sc *sc, uint32_t request);
+char *ixlv_vc_speed_to_string(enum virtchnl_link_speed link_speed);
+void *ixl_vc_get_op_chan(struct ixlv_sc *sc, uint32_t request);
#endif /* _IXLV_H_ */
diff --git a/sys/dev/ixl/ixlv_vc_mgr.h b/sys/dev/ixl/ixlv_vc_mgr.h
deleted file mode 100644
index 424348b5b595..000000000000
--- a/sys/dev/ixl/ixlv_vc_mgr.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/******************************************************************************
-
- Copyright (c) 2013-2018, Intel Corporation
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- 3. Neither the name of the Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-
-******************************************************************************/
-/*$FreeBSD$*/
-
-#ifndef _IXLV_VC_MGR_H_
-#define _IXLV_VC_MGR_H_
-
-#include <sys/queue.h>
-
-struct ixl_vc_cmd;
-
-typedef void ixl_vc_callback_t(struct ixl_vc_cmd *, void *,
- enum i40e_status_code);
-
-
-#define IXLV_VC_CMD_FLAG_BUSY 0x0001
-
-struct ixl_vc_cmd
-{
- uint32_t request;
- uint32_t flags;
-
- ixl_vc_callback_t *callback;
- void *arg;
-
- TAILQ_ENTRY(ixl_vc_cmd) next;
-};
-
-struct ixl_vc_mgr
-{
- struct ixlv_sc *sc;
- struct ixl_vc_cmd *current;
- struct callout callout;
-
- TAILQ_HEAD(, ixl_vc_cmd) pending;
-};
-
-#define IXLV_VC_TIMEOUT (2 * hz)
-
-void ixl_vc_init_mgr(struct ixlv_sc *, struct ixl_vc_mgr *);
-void ixl_vc_enqueue(struct ixl_vc_mgr *, struct ixl_vc_cmd *,
- uint32_t, ixl_vc_callback_t *, void *);
-void ixl_vc_flush(struct ixl_vc_mgr *mgr);
-
-#endif
-
diff --git a/sys/dev/ixl/ixlvc.c b/sys/dev/ixl/ixlvc.c
index 12a21ba35933..9a33310f0e75 100644
--- a/sys/dev/ixl/ixlvc.c
+++ b/sys/dev/ixl/ixlvc.c
@@ -40,118 +40,11 @@
#include "ixl.h"
#include "ixlv.h"
-#include "i40e_prototype.h"
-
/* busy wait delay in msec */
#define IXLV_BUSY_WAIT_DELAY 10
#define IXLV_BUSY_WAIT_COUNT 50
-static void ixl_vc_process_resp(struct ixl_vc_mgr *, uint32_t,
- enum virtchnl_status_code);
-static void ixl_vc_process_next(struct ixl_vc_mgr *mgr);
-static void ixl_vc_schedule_retry(struct ixl_vc_mgr *mgr);
-static void ixl_vc_send_current(struct ixl_vc_mgr *mgr);
-
-#ifdef IXL_DEBUG
-/*
-** Validate VF messages
-*/
-static int ixl_vc_validate_vf_msg(struct ixlv_sc *sc, u32 v_opcode,
- u8 *msg, u16 msglen)
-{
- bool err_msg_format = false;
- int valid_len;
-
- /* Validate message length. */
- switch (v_opcode) {
- case VIRTCHNL_OP_VERSION:
- valid_len = sizeof(struct virtchnl_version_info);
- break;
- case VIRTCHNL_OP_RESET_VF:
- valid_len = 0;
- break;
- case VIRTCHNL_OP_GET_VF_RESOURCES:
- /* Valid length in api v1.0 is 0, v1.1 is 4 */
- valid_len = 4;
- break;
- case VIRTCHNL_OP_CONFIG_TX_QUEUE:
- valid_len = sizeof(struct virtchnl_txq_info);
- break;
- case VIRTCHNL_OP_CONFIG_RX_QUEUE:
- valid_len = sizeof(struct virtchnl_rxq_info);
- break;
- case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
- valid_len = sizeof(struct virtchnl_vsi_queue_config_info);
- if (msglen >= valid_len) {
- struct virtchnl_vsi_queue_config_info *vqc =
- (struct virtchnl_vsi_queue_config_info *)msg;
- valid_len += (vqc->num_queue_pairs *
- sizeof(struct
- virtchnl_queue_pair_info));
- if (vqc->num_queue_pairs == 0)
- err_msg_format = true;
- }
- break;
- case VIRTCHNL_OP_CONFIG_IRQ_MAP:
- valid_len = sizeof(struct virtchnl_irq_map_info);
- if (msglen >= valid_len) {
- struct virtchnl_irq_map_info *vimi =
- (struct virtchnl_irq_map_info *)msg;
- valid_len += (vimi->num_vectors *
- sizeof(struct virtchnl_vector_map));
- if (vimi->num_vectors == 0)
- err_msg_format = true;
- }
- break;
- case VIRTCHNL_OP_ENABLE_QUEUES:
- case VIRTCHNL_OP_DISABLE_QUEUES:
- valid_len = sizeof(struct virtchnl_queue_select);
- break;
- case VIRTCHNL_OP_ADD_ETH_ADDR:
- case VIRTCHNL_OP_DEL_ETH_ADDR:
- valid_len = sizeof(struct virtchnl_ether_addr_list);
- if (msglen >= valid_len) {
- struct virtchnl_ether_addr_list *veal =
- (struct virtchnl_ether_addr_list *)msg;
- valid_len += veal->num_elements *
- sizeof(struct virtchnl_ether_addr);
- if (veal->num_elements == 0)
- err_msg_format = true;
- }
- break;
- case VIRTCHNL_OP_ADD_VLAN:
- case VIRTCHNL_OP_DEL_VLAN:
- valid_len = sizeof(struct virtchnl_vlan_filter_list);
- if (msglen >= valid_len) {
- struct virtchnl_vlan_filter_list *vfl =
- (struct virtchnl_vlan_filter_list *)msg;
- valid_len += vfl->num_elements * sizeof(u16);
- if (vfl->num_elements == 0)
- err_msg_format = true;
- }
- break;
- case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
- valid_len = sizeof(struct virtchnl_promisc_info);
- break;
- case VIRTCHNL_OP_GET_STATS:
- valid_len = sizeof(struct virtchnl_queue_select);
- break;
- /* These are always errors coming from the VF. */
- case VIRTCHNL_OP_EVENT:
- case VIRTCHNL_OP_UNKNOWN:
- default:
- return EPERM;
- break;
- }
- /* few more checks */
- if ((valid_len != msglen) || (err_msg_format))
- return EINVAL;
- else
- return 0;
-}
-#endif
-
/*
** ixlv_send_pf_msg
**
@@ -161,31 +54,39 @@ static int
ixlv_send_pf_msg(struct ixlv_sc *sc,
enum virtchnl_ops op, u8 *msg, u16 len)
{
- struct i40e_hw *hw = &sc->hw;
- device_t dev = sc->dev;
- i40e_status err;
-
-#ifdef IXL_DEBUG
- /*
- ** Pre-validating messages to the PF
- */
+ struct i40e_hw *hw = &sc->hw;
+ device_t dev = sc->dev;
+ i40e_status status;
int val_err;
- val_err = ixl_vc_validate_vf_msg(sc, op, msg, len);
+
+ /* Validating message before sending it to the PF */
+ val_err = virtchnl_vc_validate_vf_msg(&sc->version, op, msg, len);
if (val_err)
device_printf(dev, "Error validating msg to PF for op %d,"
" msglen %d: error %d\n", op, len, val_err);
-#endif
- err = i40e_aq_send_msg_to_pf(hw, op, I40E_SUCCESS, msg, len, NULL);
- if (err)
+ if (!i40e_check_asq_alive(hw)) {
+ if (op != VIRTCHNL_OP_GET_STATS)
+ device_printf(dev, "Unable to send opcode %s to PF, "
+ "ASQ is not alive\n", ixl_vc_opcode_str(op));
+ return (0);
+ }
+
+ if (op != VIRTCHNL_OP_GET_STATS)
+ ixlv_dbg_vc(sc,
+ "Sending msg (op=%s[%d]) to PF\n",
+ ixl_vc_opcode_str(op), op);
+
+ status = i40e_aq_send_msg_to_pf(hw, op, I40E_SUCCESS, msg, len, NULL);
+ if (status && op != VIRTCHNL_OP_GET_STATS)
device_printf(dev, "Unable to send opcode %s to PF, "
"status %s, aq error %s\n",
ixl_vc_opcode_str(op),
- i40e_stat_str(hw, err),
+ i40e_stat_str(hw, status),
i40e_aq_str(hw, hw->aq.asq_last_status));
- return err;
-}
+ return (status);
+}
/*
** ixlv_send_api_ver
@@ -224,11 +125,7 @@ ixlv_verify_api_ver(struct ixlv_sc *sc)
int retries = 0;
event.buf_len = IXL_AQ_BUF_SZ;
- event.msg_buf = malloc(event.buf_len, M_DEVBUF, M_NOWAIT);
- if (!event.msg_buf) {
- err = ENOMEM;
- goto out;
- }
+ event.msg_buf = malloc(event.buf_len, M_IXLV, M_WAITOK);
for (;;) {
if (++retries > IXLV_AQ_MAX_ERR)
@@ -266,8 +163,10 @@ ixlv_verify_api_ver(struct ixlv_sc *sc)
(pf_vvi->minor > VIRTCHNL_VERSION_MINOR))) {
device_printf(dev, "Critical PF/VF API version mismatch!\n");
err = EIO;
- } else
- sc->pf_version = pf_vvi->minor;
+ } else {
+ sc->version.major = pf_vvi->major;
+ sc->version.minor = pf_vvi->minor;
+ }
/* Log PF/VF api versions */
device_printf(dev, "PF API %d.%d / VF API %d.%d\n",
@@ -275,8 +174,7 @@ ixlv_verify_api_ver(struct ixlv_sc *sc)
VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
out_alloc:
- free(event.msg_buf, M_DEVBUF);
-out:
+ free(event.msg_buf, M_IXLV);
return (err);
}
@@ -296,7 +194,10 @@ ixlv_send_vf_config_msg(struct ixlv_sc *sc)
VIRTCHNL_VF_OFFLOAD_RSS_PF |
VIRTCHNL_VF_OFFLOAD_VLAN;
- if (sc->pf_version == VIRTCHNL_VERSION_MINOR_NO_VF_CAPS)
+ ixlv_dbg_info(sc, "Sending offload flags: 0x%b\n",
+ caps, IXLV_PRINTF_VF_OFFLOAD_FLAGS);
+
+ if (sc->version.minor == VIRTCHNL_VERSION_MINOR_NO_VF_CAPS)
return ixlv_send_pf_msg(sc, VIRTCHNL_OP_GET_VF_RESOURCES,
NULL, 0);
else
@@ -326,11 +227,7 @@ ixlv_get_vf_config(struct ixlv_sc *sc)
len = sizeof(struct virtchnl_vf_resource) +
sizeof(struct virtchnl_vsi_resource);
event.buf_len = len;
- event.msg_buf = malloc(event.buf_len, M_DEVBUF, M_NOWAIT);
- if (!event.msg_buf) {
- err = ENOMEM;
- goto out;
- }
+ event.msg_buf = malloc(event.buf_len, M_IXLV, M_WAITOK);
for (;;) {
err = i40e_clean_arq_element(hw, &event, NULL);
@@ -371,8 +268,7 @@ ixlv_get_vf_config(struct ixlv_sc *sc)
i40e_vf_parse_hw_config(hw, sc->vf_res);
out_alloc:
- free(event.msg_buf, M_DEVBUF);
-out:
+ free(event.msg_buf, M_IXLV);
return err;
}
@@ -381,7 +277,7 @@ out:
**
** Request that the PF set up our queues.
*/
-void
+int
ixlv_configure_queues(struct ixlv_sc *sc)
{
device_t dev = sc->dev;
@@ -401,11 +297,10 @@ ixlv_configure_queues(struct ixlv_sc *sc)
pairs = max(vsi->num_tx_queues, vsi->num_rx_queues);
len = sizeof(struct virtchnl_vsi_queue_config_info) +
(sizeof(struct virtchnl_queue_pair_info) * pairs);
- vqci = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
+ vqci = malloc(len, M_IXLV, M_NOWAIT | M_ZERO);
if (!vqci) {
device_printf(dev, "%s: unable to allocate memory\n", __func__);
- ixl_vc_schedule_retry(&sc->vc_mgr);
- return;
+ return (ENOMEM);
}
vqci->vsi_id = sc->vsi_res->vsi_id;
vqci->num_queue_pairs = pairs;
@@ -413,6 +308,7 @@ ixlv_configure_queues(struct ixlv_sc *sc)
/* Size check is not needed here - HW max is 16 queue pairs, and we
* can fit info for 31 of them into the AQ buffer before it overflows.
*/
+ // TODO: the above is wrong now; X722 VFs can have 256 queues
for (int i = 0; i < pairs; i++, tx_que++, rx_que++, vqpi++) {
txr = &tx_que->txr;
rxr = &rx_que->rxr;
@@ -422,22 +318,29 @@ ixlv_configure_queues(struct ixlv_sc *sc)
vqpi->txq.ring_len = scctx->isc_ntxd[0];
vqpi->txq.dma_ring_addr = txr->tx_paddr;
/* Enable Head writeback */
- vqpi->txq.headwb_enabled = 0;
- vqpi->txq.dma_headwb_addr = 0;
+ if (!vsi->enable_head_writeback) {
+ vqpi->txq.headwb_enabled = 0;
+ vqpi->txq.dma_headwb_addr = 0;
+ } else {
+ vqpi->txq.headwb_enabled = 1;
+ vqpi->txq.dma_headwb_addr = txr->tx_paddr +
+ sizeof(struct i40e_tx_desc) * scctx->isc_ntxd[0];
+ }
vqpi->rxq.vsi_id = vqci->vsi_id;
vqpi->rxq.queue_id = i;
vqpi->rxq.ring_len = scctx->isc_nrxd[0];
vqpi->rxq.dma_ring_addr = rxr->rx_paddr;
vqpi->rxq.max_pkt_size = scctx->isc_max_frame_size;
- // TODO: Get this value from iflib, somehow
vqpi->rxq.databuffer_size = rxr->mbuf_sz;
vqpi->rxq.splithdr_enabled = 0;
}
ixlv_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_VSI_QUEUES,
(u8 *)vqci, len);
- free(vqci, M_DEVBUF);
+ free(vqci, M_IXLV);
+
+ return (0);
}
/*
@@ -445,7 +348,7 @@ ixlv_configure_queues(struct ixlv_sc *sc)
**
** Request that the PF enable all of our queues.
*/
-void
+int
ixlv_enable_queues(struct ixlv_sc *sc)
{
struct virtchnl_queue_select vqs;
@@ -453,10 +356,11 @@ ixlv_enable_queues(struct ixlv_sc *sc)
vqs.vsi_id = sc->vsi_res->vsi_id;
/* XXX: In Linux PF, as long as neither of these is 0,
* every queue in VF VSI is enabled. */
- vqs.tx_queues = (1 << sc->vsi_res->num_queue_pairs) - 1;
+ vqs.tx_queues = (1 << sc->vsi.num_tx_queues) - 1;
vqs.rx_queues = vqs.tx_queues;
ixlv_send_pf_msg(sc, VIRTCHNL_OP_ENABLE_QUEUES,
(u8 *)&vqs, sizeof(vqs));
+ return (0);
}
/*
@@ -464,7 +368,7 @@ ixlv_enable_queues(struct ixlv_sc *sc)
**
** Request that the PF disable all of our queues.
*/
-void
+int
ixlv_disable_queues(struct ixlv_sc *sc)
{
struct virtchnl_queue_select vqs;
@@ -472,10 +376,11 @@ ixlv_disable_queues(struct ixlv_sc *sc)
vqs.vsi_id = sc->vsi_res->vsi_id;
/* XXX: In Linux PF, as long as neither of these is 0,
* every queue in VF VSI is disabled. */
- vqs.tx_queues = (1 << sc->vsi_res->num_queue_pairs) - 1;
+ vqs.tx_queues = (1 << sc->vsi.num_tx_queues) - 1;
vqs.rx_queues = vqs.tx_queues;
ixlv_send_pf_msg(sc, VIRTCHNL_OP_DISABLE_QUEUES,
(u8 *)&vqs, sizeof(vqs));
+ return (0);
}
/*
@@ -484,7 +389,7 @@ ixlv_disable_queues(struct ixlv_sc *sc)
** Request that the PF map queues to interrupt vectors. Misc causes, including
** admin queue, are always mapped to vector 0.
*/
-void
+int
ixlv_map_queues(struct ixlv_sc *sc)
{
struct virtchnl_irq_map_info *vm;
@@ -502,12 +407,11 @@ ixlv_map_queues(struct ixlv_sc *sc)
q = scctx->isc_vectors - 1;
len = sizeof(struct virtchnl_irq_map_info) +
- (scctx->isc_vectors * sizeof(struct i40e_virtchnl_vector_map));
- vm = malloc(len, M_DEVBUF, M_NOWAIT);
+ (scctx->isc_vectors * sizeof(struct virtchnl_vector_map));
+ vm = malloc(len, M_IXLV, M_NOWAIT);
if (!vm) {
device_printf(dev, "%s: unable to allocate memory\n", __func__);
- ixl_vc_schedule_retry(&sc->vc_mgr);
- return;
+ return (ENOMEM);
}
vm->num_vectors = scctx->isc_vectors;
@@ -515,7 +419,8 @@ ixlv_map_queues(struct ixlv_sc *sc)
for (i = 0; i < q; i++, rx_que++) {
vm->vecmap[i].vsi_id = sc->vsi_res->vsi_id;
vm->vecmap[i].vector_id = i + 1; /* first is adminq */
- // vm->vecmap[i].txq_map = (1 << que->me);
+ // TODO: Re-examine this
+ vm->vecmap[i].txq_map = (1 << rx_que->rxr.me);
vm->vecmap[i].rxq_map = (1 << rx_que->rxr.me);
vm->vecmap[i].rxitr_idx = 0;
vm->vecmap[i].txitr_idx = 1;
@@ -531,7 +436,9 @@ ixlv_map_queues(struct ixlv_sc *sc)
ixlv_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_IRQ_MAP,
(u8 *)vm, len);
- free(vm, M_DEVBUF);
+ free(vm, M_IXLV);
+
+ return (0);
}
/*
@@ -539,10 +446,10 @@ ixlv_map_queues(struct ixlv_sc *sc)
** to be added, then create the data to hand to the AQ
** for handling.
*/
-void
+int
ixlv_add_vlans(struct ixlv_sc *sc)
{
- struct virtchnl_vlan_filter_list *v;
+ struct virtchnl_vlan_filter_list *v;
struct ixlv_vlan_filter *f, *ftmp;
device_t dev = sc->dev;
int len, i = 0, cnt = 0;
@@ -553,11 +460,8 @@ ixlv_add_vlans(struct ixlv_sc *sc)
cnt++;
}
- if (!cnt) { /* no work... */
- ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_ADD_VLAN_FILTER,
- VIRTCHNL_STATUS_SUCCESS);
- return;
- }
+ if (!cnt) /* no work... */
+ return (ENOENT);
len = sizeof(struct virtchnl_vlan_filter_list) +
(cnt * sizeof(u16));
@@ -565,16 +469,14 @@ ixlv_add_vlans(struct ixlv_sc *sc)
if (len > IXL_AQ_BUF_SZ) {
device_printf(dev, "%s: Exceeded Max AQ Buf size\n",
__func__);
- ixl_vc_schedule_retry(&sc->vc_mgr);
- return;
+ return (EFBIG);
}
- v = malloc(len, M_DEVBUF, M_NOWAIT);
+ v = malloc(len, M_IXLV, M_NOWAIT);
if (!v) {
device_printf(dev, "%s: unable to allocate memory\n",
__func__);
- ixl_vc_schedule_retry(&sc->vc_mgr);
- return;
+ return (ENOMEM);
}
v->vsi_id = sc->vsi_res->vsi_id;
@@ -592,8 +494,9 @@ ixlv_add_vlans(struct ixlv_sc *sc)
}
ixlv_send_pf_msg(sc, VIRTCHNL_OP_ADD_VLAN, (u8 *)v, len);
- free(v, M_DEVBUF);
+ free(v, M_IXLV);
/* add stats? */
+ return (0);
}
/*
@@ -601,12 +504,12 @@ ixlv_add_vlans(struct ixlv_sc *sc)
** to be removed, then create the data to hand to the AQ
** for handling.
*/
-void
+int
ixlv_del_vlans(struct ixlv_sc *sc)
{
- device_t dev = sc->dev;
struct virtchnl_vlan_filter_list *v;
struct ixlv_vlan_filter *f, *ftmp;
+ device_t dev = sc->dev;
int len, i = 0, cnt = 0;
/* Get count of VLAN filters to delete */
@@ -615,11 +518,8 @@ ixlv_del_vlans(struct ixlv_sc *sc)
cnt++;
}
- if (!cnt) { /* no work... */
- ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_DEL_VLAN_FILTER,
- VIRTCHNL_STATUS_SUCCESS);
- return;
- }
+ if (!cnt) /* no work... */
+ return (ENOENT);
len = sizeof(struct virtchnl_vlan_filter_list) +
(cnt * sizeof(u16));
@@ -627,16 +527,14 @@ ixlv_del_vlans(struct ixlv_sc *sc)
if (len > IXL_AQ_BUF_SZ) {
device_printf(dev, "%s: Exceeded Max AQ Buf size\n",
__func__);
- ixl_vc_schedule_retry(&sc->vc_mgr);
- return;
+ return (EFBIG);
}
- v = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
+ v = malloc(len, M_IXLV, M_NOWAIT | M_ZERO);
if (!v) {
device_printf(dev, "%s: unable to allocate memory\n",
__func__);
- ixl_vc_schedule_retry(&sc->vc_mgr);
- return;
+ return (ENOMEM);
}
v->vsi_id = sc->vsi_res->vsi_id;
@@ -648,15 +546,16 @@ ixlv_del_vlans(struct ixlv_sc *sc)
bcopy(&f->vlan, &v->vlan_id[i], sizeof(u16));
i++;
SLIST_REMOVE(sc->vlan_filters, f, ixlv_vlan_filter, next);
- free(f, M_DEVBUF);
+ free(f, M_IXLV);
}
if (i == cnt)
break;
}
ixlv_send_pf_msg(sc, VIRTCHNL_OP_DEL_VLAN, (u8 *)v, len);
- free(v, M_DEVBUF);
+ free(v, M_IXLV);
/* add stats? */
+ return (0);
}
@@ -665,13 +564,14 @@ ixlv_del_vlans(struct ixlv_sc *sc)
** table and creates an Admin Queue call to create
** the filters in the hardware.
*/
-void
+int
ixlv_add_ether_filters(struct ixlv_sc *sc)
{
struct virtchnl_ether_addr_list *a;
struct ixlv_mac_filter *f;
- device_t dev = sc->dev;
- int len, j = 0, cnt = 0;
+ device_t dev = sc->dev;
+ int len, j = 0, cnt = 0;
+ enum i40e_status_code status;
/* Get count of MAC addresses to add */
SLIST_FOREACH(f, sc->mac_filters, next) {
@@ -679,21 +579,18 @@ ixlv_add_ether_filters(struct ixlv_sc *sc)
cnt++;
}
if (cnt == 0) { /* Should not happen... */
- DDPRINTF(dev, "cnt == 0, exiting...");
- ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_ADD_MAC_FILTER,
- VIRTCHNL_STATUS_SUCCESS);
- return;
+ ixlv_dbg_vc(sc, "%s: cnt == 0, exiting...\n", __func__);
+ return (ENOENT);
}
len = sizeof(struct virtchnl_ether_addr_list) +
(cnt * sizeof(struct virtchnl_ether_addr));
- a = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
+ a = malloc(len, M_IXLV, M_NOWAIT | M_ZERO);
if (a == NULL) {
device_printf(dev, "%s: Failed to get memory for "
"virtchnl_ether_addr_list\n", __func__);
- ixl_vc_schedule_retry(&sc->vc_mgr);
- return;
+ return (ENOMEM);
}
a->vsi_id = sc->vsi.id;
a->num_elements = cnt;
@@ -705,7 +602,7 @@ ixlv_add_ether_filters(struct ixlv_sc *sc)
f->flags &= ~IXL_FILTER_ADD;
j++;
- DDPRINTF(dev, "ADD: " MAC_FORMAT,
+ ixlv_dbg_vc(sc, "ADD: " MAC_FORMAT "\n",
MAC_FORMAT_ARGS(f->macaddr));
}
if (j == cnt)
@@ -713,11 +610,12 @@ ixlv_add_ether_filters(struct ixlv_sc *sc)
}
DDPRINTF(dev, "len %d, j %d, cnt %d",
len, j, cnt);
- ixlv_send_pf_msg(sc,
+
+ status = ixlv_send_pf_msg(sc,
VIRTCHNL_OP_ADD_ETH_ADDR, (u8 *)a, len);
/* add stats? */
- free(a, M_DEVBUF);
- return;
+ free(a, M_IXLV);
+ return (status);
}
/*
@@ -725,13 +623,13 @@ ixlv_add_ether_filters(struct ixlv_sc *sc)
** sc MAC filter list and creates an Admin Queue call
** to delete those filters in the hardware.
*/
-void
+int
ixlv_del_ether_filters(struct ixlv_sc *sc)
{
struct virtchnl_ether_addr_list *d;
- device_t dev = sc->dev;
- struct ixlv_mac_filter *f, *f_temp;
- int len, j = 0, cnt = 0;
+ struct ixlv_mac_filter *f, *f_temp;
+ device_t dev = sc->dev;
+ int len, j = 0, cnt = 0;
/* Get count of MAC addresses to delete */
SLIST_FOREACH(f, sc->mac_filters, next) {
@@ -739,21 +637,18 @@ ixlv_del_ether_filters(struct ixlv_sc *sc)
cnt++;
}
if (cnt == 0) {
- DDPRINTF(dev, "cnt == 0, exiting...");
- ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_DEL_MAC_FILTER,
- VIRTCHNL_STATUS_SUCCESS);
- return;
+ ixlv_dbg_vc(sc, "%s: cnt == 0, exiting...\n", __func__);
+ return (ENOENT);
}
len = sizeof(struct virtchnl_ether_addr_list) +
(cnt * sizeof(struct virtchnl_ether_addr));
- d = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
+ d = malloc(len, M_IXLV, M_NOWAIT | M_ZERO);
if (d == NULL) {
device_printf(dev, "%s: Failed to get memory for "
"virtchnl_ether_addr_list\n", __func__);
- ixl_vc_schedule_retry(&sc->vc_mgr);
- return;
+ return (ENOMEM);
}
d->vsi_id = sc->vsi.id;
d->num_elements = cnt;
@@ -762,11 +657,11 @@ ixlv_del_ether_filters(struct ixlv_sc *sc)
SLIST_FOREACH_SAFE(f, sc->mac_filters, next, f_temp) {
if (f->flags & IXL_FILTER_DEL) {
bcopy(f->macaddr, d->list[j].addr, ETHER_ADDR_LEN);
- DDPRINTF(dev, "DEL: " MAC_FORMAT,
+ ixlv_dbg_vc(sc, "DEL: " MAC_FORMAT "\n",
MAC_FORMAT_ARGS(f->macaddr));
j++;
SLIST_REMOVE(sc->mac_filters, f, ixlv_mac_filter, next);
- free(f, M_DEVBUF);
+ free(f, M_IXLV);
}
if (j == cnt)
break;
@@ -774,15 +669,15 @@ ixlv_del_ether_filters(struct ixlv_sc *sc)
ixlv_send_pf_msg(sc,
VIRTCHNL_OP_DEL_ETH_ADDR, (u8 *)d, len);
/* add stats? */
- free(d, M_DEVBUF);
- return;
+ free(d, M_IXLV);
+ return (0);
}
/*
** ixlv_request_reset
** Request that the PF reset this VF. No response is expected.
*/
-void
+int
ixlv_request_reset(struct ixlv_sc *sc)
{
/*
@@ -792,13 +687,14 @@ ixlv_request_reset(struct ixlv_sc *sc)
*/
wr32(&sc->hw, I40E_VFGEN_RSTAT, VIRTCHNL_VFR_INPROGRESS);
ixlv_send_pf_msg(sc, VIRTCHNL_OP_RESET_VF, NULL, 0);
+ return (0);
}
/*
** ixlv_request_stats
** Request the statistics for this VF's VSI from PF.
*/
-void
+int
ixlv_request_stats(struct ixlv_sc *sc)
{
struct virtchnl_queue_select vqs;
@@ -808,10 +704,10 @@ ixlv_request_stats(struct ixlv_sc *sc)
/* Low priority, we don't need to error check */
error = ixlv_send_pf_msg(sc, VIRTCHNL_OP_GET_STATS,
(u8 *)&vqs, sizeof(vqs));
-#ifdef IXL_DEBUG
if (error)
device_printf(sc->dev, "Error sending stats request to PF: %d\n", error);
-#endif
+
+ return (0);
}
/*
@@ -850,7 +746,7 @@ ixlv_update_stats_counters(struct ixlv_sc *sc, struct i40e_eth_stats *es)
vsi->eth_stats = *es;
}
-void
+int
ixlv_config_rss_key(struct ixlv_sc *sc)
{
struct virtchnl_rss_key *rss_key_msg;
@@ -867,26 +763,27 @@ ixlv_config_rss_key(struct ixlv_sc *sc)
/* Send the fetched key */
key_length = IXL_RSS_KEY_SIZE;
msg_len = sizeof(struct virtchnl_rss_key) + (sizeof(u8) * key_length) - 1;
- rss_key_msg = malloc(msg_len, M_DEVBUF, M_NOWAIT | M_ZERO);
+ rss_key_msg = malloc(msg_len, M_IXLV, M_NOWAIT | M_ZERO);
if (rss_key_msg == NULL) {
device_printf(sc->dev, "Unable to allocate msg memory for RSS key msg.\n");
- return;
+ return (ENOMEM);
}
rss_key_msg->vsi_id = sc->vsi_res->vsi_id;
rss_key_msg->key_len = key_length;
bcopy(rss_seed, &rss_key_msg->key[0], key_length);
- DDPRINTF(sc->dev, "config_rss: vsi_id %d, key_len %d",
+ ixlv_dbg_vc(sc, "config_rss: vsi_id %d, key_len %d\n",
rss_key_msg->vsi_id, rss_key_msg->key_len);
ixlv_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_RSS_KEY,
(u8 *)rss_key_msg, msg_len);
- free(rss_key_msg, M_DEVBUF);
+ free(rss_key_msg, M_IXLV);
+ return (0);
}
-void
+int
ixlv_set_rss_hena(struct ixlv_sc *sc)
{
struct virtchnl_rss_hena hena;
@@ -899,9 +796,10 @@ ixlv_set_rss_hena(struct ixlv_sc *sc)
ixlv_send_pf_msg(sc, VIRTCHNL_OP_SET_RSS_HENA,
(u8 *)&hena, sizeof(hena));
+ return (0);
}
-void
+int
ixlv_config_rss_lut(struct ixlv_sc *sc)
{
struct virtchnl_rss_lut *rss_lut_msg;
@@ -912,10 +810,10 @@ ixlv_config_rss_lut(struct ixlv_sc *sc)
lut_length = IXL_RSS_VSI_LUT_SIZE;
msg_len = sizeof(struct virtchnl_rss_lut) + (lut_length * sizeof(u8)) - 1;
- rss_lut_msg = malloc(msg_len, M_DEVBUF, M_NOWAIT | M_ZERO);
+ rss_lut_msg = malloc(msg_len, M_IXLV, M_NOWAIT | M_ZERO);
if (rss_lut_msg == NULL) {
device_printf(sc->dev, "Unable to allocate msg memory for RSS lut msg.\n");
- return;
+ return (ENOMEM);
}
rss_lut_msg->vsi_id = sc->vsi_res->vsi_id;
@@ -942,7 +840,21 @@ ixlv_config_rss_lut(struct ixlv_sc *sc)
ixlv_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_RSS_LUT,
(u8 *)rss_lut_msg, msg_len);
- free(rss_lut_msg, M_DEVBUF);
+ free(rss_lut_msg, M_IXLV);
+ return (0);
+}
+
+int
+ixlv_config_promisc_mode(struct ixlv_sc *sc)
+{
+ struct virtchnl_promisc_info pinfo;
+
+ pinfo.vsi_id = sc->vsi_res->vsi_id;
+ pinfo.flags = sc->promisc_flags;
+
+ ixlv_send_pf_msg(sc, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE,
+ (u8 *)&pinfo, sizeof(pinfo));
+ return (0);
}
/*
@@ -958,7 +870,10 @@ ixlv_vc_completion(struct ixlv_sc *sc,
enum virtchnl_status_code v_retval, u8 *msg, u16 msglen)
{
device_t dev = sc->dev;
- struct ixl_vsi *vsi = &sc->vsi;
+
+ if (v_opcode != VIRTCHNL_OP_GET_STATS)
+ ixlv_dbg_vc(sc, "%s: opcode %s\n", __func__,
+ ixl_vc_opcode_str(v_opcode));
if (v_opcode == VIRTCHNL_OP_EVENT) {
struct virtchnl_pf_event *vpe =
@@ -966,11 +881,9 @@ ixlv_vc_completion(struct ixlv_sc *sc,
switch (vpe->event) {
case VIRTCHNL_EVENT_LINK_CHANGE:
-#ifdef IXL_DEBUG
- device_printf(dev, "Link change: status %d, speed %d\n",
+ ixlv_dbg_vc(sc, "Link change: status %d, speed %s\n",
vpe->event_data.link_event.link_status,
- vpe->event_data.link_event.link_speed);
-#endif
+ ixlv_vc_speed_to_string(vpe->event_data.link_event.link_speed));
sc->link_up =
vpe->event_data.link_event.link_status;
sc->link_speed =
@@ -983,8 +896,8 @@ ixlv_vc_completion(struct ixlv_sc *sc,
ixlv_if_init(sc->vsi.ctx);
break;
default:
- device_printf(dev, "%s: Unknown event %d from AQ\n",
- __func__, vpe->event);
+ ixlv_dbg_vc(sc, "Unknown event %d from AQ\n",
+ vpe->event);
break;
}
@@ -998,273 +911,104 @@ ixlv_vc_completion(struct ixlv_sc *sc,
__func__, i40e_vc_stat_str(&sc->hw, v_retval), ixl_vc_opcode_str(v_opcode));
}
-#ifdef IXL_DEBUG
- if (v_opcode != VIRTCHNL_OP_GET_STATS)
- DDPRINTF(dev, "opcode %d", v_opcode);
-#endif
-
switch (v_opcode) {
case VIRTCHNL_OP_GET_STATS:
ixlv_update_stats_counters(sc, (struct i40e_eth_stats *)msg);
break;
case VIRTCHNL_OP_ADD_ETH_ADDR:
- ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_ADD_MAC_FILTER,
- v_retval);
if (v_retval) {
device_printf(dev, "WARNING: Error adding VF mac filter!\n");
device_printf(dev, "WARNING: Device may not receive traffic!\n");
}
break;
case VIRTCHNL_OP_DEL_ETH_ADDR:
- ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_DEL_MAC_FILTER,
- v_retval);
break;
case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
- ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_CONFIGURE_PROMISC,
- v_retval);
break;
case VIRTCHNL_OP_ADD_VLAN:
- ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_ADD_VLAN_FILTER,
- v_retval);
break;
case VIRTCHNL_OP_DEL_VLAN:
- ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_DEL_VLAN_FILTER,
- v_retval);
break;
case VIRTCHNL_OP_ENABLE_QUEUES:
- ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_ENABLE_QUEUES,
- v_retval);
- if (v_retval == 0) {
- /* Update link status */
- ixlv_update_link_status(sc);
- /* Turn on all interrupts */
- ixlv_enable_intr(vsi);
- /* And inform the stack we're ready */
- // vsi->ifp->if_drv_flags |= IFF_DRV_RUNNING;
- /* TODO: Clear a state flag, so we know we're ready to run init again */
- }
+ atomic_store_rel_32(&sc->queues_enabled, 1);
+ wakeup_one(&sc->enable_queues_chan);
break;
case VIRTCHNL_OP_DISABLE_QUEUES:
- ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_DISABLE_QUEUES,
- v_retval);
- if (v_retval == 0) {
- /* Turn off all interrupts */
- ixlv_disable_intr(vsi);
- /* Tell the stack that the interface is no longer active */
- vsi->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING);
- }
+ atomic_store_rel_32(&sc->queues_enabled, 0);
+ wakeup_one(&sc->disable_queues_chan);
break;
case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
- ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_CONFIGURE_QUEUES,
- v_retval);
break;
case VIRTCHNL_OP_CONFIG_IRQ_MAP:
- ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_MAP_VECTORS,
- v_retval);
break;
case VIRTCHNL_OP_CONFIG_RSS_KEY:
- ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_CONFIG_RSS_KEY,
- v_retval);
break;
case VIRTCHNL_OP_SET_RSS_HENA:
- ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_SET_RSS_HENA,
- v_retval);
break;
case VIRTCHNL_OP_CONFIG_RSS_LUT:
- ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_CONFIG_RSS_LUT,
- v_retval);
break;
default:
-#ifdef IXL_DEBUG
- device_printf(dev,
- "%s: Received unexpected message %s from PF.\n",
- __func__, ixl_vc_opcode_str(v_opcode));
-#endif
+ ixlv_dbg_vc(sc,
+ "Received unexpected message %s from PF.\n",
+ ixl_vc_opcode_str(v_opcode));
break;
}
- return;
}
-static void
+int
ixl_vc_send_cmd(struct ixlv_sc *sc, uint32_t request)
{
switch (request) {
case IXLV_FLAG_AQ_MAP_VECTORS:
- ixlv_map_queues(sc);
- break;
+ return ixlv_map_queues(sc);
case IXLV_FLAG_AQ_ADD_MAC_FILTER:
- ixlv_add_ether_filters(sc);
- break;
+ return ixlv_add_ether_filters(sc);
case IXLV_FLAG_AQ_ADD_VLAN_FILTER:
- ixlv_add_vlans(sc);
- break;
+ return ixlv_add_vlans(sc);
case IXLV_FLAG_AQ_DEL_MAC_FILTER:
- ixlv_del_ether_filters(sc);
- break;
+ return ixlv_del_ether_filters(sc);
case IXLV_FLAG_AQ_DEL_VLAN_FILTER:
- ixlv_del_vlans(sc);
- break;
+ return ixlv_del_vlans(sc);
case IXLV_FLAG_AQ_CONFIGURE_QUEUES:
- ixlv_configure_queues(sc);
- break;
+ return ixlv_configure_queues(sc);
case IXLV_FLAG_AQ_DISABLE_QUEUES:
- ixlv_disable_queues(sc);
- break;
+ return ixlv_disable_queues(sc);
case IXLV_FLAG_AQ_ENABLE_QUEUES:
- ixlv_enable_queues(sc);
- break;
+ return ixlv_enable_queues(sc);
case IXLV_FLAG_AQ_CONFIG_RSS_KEY:
- ixlv_config_rss_key(sc);
- break;
+ return ixlv_config_rss_key(sc);
case IXLV_FLAG_AQ_SET_RSS_HENA:
- ixlv_set_rss_hena(sc);
- break;
+ return ixlv_set_rss_hena(sc);
case IXLV_FLAG_AQ_CONFIG_RSS_LUT:
- ixlv_config_rss_lut(sc);
- break;
- }
-}
-
-void
-ixl_vc_init_mgr(struct ixlv_sc *sc, struct ixl_vc_mgr *mgr)
-{
- mgr->sc = sc;
- mgr->current = NULL;
- TAILQ_INIT(&mgr->pending);
- callout_init_mtx(&mgr->callout, &sc->mtx, 0);
-}
+ return ixlv_config_rss_lut(sc);
-static void
-ixl_vc_process_completion(struct ixl_vc_mgr *mgr, enum i40e_status_code err)
-{
- struct ixl_vc_cmd *cmd;
-
- cmd = mgr->current;
- mgr->current = NULL;
- cmd->flags &= ~IXLV_VC_CMD_FLAG_BUSY;
-
- cmd->callback(cmd, cmd->arg, err);
- ixl_vc_process_next(mgr);
-}
-
-static void
-ixl_vc_process_resp(struct ixl_vc_mgr *mgr, uint32_t request,
- enum virtchnl_status_code err)
-{
- struct ixl_vc_cmd *cmd;
-
- cmd = mgr->current;
- if (cmd == NULL || cmd->request != request)
- return;
-
- callout_stop(&mgr->callout);
- /* ATM, the virtchnl codes map to i40e ones directly */
- ixl_vc_process_completion(mgr, (enum i40e_status_code)err);
-}
-
-static void
-ixl_vc_cmd_timeout(void *arg)
-{
- struct ixl_vc_mgr *mgr = (struct ixl_vc_mgr *)arg;
-
- ixl_vc_process_completion(mgr, I40E_ERR_TIMEOUT);
-}
-
-static void
-ixl_vc_cmd_retry(void *arg)
-{
- struct ixl_vc_mgr *mgr = (struct ixl_vc_mgr *)arg;
-
- ixl_vc_send_current(mgr);
-}
-
-static void
-ixl_vc_send_current(struct ixl_vc_mgr *mgr)
-{
- struct ixl_vc_cmd *cmd;
-
- cmd = mgr->current;
- ixl_vc_send_cmd(mgr->sc, cmd->request);
- callout_reset(&mgr->callout, IXLV_VC_TIMEOUT, ixl_vc_cmd_timeout, mgr);
-}
-
-static void
-ixl_vc_process_next(struct ixl_vc_mgr *mgr)
-{
- struct ixl_vc_cmd *cmd;
-
- if (mgr->current != NULL)
- return;
-
- if (TAILQ_EMPTY(&mgr->pending))
- return;
-
- cmd = TAILQ_FIRST(&mgr->pending);
- TAILQ_REMOVE(&mgr->pending, cmd, next);
-
- mgr->current = cmd;
- ixl_vc_send_current(mgr);
-}
-
-static void
-ixl_vc_schedule_retry(struct ixl_vc_mgr *mgr)
-{
-
- callout_reset(&mgr->callout, howmany(hz, 100), ixl_vc_cmd_retry, mgr);
-}
-
-void
-ixl_vc_enqueue(struct ixl_vc_mgr *mgr, struct ixl_vc_cmd *cmd,
- uint32_t req, ixl_vc_callback_t *callback, void *arg)
-{
- if (cmd->flags & IXLV_VC_CMD_FLAG_BUSY) {
- if (mgr->current == cmd)
- mgr->current = NULL;
- else
- TAILQ_REMOVE(&mgr->pending, cmd, next);
+ case IXLV_FLAG_AQ_CONFIGURE_PROMISC:
+ return ixlv_config_promisc_mode(sc);
}
- cmd->request = req;
- cmd->callback = callback;
- cmd->arg = arg;
- cmd->flags |= IXLV_VC_CMD_FLAG_BUSY;
- TAILQ_INSERT_TAIL(&mgr->pending, cmd, next);
-
- ixl_vc_process_next(mgr);
+ return (0);
}
-void
-ixl_vc_flush(struct ixl_vc_mgr *mgr)
+void *
+ixl_vc_get_op_chan(struct ixlv_sc *sc, uint32_t request)
{
- struct ixl_vc_cmd *cmd;
-
- KASSERT(TAILQ_EMPTY(&mgr->pending) || mgr->current != NULL,
- ("ixlv: pending commands waiting but no command in progress"));
-
- cmd = mgr->current;
- if (cmd != NULL) {
- mgr->current = NULL;
- cmd->flags &= ~IXLV_VC_CMD_FLAG_BUSY;
- cmd->callback(cmd, cmd->arg, I40E_ERR_ADAPTER_STOPPED);
- }
-
- while ((cmd = TAILQ_FIRST(&mgr->pending)) != NULL) {
- TAILQ_REMOVE(&mgr->pending, cmd, next);
- cmd->flags &= ~IXLV_VC_CMD_FLAG_BUSY;
- cmd->callback(cmd, cmd->arg, I40E_ERR_ADAPTER_STOPPED);
+ switch (request) {
+ case IXLV_FLAG_AQ_ENABLE_QUEUES:
+ return (&sc->enable_queues_chan);
+ case IXLV_FLAG_AQ_DISABLE_QUEUES:
+ return (&sc->disable_queues_chan);
+ default:
+ return (NULL);
}
-
- callout_stop(&mgr->callout);
}
-
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 726144753c8b..33dad3f6a145 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -153,6 +153,7 @@ SUBDIR= \
${_hwpmc_mips74k} \
${_hyperv} \
i2c \
+ ${_iavf} \
${_ibcore} \
${_ibcs2} \
${_ichwd} \
@@ -717,9 +718,9 @@ _x86bios= x86bios
.if ${MACHINE_CPUARCH} == "amd64"
_ccp= ccp
_efirt= efirt
+_iavf= iavf
_ioat= ioat
_ixl= ixl
-_ixlv= ixlv
_linux64= linux64
_linux_common= linux_common
_ntb= ntb
diff --git a/sys/modules/ixlv/Makefile b/sys/modules/iavf/Makefile
index 36b8eb4171a1..e1fd0083be99 100644
--- a/sys/modules/ixlv/Makefile
+++ b/sys/modules/iavf/Makefile
@@ -2,9 +2,9 @@
.PATH: ${SRCTOP}/sys/dev/ixl
-KMOD = if_ixlv
+KMOD = if_iavf
SRCS = device_if.h bus_if.h pci_if.h ifdi_if.h
-SRCS += opt_inet.h opt_inet6.h opt_rss.h opt_ixl.h opt_iflib.h
+SRCS += opt_inet.h opt_inet6.h opt_rss.h opt_ixl.h opt_iflib.h opt_global.h
SRCS += if_ixlv.c ixlvc.c ixl_txrx.c i40e_osdep.c
# Shared source
@@ -12,5 +12,7 @@ SRCS += i40e_common.c i40e_nvm.c i40e_adminq.c
# Debug messages / sysctls
# CFLAGS += -DIXL_DEBUG
+# Enable asserts and other debugging facilities
+# CFLAGS += -DINVARIANTS -DINVARIANTS_SUPPORT -DWITNESS
.include <bsd.kmod.mk>
diff --git a/sys/modules/ixl/Makefile b/sys/modules/ixl/Makefile
index ac199617077e..beeb8f9a5564 100644
--- a/sys/modules/ixl/Makefile
+++ b/sys/modules/ixl/Makefile
@@ -6,7 +6,7 @@ KMOD = if_ixl
SRCS = device_if.h bus_if.h pci_if.h ifdi_if.h
SRCS += opt_inet.h opt_inet6.h opt_rss.h opt_ixl.h opt_iflib.h
SRCS += if_ixl.c ixl_pf_main.c ixl_pf_qmgr.c ixl_txrx.c ixl_pf_i2c.c i40e_osdep.c
-SRCS.PCI_IOV = pci_iov_if.h ixl_pf_iov.c
+SRCS.PCI_IOV += pci_iov_if.h ixl_pf_iov.c
# Shared source
SRCS += i40e_common.c i40e_nvm.c i40e_adminq.c i40e_lan_hmc.c i40e_hmc.c i40e_dcb.c
@@ -14,7 +14,11 @@ SRCS += i40e_common.c i40e_nvm.c i40e_adminq.c i40e_lan_hmc.c i40e_hmc.c i40e
# Debug messages / sysctls
# CFLAGS += -DIXL_DEBUG
-#CFLAGS += -DIXL_IW
-#SRCS += ixl_iw.c
+# Enable asserts and other debugging facilities
+# CFLAGS += -DINVARIANTS -DINVARIANTS_SUPPORT -DWITNESS
+
+# Enable iWARP client interface
+# CFLAGS += -DIXL_IW
+# SRCS += ixl_iw.c
.include <bsd.kmod.mk>
diff --git a/sys/net/iflib.c b/sys/net/iflib.c
index d9a6e3b962d7..594d50395d82 100644
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -101,6 +101,10 @@ __FBSDID("$FreeBSD$");
#include <x86/iommu/busdma_dmar.h>
#endif
+#ifdef PCI_IOV
+#include <dev/pci/pci_iov.h>
+#endif
+
#include <sys/bitstring.h>
/*
* enable accounting of every mbuf as it comes in to and goes out of
@@ -157,9 +161,9 @@ typedef struct iflib_filter_info {
struct iflib_ctx {
KOBJ_FIELDS;
- /*
- * Pointer to hardware driver's softc
- */
+ /*
+ * Pointer to hardware driver's softc
+ */
void *ifc_softc;
device_t ifc_dev;
if_t ifc_ifp;
@@ -178,7 +182,6 @@ struct iflib_ctx {
uint32_t ifc_if_flags;
uint32_t ifc_flags;
uint32_t ifc_max_fl_buf_size;
- int ifc_in_detach;
int ifc_link_state;
int ifc_link_irq;
@@ -254,12 +257,6 @@ iflib_get_flags(if_ctx_t ctx)
}
void
-iflib_set_detach(if_ctx_t ctx)
-{
- ctx->ifc_in_detach = 1;
-}
-
-void
iflib_set_mac(if_ctx_t ctx, uint8_t mac[ETHER_ADDR_LEN])
{
@@ -571,6 +568,13 @@ rxd_info_zero(if_rxd_info_t ri)
#define CALLOUT_LOCK(txq) mtx_lock(&txq->ift_mtx)
#define CALLOUT_UNLOCK(txq) mtx_unlock(&txq->ift_mtx)
+void
+iflib_set_detach(if_ctx_t ctx)
+{
+ STATE_LOCK(ctx);
+ ctx->ifc_flags |= IFC_IN_DETACH;
+ STATE_UNLOCK(ctx);
+}
/* Our boot-time initialization hook */
static int iflib_module_event_handler(module_t, int, void *);
@@ -738,6 +742,7 @@ static void iflib_add_device_sysctl_post(if_ctx_t ctx);
static void iflib_ifmp_purge(iflib_txq_t txq);
static void _iflib_pre_assert(if_softc_ctx_t scctx);
static void iflib_if_init_locked(if_ctx_t ctx);
+static void iflib_free_intr_mem(if_ctx_t ctx);
#ifndef __NO_STRICT_ALIGNMENT
static struct mbuf * iflib_fixup_rx(struct mbuf *m);
#endif
@@ -2072,6 +2077,16 @@ __iflib_fl_refill_lt(if_ctx_t ctx, iflib_fl_t fl, int max)
_iflib_fl_refill(ctx, fl, min(max, reclaimable));
}
+uint8_t
+iflib_in_detach(if_ctx_t ctx)
+{
+ bool in_detach;
+ STATE_LOCK(ctx);
+ in_detach = !!(ctx->ifc_flags & IFC_IN_DETACH);
+ STATE_UNLOCK(ctx);
+ return (in_detach);
+}
+
static void
iflib_fl_bufs_free(iflib_fl_t fl)
{
@@ -2087,7 +2102,8 @@ iflib_fl_bufs_free(iflib_fl_t fl)
if (fl->ifl_sds.ifsd_map != NULL) {
bus_dmamap_t sd_map = fl->ifl_sds.ifsd_map[i];
bus_dmamap_unload(fl->ifl_desc_tag, sd_map);
- if (fl->ifl_rxq->ifr_ctx->ifc_in_detach)
+ // XXX: Should this get moved out?
+ if (iflib_in_detach(fl->ifl_rxq->ifr_ctx))
bus_dmamap_destroy(fl->ifl_desc_tag, sd_map);
}
if (*sd_m != NULL) {
@@ -3842,7 +3858,7 @@ _task_fn_admin(void *context)
if_softc_ctx_t sctx = &ctx->ifc_softc_ctx;
iflib_txq_t txq;
int i;
- bool oactive, running, do_reset, do_watchdog;
+ bool oactive, running, do_reset, do_watchdog, in_detach;
uint32_t reset_on = hz / 2;
STATE_LOCK(ctx);
@@ -3850,11 +3866,13 @@ _task_fn_admin(void *context)
oactive = (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_OACTIVE);
do_reset = (ctx->ifc_flags & IFC_DO_RESET);
do_watchdog = (ctx->ifc_flags & IFC_DO_WATCHDOG);
+ in_detach = (ctx->ifc_flags & IFC_IN_DETACH);
ctx->ifc_flags &= ~(IFC_DO_RESET|IFC_DO_WATCHDOG);
STATE_UNLOCK(ctx);
- if ((!running & !oactive) &&
- !(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN))
+ if ((!running && !oactive) && !(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN))
+ return;
+ if (in_detach)
return;
CTX_LOCK(ctx);
@@ -3893,7 +3911,8 @@ _task_fn_iov(void *context)
{
if_ctx_t ctx = context;
- if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING))
+ if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING) &&
+ !(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN))
return;
CTX_LOCK(ctx);
@@ -4680,17 +4699,18 @@ iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ct
ctx->ifc_flags |= IFC_INIT_DONE;
CTX_UNLOCK(ctx);
return (0);
+
fail_detach:
ether_ifdetach(ctx->ifc_ifp);
fail_intr_free:
- if (scctx->isc_intr == IFLIB_INTR_MSIX || scctx->isc_intr == IFLIB_INTR_MSI)
- pci_release_msi(ctx->ifc_dev);
fail_queues:
iflib_tx_structures_free(ctx);
iflib_rx_structures_free(ctx);
fail:
+ iflib_free_intr_mem(ctx);
IFDI_DETACH(ctx);
CTX_UNLOCK(ctx);
+
return (err);
}
@@ -4975,12 +4995,21 @@ iflib_device_deregister(if_ctx_t ctx)
/* Make sure VLANS are not using driver */
if (if_vlantrunkinuse(ifp)) {
- device_printf(dev,"Vlan in use, detach first\n");
+ device_printf(dev, "Vlan in use, detach first\n");
return (EBUSY);
}
+#ifdef PCI_IOV
+ if (!CTX_IS_VF(ctx) && pci_iov_detach(dev) != 0) {
+ device_printf(dev, "SR-IOV in use; detach first.\n");
+ return (EBUSY);
+ }
+#endif
+
+ STATE_LOCK(ctx);
+ ctx->ifc_flags |= IFC_IN_DETACH;
+ STATE_UNLOCK(ctx);
CTX_LOCK(ctx);
- ctx->ifc_in_detach = 1;
iflib_stop(ctx);
CTX_UNLOCK(ctx);
@@ -5021,17 +5050,7 @@ iflib_device_deregister(if_ctx_t ctx)
/* ether_ifdetach calls if_qflush - lock must be destroy afterwards*/
CTX_LOCK_DESTROY(ctx);
device_set_softc(ctx->ifc_dev, NULL);
- if (ctx->ifc_softc_ctx.isc_intr != IFLIB_INTR_LEGACY) {
- pci_release_msi(dev);
- }
- if (ctx->ifc_softc_ctx.isc_intr != IFLIB_INTR_MSIX) {
- iflib_irq_free(ctx, &ctx->ifc_legacy_irq);
- }
- if (ctx->ifc_msix_mem != NULL) {
- bus_release_resource(ctx->ifc_dev, SYS_RES_MEMORY,
- ctx->ifc_softc_ctx.isc_msix_bar, ctx->ifc_msix_mem);
- ctx->ifc_msix_mem = NULL;
- }
+ iflib_free_intr_mem(ctx);
bus_generic_detach(dev);
if_free(ifp);
@@ -5040,10 +5059,27 @@ iflib_device_deregister(if_ctx_t ctx)
iflib_rx_structures_free(ctx);
if (ctx->ifc_flags & IFC_SC_ALLOCATED)
free(ctx->ifc_softc, M_IFLIB);
+ STATE_LOCK_DESTROY(ctx);
free(ctx, M_IFLIB);
return (0);
}
+static void
+iflib_free_intr_mem(if_ctx_t ctx)
+{
+
+ if (ctx->ifc_softc_ctx.isc_intr != IFLIB_INTR_LEGACY) {
+ pci_release_msi(ctx->ifc_dev);
+ }
+ if (ctx->ifc_softc_ctx.isc_intr != IFLIB_INTR_MSIX) {
+ iflib_irq_free(ctx, &ctx->ifc_legacy_irq);
+ }
+ if (ctx->ifc_msix_mem != NULL) {
+ bus_release_resource(ctx->ifc_dev, SYS_RES_MEMORY,
+ ctx->ifc_softc_ctx.isc_msix_bar, ctx->ifc_msix_mem);
+ ctx->ifc_msix_mem = NULL;
+ }
+}
int
iflib_device_detach(device_t dev)
@@ -5215,7 +5251,7 @@ iflib_register(if_ctx_t ctx)
CTX_LOCK_INIT(ctx);
STATE_LOCK_INIT(ctx, device_get_nameunit(ctx->ifc_dev));
- ifp = ctx->ifc_ifp = if_gethandle(IFT_ETHER);
+ ifp = ctx->ifc_ifp = if_alloc(IFT_ETHER);
if (ifp == NULL) {
device_printf(dev, "can not allocate ifnet structure\n");
return (ENOMEM);
@@ -5399,7 +5435,7 @@ iflib_queues_alloc(if_ctx_t ctx)
fl[j].ifl_ifdi = &rxq->ifr_ifdi[j + rxq->ifr_fl_offset];
fl[j].ifl_rxd_size = scctx->isc_rxd_size[j];
}
- /* Allocate receive buffers for the ring*/
+ /* Allocate receive buffers for the ring */
if (iflib_rxsd_alloc(rxq)) {
device_printf(dev,
"Critical Failure setting up receive buffers\n");
@@ -5554,6 +5590,8 @@ iflib_rx_structures_free(if_ctx_t ctx)
for (int i = 0; i < ctx->ifc_softc_ctx.isc_nrxqsets; i++, rxq++) {
iflib_rx_sds_free(rxq);
}
+ free(ctx->ifc_rxqs, M_IFLIB);
+ ctx->ifc_rxqs = NULL;
}
static int
@@ -5814,7 +5852,7 @@ iflib_irq_alloc_generic(if_ctx_t ctx, if_irq_t irq, int rid,
}
void
-iflib_softirq_alloc_generic(if_ctx_t ctx, if_irq_t irq, iflib_intr_type_t type, void *arg, int qid, const char *name)
+iflib_softirq_alloc_generic(if_ctx_t ctx, if_irq_t irq, iflib_intr_type_t type, void *arg, int qid, const char *name)
{
struct grouptask *gtask;
struct taskqgroup *tqg;
@@ -6132,8 +6170,9 @@ iflib_msix_init(if_ctx_t ctx)
if (ctx->ifc_sysctl_qs_eq_override == 0) {
#ifdef INVARIANTS
if (tx_queues != rx_queues)
- device_printf(dev, "queue equality override not set, capping rx_queues at %d and tx_queues at %d\n",
- min(rx_queues, tx_queues), min(rx_queues, tx_queues));
+ device_printf(dev,
+ "queue equality override not set, capping rx_queues at %d and tx_queues at %d\n",
+ min(rx_queues, tx_queues), min(rx_queues, tx_queues));
#endif
tx_queues = min(rx_queues, tx_queues);
rx_queues = min(rx_queues, tx_queues);
@@ -6143,8 +6182,7 @@ iflib_msix_init(if_ctx_t ctx)
vectors = rx_queues + admincnt;
if ((err = pci_alloc_msix(dev, &vectors)) == 0) {
- device_printf(dev,
- "Using MSIX interrupts with %d vectors\n", vectors);
+ device_printf(dev, "Using MSIX interrupts with %d vectors\n", vectors);
scctx->isc_vectors = vectors;
scctx->isc_nrxqsets = rx_queues;
scctx->isc_ntxqsets = tx_queues;
@@ -6152,7 +6190,8 @@ iflib_msix_init(if_ctx_t ctx)
return (vectors);
} else {
- device_printf(dev, "failed to allocate %d msix vectors, err: %d - using MSI\n", vectors, err);
+ device_printf(dev,
+ "failed to allocate %d msix vectors, err: %d - using MSI\n", vectors, err);
bus_release_resource(dev, SYS_RES_MEMORY, bar,
ctx->ifc_msix_mem);
ctx->ifc_msix_mem = NULL;
@@ -6463,6 +6502,15 @@ iflib_add_device_sysctl_post(if_ctx_t ctx)
}
+void
+iflib_request_reset(if_ctx_t ctx)
+{
+
+ STATE_LOCK(ctx);
+ ctx->ifc_flags |= IFC_DO_RESET;
+ STATE_UNLOCK(ctx);
+}
+
#ifndef __NO_STRICT_ALIGNMENT
static struct mbuf *
iflib_fixup_rx(struct mbuf *m)
diff --git a/sys/net/iflib.h b/sys/net/iflib.h
index bda5ad45dfc8..8c2be41b3f33 100644
--- a/sys/net/iflib.h
+++ b/sys/net/iflib.h
@@ -246,7 +246,7 @@ struct if_shared_ctx {
/* fields necessary for probe */
pci_vendor_info_t *isc_vendor_info;
char *isc_driver_version;
-/* optional function to transform the read values to match the table*/
+ /* optional function to transform the read values to match the table*/
void (*isc_parse_devinfo) (uint16_t *device_id, uint16_t *subvendor_id,
uint16_t *subdevice_id, uint16_t *rev_id);
int isc_nrxd_min[8];
@@ -375,6 +375,8 @@ if_softc_ctx_t iflib_get_softc_ctx(if_ctx_t ctx);
if_shared_ctx_t iflib_get_sctx(if_ctx_t ctx);
void iflib_set_mac(if_ctx_t ctx, uint8_t mac[ETHER_ADDR_LEN]);
+void iflib_request_reset(if_ctx_t ctx);
+uint8_t iflib_in_detach(if_ctx_t ctx);
/*
* If the driver can plug cleanly in to newbus use these
diff --git a/sys/net/iflib_private.h b/sys/net/iflib_private.h
index 1f10cf9d6903..508a327c03dc 100644
--- a/sys/net/iflib_private.h
+++ b/sys/net/iflib_private.h
@@ -42,6 +42,7 @@
#define IFC_DO_WATCHDOG 0x100
#define IFC_CHECK_HUNG 0x200
#define IFC_PSEUDO 0x400
+#define IFC_IN_DETACH 0x800
#define IFC_NETMAP_TX_IRQ 0x80000000