From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by dpdk.org (Postfix) with ESMTP id 3E71D3775 for ; Tue, 12 May 2015 19:06:28 +0200 (CEST) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga102.jf.intel.com with ESMTP; 12 May 2015 10:06:14 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.13,416,1427785200"; d="scan'208";a="570224570" Received: from irvmail001.ir.intel.com ([163.33.26.43]) by orsmga003.jf.intel.com with ESMTP; 12 May 2015 10:06:11 -0700 Received: from sivswdev01.ir.intel.com (sivswdev01.ir.intel.com [10.237.217.45]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id t4CH68OV021165; Tue, 12 May 2015 18:06:09 +0100 Received: from sivswdev01.ir.intel.com (localhost [127.0.0.1]) by sivswdev01.ir.intel.com with ESMTP id t4CH65ot013667; Tue, 12 May 2015 18:06:05 +0100 Received: (from bricha3@localhost) by sivswdev01.ir.intel.com with id t4CH620b013663; Tue, 12 May 2015 18:06:02 +0100 From: Bruce Richardson To: dev@dpdk.org Date: Tue, 12 May 2015 18:05:03 +0100 Message-Id: <1431450315-13179-8-git-send-email-bruce.richardson@intel.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1431450315-13179-1-git-send-email-bruce.richardson@intel.com> References: <1431012951-6423-1-git-send-email-bruce.richardson@intel.com> <1431450315-13179-1-git-send-email-bruce.richardson@intel.com> X-Mailman-Approved-At: Tue, 12 May 2015 21:24:38 +0200 Subject: [dpdk-dev] [PATCH 07/19] fm10k: move fm10k PMD to drivers directory X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 May 2015 17:06:45 -0000 move fm10k PMD to drivers directory Signed-off-by: Bruce Richardson --- drivers/Makefile | 2 +- drivers/fm10k/Makefile | 102 ++ drivers/fm10k/base/fm10k_api.c | 341 ++++ drivers/fm10k/base/fm10k_api.h | 61 + drivers/fm10k/base/fm10k_common.c | 572 +++++++ drivers/fm10k/base/fm10k_common.h | 52 + drivers/fm10k/base/fm10k_mbx.c | 2185 ++++++++++++++++++++++++ drivers/fm10k/base/fm10k_mbx.h | 329 ++++ drivers/fm10k/base/fm10k_osdep.h | 148 ++ drivers/fm10k/base/fm10k_pf.c | 1992 +++++++++++++++++++++ drivers/fm10k/base/fm10k_pf.h | 155 ++ drivers/fm10k/base/fm10k_tlv.c | 914 ++++++++++ drivers/fm10k/base/fm10k_tlv.h | 199 +++ drivers/fm10k/base/fm10k_type.h | 937 ++++++++++ drivers/fm10k/base/fm10k_vf.c | 641 +++++++ drivers/fm10k/base/fm10k_vf.h | 91 + drivers/fm10k/fm10k.h | 292 ++++ drivers/fm10k/fm10k_ethdev.c | 1872 ++++++++++++++++++++ drivers/fm10k/fm10k_logs.h | 80 + drivers/fm10k/fm10k_rxtx.c | 461 +++++ drivers/fm10k/rte_pmd_fm10k_version.map | 4 + lib/Makefile | 1 - lib/librte_pmd_fm10k/Makefile | 102 -- lib/librte_pmd_fm10k/base/fm10k_api.c | 341 ---- lib/librte_pmd_fm10k/base/fm10k_api.h | 61 - lib/librte_pmd_fm10k/base/fm10k_common.c | 572 ------- lib/librte_pmd_fm10k/base/fm10k_common.h | 52 - lib/librte_pmd_fm10k/base/fm10k_mbx.c | 2185 ------------------------ lib/librte_pmd_fm10k/base/fm10k_mbx.h | 329 ---- lib/librte_pmd_fm10k/base/fm10k_osdep.h | 148 -- lib/librte_pmd_fm10k/base/fm10k_pf.c | 1992 --------------------- lib/librte_pmd_fm10k/base/fm10k_pf.h | 155 -- lib/librte_pmd_fm10k/base/fm10k_tlv.c | 914 ---------- lib/librte_pmd_fm10k/base/fm10k_tlv.h | 199 --- lib/librte_pmd_fm10k/base/fm10k_type.h | 937 ---------- lib/librte_pmd_fm10k/base/fm10k_vf.c | 641 ------- lib/librte_pmd_fm10k/base/fm10k_vf.h | 91 - lib/librte_pmd_fm10k/fm10k.h | 292 ---- lib/librte_pmd_fm10k/fm10k_ethdev.c | 1872 -------------------- lib/librte_pmd_fm10k/fm10k_logs.h | 80 - lib/librte_pmd_fm10k/fm10k_rxtx.c | 461 ----- lib/librte_pmd_fm10k/rte_pmd_fm10k_version.map | 4 - 42 files changed, 11429 insertions(+), 11430 deletions(-) create mode 100644 drivers/fm10k/Makefile create mode 100644 drivers/fm10k/base/fm10k_api.c create mode 100644 drivers/fm10k/base/fm10k_api.h create mode 100644 drivers/fm10k/base/fm10k_common.c create mode 100644 drivers/fm10k/base/fm10k_common.h create mode 100644 drivers/fm10k/base/fm10k_mbx.c create mode 100644 drivers/fm10k/base/fm10k_mbx.h create mode 100644 drivers/fm10k/base/fm10k_osdep.h create mode 100644 drivers/fm10k/base/fm10k_pf.c create mode 100644 drivers/fm10k/base/fm10k_pf.h create mode 100644 drivers/fm10k/base/fm10k_tlv.c create mode 100644 drivers/fm10k/base/fm10k_tlv.h create mode 100644 drivers/fm10k/base/fm10k_type.h create mode 100644 drivers/fm10k/base/fm10k_vf.c create mode 100644 drivers/fm10k/base/fm10k_vf.h create mode 100644 drivers/fm10k/fm10k.h create mode 100644 drivers/fm10k/fm10k_ethdev.c create mode 100644 drivers/fm10k/fm10k_logs.h create mode 100644 drivers/fm10k/fm10k_rxtx.c create mode 100644 drivers/fm10k/rte_pmd_fm10k_version.map delete mode 100644 lib/librte_pmd_fm10k/Makefile delete mode 100644 lib/librte_pmd_fm10k/base/fm10k_api.c delete mode 100644 lib/librte_pmd_fm10k/base/fm10k_api.h delete mode 100644 lib/librte_pmd_fm10k/base/fm10k_common.c delete mode 100644 lib/librte_pmd_fm10k/base/fm10k_common.h delete mode 100644 lib/librte_pmd_fm10k/base/fm10k_mbx.c delete mode 100644 lib/librte_pmd_fm10k/base/fm10k_mbx.h delete mode 100644 lib/librte_pmd_fm10k/base/fm10k_osdep.h delete mode 100644 lib/librte_pmd_fm10k/base/fm10k_pf.c delete mode 100644 lib/librte_pmd_fm10k/base/fm10k_pf.h delete mode 100644 lib/librte_pmd_fm10k/base/fm10k_tlv.c delete mode 100644 lib/librte_pmd_fm10k/base/fm10k_tlv.h delete mode 100644 lib/librte_pmd_fm10k/base/fm10k_type.h delete mode 100644 lib/librte_pmd_fm10k/base/fm10k_vf.c delete mode 100644 lib/librte_pmd_fm10k/base/fm10k_vf.h delete mode 100644 lib/librte_pmd_fm10k/fm10k.h delete mode 100644 lib/librte_pmd_fm10k/fm10k_ethdev.c delete mode 100644 lib/librte_pmd_fm10k/fm10k_logs.h delete mode 100644 lib/librte_pmd_fm10k/fm10k_rxtx.c delete mode 100644 lib/librte_pmd_fm10k/rte_pmd_fm10k_version.map diff --git a/drivers/Makefile b/drivers/Makefile index 5d1a9c3..743e156 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -35,9 +35,9 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_AF_PACKET) += af_packet DIRS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += bonding DIRS-$(CONFIG_RTE_LIBRTE_E1000_PMD) += e1000 DIRS-$(CONFIG_RTE_LIBRTE_ENIC_PMD) += enic +DIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k #DIRS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += librte_pmd_ixgbe #DIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += librte_pmd_i40e -#DIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += librte_pmd_fm10k #DIRS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += librte_pmd_mlx4 #DIRS-$(CONFIG_RTE_LIBRTE_PMD_RING) += librte_pmd_ring #DIRS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += librte_pmd_pcap diff --git a/drivers/fm10k/Makefile b/drivers/fm10k/Makefile new file mode 100644 index 0000000..7395933 --- /dev/null +++ b/drivers/fm10k/Makefile @@ -0,0 +1,102 @@ +# BSD LICENSE +# +# Copyright(c) 2013-2015 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of 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. + +include $(RTE_SDK)/mk/rte.vars.mk + +# +# library name +# +LIB = librte_pmd_fm10k.a + +CFLAGS += -O3 +CFLAGS += $(WERROR_FLAGS) + +EXPORT_MAP := rte_pmd_fm10k_version.map + +LIBABIVER := 1 + +ifeq ($(CC), icc) +# +# CFLAGS for icc +# +CFLAGS_BASE_DRIVER = -wd174 -wd593 -wd869 -wd981 -wd2259 + +else ifeq ($(CC), clang) +# +## CFLAGS for clang +# +CFLAGS_BASE_DRIVER = -Wno-unused-parameter -Wno-unused-value +CFLAGS_BASE_DRIVER += -Wno-strict-aliasing -Wno-format-extra-args +CFLAGS_BASE_DRIVER += -Wno-unused-variable +CFLAGS_BASE_DRIVER += -Wno-missing-field-initializers + +else +# +# CFLAGS for gcc +# +CFLAGS_BASE_DRIVER = -Wno-unused-parameter -Wno-unused-value +CFLAGS_BASE_DRIVER += -Wno-strict-aliasing -Wno-format-extra-args +CFLAGS_BASE_DRIVER += -Wno-unused-variable +CFLAGS_BASE_DRIVER += -Wno-missing-field-initializers + +ifeq ($(shell test $(GCC_VERSION) -ge 44 && echo 1), 1) +CFLAGS += -Wno-deprecated +CFLAGS_BASE_DRIVER += -Wno-unused-but-set-variable +endif +endif + +# +# Add extra flags for base driver source files to disable warnings in them +# +BASE_DRIVER_OBJS=$(patsubst %.c,%.o,$(notdir $(wildcard $(SRCDIR)/base/*.c))) +$(foreach obj, $(BASE_DRIVER_OBJS), $(eval CFLAGS_$(obj)+=$(CFLAGS_BASE_DRIVER))) + +VPATH += $(SRCDIR)/base + +# +# all source are stored in SRCS-y +# +SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_ethdev.c +SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_rxtx.c + +SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_pf.c +SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_tlv.c +SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_common.c +SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_mbx.c +SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_vf.c +SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_api.c + +# this lib depends upon: +DEPDIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += lib/librte_eal lib/librte_ether +DEPDIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += lib/librte_mempool lib/librte_mbuf +DEPDIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += lib/librte_net lib/librte_malloc + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/drivers/fm10k/base/fm10k_api.c b/drivers/fm10k/base/fm10k_api.c new file mode 100644 index 0000000..c0f555c --- /dev/null +++ b/drivers/fm10k/base/fm10k_api.c @@ -0,0 +1,341 @@ +/******************************************************************************* + +Copyright (c) 2013 - 2015, 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. + +***************************************************************************/ + +#include "fm10k_api.h" +#include "fm10k_common.h" + +/** + * fm10k_set_mac_type - Sets MAC type + * @hw: pointer to the HW structure + * + * This function sets the mac type of the adapter based on the + * vendor ID and device ID stored in the hw structure. + **/ +s32 fm10k_set_mac_type(struct fm10k_hw *hw) +{ + s32 ret_val = FM10K_SUCCESS; + + DEBUGFUNC("fm10k_set_mac_type"); + + if (hw->vendor_id != FM10K_INTEL_VENDOR_ID) { + ERROR_REPORT2(FM10K_ERROR_UNSUPPORTED, + "Unsupported vendor id: %x\n", hw->vendor_id); + return FM10K_ERR_DEVICE_NOT_SUPPORTED; + } + + switch (hw->device_id) { + case FM10K_DEV_ID_PF: + hw->mac.type = fm10k_mac_pf; + break; + case FM10K_DEV_ID_VF: + hw->mac.type = fm10k_mac_vf; + break; + default: + ret_val = FM10K_ERR_DEVICE_NOT_SUPPORTED; + ERROR_REPORT2(FM10K_ERROR_UNSUPPORTED, + "Unsupported device id: %x\n", + hw->device_id); + break; + } + + DEBUGOUT2("fm10k_set_mac_type found mac: %d, returns: %d\n", + hw->mac.type, ret_val); + + return ret_val; +} + +/** + * fm10k_init_shared_code - Initialize the shared code + * @hw: pointer to hardware structure + * + * This will assign function pointers and assign the MAC type and PHY code. + * Does not touch the hardware. This function must be called prior to any + * other function in the shared code. The fm10k_hw structure should be + * memset to 0 prior to calling this function. The following fields in + * hw structure should be filled in prior to calling this function: + * hw_addr, back, device_id, vendor_id, subsystem_device_id, + * subsystem_vendor_id, and revision_id + **/ +s32 fm10k_init_shared_code(struct fm10k_hw *hw) +{ + s32 status; + + DEBUGFUNC("fm10k_init_shared_code"); + + /* Set the mac type */ + fm10k_set_mac_type(hw); + + switch (hw->mac.type) { + case fm10k_mac_pf: + status = fm10k_init_ops_pf(hw); + break; + case fm10k_mac_vf: + status = fm10k_init_ops_vf(hw); + break; + default: + status = FM10K_ERR_DEVICE_NOT_SUPPORTED; + break; + } + + return status; +} + +#define fm10k_call_func(hw, func, params, error) \ + ((func) ? (func params) : (error)) + +/** + * fm10k_reset_hw - Reset the hardware to known good state + * @hw: pointer to hardware structure + * + * This function should return the hardware to a state similar to the + * one it is in after being powered on. + **/ +s32 fm10k_reset_hw(struct fm10k_hw *hw) +{ + return fm10k_call_func(hw, hw->mac.ops.reset_hw, (hw), + FM10K_NOT_IMPLEMENTED); +} + +/** + * fm10k_init_hw - Initialize the hardware + * @hw: pointer to hardware structure + * + * Initialize the hardware by resetting and then starting the hardware + **/ +s32 fm10k_init_hw(struct fm10k_hw *hw) +{ + return fm10k_call_func(hw, hw->mac.ops.init_hw, (hw), + FM10K_NOT_IMPLEMENTED); +} + +/** + * fm10k_stop_hw - Prepares hardware to shutdown Rx/Tx + * @hw: pointer to hardware structure + * + * Disables Rx/Tx queues and disables the DMA engine. + **/ +s32 fm10k_stop_hw(struct fm10k_hw *hw) +{ + return fm10k_call_func(hw, hw->mac.ops.stop_hw, (hw), + FM10K_NOT_IMPLEMENTED); +} + +/** + * fm10k_start_hw - Prepares hardware for Rx/Tx + * @hw: pointer to hardware structure + * + * This function sets the flags indicating that the hardware is ready to + * begin operation. + **/ +s32 fm10k_start_hw(struct fm10k_hw *hw) +{ + return fm10k_call_func(hw, hw->mac.ops.start_hw, (hw), + FM10K_NOT_IMPLEMENTED); +} + +/** + * fm10k_get_bus_info - Set PCI bus info + * @hw: pointer to hardware structure + * + * Sets the PCI bus info (speed, width, type) within the fm10k_hw structure + **/ +s32 fm10k_get_bus_info(struct fm10k_hw *hw) +{ + return fm10k_call_func(hw, hw->mac.ops.get_bus_info, (hw), + FM10K_NOT_IMPLEMENTED); +} + +/** + * fm10k_is_slot_appropriate - Indicate appropriate slot for this SKU + * @hw: pointer to hardware structure + * + * Looks at the PCIe bus info to confirm whether or not this slot can support + * the necessary bandwidth for this device. + **/ +bool fm10k_is_slot_appropriate(struct fm10k_hw *hw) +{ + if (hw->mac.ops.is_slot_appropriate) + return hw->mac.ops.is_slot_appropriate(hw); + return true; +} + +/** + * fm10k_update_vlan - Clear VLAN ID to VLAN filter table + * @hw: pointer to hardware structure + * @vid: VLAN ID to add to table + * @idx: Index indicating VF ID or PF ID in table + * @set: Indicates if this is a set or clear operation + * + * This function adds or removes the corresponding VLAN ID from the VLAN + * filter table for the corresponding function. + **/ +s32 fm10k_update_vlan(struct fm10k_hw *hw, u32 vid, u8 idx, bool set) +{ + return fm10k_call_func(hw, hw->mac.ops.update_vlan, (hw, vid, idx, set), + FM10K_NOT_IMPLEMENTED); +} + +/** + * fm10k_read_mac_addr - Reads MAC address + * @hw: pointer to hardware structure + * + * Reads the MAC address out of the interface and stores it in the HW + * structures. + **/ +s32 fm10k_read_mac_addr(struct fm10k_hw *hw) +{ + return fm10k_call_func(hw, hw->mac.ops.read_mac_addr, (hw), + FM10K_NOT_IMPLEMENTED); +} + +/** + * fm10k_update_hw_stats - Update hw statistics + * @hw: pointer to hardware structure + * + * This function updates statistics that are related to hardware. + * */ +void fm10k_update_hw_stats(struct fm10k_hw *hw, struct fm10k_hw_stats *stats) +{ + if (hw->mac.ops.update_hw_stats) + hw->mac.ops.update_hw_stats(hw, stats); +} + +/** + * fm10k_rebind_hw_stats - Reset base for hw statistics + * @hw: pointer to hardware structure + * + * This function resets the base for statistics that are related to hardware. + * */ +void fm10k_rebind_hw_stats(struct fm10k_hw *hw, struct fm10k_hw_stats *stats) +{ + if (hw->mac.ops.rebind_hw_stats) + hw->mac.ops.rebind_hw_stats(hw, stats); +} + +/** + * fm10k_configure_dglort_map - Configures GLORT entry and queues + * @hw: pointer to hardware structure + * @dglort: pointer to dglort configuration structure + * + * Reads the configuration structure contained in dglort_cfg and uses + * that information to then populate a DGLORTMAP/DEC entry and the queues + * to which it has been assigned. + **/ +s32 fm10k_configure_dglort_map(struct fm10k_hw *hw, + struct fm10k_dglort_cfg *dglort) +{ + return fm10k_call_func(hw, hw->mac.ops.configure_dglort_map, + (hw, dglort), FM10K_NOT_IMPLEMENTED); +} + +/** + * fm10k_set_dma_mask - Configures PhyAddrSpace to limit DMA to system + * @hw: pointer to hardware structure + * @dma_mask: 64 bit DMA mask required for platform + * + * This function configures the endpoint to limit the access to memory + * beyond what is physically in the system. + **/ +void fm10k_set_dma_mask(struct fm10k_hw *hw, u64 dma_mask) +{ + if (hw->mac.ops.set_dma_mask) + hw->mac.ops.set_dma_mask(hw, dma_mask); +} + +/** + * fm10k_get_fault - Record a fault in one of the interface units + * @hw: pointer to hardware structure + * @type: pointer to fault type register offset + * @fault: pointer to memory location to record the fault + * + * Record the fault register contents to the fault data structure and + * clear the entry from the register. + * + * Returns ERR_PARAM if invalid register is specified or no error is present. + **/ +s32 fm10k_get_fault(struct fm10k_hw *hw, int type, struct fm10k_fault *fault) +{ + return fm10k_call_func(hw, hw->mac.ops.get_fault, (hw, type, fault), + FM10K_NOT_IMPLEMENTED); +} + +/** + * fm10k_update_uc_addr - Update device unicast address + * @hw: pointer to the HW structure + * @lport: logical port ID to update - unused + * @mac: MAC address to add/remove from table + * @vid: VLAN ID to add/remove from table + * @add: Indicates if this is an add or remove operation + * @flags: flags field to indicate add and secure - unused + * + * This function is used to add or remove unicast MAC addresses + **/ +s32 fm10k_update_uc_addr(struct fm10k_hw *hw, u16 lport, + const u8 *mac, u16 vid, bool add, u8 flags) +{ + return fm10k_call_func(hw, hw->mac.ops.update_uc_addr, + (hw, lport, mac, vid, add, flags), + FM10K_NOT_IMPLEMENTED); +} + +/** + * fm10k_update_mc_addr - Update device multicast address + * @hw: pointer to the HW structure + * @lport: logical port ID to update - unused + * @mac: MAC address to add/remove from table + * @vid: VLAN ID to add/remove from table + * @add: Indicates if this is an add or remove operation + * + * This function is used to add or remove multicast MAC addresses + **/ +s32 fm10k_update_mc_addr(struct fm10k_hw *hw, u16 lport, + const u8 *mac, u16 vid, bool add) +{ + return fm10k_call_func(hw, hw->mac.ops.update_mc_addr, + (hw, lport, mac, vid, add), + FM10K_NOT_IMPLEMENTED); +} + +/** + * fm10k_adjust_systime - Adjust systime frequency + * @hw: pointer to hardware structure + * @ppb: adjustment rate in parts per billion + * + * This function is meant to update the frequency of the clock represented + * by the SYSTIME register. + **/ +s32 fm10k_adjust_systime(struct fm10k_hw *hw, s32 ppb) +{ + return fm10k_call_func(hw, hw->mac.ops.adjust_systime, + (hw, ppb), FM10K_NOT_IMPLEMENTED); +} diff --git a/drivers/fm10k/base/fm10k_api.h b/drivers/fm10k/base/fm10k_api.h new file mode 100644 index 0000000..343d750 --- /dev/null +++ b/drivers/fm10k/base/fm10k_api.h @@ -0,0 +1,61 @@ +/******************************************************************************* + +Copyright (c) 2013 - 2015, 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. + +***************************************************************************/ + +#ifndef _FM10K_API_H_ +#define _FM10K_API_H_ + +#include "fm10k_pf.h" +#include "fm10k_vf.h" + +s32 fm10k_set_mac_type(struct fm10k_hw *hw); +s32 fm10k_reset_hw(struct fm10k_hw *hw); +s32 fm10k_init_hw(struct fm10k_hw *hw); +s32 fm10k_stop_hw(struct fm10k_hw *hw); +s32 fm10k_start_hw(struct fm10k_hw *hw); +s32 fm10k_init_shared_code(struct fm10k_hw *hw); +s32 fm10k_get_bus_info(struct fm10k_hw *hw); +bool fm10k_is_slot_appropriate(struct fm10k_hw *hw); +s32 fm10k_update_vlan(struct fm10k_hw *hw, u32 vid, u8 idx, bool set); +s32 fm10k_read_mac_addr(struct fm10k_hw *hw); +void fm10k_update_hw_stats(struct fm10k_hw *hw, struct fm10k_hw_stats *stats); +void fm10k_rebind_hw_stats(struct fm10k_hw *hw, struct fm10k_hw_stats *stats); +s32 fm10k_configure_dglort_map(struct fm10k_hw *hw, + struct fm10k_dglort_cfg *dglort); +void fm10k_set_dma_mask(struct fm10k_hw *hw, u64 dma_mask); +s32 fm10k_get_fault(struct fm10k_hw *hw, int type, struct fm10k_fault *fault); +s32 fm10k_update_uc_addr(struct fm10k_hw *hw, u16 lport, + const u8 *mac, u16 vid, bool add, u8 flags); +s32 fm10k_update_mc_addr(struct fm10k_hw *hw, u16 lport, + const u8 *mac, u16 vid, bool add); +s32 fm10k_adjust_systime(struct fm10k_hw *hw, s32 ppb); +#endif /* _FM10K_API_H_ */ diff --git a/drivers/fm10k/base/fm10k_common.c b/drivers/fm10k/base/fm10k_common.c new file mode 100644 index 0000000..a90d2f0 --- /dev/null +++ b/drivers/fm10k/base/fm10k_common.c @@ -0,0 +1,572 @@ +/******************************************************************************* + +Copyright (c) 2013 - 2015, 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. + +***************************************************************************/ + +#include "fm10k_common.h" + +/** + * fm10k_get_bus_info_generic - Generic set PCI bus info + * @hw: pointer to hardware structure + * + * Gets the PCI bus info (speed, width, type) then calls helper function to + * store this data within the fm10k_hw structure. + **/ +STATIC s32 fm10k_get_bus_info_generic(struct fm10k_hw *hw) +{ + u16 link_cap, link_status, device_cap, device_control; + + DEBUGFUNC("fm10k_get_bus_info_generic"); + + /* Get the maximum link width and speed from PCIe config space */ + link_cap = FM10K_READ_PCI_WORD(hw, FM10K_PCIE_LINK_CAP); + + switch (link_cap & FM10K_PCIE_LINK_WIDTH) { + case FM10K_PCIE_LINK_WIDTH_1: + hw->bus_caps.width = fm10k_bus_width_pcie_x1; + break; + case FM10K_PCIE_LINK_WIDTH_2: + hw->bus_caps.width = fm10k_bus_width_pcie_x2; + break; + case FM10K_PCIE_LINK_WIDTH_4: + hw->bus_caps.width = fm10k_bus_width_pcie_x4; + break; + case FM10K_PCIE_LINK_WIDTH_8: + hw->bus_caps.width = fm10k_bus_width_pcie_x8; + break; + default: + hw->bus_caps.width = fm10k_bus_width_unknown; + break; + } + + switch (link_cap & FM10K_PCIE_LINK_SPEED) { + case FM10K_PCIE_LINK_SPEED_2500: + hw->bus_caps.speed = fm10k_bus_speed_2500; + break; + case FM10K_PCIE_LINK_SPEED_5000: + hw->bus_caps.speed = fm10k_bus_speed_5000; + break; + case FM10K_PCIE_LINK_SPEED_8000: + hw->bus_caps.speed = fm10k_bus_speed_8000; + break; + default: + hw->bus_caps.speed = fm10k_bus_speed_unknown; + break; + } + + /* Get the PCIe maximum payload size for the PCIe function */ + device_cap = FM10K_READ_PCI_WORD(hw, FM10K_PCIE_DEV_CAP); + + switch (device_cap & FM10K_PCIE_DEV_CAP_PAYLOAD) { + case FM10K_PCIE_DEV_CAP_PAYLOAD_128: + hw->bus_caps.payload = fm10k_bus_payload_128; + break; + case FM10K_PCIE_DEV_CAP_PAYLOAD_256: + hw->bus_caps.payload = fm10k_bus_payload_256; + break; + case FM10K_PCIE_DEV_CAP_PAYLOAD_512: + hw->bus_caps.payload = fm10k_bus_payload_512; + break; + default: + hw->bus_caps.payload = fm10k_bus_payload_unknown; + break; + } + + /* Get the negotiated link width and speed from PCIe config space */ + link_status = FM10K_READ_PCI_WORD(hw, FM10K_PCIE_LINK_STATUS); + + switch (link_status & FM10K_PCIE_LINK_WIDTH) { + case FM10K_PCIE_LINK_WIDTH_1: + hw->bus.width = fm10k_bus_width_pcie_x1; + break; + case FM10K_PCIE_LINK_WIDTH_2: + hw->bus.width = fm10k_bus_width_pcie_x2; + break; + case FM10K_PCIE_LINK_WIDTH_4: + hw->bus.width = fm10k_bus_width_pcie_x4; + break; + case FM10K_PCIE_LINK_WIDTH_8: + hw->bus.width = fm10k_bus_width_pcie_x8; + break; + default: + hw->bus.width = fm10k_bus_width_unknown; + break; + } + + switch (link_status & FM10K_PCIE_LINK_SPEED) { + case FM10K_PCIE_LINK_SPEED_2500: + hw->bus.speed = fm10k_bus_speed_2500; + break; + case FM10K_PCIE_LINK_SPEED_5000: + hw->bus.speed = fm10k_bus_speed_5000; + break; + case FM10K_PCIE_LINK_SPEED_8000: + hw->bus.speed = fm10k_bus_speed_8000; + break; + default: + hw->bus.speed = fm10k_bus_speed_unknown; + break; + } + + /* Get the negotiated PCIe maximum payload size for the PCIe function */ + device_control = FM10K_READ_PCI_WORD(hw, FM10K_PCIE_DEV_CTRL); + + switch (device_control & FM10K_PCIE_DEV_CTRL_PAYLOAD) { + case FM10K_PCIE_DEV_CTRL_PAYLOAD_128: + hw->bus.payload = fm10k_bus_payload_128; + break; + case FM10K_PCIE_DEV_CTRL_PAYLOAD_256: + hw->bus.payload = fm10k_bus_payload_256; + break; + case FM10K_PCIE_DEV_CTRL_PAYLOAD_512: + hw->bus.payload = fm10k_bus_payload_512; + break; + default: + hw->bus.payload = fm10k_bus_payload_unknown; + break; + } + + return FM10K_SUCCESS; +} + +u16 fm10k_get_pcie_msix_count_generic(struct fm10k_hw *hw) +{ + u16 msix_count; + + DEBUGFUNC("fm10k_get_pcie_msix_count_generic"); + + /* read in value from MSI-X capability register */ + msix_count = FM10K_READ_PCI_WORD(hw, FM10K_PCI_MSIX_MSG_CTRL); + msix_count &= FM10K_PCI_MSIX_MSG_CTRL_TBL_SZ_MASK; + + /* MSI-X count is zero-based in HW */ + msix_count++; + + if (msix_count > FM10K_MAX_MSIX_VECTORS) + msix_count = FM10K_MAX_MSIX_VECTORS; + + return msix_count; +} + +/** + * fm10k_init_ops_generic - Inits function ptrs + * @hw: pointer to the hardware structure + * + * Initialize the function pointers. + **/ +s32 fm10k_init_ops_generic(struct fm10k_hw *hw) +{ + struct fm10k_mac_info *mac = &hw->mac; + + DEBUGFUNC("fm10k_init_ops_generic"); + + /* MAC */ + mac->ops.get_bus_info = &fm10k_get_bus_info_generic; + + /* initialize GLORT state to avoid any false hits */ + mac->dglort_map = FM10K_DGLORTMAP_NONE; + + return FM10K_SUCCESS; +} + +/** + * fm10k_start_hw_generic - Prepare hardware for Tx/Rx + * @hw: pointer to hardware structure + * + * This function sets the Tx ready flag to indicate that the Tx path has + * been initialized. + **/ +s32 fm10k_start_hw_generic(struct fm10k_hw *hw) +{ + DEBUGFUNC("fm10k_start_hw_generic"); + + /* set flag indicating we are beginning Tx */ + hw->mac.tx_ready = true; + + return FM10K_SUCCESS; +} + +/** + * fm10k_disable_queues_generic - Stop Tx/Rx queues + * @hw: pointer to hardware structure + * @q_cnt: number of queues to be disabled + * + **/ +s32 fm10k_disable_queues_generic(struct fm10k_hw *hw, u16 q_cnt) +{ + u32 reg; + u16 i, time; + + DEBUGFUNC("fm10k_disable_queues_generic"); + + /* clear tx_ready to prevent any false hits for reset */ + hw->mac.tx_ready = false; + + /* clear the enable bit for all rings */ + for (i = 0; i < q_cnt; i++) { + reg = FM10K_READ_REG(hw, FM10K_TXDCTL(i)); + FM10K_WRITE_REG(hw, FM10K_TXDCTL(i), + reg & ~FM10K_TXDCTL_ENABLE); + reg = FM10K_READ_REG(hw, FM10K_RXQCTL(i)); + FM10K_WRITE_REG(hw, FM10K_RXQCTL(i), + reg & ~FM10K_RXQCTL_ENABLE); + } + + FM10K_WRITE_FLUSH(hw); + usec_delay(1); + + /* loop through all queues to verify that they are all disabled */ + for (i = 0, time = FM10K_QUEUE_DISABLE_TIMEOUT; time;) { + /* if we are at end of rings all rings are disabled */ + if (i == q_cnt) + return FM10K_SUCCESS; + + /* if queue enables cleared, then move to next ring pair */ + reg = FM10K_READ_REG(hw, FM10K_TXDCTL(i)); + if (!~reg || !(reg & FM10K_TXDCTL_ENABLE)) { + reg = FM10K_READ_REG(hw, FM10K_RXQCTL(i)); + if (!~reg || !(reg & FM10K_RXQCTL_ENABLE)) { + i++; + continue; + } + } + + /* decrement time and wait 1 usec */ + time--; + if (time) + usec_delay(1); + } + + return FM10K_ERR_REQUESTS_PENDING; +} + +/** + * fm10k_stop_hw_generic - Stop Tx/Rx units + * @hw: pointer to hardware structure + * + **/ +s32 fm10k_stop_hw_generic(struct fm10k_hw *hw) +{ + DEBUGFUNC("fm10k_stop_hw_generic"); + + return fm10k_disable_queues_generic(hw, hw->mac.max_queues); +} + +/** + * fm10k_read_hw_stats_32b - Reads value of 32-bit registers + * @hw: pointer to the hardware structure + * @addr: address of register containing a 32-bit value + * + * Function reads the content of the register and returns the delta + * between the base and the current value. + * **/ +u32 fm10k_read_hw_stats_32b(struct fm10k_hw *hw, u32 addr, + struct fm10k_hw_stat *stat) +{ + u32 delta = FM10K_READ_REG(hw, addr) - stat->base_l; + + DEBUGFUNC("fm10k_read_hw_stats_32b"); + + if (FM10K_REMOVED(hw->hw_addr)) + stat->base_h = 0; + + return delta; +} + +/** + * fm10k_read_hw_stats_48b - Reads value of 48-bit registers + * @hw: pointer to the hardware structure + * @addr: address of register containing the lower 32-bit value + * + * Function reads the content of 2 registers, combined to represent a 48-bit + * statistical value. Extra processing is required to handle overflowing. + * Finally, a delta value is returned representing the difference between the + * values stored in registers and values stored in the statistic counters. + * **/ +STATIC u64 fm10k_read_hw_stats_48b(struct fm10k_hw *hw, u32 addr, + struct fm10k_hw_stat *stat) +{ + u32 count_l; + u32 count_h; + u32 count_tmp; + u64 delta; + + DEBUGFUNC("fm10k_read_hw_stats_48b"); + + count_h = FM10K_READ_REG(hw, addr + 1); + + /* Check for overflow */ + do { + count_tmp = count_h; + count_l = FM10K_READ_REG(hw, addr); + count_h = FM10K_READ_REG(hw, addr + 1); + } while (count_h != count_tmp); + + delta = ((u64)(count_h - stat->base_h) << 32) + count_l; + delta -= stat->base_l; + + return delta & FM10K_48_BIT_MASK; +} + +/** + * fm10k_update_hw_base_48b - Updates 48-bit statistic base value + * @stat: pointer to the hardware statistic structure + * @delta: value to be updated into the hardware statistic structure + * + * Function receives a value and determines if an update is required based on + * a delta calculation. Only the base value will be updated. + **/ +STATIC void fm10k_update_hw_base_48b(struct fm10k_hw_stat *stat, u64 delta) +{ + DEBUGFUNC("fm10k_update_hw_base_48b"); + + if (!delta) + return; + + /* update lower 32 bits */ + delta += stat->base_l; + stat->base_l = (u32)delta; + + /* update upper 32 bits */ + stat->base_h += (u32)(delta >> 32); +} + +/** + * fm10k_update_hw_stats_tx_q - Updates TX queue statistics counters + * @hw: pointer to the hardware structure + * @q: pointer to the ring of hardware statistics queue + * @idx: index pointing to the start of the ring iteration + * + * Function updates the TX queue statistics counters that are related to the + * hardware. + **/ +STATIC void fm10k_update_hw_stats_tx_q(struct fm10k_hw *hw, + struct fm10k_hw_stats_q *q, + u32 idx) +{ + u32 id_tx, id_tx_prev, tx_packets; + u64 tx_bytes = 0; + + DEBUGFUNC("fm10k_update_hw_stats_tx_q"); + + /* Retrieve TX Owner Data */ + id_tx = FM10K_READ_REG(hw, FM10K_TXQCTL(idx)); + + /* Process TX Ring */ + do { + tx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPTC(idx), + &q->tx_packets); + + if (tx_packets) + tx_bytes = fm10k_read_hw_stats_48b(hw, + FM10K_QBTC_L(idx), + &q->tx_bytes); + + /* Re-Check Owner Data */ + id_tx_prev = id_tx; + id_tx = FM10K_READ_REG(hw, FM10K_TXQCTL(idx)); + } while ((id_tx ^ id_tx_prev) & FM10K_TXQCTL_ID_MASK); + + /* drop non-ID bits and set VALID ID bit */ + id_tx &= FM10K_TXQCTL_ID_MASK; + id_tx |= FM10K_STAT_VALID; + + /* update packet counts */ + if (q->tx_stats_idx == id_tx) { + q->tx_packets.count += tx_packets; + q->tx_bytes.count += tx_bytes; + } + + /* update bases and record ID */ + fm10k_update_hw_base_32b(&q->tx_packets, tx_packets); + fm10k_update_hw_base_48b(&q->tx_bytes, tx_bytes); + + q->tx_stats_idx = id_tx; +} + +/** + * fm10k_update_hw_stats_rx_q - Updates RX queue statistics counters + * @hw: pointer to the hardware structure + * @q: pointer to the ring of hardware statistics queue + * @idx: index pointing to the start of the ring iteration + * + * Function updates the RX queue statistics counters that are related to the + * hardware. + **/ +STATIC void fm10k_update_hw_stats_rx_q(struct fm10k_hw *hw, + struct fm10k_hw_stats_q *q, + u32 idx) +{ + u32 id_rx, id_rx_prev, rx_packets, rx_drops; + u64 rx_bytes = 0; + + DEBUGFUNC("fm10k_update_hw_stats_rx_q"); + + /* Retrieve RX Owner Data */ + id_rx = FM10K_READ_REG(hw, FM10K_RXQCTL(idx)); + + /* Process RX Ring */ + do { + rx_drops = fm10k_read_hw_stats_32b(hw, FM10K_QPRDC(idx), + &q->rx_drops); + + rx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPRC(idx), + &q->rx_packets); + + if (rx_packets) + rx_bytes = fm10k_read_hw_stats_48b(hw, + FM10K_QBRC_L(idx), + &q->rx_bytes); + + /* Re-Check Owner Data */ + id_rx_prev = id_rx; + id_rx = FM10K_READ_REG(hw, FM10K_RXQCTL(idx)); + } while ((id_rx ^ id_rx_prev) & FM10K_RXQCTL_ID_MASK); + + /* drop non-ID bits and set VALID ID bit */ + id_rx &= FM10K_RXQCTL_ID_MASK; + id_rx |= FM10K_STAT_VALID; + + /* update packet counts */ + if (q->rx_stats_idx == id_rx) { + q->rx_drops.count += rx_drops; + q->rx_packets.count += rx_packets; + q->rx_bytes.count += rx_bytes; + } + + /* update bases and record ID */ + fm10k_update_hw_base_32b(&q->rx_drops, rx_drops); + fm10k_update_hw_base_32b(&q->rx_packets, rx_packets); + fm10k_update_hw_base_48b(&q->rx_bytes, rx_bytes); + + q->rx_stats_idx = id_rx; +} + +/** + * fm10k_update_hw_stats_q - Updates queue statistics counters + * @hw: pointer to the hardware structure + * @q: pointer to the ring of hardware statistics queue + * @idx: index pointing to the start of the ring iteration + * @count: number of queues to iterate over + * + * Function updates the queue statistics counters that are related to the + * hardware. + **/ +void fm10k_update_hw_stats_q(struct fm10k_hw *hw, struct fm10k_hw_stats_q *q, + u32 idx, u32 count) +{ + u32 i; + + DEBUGFUNC("fm10k_update_hw_stats_q"); + + for (i = 0; i < count; i++, idx++, q++) { + fm10k_update_hw_stats_tx_q(hw, q, idx); + fm10k_update_hw_stats_rx_q(hw, q, idx); + } +} + +/** + * fm10k_unbind_hw_stats_q - Unbind the queue counters from their queues + * @hw: pointer to the hardware structure + * @q: pointer to the ring of hardware statistics queue + * @idx: index pointing to the start of the ring iteration + * @count: number of queues to iterate over + * + * Function invalidates the index values for the queues so any updates that + * may have happened are ignored and the base for the queue stats is reset. + **/ +void fm10k_unbind_hw_stats_q(struct fm10k_hw_stats_q *q, u32 idx, u32 count) +{ + u32 i; + + for (i = 0; i < count; i++, idx++, q++) { + q->rx_stats_idx = 0; + q->tx_stats_idx = 0; + } +} + +/** + * fm10k_get_host_state_generic - Returns the state of the host + * @hw: pointer to hardware structure + * @host_ready: pointer to boolean value that will record host state + * + * This function will check the health of the mailbox and Tx queue 0 + * in order to determine if we should report that the link is up or not. + **/ +s32 fm10k_get_host_state_generic(struct fm10k_hw *hw, bool *host_ready) +{ + struct fm10k_mbx_info *mbx = &hw->mbx; + struct fm10k_mac_info *mac = &hw->mac; + s32 ret_val = FM10K_SUCCESS; + u32 txdctl = FM10K_READ_REG(hw, FM10K_TXDCTL(0)); + + DEBUGFUNC("fm10k_get_host_state_generic"); + + /* process upstream mailbox in case interrupts were disabled */ + mbx->ops.process(hw, mbx); + + /* If Tx is no longer enabled link should come down */ + if (!(~txdctl) || !(txdctl & FM10K_TXDCTL_ENABLE)) + mac->get_host_state = true; + + /* exit if not checking for link, or link cannot be changed */ + if (!mac->get_host_state || !(~txdctl)) + goto out; + + /* if we somehow dropped the Tx enable we should reset */ + if (hw->mac.tx_ready && !(txdctl & FM10K_TXDCTL_ENABLE)) { + ret_val = FM10K_ERR_RESET_REQUESTED; + goto out; + } + + /* if Mailbox timed out we should request reset */ + if (!mbx->timeout) { + ret_val = FM10K_ERR_RESET_REQUESTED; + goto out; + } + + /* verify Mailbox is still valid */ + if (!mbx->ops.tx_ready(mbx, FM10K_VFMBX_MSG_MTU)) + goto out; + + /* interface cannot receive traffic without logical ports */ + if (mac->dglort_map == FM10K_DGLORTMAP_NONE) + goto out; + + /* if we passed all the tests above then the switch is ready and we no + * longer need to check for link + */ + mac->get_host_state = false; + +out: + *host_ready = !mac->get_host_state; + return ret_val; +} diff --git a/drivers/fm10k/base/fm10k_common.h b/drivers/fm10k/base/fm10k_common.h new file mode 100644 index 0000000..45fbbc0 --- /dev/null +++ b/drivers/fm10k/base/fm10k_common.h @@ -0,0 +1,52 @@ +/******************************************************************************* + +Copyright (c) 2013 - 2015, 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. + +***************************************************************************/ + +#ifndef _FM10K_COMMON_H_ +#define _FM10K_COMMON_H_ + +#include "fm10k_type.h" + +u16 fm10k_get_pcie_msix_count_generic(struct fm10k_hw *hw); +s32 fm10k_init_ops_generic(struct fm10k_hw *hw); +s32 fm10k_disable_queues_generic(struct fm10k_hw *hw, u16 q_cnt); +s32 fm10k_start_hw_generic(struct fm10k_hw *hw); +s32 fm10k_stop_hw_generic(struct fm10k_hw *hw); +u32 fm10k_read_hw_stats_32b(struct fm10k_hw *hw, u32 addr, + struct fm10k_hw_stat *stat); +#define fm10k_update_hw_base_32b(stat, delta) ((stat)->base_l += (delta)) +void fm10k_update_hw_stats_q(struct fm10k_hw *hw, struct fm10k_hw_stats_q *q, + u32 idx, u32 count); +#define fm10k_unbind_hw_stats_32b(s) ((s)->base_h = 0) +void fm10k_unbind_hw_stats_q(struct fm10k_hw_stats_q *q, u32 idx, u32 count); +s32 fm10k_get_host_state_generic(struct fm10k_hw *hw, bool *host_ready); +#endif /* _FM10K_COMMON_H_ */ diff --git a/drivers/fm10k/base/fm10k_mbx.c b/drivers/fm10k/base/fm10k_mbx.c new file mode 100644 index 0000000..2081414 --- /dev/null +++ b/drivers/fm10k/base/fm10k_mbx.c @@ -0,0 +1,2185 @@ +/******************************************************************************* + +Copyright (c) 2013 - 2015, 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. + +***************************************************************************/ + +#include "fm10k_common.h" + +/** + * fm10k_fifo_init - Initialize a message FIFO + * @fifo: pointer to FIFO + * @buffer: pointer to memory to be used to store FIFO + * @size: maximum message size to store in FIFO, must be 2^n - 1 + **/ +STATIC void fm10k_fifo_init(struct fm10k_mbx_fifo *fifo, u32 *buffer, u16 size) +{ + fifo->buffer = buffer; + fifo->size = size; + fifo->head = 0; + fifo->tail = 0; +} + +/** + * fm10k_fifo_used - Retrieve used space in FIFO + * @fifo: pointer to FIFO + * + * This function returns the number of DWORDs used in the FIFO + **/ +STATIC u16 fm10k_fifo_used(struct fm10k_mbx_fifo *fifo) +{ + return fifo->tail - fifo->head; +} + +/** + * fm10k_fifo_unused - Retrieve unused space in FIFO + * @fifo: pointer to FIFO + * + * This function returns the number of unused DWORDs in the FIFO + **/ +STATIC u16 fm10k_fifo_unused(struct fm10k_mbx_fifo *fifo) +{ + return fifo->size + fifo->head - fifo->tail; +} + +/** + * fm10k_fifo_empty - Test to verify if fifo is empty + * @fifo: pointer to FIFO + * + * This function returns true if the FIFO is empty, else false + **/ +STATIC bool fm10k_fifo_empty(struct fm10k_mbx_fifo *fifo) +{ + return fifo->head == fifo->tail; +} + +/** + * fm10k_fifo_head_offset - returns indices of head with given offset + * @fifo: pointer to FIFO + * @offset: offset to add to head + * + * This function returns the indices into the fifo based on head + offset + **/ +STATIC u16 fm10k_fifo_head_offset(struct fm10k_mbx_fifo *fifo, u16 offset) +{ + return (fifo->head + offset) & (fifo->size - 1); +} + +/** + * fm10k_fifo_tail_offset - returns indices of tail with given offset + * @fifo: pointer to FIFO + * @offset: offset to add to tail + * + * This function returns the indices into the fifo based on tail + offset + **/ +STATIC u16 fm10k_fifo_tail_offset(struct fm10k_mbx_fifo *fifo, u16 offset) +{ + return (fifo->tail + offset) & (fifo->size - 1); +} + +/** + * fm10k_fifo_head_len - Retrieve length of first message in FIFO + * @fifo: pointer to FIFO + * + * This function returns the size of the first message in the FIFO + **/ +STATIC u16 fm10k_fifo_head_len(struct fm10k_mbx_fifo *fifo) +{ + u32 *head = fifo->buffer + fm10k_fifo_head_offset(fifo, 0); + + /* verify there is at least 1 DWORD in the fifo so *head is valid */ + if (fm10k_fifo_empty(fifo)) + return 0; + + /* retieve the message length */ + return FM10K_TLV_DWORD_LEN(*head); +} + +/** + * fm10k_fifo_head_drop - Drop the first message in FIFO + * @fifo: pointer to FIFO + * + * This function returns the size of the message dropped from the FIFO + **/ +STATIC u16 fm10k_fifo_head_drop(struct fm10k_mbx_fifo *fifo) +{ + u16 len = fm10k_fifo_head_len(fifo); + + /* update head so it is at the start of next frame */ + fifo->head += len; + + return len; +} + +/** + * fm10k_mbx_index_len - Convert a head/tail index into a length value + * @mbx: pointer to mailbox + * @head: head index + * @tail: head index + * + * This function takes the head and tail index and determines the length + * of the data indicated by this pair. + **/ +STATIC u16 fm10k_mbx_index_len(struct fm10k_mbx_info *mbx, u16 head, u16 tail) +{ + u16 len = tail - head; + + /* we wrapped so subtract 2, one for index 0, one for all 1s index */ + if (len > tail) + len -= 2; + + return len & ((mbx->mbmem_len << 1) - 1); +} + +/** + * fm10k_mbx_tail_add - Determine new tail value with added offset + * @mbx: pointer to mailbox + * @offset: length to add to head offset + * + * This function takes the local tail index and recomputes it for + * a given length added as an offset. + **/ +STATIC u16 fm10k_mbx_tail_add(struct fm10k_mbx_info *mbx, u16 offset) +{ + u16 tail = (mbx->tail + offset + 1) & ((mbx->mbmem_len << 1) - 1); + + /* add/sub 1 because we cannot have offset 0 or all 1s */ + return (tail > mbx->tail) ? --tail : ++tail; +} + +/** + * fm10k_mbx_tail_sub - Determine new tail value with subtracted offset + * @mbx: pointer to mailbox + * @offset: length to add to head offset + * + * This function takes the local tail index and recomputes it for + * a given length added as an offset. + **/ +STATIC u16 fm10k_mbx_tail_sub(struct fm10k_mbx_info *mbx, u16 offset) +{ + u16 tail = (mbx->tail - offset - 1) & ((mbx->mbmem_len << 1) - 1); + + /* sub/add 1 because we cannot have offset 0 or all 1s */ + return (tail < mbx->tail) ? ++tail : --tail; +} + +/** + * fm10k_mbx_head_add - Determine new head value with added offset + * @mbx: pointer to mailbox + * @offset: length to add to head offset + * + * This function takes the local head index and recomputes it for + * a given length added as an offset. + **/ +STATIC u16 fm10k_mbx_head_add(struct fm10k_mbx_info *mbx, u16 offset) +{ + u16 head = (mbx->head + offset + 1) & ((mbx->mbmem_len << 1) - 1); + + /* add/sub 1 because we cannot have offset 0 or all 1s */ + return (head > mbx->head) ? --head : ++head; +} + +/** + * fm10k_mbx_head_sub - Determine new head value with subtracted offset + * @mbx: pointer to mailbox + * @offset: length to add to head offset + * + * This function takes the local head index and recomputes it for + * a given length added as an offset. + **/ +STATIC u16 fm10k_mbx_head_sub(struct fm10k_mbx_info *mbx, u16 offset) +{ + u16 head = (mbx->head - offset - 1) & ((mbx->mbmem_len << 1) - 1); + + /* sub/add 1 because we cannot have offset 0 or all 1s */ + return (head < mbx->head) ? ++head : --head; +} + +/** + * fm10k_mbx_pushed_tail_len - Retrieve the length of message being pushed + * @mbx: pointer to mailbox + * + * This function will return the length of the message currently being + * pushed onto the tail of the Rx queue. + **/ +STATIC u16 fm10k_mbx_pushed_tail_len(struct fm10k_mbx_info *mbx) +{ + u32 *tail = mbx->rx.buffer + fm10k_fifo_tail_offset(&mbx->rx, 0); + + /* pushed tail is only valid if pushed is set */ + if (!mbx->pushed) + return 0; + + return FM10K_TLV_DWORD_LEN(*tail); +} + +/** + * fm10k_fifo_write_copy - pulls data off of msg and places it in fifo + * @fifo: pointer to FIFO + * @msg: message array to populate + * @tail_offset: additional offset to add to tail pointer + * @len: length of FIFO to copy into message header + * + * This function will take a message and copy it into a section of the + * FIFO. In order to get something into a location other than just + * the tail you can use tail_offset to adjust the pointer. + **/ +STATIC void fm10k_fifo_write_copy(struct fm10k_mbx_fifo *fifo, + const u32 *msg, u16 tail_offset, u16 len) +{ + u16 end = fm10k_fifo_tail_offset(fifo, tail_offset); + u32 *tail = fifo->buffer + end; + + /* track when we should cross the end of the FIFO */ + end = fifo->size - end; + + /* copy end of message before start of message */ + if (end < len) + memcpy(fifo->buffer, msg + end, (len - end) << 2); + else + end = len; + + /* Copy remaining message into Tx FIFO */ + memcpy(tail, msg, end << 2); +} + +/** + * fm10k_fifo_enqueue - Enqueues the message to the tail of the FIFO + * @fifo: pointer to FIFO + * @msg: message array to read + * + * This function enqueues a message up to the size specified by the length + * contained in the first DWORD of the message and will place at the tail + * of the FIFO. It will return 0 on success, or a negative value on error. + **/ +STATIC s32 fm10k_fifo_enqueue(struct fm10k_mbx_fifo *fifo, const u32 *msg) +{ + u16 len = FM10K_TLV_DWORD_LEN(*msg); + + DEBUGFUNC("fm10k_fifo_enqueue"); + + /* verify parameters */ + if (len > fifo->size) + return FM10K_MBX_ERR_SIZE; + + /* verify there is room for the message */ + if (len > fm10k_fifo_unused(fifo)) + return FM10K_MBX_ERR_NO_SPACE; + + /* Copy message into FIFO */ + fm10k_fifo_write_copy(fifo, msg, 0, len); + + /* memory barrier to guarantee FIFO is written before tail update */ + FM10K_WMB(); + + /* Update Tx FIFO tail */ + fifo->tail += len; + + return FM10K_SUCCESS; +} + +/** + * fm10k_mbx_validate_msg_size - Validate incoming message based on size + * @mbx: pointer to mailbox + * @len: length of data pushed onto buffer + * + * This function analyzes the frame and will return a non-zero value when + * the start of a message larger than the mailbox is detected. + **/ +STATIC u16 fm10k_mbx_validate_msg_size(struct fm10k_mbx_info *mbx, u16 len) +{ + struct fm10k_mbx_fifo *fifo = &mbx->rx; + u16 total_len = 0, msg_len; + u32 *msg; + + DEBUGFUNC("fm10k_mbx_validate_msg"); + + /* length should include previous amounts pushed */ + len += mbx->pushed; + + /* offset in message is based off of current message size */ + do { + msg = fifo->buffer + fm10k_fifo_tail_offset(fifo, total_len); + msg_len = FM10K_TLV_DWORD_LEN(*msg); + total_len += msg_len; + } while (total_len < len); + + /* message extends out of pushed section, but fits in FIFO */ + if ((len < total_len) && (msg_len <= mbx->rx.size)) + return 0; + + /* return length of invalid section */ + return (len < total_len) ? len : (len - total_len); +} + +/** + * fm10k_mbx_write_copy - pulls data off of Tx FIFO and places it in mbmem + * @mbx: pointer to mailbox + * + * This function will take a section of the Rx FIFO and copy it into the + mbx->tail--; + * mailbox memory. The offset in mbmem is based on the lower bits of the + * tail and len determines the length to copy. + **/ +STATIC void fm10k_mbx_write_copy(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx) +{ + struct fm10k_mbx_fifo *fifo = &mbx->tx; + u32 mbmem = mbx->mbmem_reg; + u32 *head = fifo->buffer; + u16 end, len, tail, mask; + + DEBUGFUNC("fm10k_mbx_write_copy"); + + if (!mbx->tail_len) + return; + + /* determine data length and mbmem tail index */ + mask = mbx->mbmem_len - 1; + len = mbx->tail_len; + tail = fm10k_mbx_tail_sub(mbx, len); + if (tail > mask) + tail++; + + /* determine offset in the ring */ + end = fm10k_fifo_head_offset(fifo, mbx->pulled); + head += end; + + /* memory barrier to guarantee data is ready to be read */ + FM10K_RMB(); + + /* Copy message from Tx FIFO */ + for (end = fifo->size - end; len; head = fifo->buffer) { + do { + /* adjust tail to match offset for FIFO */ + tail &= mask; + if (!tail) + tail++; + + /* write message to hardware FIFO */ + FM10K_WRITE_MBX(hw, mbmem + tail++, *(head++)); + } while (--len && --end); + } +} + +/** + * fm10k_mbx_pull_head - Pulls data off of head of Tx FIFO + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * @head: acknowledgement number last received + * + * This function will push the tail index forward based on the remote + * head index. It will then pull up to mbmem_len DWORDs off of the + * head of the FIFO and will place it in the MBMEM registers + * associated with the mailbox. + **/ +STATIC void fm10k_mbx_pull_head(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx, u16 head) +{ + u16 mbmem_len, len, ack = fm10k_mbx_index_len(mbx, head, mbx->tail); + struct fm10k_mbx_fifo *fifo = &mbx->tx; + + /* update number of bytes pulled and update bytes in transit */ + mbx->pulled += mbx->tail_len - ack; + + /* determine length of data to pull, reserve space for mbmem header */ + mbmem_len = mbx->mbmem_len - 1; + len = fm10k_fifo_used(fifo) - mbx->pulled; + if (len > mbmem_len) + len = mbmem_len; + + /* update tail and record number of bytes in transit */ + mbx->tail = fm10k_mbx_tail_add(mbx, len - ack); + mbx->tail_len = len; + + /* drop pulled messages from the FIFO */ + for (len = fm10k_fifo_head_len(fifo); + len && (mbx->pulled >= len); + len = fm10k_fifo_head_len(fifo)) { + mbx->pulled -= fm10k_fifo_head_drop(fifo); + mbx->tx_messages++; + mbx->tx_dwords += len; + } + + /* Copy message out from the Tx FIFO */ + fm10k_mbx_write_copy(hw, mbx); +} + +/** + * fm10k_mbx_read_copy - pulls data off of mbmem and places it in Rx FIFO + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * + * This function will take a section of the mailbox memory and copy it + * into the Rx FIFO. The offset is based on the lower bits of the + * head and len determines the length to copy. + **/ +STATIC void fm10k_mbx_read_copy(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx) +{ + struct fm10k_mbx_fifo *fifo = &mbx->rx; + u32 mbmem = mbx->mbmem_reg ^ mbx->mbmem_len; + u32 *tail = fifo->buffer; + u16 end, len, head; + + DEBUGFUNC("fm10k_mbx_read_copy"); + + /* determine data length and mbmem head index */ + len = mbx->head_len; + head = fm10k_mbx_head_sub(mbx, len); + if (head >= mbx->mbmem_len) + head++; + + /* determine offset in the ring */ + end = fm10k_fifo_tail_offset(fifo, mbx->pushed); + tail += end; + + /* Copy message into Rx FIFO */ + for (end = fifo->size - end; len; tail = fifo->buffer) { + do { + /* adjust head to match offset for FIFO */ + head &= mbx->mbmem_len - 1; + if (!head) + head++; + + /* read message from hardware FIFO */ + *(tail++) = FM10K_READ_MBX(hw, mbmem + head++); + } while (--len && --end); + } + + /* memory barrier to guarantee FIFO is written before tail update */ + FM10K_WMB(); +} + +/** + * fm10k_mbx_push_tail - Pushes up to 15 DWORDs on to tail of FIFO + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * @tail: tail index of message + * + * This function will first validate the tail index and size for the + * incoming message. It then updates the acknowledgment number and + * copies the data into the FIFO. It will return the number of messages + * dequeued on success and a negative value on error. + **/ +STATIC s32 fm10k_mbx_push_tail(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx, + u16 tail) +{ + struct fm10k_mbx_fifo *fifo = &mbx->rx; + u16 len, seq = fm10k_mbx_index_len(mbx, mbx->head, tail); + + DEBUGFUNC("fm10k_mbx_push_tail"); + + /* determine length of data to push */ + len = fm10k_fifo_unused(fifo) - mbx->pushed; + if (len > seq) + len = seq; + + /* update head and record bytes received */ + mbx->head = fm10k_mbx_head_add(mbx, len); + mbx->head_len = len; + + /* nothing to do if there is no data */ + if (!len) + return FM10K_SUCCESS; + + /* Copy msg into Rx FIFO */ + fm10k_mbx_read_copy(hw, mbx); + + /* determine if there are any invalid lengths in message */ + if (fm10k_mbx_validate_msg_size(mbx, len)) + return FM10K_MBX_ERR_SIZE; + + /* Update pushed */ + mbx->pushed += len; + + /* flush any completed messages */ + for (len = fm10k_mbx_pushed_tail_len(mbx); + len && (mbx->pushed >= len); + len = fm10k_mbx_pushed_tail_len(mbx)) { + fifo->tail += len; + mbx->pushed -= len; + mbx->rx_messages++; + mbx->rx_dwords += len; + } + + return FM10K_SUCCESS; +} + +/* pre-generated data for generating the CRC based on the poly 0xAC9A. */ +static const u16 fm10k_crc_16b_table[256] = { + 0x0000, 0x7956, 0xF2AC, 0x8BFA, 0xBC6D, 0xC53B, 0x4EC1, 0x3797, + 0x21EF, 0x58B9, 0xD343, 0xAA15, 0x9D82, 0xE4D4, 0x6F2E, 0x1678, + 0x43DE, 0x3A88, 0xB172, 0xC824, 0xFFB3, 0x86E5, 0x0D1F, 0x7449, + 0x6231, 0x1B67, 0x909D, 0xE9CB, 0xDE5C, 0xA70A, 0x2CF0, 0x55A6, + 0x87BC, 0xFEEA, 0x7510, 0x0C46, 0x3BD1, 0x4287, 0xC97D, 0xB02B, + 0xA653, 0xDF05, 0x54FF, 0x2DA9, 0x1A3E, 0x6368, 0xE892, 0x91C4, + 0xC462, 0xBD34, 0x36CE, 0x4F98, 0x780F, 0x0159, 0x8AA3, 0xF3F5, + 0xE58D, 0x9CDB, 0x1721, 0x6E77, 0x59E0, 0x20B6, 0xAB4C, 0xD21A, + 0x564D, 0x2F1B, 0xA4E1, 0xDDB7, 0xEA20, 0x9376, 0x188C, 0x61DA, + 0x77A2, 0x0EF4, 0x850E, 0xFC58, 0xCBCF, 0xB299, 0x3963, 0x4035, + 0x1593, 0x6CC5, 0xE73F, 0x9E69, 0xA9FE, 0xD0A8, 0x5B52, 0x2204, + 0x347C, 0x4D2A, 0xC6D0, 0xBF86, 0x8811, 0xF147, 0x7ABD, 0x03EB, + 0xD1F1, 0xA8A7, 0x235D, 0x5A0B, 0x6D9C, 0x14CA, 0x9F30, 0xE666, + 0xF01E, 0x8948, 0x02B2, 0x7BE4, 0x4C73, 0x3525, 0xBEDF, 0xC789, + 0x922F, 0xEB79, 0x6083, 0x19D5, 0x2E42, 0x5714, 0xDCEE, 0xA5B8, + 0xB3C0, 0xCA96, 0x416C, 0x383A, 0x0FAD, 0x76FB, 0xFD01, 0x8457, + 0xAC9A, 0xD5CC, 0x5E36, 0x2760, 0x10F7, 0x69A1, 0xE25B, 0x9B0D, + 0x8D75, 0xF423, 0x7FD9, 0x068F, 0x3118, 0x484E, 0xC3B4, 0xBAE2, + 0xEF44, 0x9612, 0x1DE8, 0x64BE, 0x5329, 0x2A7F, 0xA185, 0xD8D3, + 0xCEAB, 0xB7FD, 0x3C07, 0x4551, 0x72C6, 0x0B90, 0x806A, 0xF93C, + 0x2B26, 0x5270, 0xD98A, 0xA0DC, 0x974B, 0xEE1D, 0x65E7, 0x1CB1, + 0x0AC9, 0x739F, 0xF865, 0x8133, 0xB6A4, 0xCFF2, 0x4408, 0x3D5E, + 0x68F8, 0x11AE, 0x9A54, 0xE302, 0xD495, 0xADC3, 0x2639, 0x5F6F, + 0x4917, 0x3041, 0xBBBB, 0xC2ED, 0xF57A, 0x8C2C, 0x07D6, 0x7E80, + 0xFAD7, 0x8381, 0x087B, 0x712D, 0x46BA, 0x3FEC, 0xB416, 0xCD40, + 0xDB38, 0xA26E, 0x2994, 0x50C2, 0x6755, 0x1E03, 0x95F9, 0xECAF, + 0xB909, 0xC05F, 0x4BA5, 0x32F3, 0x0564, 0x7C32, 0xF7C8, 0x8E9E, + 0x98E6, 0xE1B0, 0x6A4A, 0x131C, 0x248B, 0x5DDD, 0xD627, 0xAF71, + 0x7D6B, 0x043D, 0x8FC7, 0xF691, 0xC106, 0xB850, 0x33AA, 0x4AFC, + 0x5C84, 0x25D2, 0xAE28, 0xD77E, 0xE0E9, 0x99BF, 0x1245, 0x6B13, + 0x3EB5, 0x47E3, 0xCC19, 0xB54F, 0x82D8, 0xFB8E, 0x7074, 0x0922, + 0x1F5A, 0x660C, 0xEDF6, 0x94A0, 0xA337, 0xDA61, 0x519B, 0x28CD }; + +/** + * fm10k_crc_16b - Generate a 16 bit CRC for a region of 16 bit data + * @data: pointer to data to process + * @seed: seed value for CRC + * @len: length measured in 16 bits words + * + * This function will generate a CRC based on the polynomial 0xAC9A and + * whatever value is stored in the seed variable. Note that this + * value inverts the local seed and the result in order to capture all + * leading and trailing zeros. + */ +STATIC u16 fm10k_crc_16b(const u32 *data, u16 seed, u16 len) +{ + u32 result = seed; + + while (len--) { + result ^= *(data++); + result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF]; + result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF]; + + if (!(len--)) + break; + + result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF]; + result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF]; + } + + return (u16)result; +} + +/** + * fm10k_fifo_crc - generate a CRC based off of FIFO data + * @fifo: pointer to FIFO + * @offset: offset point for start of FIFO + * @len: number of DWORDS words to process + * @seed: seed value for CRC + * + * This function generates a CRC for some region of the FIFO + **/ +STATIC u16 fm10k_fifo_crc(struct fm10k_mbx_fifo *fifo, u16 offset, + u16 len, u16 seed) +{ + u32 *data = fifo->buffer + offset; + + /* track when we should cross the end of the FIFO */ + offset = fifo->size - offset; + + /* if we are in 2 blocks process the end of the FIFO first */ + if (offset < len) { + seed = fm10k_crc_16b(data, seed, offset * 2); + data = fifo->buffer; + len -= offset; + } + + /* process any remaining bits */ + return fm10k_crc_16b(data, seed, len * 2); +} + +/** + * fm10k_mbx_update_local_crc - Update the local CRC for outgoing data + * @mbx: pointer to mailbox + * @head: head index provided by remote mailbox + * + * This function will generate the CRC for all data from the end of the + * last head update to the current one. It uses the result of the + * previous CRC as the seed for this update. The result is stored in + * mbx->local. + **/ +STATIC void fm10k_mbx_update_local_crc(struct fm10k_mbx_info *mbx, u16 head) +{ + u16 len = mbx->tail_len - fm10k_mbx_index_len(mbx, head, mbx->tail); + + /* determine the offset for the start of the region to be pulled */ + head = fm10k_fifo_head_offset(&mbx->tx, mbx->pulled); + + /* update local CRC to include all of the pulled data */ + mbx->local = fm10k_fifo_crc(&mbx->tx, head, len, mbx->local); +} + +/** + * fm10k_mbx_verify_remote_crc - Verify the CRC is correct for current data + * @mbx: pointer to mailbox + * + * This function will take all data that has been provided from the remote + * end and generate a CRC for it. This is stored in mbx->remote. The + * CRC for the header is then computed and if the result is non-zero this + * is an error and we signal an error dropping all data and resetting the + * connection. + */ +STATIC s32 fm10k_mbx_verify_remote_crc(struct fm10k_mbx_info *mbx) +{ + struct fm10k_mbx_fifo *fifo = &mbx->rx; + u16 len = mbx->head_len; + u16 offset = fm10k_fifo_tail_offset(fifo, mbx->pushed) - len; + u16 crc; + + /* update the remote CRC if new data has been received */ + if (len) + mbx->remote = fm10k_fifo_crc(fifo, offset, len, mbx->remote); + + /* process the full header as we have to validate the CRC */ + crc = fm10k_crc_16b(&mbx->mbx_hdr, mbx->remote, 1); + + /* notify other end if we have a problem */ + return crc ? FM10K_MBX_ERR_CRC : FM10K_SUCCESS; +} + +/** + * fm10k_mbx_rx_ready - Indicates that a message is ready in the Rx FIFO + * @mbx: pointer to mailbox + * + * This function returns true if there is a message in the Rx FIFO to dequeue. + **/ +STATIC bool fm10k_mbx_rx_ready(struct fm10k_mbx_info *mbx) +{ + u16 msg_size = fm10k_fifo_head_len(&mbx->rx); + + return msg_size && (fm10k_fifo_used(&mbx->rx) >= msg_size); +} + +/** + * fm10k_mbx_tx_ready - Indicates that the mailbox is in state ready for Tx + * @mbx: pointer to mailbox + * @len: verify free space is >= this value + * + * This function returns true if the mailbox is in a state ready to transmit. + **/ +STATIC bool fm10k_mbx_tx_ready(struct fm10k_mbx_info *mbx, u16 len) +{ + u16 fifo_unused = fm10k_fifo_unused(&mbx->tx); + + return (mbx->state == FM10K_STATE_OPEN) && (fifo_unused >= len); +} + +/** + * fm10k_mbx_tx_complete - Indicates that the Tx FIFO has been emptied + * @mbx: pointer to mailbox + * + * This function returns true if the Tx FIFO is empty. + **/ +STATIC bool fm10k_mbx_tx_complete(struct fm10k_mbx_info *mbx) +{ + return fm10k_fifo_empty(&mbx->tx); +} + +/** + * fm10k_mbx_deqeueue_rx - Dequeues the message from the head in the Rx FIFO + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * + * This function dequeues messages and hands them off to the tlv parser. + * It will return the number of messages processed when called. + **/ +STATIC u16 fm10k_mbx_dequeue_rx(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx) +{ + struct fm10k_mbx_fifo *fifo = &mbx->rx; + s32 err; + u16 cnt; + + /* parse Rx messages out of the Rx FIFO to empty it */ + for (cnt = 0; !fm10k_fifo_empty(fifo); cnt++) { + err = fm10k_tlv_msg_parse(hw, fifo->buffer + fifo->head, + mbx, mbx->msg_data); + if (err < 0) + mbx->rx_parse_err++; + + fm10k_fifo_head_drop(fifo); + } + + /* shift remaining bytes back to start of FIFO */ + memmove(fifo->buffer, fifo->buffer + fifo->tail, mbx->pushed << 2); + + /* shift head and tail based on the memory we moved */ + fifo->tail -= fifo->head; + fifo->head = 0; + + return cnt; +} + +/** + * fm10k_mbx_enqueue_tx - Enqueues the message to the tail of the Tx FIFO + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * @msg: message array to read + * + * This function enqueues a message up to the size specified by the length + * contained in the first DWORD of the message and will place at the tail + * of the FIFO. It will return 0 on success, or a negative value on error. + **/ +STATIC s32 fm10k_mbx_enqueue_tx(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx, const u32 *msg) +{ + u32 countdown = mbx->timeout; + s32 err; + + switch (mbx->state) { + case FM10K_STATE_CLOSED: + case FM10K_STATE_DISCONNECT: + return FM10K_MBX_ERR_NO_MBX; + default: + break; + } + + /* enqueue the message on the Tx FIFO */ + err = fm10k_fifo_enqueue(&mbx->tx, msg); + + /* if it failed give the FIFO a chance to drain */ + while (err && countdown) { + countdown--; + usec_delay(mbx->usec_delay); + mbx->ops.process(hw, mbx); + err = fm10k_fifo_enqueue(&mbx->tx, msg); + } + + /* if we failed treat the error */ + if (err) { + mbx->timeout = 0; + mbx->tx_busy++; + } + + /* begin processing message, ignore errors as this is just meant + * to start the mailbox flow so we are not concerned if there + * is a bad error, or the mailbox is already busy with a request + */ + if (!mbx->tail_len) + mbx->ops.process(hw, mbx); + + return FM10K_SUCCESS; +} + +/** + * fm10k_mbx_read - Copies the mbmem to local message buffer + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * + * This function copies the message from the mbmem to the message array + **/ +STATIC s32 fm10k_mbx_read(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx) +{ + DEBUGFUNC("fm10k_mbx_read"); + + /* only allow one reader in here at a time */ + if (mbx->mbx_hdr) + return FM10K_MBX_ERR_BUSY; + + /* read to capture initial interrupt bits */ + if (FM10K_READ_MBX(hw, mbx->mbx_reg) & FM10K_MBX_REQ_INTERRUPT) + mbx->mbx_lock = FM10K_MBX_ACK; + + /* write back interrupt bits to clear */ + FM10K_WRITE_MBX(hw, mbx->mbx_reg, + FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT); + + /* read remote header */ + mbx->mbx_hdr = FM10K_READ_MBX(hw, mbx->mbmem_reg ^ mbx->mbmem_len); + + return FM10K_SUCCESS; +} + +/** + * fm10k_mbx_write - Copies the local message buffer to mbmem + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * + * This function copies the message from the the message array to mbmem + **/ +STATIC void fm10k_mbx_write(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx) +{ + u32 mbmem = mbx->mbmem_reg; + + DEBUGFUNC("fm10k_mbx_write"); + + /* write new msg header to notify recipient of change */ + FM10K_WRITE_MBX(hw, mbmem, mbx->mbx_hdr); + + /* write mailbox to send interrupt */ + if (mbx->mbx_lock) + FM10K_WRITE_MBX(hw, mbx->mbx_reg, mbx->mbx_lock); + + /* we no longer are using the header so free it */ + mbx->mbx_hdr = 0; + mbx->mbx_lock = 0; +} + +/** + * fm10k_mbx_create_connect_hdr - Generate a connect mailbox header + * @mbx: pointer to mailbox + * + * This function returns a connection mailbox header + **/ +STATIC void fm10k_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx) +{ + mbx->mbx_lock |= FM10K_MBX_REQ; + + mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_CONNECT, TYPE) | + FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD) | + FM10K_MSG_HDR_FIELD_SET(mbx->rx.size - 1, CONNECT_SIZE); +} + +/** + * fm10k_mbx_create_data_hdr - Generate a data mailbox header + * @mbx: pointer to mailbox + * + * This function returns a data mailbox header + **/ +STATIC void fm10k_mbx_create_data_hdr(struct fm10k_mbx_info *mbx) +{ + u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DATA, TYPE) | + FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) | + FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD); + struct fm10k_mbx_fifo *fifo = &mbx->tx; + u16 crc; + + if (mbx->tail_len) + mbx->mbx_lock |= FM10K_MBX_REQ; + + /* generate CRC for data in flight and header */ + crc = fm10k_fifo_crc(fifo, fm10k_fifo_head_offset(fifo, mbx->pulled), + mbx->tail_len, mbx->local); + crc = fm10k_crc_16b(&hdr, crc, 1); + + /* load header to memory to be written */ + mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC); +} + +/** + * fm10k_mbx_create_disconnect_hdr - Generate a disconnect mailbox header + * @mbx: pointer to mailbox + * + * This function returns a disconnect mailbox header + **/ +STATIC void fm10k_mbx_create_disconnect_hdr(struct fm10k_mbx_info *mbx) +{ + u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) | + FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) | + FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD); + u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1); + + mbx->mbx_lock |= FM10K_MBX_ACK; + + /* load header to memory to be written */ + mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC); +} + +/** + * fm10k_mbx_create_error_msg - Generate a error message + * @mbx: pointer to mailbox + * @err: local error encountered + * + * This function will interpret the error provided by err, and based on + * that it may shift the message by 1 DWORD and then place an error header + * at the start of the message. + **/ +STATIC void fm10k_mbx_create_error_msg(struct fm10k_mbx_info *mbx, s32 err) +{ + /* only generate an error message for these types */ + switch (err) { + case FM10K_MBX_ERR_TAIL: + case FM10K_MBX_ERR_HEAD: + case FM10K_MBX_ERR_TYPE: + case FM10K_MBX_ERR_SIZE: + case FM10K_MBX_ERR_RSVD0: + case FM10K_MBX_ERR_CRC: + break; + default: + return; + } + + mbx->mbx_lock |= FM10K_MBX_REQ; + + mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_ERROR, TYPE) | + FM10K_MSG_HDR_FIELD_SET(err, ERR_NO) | + FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD); +} + +/** + * fm10k_mbx_validate_msg_hdr - Validate common fields in the message header + * @mbx: pointer to mailbox + * @msg: message array to read + * + * This function will parse up the fields in the mailbox header and return + * an error if the header contains any of a number of invalid configurations + * including unrecognized type, invalid route, or a malformed message. + **/ +STATIC s32 fm10k_mbx_validate_msg_hdr(struct fm10k_mbx_info *mbx) +{ + u16 type, rsvd0, head, tail, size; + const u32 *hdr = &mbx->mbx_hdr; + + DEBUGFUNC("fm10k_mbx_validate_msg_hdr"); + + type = FM10K_MSG_HDR_FIELD_GET(*hdr, TYPE); + rsvd0 = FM10K_MSG_HDR_FIELD_GET(*hdr, RSVD0); + tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL); + head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD); + size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE); + + if (rsvd0) + return FM10K_MBX_ERR_RSVD0; + + switch (type) { + case FM10K_MSG_DISCONNECT: + /* validate that all data has been received */ + if (tail != mbx->head) + return FM10K_MBX_ERR_TAIL; + + /* fall through */ + case FM10K_MSG_DATA: + /* validate that head is moving correctly */ + if (!head || (head == FM10K_MSG_HDR_MASK(HEAD))) + return FM10K_MBX_ERR_HEAD; + if (fm10k_mbx_index_len(mbx, head, mbx->tail) > mbx->tail_len) + return FM10K_MBX_ERR_HEAD; + + /* validate that tail is moving correctly */ + if (!tail || (tail == FM10K_MSG_HDR_MASK(TAIL))) + return FM10K_MBX_ERR_TAIL; + if (fm10k_mbx_index_len(mbx, mbx->head, tail) < mbx->mbmem_len) + break; + + return FM10K_MBX_ERR_TAIL; + case FM10K_MSG_CONNECT: + /* validate size is in range and is power of 2 mask */ + if ((size < FM10K_VFMBX_MSG_MTU) || (size & (size + 1))) + return FM10K_MBX_ERR_SIZE; + + /* fall through */ + case FM10K_MSG_ERROR: + if (!head || (head == FM10K_MSG_HDR_MASK(HEAD))) + return FM10K_MBX_ERR_HEAD; + /* neither create nor error include a tail offset */ + if (tail) + return FM10K_MBX_ERR_TAIL; + + break; + default: + return FM10K_MBX_ERR_TYPE; + } + + return FM10K_SUCCESS; +} + +/** + * fm10k_mbx_create_reply - Generate reply based on state and remote head + * @mbx: pointer to mailbox + * @head: acknowledgement number + * + * This function will generate an outgoing message based on the current + * mailbox state and the remote fifo head. It will return the length + * of the outgoing message excluding header on success, and a negative value + * on error. + **/ +STATIC s32 fm10k_mbx_create_reply(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx, u16 head) +{ + switch (mbx->state) { + case FM10K_STATE_OPEN: + case FM10K_STATE_DISCONNECT: + /* update our checksum for the outgoing data */ + fm10k_mbx_update_local_crc(mbx, head); + + /* as long as other end recognizes us keep sending data */ + fm10k_mbx_pull_head(hw, mbx, head); + + /* generate new header based on data */ + if (mbx->tail_len || (mbx->state == FM10K_STATE_OPEN)) + fm10k_mbx_create_data_hdr(mbx); + else + fm10k_mbx_create_disconnect_hdr(mbx); + break; + case FM10K_STATE_CONNECT: + /* send disconnect even if we aren't connected */ + fm10k_mbx_create_connect_hdr(mbx); + break; + case FM10K_STATE_CLOSED: + /* generate new header based on data */ + fm10k_mbx_create_disconnect_hdr(mbx); + default: + break; + } + + return FM10K_SUCCESS; +} + +/** + * fm10k_mbx_reset_work- Reset internal pointers for any pending work + * @mbx: pointer to mailbox + * + * This function will reset all internal pointers so any work in progress + * is dropped. This call should occur every time we transition from the + * open state to the connect state. + **/ +STATIC void fm10k_mbx_reset_work(struct fm10k_mbx_info *mbx) +{ + /* reset our outgoing max size back to Rx limits */ + mbx->max_size = mbx->rx.size - 1; + + /* just do a quick resysnc to start of message */ + mbx->pushed = 0; + mbx->pulled = 0; + mbx->tail_len = 0; + mbx->head_len = 0; + mbx->rx.tail = 0; + mbx->rx.head = 0; +} + +/** + * fm10k_mbx_update_max_size - Update the max_size and drop any large messages + * @mbx: pointer to mailbox + * @size: new value for max_size + * + * This function will update the max_size value and drop any outgoing messages + * from the head of the Tx FIFO that are larger than max_size. + **/ +STATIC void fm10k_mbx_update_max_size(struct fm10k_mbx_info *mbx, u16 size) +{ + u16 len; + + DEBUGFUNC("fm10k_mbx_update_max_size_hdr"); + + mbx->max_size = size; + + /* flush any oversized messages from the queue */ + for (len = fm10k_fifo_head_len(&mbx->tx); + len > size; + len = fm10k_fifo_head_len(&mbx->tx)) { + fm10k_fifo_head_drop(&mbx->tx); + mbx->tx_dropped++; + } +} + +/** + * fm10k_mbx_connect_reset - Reset following request for reset + * @mbx: pointer to mailbox + * + * This function resets the mailbox to either a disconnected state + * or a connect state depending on the current mailbox state + **/ +STATIC void fm10k_mbx_connect_reset(struct fm10k_mbx_info *mbx) +{ + /* just do a quick resysnc to start of frame */ + fm10k_mbx_reset_work(mbx); + + /* reset CRC seeds */ + mbx->local = FM10K_MBX_CRC_SEED; + mbx->remote = FM10K_MBX_CRC_SEED; + + /* we cannot exit connect until the size is good */ + if (mbx->state == FM10K_STATE_OPEN) + mbx->state = FM10K_STATE_CONNECT; + else + mbx->state = FM10K_STATE_CLOSED; +} + +/** + * fm10k_mbx_process_connect - Process connect header + * @mbx: pointer to mailbox + * @msg: message array to process + * + * This function will read an incoming connect header and reply with the + * appropriate message. It will return a value indicating the number of + * data DWORDs on success, or will return a negative value on failure. + **/ +STATIC s32 fm10k_mbx_process_connect(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx) +{ + const enum fm10k_mbx_state state = mbx->state; + const u32 *hdr = &mbx->mbx_hdr; + u16 size, head; + + /* we will need to pull all of the fields for verification */ + size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE); + head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD); + + switch (state) { + case FM10K_STATE_DISCONNECT: + case FM10K_STATE_OPEN: + /* reset any in-progress work */ + fm10k_mbx_connect_reset(mbx); + break; + case FM10K_STATE_CONNECT: + /* we cannot exit connect until the size is good */ + if (size > mbx->rx.size) { + mbx->max_size = mbx->rx.size - 1; + } else { + /* record the remote system requesting connection */ + mbx->state = FM10K_STATE_OPEN; + + fm10k_mbx_update_max_size(mbx, size); + } + break; + default: + break; + } + + /* align our tail index to remote head index */ + mbx->tail = head; + + return fm10k_mbx_create_reply(hw, mbx, head); +} + +/** + * fm10k_mbx_process_data - Process data header + * @mbx: pointer to mailbox + * + * This function will read an incoming data header and reply with the + * appropriate message. It will return a value indicating the number of + * data DWORDs on success, or will return a negative value on failure. + **/ +STATIC s32 fm10k_mbx_process_data(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx) +{ + const u32 *hdr = &mbx->mbx_hdr; + u16 head, tail; + s32 err; + + DEBUGFUNC("fm10k_mbx_process_data"); + + /* we will need to pull all of the fields for verification */ + head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD); + tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL); + + /* if we are in connect just update our data and go */ + if (mbx->state == FM10K_STATE_CONNECT) { + mbx->tail = head; + mbx->state = FM10K_STATE_OPEN; + } + + /* abort on message size errors */ + err = fm10k_mbx_push_tail(hw, mbx, tail); + if (err < 0) + return err; + + /* verify the checksum on the incoming data */ + err = fm10k_mbx_verify_remote_crc(mbx); + if (err) + return err; + + /* process messages if we have received any */ + fm10k_mbx_dequeue_rx(hw, mbx); + + return fm10k_mbx_create_reply(hw, mbx, head); +} + +/** + * fm10k_mbx_process_disconnect - Process disconnect header + * @mbx: pointer to mailbox + * + * This function will read an incoming disconnect header and reply with the + * appropriate message. It will return a value indicating the number of + * data DWORDs on success, or will return a negative value on failure. + **/ +STATIC s32 fm10k_mbx_process_disconnect(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx) +{ + const enum fm10k_mbx_state state = mbx->state; + const u32 *hdr = &mbx->mbx_hdr; + u16 head; + s32 err; + + /* we will need to pull the header field for verification */ + head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD); + + /* We should not be receiving disconnect if Rx is incomplete */ + if (mbx->pushed) + return FM10K_MBX_ERR_TAIL; + + /* we have already verified mbx->head == tail so we know this is 0 */ + mbx->head_len = 0; + + /* verify the checksum on the incoming header is correct */ + err = fm10k_mbx_verify_remote_crc(mbx); + if (err) + return err; + + switch (state) { + case FM10K_STATE_DISCONNECT: + case FM10K_STATE_OPEN: + /* state doesn't change if we still have work to do */ + if (!fm10k_mbx_tx_complete(mbx)) + break; + + /* verify the head indicates we completed all transmits */ + if (head != mbx->tail) + return FM10K_MBX_ERR_HEAD; + + /* reset any in-progress work */ + fm10k_mbx_connect_reset(mbx); + break; + default: + break; + } + + return fm10k_mbx_create_reply(hw, mbx, head); +} + +/** + * fm10k_mbx_process_error - Process error header + * @mbx: pointer to mailbox + * + * This function will read an incoming error header and reply with the + * appropriate message. It will return a value indicating the number of + * data DWORDs on success, or will return a negative value on failure. + **/ +STATIC s32 fm10k_mbx_process_error(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx) +{ + const u32 *hdr = &mbx->mbx_hdr; + s32 err_no; + u16 head; + + /* we will need to pull all of the fields for verification */ + head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD); + + /* we only have lower 10 bits of error number so add upper bits */ + err_no = FM10K_MSG_HDR_FIELD_GET(*hdr, ERR_NO); + err_no |= ~FM10K_MSG_HDR_MASK(ERR_NO); + + switch (mbx->state) { + case FM10K_STATE_OPEN: + case FM10K_STATE_DISCONNECT: + /* flush any uncompleted work */ + fm10k_mbx_reset_work(mbx); + + /* reset CRC seeds */ + mbx->local = FM10K_MBX_CRC_SEED; + mbx->remote = FM10K_MBX_CRC_SEED; + + /* reset tail index and size to prepare for reconnect */ + mbx->tail = head; + + /* if open then reset max_size and go back to connect */ + if (mbx->state == FM10K_STATE_OPEN) { + mbx->state = FM10K_STATE_CONNECT; + break; + } + + /* send a connect message to get data flowing again */ + fm10k_mbx_create_connect_hdr(mbx); + return FM10K_SUCCESS; + default: + break; + } + + return fm10k_mbx_create_reply(hw, mbx, mbx->tail); +} + +/** + * fm10k_mbx_process - Process mailbox interrupt + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * + * This function will process incoming mailbox events and generate mailbox + * replies. It will return a value indicating the number of DWORDs + * transmitted excluding header on success or a negative value on error. + **/ +STATIC s32 fm10k_mbx_process(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx) +{ + s32 err; + + DEBUGFUNC("fm10k_mbx_process"); + + /* we do not read mailbox if closed */ + if (mbx->state == FM10K_STATE_CLOSED) + return FM10K_SUCCESS; + + /* copy data from mailbox */ + err = fm10k_mbx_read(hw, mbx); + if (err) + return err; + + /* validate type, source, and destination */ + err = fm10k_mbx_validate_msg_hdr(mbx); + if (err < 0) + goto msg_err; + + switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, TYPE)) { + case FM10K_MSG_CONNECT: + err = fm10k_mbx_process_connect(hw, mbx); + break; + case FM10K_MSG_DATA: + err = fm10k_mbx_process_data(hw, mbx); + break; + case FM10K_MSG_DISCONNECT: + err = fm10k_mbx_process_disconnect(hw, mbx); + break; + case FM10K_MSG_ERROR: + err = fm10k_mbx_process_error(hw, mbx); + break; + default: + err = FM10K_MBX_ERR_TYPE; + break; + } + +msg_err: + /* notify partner of errors on our end */ + if (err < 0) + fm10k_mbx_create_error_msg(mbx, err); + + /* copy data from mailbox */ + fm10k_mbx_write(hw, mbx); + + return err; +} + +/** + * fm10k_mbx_disconnect - Shutdown mailbox connection + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * + * This function will shut down the mailbox. It places the mailbox first + * in the disconnect state, it then allows up to a predefined timeout for + * the mailbox to transition to close on its own. If this does not occur + * then the mailbox will be forced into the closed state. + * + * Any mailbox transactions not completed before calling this function + * are not guaranteed to complete and may be dropped. + **/ +STATIC void fm10k_mbx_disconnect(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx) +{ + int timeout = mbx->timeout ? FM10K_MBX_DISCONNECT_TIMEOUT : 0; + + DEBUGFUNC("fm10k_mbx_disconnect"); + + /* Place mbx in ready to disconnect state */ + mbx->state = FM10K_STATE_DISCONNECT; + + /* trigger interrupt to start shutdown process */ + FM10K_WRITE_MBX(hw, mbx->mbx_reg, FM10K_MBX_REQ | + FM10K_MBX_INTERRUPT_DISABLE); + do { + usec_delay(FM10K_MBX_POLL_DELAY); + mbx->ops.process(hw, mbx); + timeout -= FM10K_MBX_POLL_DELAY; + } while ((timeout > 0) && (mbx->state != FM10K_STATE_CLOSED)); + + /* in case we didn't close just force the mailbox into shutdown */ + fm10k_mbx_connect_reset(mbx); + fm10k_mbx_update_max_size(mbx, 0); + + FM10K_WRITE_MBX(hw, mbx->mbmem_reg, 0); +} + +/** + * fm10k_mbx_connect - Start mailbox connection + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * + * This function will initiate a mailbox connection. It will populate the + * mailbox with a broadcast connect message and then initialize the lock. + * This is safe since the connect message is a single DWORD so the mailbox + * transaction is guaranteed to be atomic. + * + * This function will return an error if the mailbox has not been initiated + * or is currently in use. + **/ +STATIC s32 fm10k_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx) +{ + DEBUGFUNC("fm10k_mbx_connect"); + + /* we cannot connect an uninitialized mailbox */ + if (!mbx->rx.buffer) + return FM10K_MBX_ERR_NO_SPACE; + + /* we cannot connect an already connected mailbox */ + if (mbx->state != FM10K_STATE_CLOSED) + return FM10K_MBX_ERR_BUSY; + + /* mailbox timeout can now become active */ + mbx->timeout = FM10K_MBX_INIT_TIMEOUT; + + /* Place mbx in ready to connect state */ + mbx->state = FM10K_STATE_CONNECT; + + /* initialize header of remote mailbox */ + fm10k_mbx_create_disconnect_hdr(mbx); + FM10K_WRITE_MBX(hw, mbx->mbmem_reg ^ mbx->mbmem_len, mbx->mbx_hdr); + + /* enable interrupt and notify other party of new message */ + mbx->mbx_lock = FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT | + FM10K_MBX_INTERRUPT_ENABLE; + + /* generate and load connect header into mailbox */ + fm10k_mbx_create_connect_hdr(mbx); + fm10k_mbx_write(hw, mbx); + + return FM10K_SUCCESS; +} + +/** + * fm10k_mbx_validate_handlers - Validate layout of message parsing data + * @msg_data: handlers for mailbox events + * + * This function validates the layout of the message parsing data. This + * should be mostly static, but it is important to catch any errors that + * are made when constructing the parsers. + **/ +STATIC s32 fm10k_mbx_validate_handlers(const struct fm10k_msg_data *msg_data) +{ + const struct fm10k_tlv_attr *attr; + unsigned int id; + + DEBUGFUNC("fm10k_mbx_validate_handlers"); + + /* Allow NULL mailboxes that transmit but don't receive */ + if (!msg_data) + return FM10K_SUCCESS; + + while (msg_data->id != FM10K_TLV_ERROR) { + /* all messages should have a function handler */ + if (!msg_data->func) + return FM10K_ERR_PARAM; + + /* parser is optional */ + attr = msg_data->attr; + if (attr) { + while (attr->id != FM10K_TLV_ERROR) { + id = attr->id; + attr++; + /* ID should always be increasing */ + if (id >= attr->id) + return FM10K_ERR_PARAM; + /* ID should fit in results array */ + if (id >= FM10K_TLV_RESULTS_MAX) + return FM10K_ERR_PARAM; + } + + /* verify terminator is in the list */ + if (attr->id != FM10K_TLV_ERROR) + return FM10K_ERR_PARAM; + } + + id = msg_data->id; + msg_data++; + /* ID should always be increasing */ + if (id >= msg_data->id) + return FM10K_ERR_PARAM; + } + + /* verify terminator is in the list */ + if ((msg_data->id != FM10K_TLV_ERROR) || !msg_data->func) + return FM10K_ERR_PARAM; + + return FM10K_SUCCESS; +} + +/** + * fm10k_mbx_register_handlers - Register a set of handler ops for mailbox + * @mbx: pointer to mailbox + * @msg_data: handlers for mailbox events + * + * This function associates a set of message handling ops with a mailbox. + **/ +STATIC s32 fm10k_mbx_register_handlers(struct fm10k_mbx_info *mbx, + const struct fm10k_msg_data *msg_data) +{ + DEBUGFUNC("fm10k_mbx_register_handlers"); + + /* validate layout of handlers before assigning them */ + if (fm10k_mbx_validate_handlers(msg_data)) + return FM10K_ERR_PARAM; + + /* initialize the message handlers */ + mbx->msg_data = msg_data; + + return FM10K_SUCCESS; +} + +/** + * fm10k_pfvf_mbx_init - Initialize mailbox memory for PF/VF mailbox + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * @msg_data: handlers for mailbox events + * @id: ID reference for PF as it supports up to 64 PF/VF mailboxes + * + * This function initializes the mailbox for use. It will split the + * buffer provided an use that th populate both the Tx and Rx FIFO by + * evenly splitting it. In order to allow for easy masking of head/tail + * the value reported in size must be a power of 2 and is reported in + * DWORDs, not bytes. Any invalid values will cause the mailbox to return + * error. + **/ +s32 fm10k_pfvf_mbx_init(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx, + const struct fm10k_msg_data *msg_data, u8 id) +{ + DEBUGFUNC("fm10k_pfvf_mbx_init"); + + /* initialize registers */ + switch (hw->mac.type) { + case fm10k_mac_vf: + mbx->mbx_reg = FM10K_VFMBX; + mbx->mbmem_reg = FM10K_VFMBMEM(FM10K_VFMBMEM_VF_XOR); + break; + case fm10k_mac_pf: + /* there are only 64 VF <-> PF mailboxes */ + if (id < 64) { + mbx->mbx_reg = FM10K_MBX(id); + mbx->mbmem_reg = FM10K_MBMEM_VF(id, 0); + break; + } + /* fallthough */ + default: + return FM10K_MBX_ERR_NO_MBX; + } + + /* start out in closed state */ + mbx->state = FM10K_STATE_CLOSED; + + /* validate layout of handlers before assigning them */ + if (fm10k_mbx_validate_handlers(msg_data)) + return FM10K_ERR_PARAM; + + /* initialize the message handlers */ + mbx->msg_data = msg_data; + + /* start mailbox as timed out and let the reset_hw call + * set the timeout value to begin communications + */ + mbx->timeout = 0; + mbx->usec_delay = FM10K_MBX_INIT_DELAY; + + /* initialize tail and head */ + mbx->tail = 1; + mbx->head = 1; + + /* initialize CRC seeds */ + mbx->local = FM10K_MBX_CRC_SEED; + mbx->remote = FM10K_MBX_CRC_SEED; + + /* Split buffer for use by Tx/Rx FIFOs */ + mbx->max_size = FM10K_MBX_MSG_MAX_SIZE; + mbx->mbmem_len = FM10K_VFMBMEM_VF_XOR; + + /* initialize the FIFOs, sizes are in 4 byte increments */ + fm10k_fifo_init(&mbx->tx, mbx->buffer, FM10K_MBX_TX_BUFFER_SIZE); + fm10k_fifo_init(&mbx->rx, &mbx->buffer[FM10K_MBX_TX_BUFFER_SIZE], + FM10K_MBX_RX_BUFFER_SIZE); + + /* initialize function pointers */ + mbx->ops.connect = fm10k_mbx_connect; + mbx->ops.disconnect = fm10k_mbx_disconnect; + mbx->ops.rx_ready = fm10k_mbx_rx_ready; + mbx->ops.tx_ready = fm10k_mbx_tx_ready; + mbx->ops.tx_complete = fm10k_mbx_tx_complete; + mbx->ops.enqueue_tx = fm10k_mbx_enqueue_tx; + mbx->ops.process = fm10k_mbx_process; + mbx->ops.register_handlers = fm10k_mbx_register_handlers; + + return FM10K_SUCCESS; +} + +/** + * fm10k_sm_mbx_create_data_hdr - Generate a mailbox header for local FIFO + * @mbx: pointer to mailbox + * + * This function returns a connection mailbox header + **/ +STATIC void fm10k_sm_mbx_create_data_hdr(struct fm10k_mbx_info *mbx) +{ + if (mbx->tail_len) + mbx->mbx_lock |= FM10K_MBX_REQ; + + mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(mbx->tail, SM_TAIL) | + FM10K_MSG_HDR_FIELD_SET(mbx->remote, SM_VER) | + FM10K_MSG_HDR_FIELD_SET(mbx->head, SM_HEAD); +} + +/** + * fm10k_sm_mbx_create_connect_hdr - Generate a mailbox header for local FIFO + * @mbx: pointer to mailbox + * @err: error flags to report if any + * + * This function returns a connection mailbox header + **/ +STATIC void fm10k_sm_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx, u8 err) +{ + if (mbx->local) + mbx->mbx_lock |= FM10K_MBX_REQ; + + mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(mbx->tail, SM_TAIL) | + FM10K_MSG_HDR_FIELD_SET(mbx->remote, SM_VER) | + FM10K_MSG_HDR_FIELD_SET(mbx->head, SM_HEAD) | + FM10K_MSG_HDR_FIELD_SET(err, SM_ERR); +} + +/** + * fm10k_sm_mbx_connect_reset - Reset following request for reset + * @mbx: pointer to mailbox + * + * This function resets the mailbox to a just connected state + **/ +STATIC void fm10k_sm_mbx_connect_reset(struct fm10k_mbx_info *mbx) +{ + /* flush any uncompleted work */ + fm10k_mbx_reset_work(mbx); + + /* set local version to max and remote version to 0 */ + mbx->local = FM10K_SM_MBX_VERSION; + mbx->remote = 0; + + /* initialize tail and head */ + mbx->tail = 1; + mbx->head = 1; + + /* reset state back to connect */ + mbx->state = FM10K_STATE_CONNECT; +} + +/** + * fm10k_sm_mbx_connect - Start switch manager mailbox connection + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * + * This function will initiate a mailbox connection with the switch + * manager. To do this it will first disconnect the mailbox, and then + * reconnect it in order to complete a reset of the mailbox. + * + * This function will return an error if the mailbox has not been initiated + * or is currently in use. + **/ +STATIC s32 fm10k_sm_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx) +{ + DEBUGFUNC("fm10k_mbx_connect"); + + /* we cannot connect an uninitialized mailbox */ + if (!mbx->rx.buffer) + return FM10K_MBX_ERR_NO_SPACE; + + /* we cannot connect an already connected mailbox */ + if (mbx->state != FM10K_STATE_CLOSED) + return FM10K_MBX_ERR_BUSY; + + /* mailbox timeout can now become active */ + mbx->timeout = FM10K_MBX_INIT_TIMEOUT; + + /* Place mbx in ready to connect state */ + mbx->state = FM10K_STATE_CONNECT; + mbx->max_size = FM10K_MBX_MSG_MAX_SIZE; + + /* reset interface back to connect */ + fm10k_sm_mbx_connect_reset(mbx); + + /* enable interrupt and notify other party of new message */ + mbx->mbx_lock = FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT | + FM10K_MBX_INTERRUPT_ENABLE; + + /* generate and load connect header into mailbox */ + fm10k_sm_mbx_create_connect_hdr(mbx, 0); + fm10k_mbx_write(hw, mbx); + + /* enable interrupt and notify other party of new message */ + + return FM10K_SUCCESS; +} + +/** + * fm10k_sm_mbx_disconnect - Shutdown mailbox connection + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * + * This function will shut down the mailbox. It places the mailbox first + * in the disconnect state, it then allows up to a predefined timeout for + * the mailbox to transition to close on its own. If this does not occur + * then the mailbox will be forced into the closed state. + * + * Any mailbox transactions not completed before calling this function + * are not guaranteed to complete and may be dropped. + **/ +STATIC void fm10k_sm_mbx_disconnect(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx) +{ + int timeout = mbx->timeout ? FM10K_MBX_DISCONNECT_TIMEOUT : 0; + + DEBUGFUNC("fm10k_sm_mbx_disconnect"); + + /* Place mbx in ready to disconnect state */ + mbx->state = FM10K_STATE_DISCONNECT; + + /* trigger interrupt to start shutdown process */ + FM10K_WRITE_REG(hw, mbx->mbx_reg, FM10K_MBX_REQ | + FM10K_MBX_INTERRUPT_DISABLE); + do { + usec_delay(FM10K_MBX_POLL_DELAY); + mbx->ops.process(hw, mbx); + timeout -= FM10K_MBX_POLL_DELAY; + } while ((timeout > 0) && (mbx->state != FM10K_STATE_CLOSED)); + + /* in case we didn't close just force the mailbox into shutdown */ + mbx->state = FM10K_STATE_CLOSED; + mbx->remote = 0; + fm10k_mbx_reset_work(mbx); + fm10k_mbx_update_max_size(mbx, 0); + + FM10K_WRITE_REG(hw, mbx->mbmem_reg, 0); +} + +/** + * fm10k_mbx_validate_fifo_hdr - Validate fields in the remote FIFO header + * @mbx: pointer to mailbox + * + * This function will parse up the fields in the mailbox header and return + * an error if the header contains any of a number of invalid configurations + * including unrecognized offsets or version numbers. + **/ +STATIC s32 fm10k_sm_mbx_validate_fifo_hdr(struct fm10k_mbx_info *mbx) +{ + const u32 *hdr = &mbx->mbx_hdr; + u16 tail, head, ver; + + DEBUGFUNC("fm10k_mbx_validate_msg_hdr"); + + tail = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_TAIL); + ver = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_VER); + head = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_HEAD); + + switch (ver) { + case 0: + break; + case FM10K_SM_MBX_VERSION: + if (!head || head > FM10K_SM_MBX_FIFO_LEN) + return FM10K_MBX_ERR_HEAD; + if (!tail || tail > FM10K_SM_MBX_FIFO_LEN) + return FM10K_MBX_ERR_TAIL; + if (mbx->tail < head) + head += mbx->mbmem_len - 1; + if (tail < mbx->head) + tail += mbx->mbmem_len - 1; + if (fm10k_mbx_index_len(mbx, head, mbx->tail) > mbx->tail_len) + return FM10K_MBX_ERR_HEAD; + if (fm10k_mbx_index_len(mbx, mbx->head, tail) < mbx->mbmem_len) + break; + return FM10K_MBX_ERR_TAIL; + default: + return FM10K_MBX_ERR_SRC; + } + + return FM10K_SUCCESS; +} + +/** + * fm10k_sm_mbx_process_error - Process header with error flag set + * @mbx: pointer to mailbox + * + * This function is meant to respond to a request where the error flag + * is set. As a result we will terminate a connection if one is present + * and fall back into the reset state with a connection header of version + * 0 (RESET). + **/ +STATIC void fm10k_sm_mbx_process_error(struct fm10k_mbx_info *mbx) +{ + const enum fm10k_mbx_state state = mbx->state; + + switch (state) { + case FM10K_STATE_DISCONNECT: + /* if there is an error just disconnect */ + mbx->remote = 0; + break; + case FM10K_STATE_OPEN: + /* flush any uncompleted work */ + fm10k_sm_mbx_connect_reset(mbx); + break; + case FM10K_STATE_CONNECT: + /* try connnecting at lower version */ + if (mbx->remote) { + while (mbx->local > 1) + mbx->local--; + mbx->remote = 0; + } + break; + default: + break; + } + + fm10k_sm_mbx_create_connect_hdr(mbx, 0); +} + +/** + * fm10k_sm_mbx_create_error_message - Process an error in FIFO hdr + * @mbx: pointer to mailbox + * @err: local error encountered + * + * This function will interpret the error provided by err, and based on + * that it may set the error bit in the local message header + **/ +STATIC void fm10k_sm_mbx_create_error_msg(struct fm10k_mbx_info *mbx, s32 err) +{ + /* only generate an error message for these types */ + switch (err) { + case FM10K_MBX_ERR_TAIL: + case FM10K_MBX_ERR_HEAD: + case FM10K_MBX_ERR_SRC: + case FM10K_MBX_ERR_SIZE: + case FM10K_MBX_ERR_RSVD0: + break; + default: + return; + } + + /* process it as though we received an error, and send error reply */ + fm10k_sm_mbx_process_error(mbx); + fm10k_sm_mbx_create_connect_hdr(mbx, 1); +} + +/** + * fm10k_sm_mbx_receive - Take message from Rx mailbox FIFO and put it in Rx + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * + * This function will dequeue one message from the Rx switch manager mailbox + * FIFO and place it in the Rx mailbox FIFO for processing by software. + **/ +STATIC s32 fm10k_sm_mbx_receive(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx, + u16 tail) +{ + /* reduce length by 1 to convert to a mask */ + u16 mbmem_len = mbx->mbmem_len - 1; + s32 err; + + DEBUGFUNC("fm10k_sm_mbx_receive"); + + /* push tail in front of head */ + if (tail < mbx->head) + tail += mbmem_len; + + /* copy data to the Rx FIFO */ + err = fm10k_mbx_push_tail(hw, mbx, tail); + if (err < 0) + return err; + + /* process messages if we have received any */ + fm10k_mbx_dequeue_rx(hw, mbx); + + /* guarantee head aligns with the end of the last message */ + mbx->head = fm10k_mbx_head_sub(mbx, mbx->pushed); + mbx->pushed = 0; + + /* clear any extra bits left over since index adds 1 extra bit */ + if (mbx->head > mbmem_len) + mbx->head -= mbmem_len; + + return err; +} + +/** + * fm10k_sm_mbx_transmit - Take message from Tx and put it in Tx mailbox FIFO + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * + * This function will dequeue one message from the Tx mailbox FIFO and place + * it in the Tx switch manager mailbox FIFO for processing by hardware. + **/ +STATIC void fm10k_sm_mbx_transmit(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx, u16 head) +{ + struct fm10k_mbx_fifo *fifo = &mbx->tx; + /* reduce length by 1 to convert to a mask */ + u16 mbmem_len = mbx->mbmem_len - 1; + u16 tail_len, len = 0; + u32 *msg; + + DEBUGFUNC("fm10k_sm_mbx_transmit"); + + /* push head behind tail */ + if (mbx->tail < head) + head += mbmem_len; + + fm10k_mbx_pull_head(hw, mbx, head); + + /* determine msg aligned offset for end of buffer */ + do { + msg = fifo->buffer + fm10k_fifo_head_offset(fifo, len); + tail_len = len; + len += FM10K_TLV_DWORD_LEN(*msg); + } while ((len <= mbx->tail_len) && (len < mbmem_len)); + + /* guarantee we stop on a message boundary */ + if (mbx->tail_len > tail_len) { + mbx->tail = fm10k_mbx_tail_sub(mbx, mbx->tail_len - tail_len); + mbx->tail_len = tail_len; + } + + /* clear any extra bits left over since index adds 1 extra bit */ + if (mbx->tail > mbmem_len) + mbx->tail -= mbmem_len; +} + +/** + * fm10k_sm_mbx_create_reply - Generate reply based on state and remote head + * @mbx: pointer to mailbox + * @head: acknowledgement number + * + * This function will generate an outgoing message based on the current + * mailbox state and the remote fifo head. It will return the length + * of the outgoing message excluding header on success, and a negative value + * on error. + **/ +STATIC void fm10k_sm_mbx_create_reply(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx, u16 head) +{ + switch (mbx->state) { + case FM10K_STATE_OPEN: + case FM10K_STATE_DISCONNECT: + /* flush out Tx data */ + fm10k_sm_mbx_transmit(hw, mbx, head); + + /* generate new header based on data */ + if (mbx->tail_len || (mbx->state == FM10K_STATE_OPEN)) { + fm10k_sm_mbx_create_data_hdr(mbx); + } else { + mbx->remote = 0; + fm10k_sm_mbx_create_connect_hdr(mbx, 0); + } + break; + case FM10K_STATE_CONNECT: + case FM10K_STATE_CLOSED: + fm10k_sm_mbx_create_connect_hdr(mbx, 0); + break; + default: + break; + } +} + +/** + * fm10k_sm_mbx_process_reset - Process header with version == 0 (RESET) + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * + * This function is meant to respond to a request where the version data + * is set to 0. As such we will either terminate the connection or go + * into the connect state in order to re-establish the connection. This + * function can also be used to respond to an error as the connection + * resetting would also be a means of dealing with errors. + **/ +STATIC void fm10k_sm_mbx_process_reset(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx) +{ + const enum fm10k_mbx_state state = mbx->state; + + switch (state) { + case FM10K_STATE_DISCONNECT: + /* drop remote connections and disconnect */ + mbx->state = FM10K_STATE_CLOSED; + mbx->remote = 0; + mbx->local = 0; + break; + case FM10K_STATE_OPEN: + /* flush any incomplete work */ + fm10k_sm_mbx_connect_reset(mbx); + break; + case FM10K_STATE_CONNECT: + /* Update remote value to match local value */ + mbx->remote = mbx->local; + default: + break; + } + + fm10k_sm_mbx_create_reply(hw, mbx, mbx->tail); +} + +/** + * fm10k_sm_mbx_process_version_1 - Process header with version == 1 + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * + * This function is meant to process messages received when the remote + * mailbox is active. + **/ +STATIC s32 fm10k_sm_mbx_process_version_1(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx) +{ + const u32 *hdr = &mbx->mbx_hdr; + u16 head, tail; + s32 len; + + /* pull all fields needed for verification */ + tail = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_TAIL); + head = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_HEAD); + + /* if we are in connect and wanting version 1 then start up and go */ + if (mbx->state == FM10K_STATE_CONNECT) { + if (!mbx->remote) + goto send_reply; + if (mbx->remote != 1) + return FM10K_MBX_ERR_SRC; + + mbx->state = FM10K_STATE_OPEN; + } + + do { + /* abort on message size errors */ + len = fm10k_sm_mbx_receive(hw, mbx, tail); + if (len < 0) + return len; + + /* continue until we have flushed the Rx FIFO */ + } while (len); + +send_reply: + fm10k_sm_mbx_create_reply(hw, mbx, head); + + return FM10K_SUCCESS; +} + +/** + * fm10k_sm_mbx_process - Process mailbox switch mailbox interrupt + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * + * This function will process incoming mailbox events and generate mailbox + * replies. It will return a value indicating the number of DWORDs + * transmitted excluding header on success or a negative value on error. + **/ +STATIC s32 fm10k_sm_mbx_process(struct fm10k_hw *hw, + struct fm10k_mbx_info *mbx) +{ + s32 err; + + DEBUGFUNC("fm10k_sm_mbx_process"); + + /* we do not read mailbox if closed */ + if (mbx->state == FM10K_STATE_CLOSED) + return FM10K_SUCCESS; + + /* retrieve data from switch manager */ + err = fm10k_mbx_read(hw, mbx); + if (err) + return err; + + err = fm10k_sm_mbx_validate_fifo_hdr(mbx); + if (err < 0) + goto fifo_err; + + if (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_ERR)) { + fm10k_sm_mbx_process_error(mbx); + goto fifo_err; + } + + switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_VER)) { + case 0: + fm10k_sm_mbx_process_reset(hw, mbx); + break; + case FM10K_SM_MBX_VERSION: + err = fm10k_sm_mbx_process_version_1(hw, mbx); + break; + } + +fifo_err: + if (err < 0) + fm10k_sm_mbx_create_error_msg(mbx, err); + + /* report data to switch manager */ + fm10k_mbx_write(hw, mbx); + + return err; +} + +/** + * fm10k_sm_mbx_init - Initialize mailbox memory for PF/SM mailbox + * @hw: pointer to hardware structure + * @mbx: pointer to mailbox + * @msg_data: handlers for mailbox events + * + * This function for now is used to stub out the PF/SM mailbox + **/ +s32 fm10k_sm_mbx_init(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx, + const struct fm10k_msg_data *msg_data) +{ + DEBUGFUNC("fm10k_sm_mbx_init"); + UNREFERENCED_1PARAMETER(hw); + + mbx->mbx_reg = FM10K_GMBX; + mbx->mbmem_reg = FM10K_MBMEM_PF(0); + + /* start out in closed state */ + mbx->state = FM10K_STATE_CLOSED; + + /* validate layout of handlers before assigning them */ + if (fm10k_mbx_validate_handlers(msg_data)) + return FM10K_ERR_PARAM; + + /* initialize the message handlers */ + mbx->msg_data = msg_data; + + /* start mailbox as timed out and let the reset_hw call + * set the timeout value to begin communications + */ + mbx->timeout = 0; + mbx->usec_delay = FM10K_MBX_INIT_DELAY; + + /* Split buffer for use by Tx/Rx FIFOs */ + mbx->max_size = FM10K_MBX_MSG_MAX_SIZE; + mbx->mbmem_len = FM10K_MBMEM_PF_XOR; + + /* initialize the FIFOs, sizes are in 4 byte increments */ + fm10k_fifo_init(&mbx->tx, mbx->buffer, FM10K_MBX_TX_BUFFER_SIZE); + fm10k_fifo_init(&mbx->rx, &mbx->buffer[FM10K_MBX_TX_BUFFER_SIZE], + FM10K_MBX_RX_BUFFER_SIZE); + + /* initialize function pointers */ + mbx->ops.connect = fm10k_sm_mbx_connect; + mbx->ops.disconnect = fm10k_sm_mbx_disconnect; + mbx->ops.rx_ready = fm10k_mbx_rx_ready; + mbx->ops.tx_ready = fm10k_mbx_tx_ready; + mbx->ops.tx_complete = fm10k_mbx_tx_complete; + mbx->ops.enqueue_tx = fm10k_mbx_enqueue_tx; + mbx->ops.process = fm10k_sm_mbx_process; + mbx->ops.register_handlers = fm10k_mbx_register_handlers; + + return FM10K_SUCCESS; +} diff --git a/drivers/fm10k/base/fm10k_mbx.h b/drivers/fm10k/base/fm10k_mbx.h new file mode 100644 index 0000000..6332584 --- /dev/null +++ b/drivers/fm10k/base/fm10k_mbx.h @@ -0,0 +1,329 @@ +/******************************************************************************* + +Copyright (c) 2013 - 2015, 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. + +***************************************************************************/ + +#ifndef _FM10K_MBX_H_ +#define _FM10K_MBX_H_ + +/* forward declaration */ +struct fm10k_mbx_info; + +#include "fm10k_type.h" +#include "fm10k_tlv.h" + +/* PF Mailbox Registers */ +#define FM10K_MBMEM(_n) ((_n) + 0x18000) +#define FM10K_MBMEM_VF(_n, _m) (((_n) * 0x10) + (_m) + 0x18000) +#define FM10K_MBMEM_SM(_n) ((_n) + 0x18400) +#define FM10K_MBMEM_PF(_n) ((_n) + 0x18600) +/* XOR provides means of switching from Tx to Rx FIFO */ +#define FM10K_MBMEM_PF_XOR (FM10K_MBMEM_SM(0) ^ FM10K_MBMEM_PF(0)) +#define FM10K_MBX(_n) ((_n) + 0x18800) +#define FM10K_MBX_OWNER 0x00000001 +#define FM10K_MBX_REQ 0x00000002 +#define FM10K_MBX_ACK 0x00000004 +#define FM10K_MBX_REQ_INTERRUPT 0x00000008 +#define FM10K_MBX_ACK_INTERRUPT 0x00000010 +#define FM10K_MBX_INTERRUPT_ENABLE 0x00000020 +#define FM10K_MBX_INTERRUPT_DISABLE 0x00000040 +#define FM10K_MBICR(_n) ((_n) + 0x18840) +#define FM10K_GMBX 0x18842 + +/* VF Mailbox Registers */ +#define FM10K_VFMBX 0x00010 +#define FM10K_VFMBMEM(_n) ((_n) + 0x00020) +#define FM10K_VFMBMEM_LEN 16 +#define FM10K_VFMBMEM_VF_XOR (FM10K_VFMBMEM_LEN / 2) + +/* Delays/timeouts */ +#define FM10K_MBX_DISCONNECT_TIMEOUT 500 +#define FM10K_MBX_POLL_DELAY 19 +#define FM10K_MBX_INT_DELAY 20 + +#define FM10K_WRITE_MBX(hw, reg, value) FM10K_WRITE_REG(hw, reg, value) + +/* PF/VF Mailbox state machine + * + * +----------+ connect() +----------+ + * | CLOSED | --------------> | CONNECT | + * +----------+ +----------+ + * ^ ^ | + * | rcv: rcv: | | rcv: + * | Connect Disconnect | | Connect + * | Disconnect Error | | Data + * | | | + * | | V + * +----------+ disconnect() +----------+ + * |DISCONNECT| <-------------- | OPEN | + * +----------+ +----------+ + * + * The diagram above describes the PF/VF mailbox state machine. There + * are four main states to this machine. + * Closed: This state represents a mailbox that is in a standby state + * with interrupts disabled. In this state the mailbox should not + * read the mailbox or write any data. The only means of exiting + * this state is for the system to make the connect() call for the + * mailbox, it will then transition to the connect state. + * Connect: In this state the mailbox is seeking a connection. It will + * post a connect message with no specified destination and will + * wait for a reply from the other side of the mailbox. This state + * is exited when either a connect with the local mailbox as the + * destination is received or when a data message is received with + * a valid sequence number. + * Open: In this state the mailbox is able to transfer data between the local + * entity and the remote. It will fall back to connect in the event of + * receiving either an error message, or a disconnect message. It will + * transition to disconnect on a call to disconnect(); + * Disconnect: In this state the mailbox is attempting to gracefully terminate + * the connection. It will do so at the first point where it knows + * that the remote endpoint is either done sending, or when the + * remote endpoint has fallen back into connect. + */ +enum fm10k_mbx_state { + FM10K_STATE_CLOSED, + FM10K_STATE_CONNECT, + FM10K_STATE_OPEN, + FM10K_STATE_DISCONNECT, +}; + +/* PF/VF Mailbox header format + * 3 2 1 0 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Size/Err_no/CRC | Rsvd0 | Head | Tail | Type | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * The layout above describes the format for the header used in the PF/VF + * mailbox. The header is broken out into the following fields: + * Type: There are 4 supported message types + * 0x8: Data header - used to transport message data + * 0xC: Connect header - used to establish connection + * 0xD: Disconnect header - used to tear down a connection + * 0xE: Error header - used to address message exceptions + * Tail: Tail index for local FIFO + * Tail index actually consists of two parts. The MSB of + * the head is a loop tracker, it is 0 on an even numbered + * loop through the FIFO, and 1 on the odd numbered loops. + * To get the actual mailbox offset based on the tail it + * is necessary to add bit 3 to bit 0 and clear bit 3. This + * gives us a valid range of 0x1 - 0xE. + * Head: Head index for remote FIFO + * Head index follows the same format as the tail index. + * Rsvd0: Reserved 0 portion of the mailbox header + * CRC: Running CRC for all data since connect plus current message header + * Size: Maximum message size - Applies only to connect headers + * The maximum message size is provided during connect to avoid + * jamming the mailbox with messages that do not fit. + * Err_no: Error number - Applies only to error headers + * The error number provides a indication of the type of error + * experienced. + */ + +/* macros for retriving and setting header values */ +#define FM10K_MSG_HDR_MASK(name) \ + ((0x1u << FM10K_MSG_##name##_SIZE) - 1) +#define FM10K_MSG_HDR_FIELD_SET(value, name) \ + (((u32)(value) & FM10K_MSG_HDR_MASK(name)) << FM10K_MSG_##name##_SHIFT) +#define FM10K_MSG_HDR_FIELD_GET(value, name) \ + ((u16)((value) >> FM10K_MSG_##name##_SHIFT) & FM10K_MSG_HDR_MASK(name)) + +/* offsets shared between all headers */ +#define FM10K_MSG_TYPE_SHIFT 0 +#define FM10K_MSG_TYPE_SIZE 4 +#define FM10K_MSG_TAIL_SHIFT 4 +#define FM10K_MSG_TAIL_SIZE 4 +#define FM10K_MSG_HEAD_SHIFT 8 +#define FM10K_MSG_HEAD_SIZE 4 +#define FM10K_MSG_RSVD0_SHIFT 12 +#define FM10K_MSG_RSVD0_SIZE 4 + +/* offsets for data/disconnect headers */ +#define FM10K_MSG_CRC_SHIFT 16 +#define FM10K_MSG_CRC_SIZE 16 + +/* offsets for connect headers */ +#define FM10K_MSG_CONNECT_SIZE_SHIFT 16 +#define FM10K_MSG_CONNECT_SIZE_SIZE 16 + +/* offsets for error headers */ +#define FM10K_MSG_ERR_NO_SHIFT 16 +#define FM10K_MSG_ERR_NO_SIZE 16 + +enum fm10k_msg_type { + FM10K_MSG_DATA = 0x8, + FM10K_MSG_CONNECT = 0xC, + FM10K_MSG_DISCONNECT = 0xD, + FM10K_MSG_ERROR = 0xE, +}; + +/* HNI/SM Mailbox FIFO format + * 3 2 1 0 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-------+-----------------------+-------+-----------------------+ + * | Error | Remote Head |Version| Local Tail | + * +-------+-----------------------+-------+-----------------------+ + * | | + * . Local FIFO Data . + * . . + * +-------+-----------------------+-------+-----------------------+ + * + * The layout above describes the format for the FIFOs used by the host + * network interface and the switch manager to communicate messages back + * and forth. Both the HNI and the switch maintain one such FIFO. The + * layout in memory has the switch manager FIFO followed immediately by + * the HNI FIFO. For this reason I am using just the pointer to the + * HNI FIFO in the mailbox ops as the offset between the two is fixed. + * + * The header for the FIFO is broken out into the following fields: + * Local Tail: Offset into FIFO region for next DWORD to write. + * Version: Version info for mailbox, only values of 0/1 are supported. + * Remote Head: Offset into remote FIFO to indicate how much we have read. + * Error: Error indication, values TBD. + */ + +/* version number for switch manager mailboxes */ +#define FM10K_SM_MBX_VERSION 1 +#define FM10K_SM_MBX_FIFO_LEN (FM10K_MBMEM_PF_XOR - 1) +#define FM10K_SM_MBX_FIFO_HDR_LEN 1 + +/* offsets shared between all SM FIFO headers */ +#define FM10K_MSG_SM_TAIL_SHIFT 0 +#define FM10K_MSG_SM_TAIL_SIZE 12 +#define FM10K_MSG_SM_VER_SHIFT 12 +#define FM10K_MSG_SM_VER_SIZE 4 +#define FM10K_MSG_SM_HEAD_SHIFT 16 +#define FM10K_MSG_SM_HEAD_SIZE 12 +#define FM10K_MSG_SM_ERR_SHIFT 28 +#define FM10K_MSG_SM_ERR_SIZE 4 + +/* All error messages returned by mailbox functions + * The value -511 is 0xFE01 in hex. The idea is to order the errors + * from 0xFE01 - 0xFEFF so error codes are easily visible in the mailbox + * messages. This also helps to avoid error number collisions as Linux + * doesn't appear to use error numbers 256 - 511. + */ +#define FM10K_MBX_ERR(_n) ((_n) - 512) +#define FM10K_MBX_ERR_NO_MBX FM10K_MBX_ERR(0x01) +#define FM10K_MBX_ERR_NO_MSG FM10K_MBX_ERR(0x02) +#define FM10K_MBX_ERR_NO_SPACE FM10K_MBX_ERR(0x03) +#define FM10K_MBX_ERR_LOCK FM10K_MBX_ERR(0x04) +#define FM10K_MBX_ERR_TAIL FM10K_MBX_ERR(0x05) +#define FM10K_MBX_ERR_HEAD FM10K_MBX_ERR(0x06) +#define FM10K_MBX_ERR_DST FM10K_MBX_ERR(0x07) +#define FM10K_MBX_ERR_SRC FM10K_MBX_ERR(0x08) +#define FM10K_MBX_ERR_TYPE FM10K_MBX_ERR(0x09) +#define FM10K_MBX_ERR_LEN FM10K_MBX_ERR(0x0A) +#define FM10K_MBX_ERR_SIZE FM10K_MBX_ERR(0x0B) +#define FM10K_MBX_ERR_BUSY FM10K_MBX_ERR(0x0C) +#define FM10K_MBX_ERR_VALUE FM10K_MBX_ERR(0x0D) +#define FM10K_MBX_ERR_RSVD0 FM10K_MBX_ERR(0x0E) +#define FM10K_MBX_ERR_CRC FM10K_MBX_ERR(0x0F) + +#define FM10K_MBX_CRC_SEED 0xFFFF + +struct fm10k_mbx_ops { + s32 (*connect)(struct fm10k_hw *, struct fm10k_mbx_info *); + void (*disconnect)(struct fm10k_hw *, struct fm10k_mbx_info *); + bool (*rx_ready)(struct fm10k_mbx_info *); + bool (*tx_ready)(struct fm10k_mbx_info *, u16); + bool (*tx_complete)(struct fm10k_mbx_info *); + s32 (*enqueue_tx)(struct fm10k_hw *, struct fm10k_mbx_info *, + const u32 *); + s32 (*process)(struct fm10k_hw *, struct fm10k_mbx_info *); + s32 (*register_handlers)(struct fm10k_mbx_info *, + const struct fm10k_msg_data *); +}; + +struct fm10k_mbx_fifo { + u32 *buffer; + u16 head; + u16 tail; + u16 size; +}; + +/* size of buffer to be stored in mailbox for FIFOs */ +#define FM10K_MBX_TX_BUFFER_SIZE 512 +#define FM10K_MBX_RX_BUFFER_SIZE 128 +#define FM10K_MBX_BUFFER_SIZE \ + (FM10K_MBX_TX_BUFFER_SIZE + FM10K_MBX_RX_BUFFER_SIZE) + +/* minimum and maximum message size in dwords */ +#define FM10K_MBX_MSG_MAX_SIZE \ + ((FM10K_MBX_TX_BUFFER_SIZE - 1) & (FM10K_MBX_RX_BUFFER_SIZE - 1)) +#define FM10K_VFMBX_MSG_MTU ((FM10K_VFMBMEM_LEN / 2) - 1) + +#define FM10K_MBX_INIT_TIMEOUT 2000 /* number of retries on mailbox */ +#define FM10K_MBX_INIT_DELAY 500 /* microseconds between retries */ + +struct fm10k_mbx_info { + /* function pointers for mailbox operations */ + struct fm10k_mbx_ops ops; + const struct fm10k_msg_data *msg_data; + + /* message FIFOs */ + struct fm10k_mbx_fifo rx; + struct fm10k_mbx_fifo tx; + + /* delay for handling timeouts */ + u32 timeout; + u32 usec_delay; + + /* mailbox state info */ + u32 mbx_reg, mbmem_reg, mbx_lock, mbx_hdr; + u16 max_size, mbmem_len; + u16 tail, tail_len, pulled; + u16 head, head_len, pushed; + u16 local, remote; + enum fm10k_mbx_state state; + + /* result of last mailbox test */ + s32 test_result; + + /* statistics */ + u64 tx_busy; + u64 tx_dropped; + u64 tx_messages; + u64 tx_dwords; + u64 rx_messages; + u64 rx_dwords; + u64 rx_parse_err; + + /* Buffer to store messages */ + u32 buffer[FM10K_MBX_BUFFER_SIZE]; +}; + +s32 fm10k_pfvf_mbx_init(struct fm10k_hw *, struct fm10k_mbx_info *, + const struct fm10k_msg_data *, u8); +s32 fm10k_sm_mbx_init(struct fm10k_hw *, struct fm10k_mbx_info *, + const struct fm10k_msg_data *); + +#endif /* _FM10K_MBX_H_ */ diff --git a/drivers/fm10k/base/fm10k_osdep.h b/drivers/fm10k/base/fm10k_osdep.h new file mode 100644 index 0000000..04f8fe9 --- /dev/null +++ b/drivers/fm10k/base/fm10k_osdep.h @@ -0,0 +1,148 @@ +/******************************************************************************* + +Copyright (c) 2013-2015, 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. + +***************************************************************************/ + +#ifndef _FM10K_OSDEP_H_ +#define _FM10K_OSDEP_H_ + +#include +#include +#include +#include +#include +#include "../fm10k_logs.h" + +/* TODO: this does not look like it should be used... */ +#define ERROR_REPORT2(v1, v2, v3) do { } while (0) + +#define STATIC static +#define DEBUGFUNC(F) DEBUGOUT(F); +#define DEBUGOUT(S, args...) PMD_DRV_LOG_RAW(DEBUG, S, ##args) +#define DEBUGOUT1(S, args...) DEBUGOUT(S, ##args) +#define DEBUGOUT2(S, args...) DEBUGOUT(S, ##args) +#define DEBUGOUT3(S, args...) DEBUGOUT(S, ##args) +#define DEBUGOUT6(S, args...) DEBUGOUT(S, ##args) +#define DEBUGOUT7(S, args...) DEBUGOUT(S, ##args) + +#define FALSE 0 +#define TRUE 1 +#ifndef false +#define false FALSE +#endif +#ifndef true +#define true TRUE +#endif + +typedef uint8_t u8; +typedef int8_t s8; +typedef uint16_t u16; +typedef int16_t s16; +typedef uint32_t u32; +typedef int32_t s32; +typedef int64_t s64; +typedef uint64_t u64; +typedef int bool; + +#ifndef __le16 +#define __le16 u16 +#define __le32 u32 +#define __le64 u64 +#endif +#ifndef __be16 +#define __be16 u16 +#define __be32 u32 +#define __be64 u64 +#endif + +/* offsets are WORD offsets, not BYTE offsets */ +#define FM10K_WRITE_REG(hw, reg, val) \ + ((((volatile uint32_t *)(hw)->hw_addr)[(reg)]) = ((uint32_t)(val))) +#define FM10K_READ_REG(hw, reg) \ + (((volatile uint32_t *)(hw)->hw_addr)[(reg)]) +#define FM10K_WRITE_FLUSH(a) FM10K_READ_REG(a, FM10K_CTRL) + +#define FM10K_PCI_REG(reg) (*((volatile uint32_t *)(reg))) + +#define FM10K_PCI_REG_WRITE(reg, value) do { \ + FM10K_PCI_REG((reg)) = (value); \ +} while (0) + +/* not implemented */ +#define FM10K_READ_PCI_WORD(hw, reg) 0 + +#define FM10K_WRITE_MBX(hw, reg, value) FM10K_WRITE_REG(hw, reg, value) +#define FM10K_READ_MBX(hw, reg) FM10K_READ_REG(hw, reg) + +#define FM10K_LE16_TO_CPU rte_le_to_cpu_16 +#define FM10K_LE32_TO_CPU rte_le_to_cpu_32 +#define FM10K_CPU_TO_LE32 rte_cpu_to_le_32 +#define FM10K_CPU_TO_LE16 rte_cpu_to_le_16 + +#define FM10K_RMB rte_rmb +#define FM10K_WMB rte_wmb + +#define usec_delay rte_delay_us + +#define FM10K_REMOVED(hw_addr) (!(hw_addr)) + +#ifndef FM10K_IS_ZERO_ETHER_ADDR +/* make certain address is not 0 */ +#define FM10K_IS_ZERO_ETHER_ADDR(addr) \ +(!((addr)[0] | (addr)[1] | (addr)[2] | (addr)[3] | (addr)[4] | (addr)[5])) +#endif + +#ifndef FM10K_IS_MULTICAST_ETHER_ADDR +#define FM10K_IS_MULTICAST_ETHER_ADDR(addr) ((addr)[0] & 0x1) +#endif + +#ifndef FM10K_IS_VALID_ETHER_ADDR +/* make certain address is not multicast or 0 */ +#define FM10K_IS_VALID_ETHER_ADDR(addr) \ +(!FM10K_IS_MULTICAST_ETHER_ADDR(addr) && !FM10K_IS_ZERO_ETHER_ADDR(addr)) +#endif + +#ifndef do_div +#define do_div(n, base) ({\ + (n) = (n) / (base);\ +}) +#endif /* do_div */ + +/* DPDK can't access IOMEM directly */ +#ifndef FM10K_WRITE_SW_REG +#define FM10K_WRITE_SW_REG(v1, v2, v3) do { } while (0) +#endif + +#ifndef fm10k_read_reg +#define fm10k_read_reg FM10K_READ_REG +#endif + +#endif /* _FM10K_OSDEP_H_ */ diff --git a/drivers/fm10k/base/fm10k_pf.c b/drivers/fm10k/base/fm10k_pf.c new file mode 100644 index 0000000..3545a24 --- /dev/null +++ b/drivers/fm10k/base/fm10k_pf.c @@ -0,0 +1,1992 @@ +/******************************************************************************* + +Copyright (c) 2013 - 2015, 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. + +***************************************************************************/ + +#include "fm10k_pf.h" +#include "fm10k_vf.h" + +/** + * fm10k_reset_hw_pf - PF hardware reset + * @hw: pointer to hardware structure + * + * This function should return the hardware to a state similar to the + * one it is in after being powered on. + **/ +STATIC s32 fm10k_reset_hw_pf(struct fm10k_hw *hw) +{ + s32 err; + u32 reg; + u16 i; + + DEBUGFUNC("fm10k_reset_hw_pf"); + + /* Disable interrupts */ + FM10K_WRITE_REG(hw, FM10K_EIMR, FM10K_EIMR_DISABLE(ALL)); + + /* Lock ITR2 reg 0 into itself and disable interrupt moderation */ + FM10K_WRITE_REG(hw, FM10K_ITR2(0), 0); + FM10K_WRITE_REG(hw, FM10K_INT_CTRL, 0); + + /* We assume here Tx and Rx queue 0 are owned by the PF */ + + /* Shut off VF access to their queues forcing them to queue 0 */ + for (i = 0; i < FM10K_TQMAP_TABLE_SIZE; i++) { + FM10K_WRITE_REG(hw, FM10K_TQMAP(i), 0); + FM10K_WRITE_REG(hw, FM10K_RQMAP(i), 0); + } + + /* shut down all rings */ + err = fm10k_disable_queues_generic(hw, FM10K_MAX_QUEUES); + if (err) + return err; + + /* Verify that DMA is no longer active */ + reg = FM10K_READ_REG(hw, FM10K_DMA_CTRL); + if (reg & (FM10K_DMA_CTRL_TX_ACTIVE | FM10K_DMA_CTRL_RX_ACTIVE)) + return FM10K_ERR_DMA_PENDING; + + /* verify the switch is ready for reset */ + reg = FM10K_READ_REG(hw, FM10K_DMA_CTRL2); + if (!(reg & FM10K_DMA_CTRL2_SWITCH_READY)) + goto out; + + /* Inititate data path reset */ + reg |= FM10K_DMA_CTRL_DATAPATH_RESET; + FM10K_WRITE_REG(hw, FM10K_DMA_CTRL, reg); + + /* Flush write and allow 100us for reset to complete */ + FM10K_WRITE_FLUSH(hw); + usec_delay(FM10K_RESET_TIMEOUT); + + /* Verify we made it out of reset */ + reg = FM10K_READ_REG(hw, FM10K_IP); + if (!(reg & FM10K_IP_NOTINRESET)) + err = FM10K_ERR_RESET_FAILED; + +out: + return err; +} + +/** + * fm10k_is_ari_hierarchy_pf - Indicate ARI hierarchy support + * @hw: pointer to hardware structure + * + * Looks at the ARI hierarchy bit to determine whether ARI is supported or not. + **/ +STATIC bool fm10k_is_ari_hierarchy_pf(struct fm10k_hw *hw) +{ + u16 sriov_ctrl = FM10K_READ_PCI_WORD(hw, FM10K_PCIE_SRIOV_CTRL); + + DEBUGFUNC("fm10k_is_ari_hierarchy_pf"); + + return !!(sriov_ctrl & FM10K_PCIE_SRIOV_CTRL_VFARI); +} + +/** + * fm10k_init_hw_pf - PF hardware initialization + * @hw: pointer to hardware structure + * + **/ +STATIC s32 fm10k_init_hw_pf(struct fm10k_hw *hw) +{ + u32 dma_ctrl, txqctl; + u16 i; + + DEBUGFUNC("fm10k_init_hw_pf"); + + /* Establish default VSI as valid */ + FM10K_WRITE_REG(hw, FM10K_DGLORTDEC(fm10k_dglort_default), 0); + FM10K_WRITE_REG(hw, FM10K_DGLORTMAP(fm10k_dglort_default), + FM10K_DGLORTMAP_ANY); + + /* Invalidate all other GLORT entries */ + for (i = 1; i < FM10K_DGLORT_COUNT; i++) + FM10K_WRITE_REG(hw, FM10K_DGLORTMAP(i), FM10K_DGLORTMAP_NONE); + + /* reset ITR2(0) to point to itself */ + FM10K_WRITE_REG(hw, FM10K_ITR2(0), 0); + + /* reset VF ITR2(0) to point to 0 avoid PF registers */ + FM10K_WRITE_REG(hw, FM10K_ITR2(FM10K_ITR_REG_COUNT_PF), 0); + + /* loop through all PF ITR2 registers pointing them to the previous */ + for (i = 1; i < FM10K_ITR_REG_COUNT_PF; i++) + FM10K_WRITE_REG(hw, FM10K_ITR2(i), i - 1); + + /* Enable interrupt moderator if not already enabled */ + FM10K_WRITE_REG(hw, FM10K_INT_CTRL, FM10K_INT_CTRL_ENABLEMODERATOR); + + /* compute the default txqctl configuration */ + txqctl = FM10K_TXQCTL_PF | FM10K_TXQCTL_UNLIMITED_BW | + (hw->mac.default_vid << FM10K_TXQCTL_VID_SHIFT); + + for (i = 0; i < FM10K_MAX_QUEUES; i++) { + /* configure rings for 256 Queue / 32 Descriptor cache mode */ + FM10K_WRITE_REG(hw, FM10K_TQDLOC(i), + (i * FM10K_TQDLOC_BASE_32_DESC) | + FM10K_TQDLOC_SIZE_32_DESC); + FM10K_WRITE_REG(hw, FM10K_TXQCTL(i), txqctl); + + /* configure rings to provide TPH processing hints */ + FM10K_WRITE_REG(hw, FM10K_TPH_TXCTRL(i), + FM10K_TPH_TXCTRL_DESC_TPHEN | + FM10K_TPH_TXCTRL_DESC_RROEN | + FM10K_TPH_TXCTRL_DESC_WROEN | + FM10K_TPH_TXCTRL_DATA_RROEN); + FM10K_WRITE_REG(hw, FM10K_TPH_RXCTRL(i), + FM10K_TPH_RXCTRL_DESC_TPHEN | + FM10K_TPH_RXCTRL_DESC_RROEN | + FM10K_TPH_RXCTRL_DATA_WROEN | + FM10K_TPH_RXCTRL_HDR_WROEN); + } + + /* set max hold interval to align with 1.024 usec in all modes */ + switch (hw->bus.speed) { + case fm10k_bus_speed_2500: + dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN1; + break; + case fm10k_bus_speed_5000: + dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN2; + break; + case fm10k_bus_speed_8000: + dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN3; + break; + default: + dma_ctrl = 0; + break; + } + + /* Configure TSO flags */ + FM10K_WRITE_REG(hw, FM10K_DTXTCPFLGL, FM10K_TSO_FLAGS_LOW); + FM10K_WRITE_REG(hw, FM10K_DTXTCPFLGH, FM10K_TSO_FLAGS_HI); + + /* Enable DMA engine + * Set Rx Descriptor size to 32 + * Set Minimum MSS to 64 + * Set Maximum number of Rx queues to 256 / 32 Descriptor + */ + dma_ctrl |= FM10K_DMA_CTRL_TX_ENABLE | FM10K_DMA_CTRL_RX_ENABLE | + FM10K_DMA_CTRL_RX_DESC_SIZE | FM10K_DMA_CTRL_MINMSS_64 | + FM10K_DMA_CTRL_32_DESC; + + FM10K_WRITE_REG(hw, FM10K_DMA_CTRL, dma_ctrl); + + /* record maximum queue count, we limit ourselves to 128 */ + hw->mac.max_queues = FM10K_MAX_QUEUES_PF; + + /* We support either 64 VFs or 7 VFs depending on if we have ARI */ + hw->iov.total_vfs = fm10k_is_ari_hierarchy_pf(hw) ? 64 : 7; + + return FM10K_SUCCESS; +} + +/** + * fm10k_is_slot_appropriate_pf - Indicate appropriate slot for this SKU + * @hw: pointer to hardware structure + * + * Looks at the PCIe bus info to confirm whether or not this slot can support + * the necessary bandwidth for this device. + **/ +STATIC bool fm10k_is_slot_appropriate_pf(struct fm10k_hw *hw) +{ + DEBUGFUNC("fm10k_is_slot_appropriate_pf"); + + return (hw->bus.speed == hw->bus_caps.speed) && + (hw->bus.width == hw->bus_caps.width); +} + +/** + * fm10k_update_vlan_pf - Update status of VLAN ID in VLAN filter table + * @hw: pointer to hardware structure + * @vid: VLAN ID to add to table + * @vsi: Index indicating VF ID or PF ID in table + * @set: Indicates if this is a set or clear operation + * + * This function adds or removes the corresponding VLAN ID from the VLAN + * filter table for the corresponding function. In addition to the + * standard set/clear that supports one bit a multi-bit write is + * supported to set 64 bits at a time. + **/ +STATIC s32 fm10k_update_vlan_pf(struct fm10k_hw *hw, u32 vid, u8 vsi, bool set) +{ + u32 vlan_table, reg, mask, bit, len; + + /* verify the VSI index is valid */ + if (vsi > FM10K_VLAN_TABLE_VSI_MAX) + return FM10K_ERR_PARAM; + + /* VLAN multi-bit write: + * The multi-bit write has several parts to it. + * 3 2 1 0 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | RSVD0 | Length |C|RSVD0| VLAN ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * VLAN ID: Vlan Starting value + * RSVD0: Reserved section, must be 0 + * C: Flag field, 0 is set, 1 is clear (Used in VF VLAN message) + * Length: Number of times to repeat the bit being set + */ + len = vid >> 16; + vid = (vid << 17) >> 17; + + /* verify the reserved 0 fields are 0 */ + if (len >= FM10K_VLAN_TABLE_VID_MAX || vid >= FM10K_VLAN_TABLE_VID_MAX) + return FM10K_ERR_PARAM; + + /* Loop through the table updating all required VLANs */ + for (reg = FM10K_VLAN_TABLE(vsi, vid / 32), bit = vid % 32; + len < FM10K_VLAN_TABLE_VID_MAX; + len -= 32 - bit, reg++, bit = 0) { + /* record the initial state of the register */ + vlan_table = FM10K_READ_REG(hw, reg); + + /* truncate mask if we are at the start or end of the run */ + mask = (~(u32)0 >> ((len < 31) ? 31 - len : 0)) << bit; + + /* make necessary modifications to the register */ + mask &= set ? ~vlan_table : vlan_table; + if (mask) + FM10K_WRITE_REG(hw, reg, vlan_table ^ mask); + } + + return FM10K_SUCCESS; +} + +/** + * fm10k_read_mac_addr_pf - Read device MAC address + * @hw: pointer to the HW structure + * + * Reads the device MAC address from the SM_AREA and stores the value. + **/ +STATIC s32 fm10k_read_mac_addr_pf(struct fm10k_hw *hw) +{ + u8 perm_addr[ETH_ALEN]; + u32 serial_num; + int i; + + DEBUGFUNC("fm10k_read_mac_addr_pf"); + + serial_num = FM10K_READ_REG(hw, FM10K_SM_AREA(1)); + + /* last byte should be all 1's */ + if ((~serial_num) << 24) + return FM10K_ERR_INVALID_MAC_ADDR; + + perm_addr[0] = (u8)(serial_num >> 24); + perm_addr[1] = (u8)(serial_num >> 16); + perm_addr[2] = (u8)(serial_num >> 8); + + serial_num = FM10K_READ_REG(hw, FM10K_SM_AREA(0)); + + /* first byte should be all 1's */ + if ((~serial_num) >> 24) + return FM10K_ERR_INVALID_MAC_ADDR; + + perm_addr[3] = (u8)(serial_num >> 16); + perm_addr[4] = (u8)(serial_num >> 8); + perm_addr[5] = (u8)(serial_num); + + for (i = 0; i < ETH_ALEN; i++) { + hw->mac.perm_addr[i] = perm_addr[i]; + hw->mac.addr[i] = perm_addr[i]; + } + + return FM10K_SUCCESS; +} + +/** + * fm10k_glort_valid_pf - Validate that the provided glort is valid + * @hw: pointer to the HW structure + * @glort: base glort to be validated + * + * This function will return an error if the provided glort is invalid + **/ +bool fm10k_glort_valid_pf(struct fm10k_hw *hw, u16 glort) +{ + glort &= hw->mac.dglort_map >> FM10K_DGLORTMAP_MASK_SHIFT; + + return glort == (hw->mac.dglort_map & FM10K_DGLORTMAP_NONE); +} + +/** + * fm10k_update_xc_addr_pf - Update device addresses + * @hw: pointer to the HW structure + * @glort: base resource tag for this request + * @mac: MAC address to add/remove from table + * @vid: VLAN ID to add/remove from table + * @add: Indicates if this is an add or remove operation + * @flags: flags field to indicate add and secure + * + * This function generates a message to the Switch API requesting + * that the given logical port add/remove the given L2 MAC/VLAN address. + **/ +STATIC s32 fm10k_update_xc_addr_pf(struct fm10k_hw *hw, u16 glort, + const u8 *mac, u16 vid, bool add, u8 flags) +{ + struct fm10k_mbx_info *mbx = &hw->mbx; + struct fm10k_mac_update mac_update; + u32 msg[5]; + + DEBUGFUNC("fm10k_update_xc_addr_pf"); + + /* if glort or VLAN are not valid return error */ + if (!fm10k_glort_valid_pf(hw, glort) || vid >= FM10K_VLAN_TABLE_VID_MAX) + return FM10K_ERR_PARAM; + + /* record fields */ + mac_update.mac_lower = FM10K_CPU_TO_LE32(((u32)mac[2] << 24) | + ((u32)mac[3] << 16) | + ((u32)mac[4] << 8) | + ((u32)mac[5])); + mac_update.mac_upper = FM10K_CPU_TO_LE16(((u32)mac[0] << 8) | + ((u32)mac[1])); + mac_update.vlan = FM10K_CPU_TO_LE16(vid); + mac_update.glort = FM10K_CPU_TO_LE16(glort); + mac_update.action = add ? 0 : 1; + mac_update.flags = flags; + + /* populate mac_update fields */ + fm10k_tlv_msg_init(msg, FM10K_PF_MSG_ID_UPDATE_MAC_FWD_RULE); + fm10k_tlv_attr_put_le_struct(msg, FM10K_PF_ATTR_ID_MAC_UPDATE, + &mac_update, sizeof(mac_update)); + + /* load onto outgoing mailbox */ + return mbx->ops.enqueue_tx(hw, mbx, msg); +} + +/** + * fm10k_update_uc_addr_pf - Update device unicast addresses + * @hw: pointer to the HW structure + * @glort: base resource tag for this request + * @mac: MAC address to add/remove from table + * @vid: VLAN ID to add/remove from table + * @add: Indicates if this is an add or remove operation + * @flags: flags field to indicate add and secure + * + * This function is used to add or remove unicast addresses for + * the PF. + **/ +STATIC s32 fm10k_update_uc_addr_pf(struct fm10k_hw *hw, u16 glort, + const u8 *mac, u16 vid, bool add, u8 flags) +{ + DEBUGFUNC("fm10k_update_uc_addr_pf"); + + /* verify MAC address is valid */ + if (!FM10K_IS_VALID_ETHER_ADDR(mac)) + return FM10K_ERR_PARAM; + + return fm10k_update_xc_addr_pf(hw, glort, mac, vid, add, flags); +} + +/** + * fm10k_update_mc_addr_pf - Update device multicast addresses + * @hw: pointer to the HW structure + * @glort: base resource tag for this request + * @mac: MAC address to add/remove from table + * @vid: VLAN ID to add/remove from table + * @add: Indicates if this is an add or remove operation + * + * This function is used to add or remove multicast MAC addresses for + * the PF. + **/ +STATIC s32 fm10k_update_mc_addr_pf(struct fm10k_hw *hw, u16 glort, + const u8 *mac, u16 vid, bool add) +{ + DEBUGFUNC("fm10k_update_mc_addr_pf"); + + /* verify multicast address is valid */ + if (!FM10K_IS_MULTICAST_ETHER_ADDR(mac)) + return FM10K_ERR_PARAM; + + return fm10k_update_xc_addr_pf(hw, glort, mac, vid, add, 0); +} + +/** + * fm10k_update_xcast_mode_pf - Request update of multicast mode + * @hw: pointer to hardware structure + * @glort: base resource tag for this request + * @mode: integer value indicating mode being requested + * + * This function will attempt to request a higher mode for the port + * so that it can enable either multicast, multicast promiscuous, or + * promiscuous mode of operation. + **/ +STATIC s32 fm10k_update_xcast_mode_pf(struct fm10k_hw *hw, u16 glort, u8 mode) +{ + struct fm10k_mbx_info *mbx = &hw->mbx; + u32 msg[3], xcast_mode; + + DEBUGFUNC("fm10k_update_xcast_mode_pf"); + + if (mode > FM10K_XCAST_MODE_NONE) + return FM10K_ERR_PARAM; + + /* if glort is not valid return error */ + if (!fm10k_glort_valid_pf(hw, glort)) + return FM10K_ERR_PARAM; + + /* write xcast mode as a single u32 value, + * lower 16 bits: glort + * upper 16 bits: mode + */ + xcast_mode = ((u32)mode << 16) | glort; + + /* generate message requesting to change xcast mode */ + fm10k_tlv_msg_init(msg, FM10K_PF_MSG_ID_XCAST_MODES); + fm10k_tlv_attr_put_u32(msg, FM10K_PF_ATTR_ID_XCAST_MODE, xcast_mode); + + /* load onto outgoing mailbox */ + return mbx->ops.enqueue_tx(hw, mbx, msg); +} + +/** + * fm10k_update_int_moderator_pf - Update interrupt moderator linked list + * @hw: pointer to hardware structure + * + * This function walks through the MSI-X vector table to determine the + * number of active interrupts and based on that information updates the + * interrupt moderator linked list. + **/ +STATIC void fm10k_update_int_moderator_pf(struct fm10k_hw *hw) +{ + u32 i; + + /* Disable interrupt moderator */ + FM10K_WRITE_REG(hw, FM10K_INT_CTRL, 0); + + /* loop through PF from last to first looking enabled vectors */ + for (i = FM10K_ITR_REG_COUNT_PF - 1; i; i--) { + if (!FM10K_READ_REG(hw, FM10K_MSIX_VECTOR_MASK(i))) + break; + } + + /* always reset VFITR2[0] to point to last enabled PF vector */ + FM10K_WRITE_REG(hw, FM10K_ITR2(FM10K_ITR_REG_COUNT_PF), i); + + /* reset ITR2[0] to point to last enabled PF vector */ + if (!hw->iov.num_vfs) + FM10K_WRITE_REG(hw, FM10K_ITR2(0), i); + + /* Enable interrupt moderator */ + FM10K_WRITE_REG(hw, FM10K_INT_CTRL, FM10K_INT_CTRL_ENABLEMODERATOR); +} + +/** + * fm10k_update_lport_state_pf - Notify the switch of a change in port state + * @hw: pointer to the HW structure + * @glort: base resource tag for this request + * @count: number of logical ports being updated + * @enable: boolean value indicating enable or disable + * + * This function is used to add/remove a logical port from the switch. + **/ +STATIC s32 fm10k_update_lport_state_pf(struct fm10k_hw *hw, u16 glort, + u16 count, bool enable) +{ + struct fm10k_mbx_info *mbx = &hw->mbx; + u32 msg[3], lport_msg; + + DEBUGFUNC("fm10k_lport_state_pf"); + + /* do nothing if we are being asked to create or destroy 0 ports */ + if (!count) + return FM10K_SUCCESS; + + /* if glort is not valid return error */ + if (!fm10k_glort_valid_pf(hw, glort)) + return FM10K_ERR_PARAM; + + /* construct the lport message from the 2 pieces of data we have */ + lport_msg = ((u32)count << 16) | glort; + + /* generate lport create/delete message */ + fm10k_tlv_msg_init(msg, enable ? FM10K_PF_MSG_ID_LPORT_CREATE : + FM10K_PF_MSG_ID_LPORT_DELETE); + fm10k_tlv_attr_put_u32(msg, FM10K_PF_ATTR_ID_PORT, lport_msg); + + /* load onto outgoing mailbox */ + return mbx->ops.enqueue_tx(hw, mbx, msg); +} + +/** + * fm10k_configure_dglort_map_pf - Configures GLORT entry and queues + * @hw: pointer to hardware structure + * @dglort: pointer to dglort configuration structure + * + * Reads the configuration structure contained in dglort_cfg and uses + * that information to then populate a DGLORTMAP/DEC entry and the queues + * to which it has been assigned. + **/ +STATIC s32 fm10k_configure_dglort_map_pf(struct fm10k_hw *hw, + struct fm10k_dglort_cfg *dglort) +{ + u16 glort, queue_count, vsi_count, pc_count; + u16 vsi, queue, pc, q_idx; + u32 txqctl, dglortdec, dglortmap; + + /* verify the dglort pointer */ + if (!dglort) + return FM10K_ERR_PARAM; + + /* verify the dglort values */ + if ((dglort->idx > 7) || (dglort->rss_l > 7) || (dglort->pc_l > 3) || + (dglort->vsi_l > 6) || (dglort->vsi_b > 64) || + (dglort->queue_l > 8) || (dglort->queue_b >= 256)) + return FM10K_ERR_PARAM; + + /* determine count of VSIs and queues */ + queue_count = 1 << (dglort->rss_l + dglort->pc_l); + vsi_count = 1 << (dglort->vsi_l + dglort->queue_l); + glort = dglort->glort; + q_idx = dglort->queue_b; + + /* configure SGLORT for queues */ + for (vsi = 0; vsi < vsi_count; vsi++, glort++) { + for (queue = 0; queue < queue_count; queue++, q_idx++) { + if (q_idx >= FM10K_MAX_QUEUES) + break; + + FM10K_WRITE_REG(hw, FM10K_TX_SGLORT(q_idx), glort); + FM10K_WRITE_REG(hw, FM10K_RX_SGLORT(q_idx), glort); + } + } + + /* determine count of PCs and queues */ + queue_count = 1 << (dglort->queue_l + dglort->rss_l + dglort->vsi_l); + pc_count = 1 << dglort->pc_l; + + /* configure PC for Tx queues */ + for (pc = 0; pc < pc_count; pc++) { + q_idx = pc + dglort->queue_b; + for (queue = 0; queue < queue_count; queue++) { + if (q_idx >= FM10K_MAX_QUEUES) + break; + + txqctl = FM10K_READ_REG(hw, FM10K_TXQCTL(q_idx)); + txqctl &= ~FM10K_TXQCTL_PC_MASK; + txqctl |= pc << FM10K_TXQCTL_PC_SHIFT; + FM10K_WRITE_REG(hw, FM10K_TXQCTL(q_idx), txqctl); + + q_idx += pc_count; + } + } + + /* configure DGLORTDEC */ + dglortdec = ((u32)(dglort->rss_l) << FM10K_DGLORTDEC_RSSLENGTH_SHIFT) | + ((u32)(dglort->queue_b) << FM10K_DGLORTDEC_QBASE_SHIFT) | + ((u32)(dglort->pc_l) << FM10K_DGLORTDEC_PCLENGTH_SHIFT) | + ((u32)(dglort->vsi_b) << FM10K_DGLORTDEC_VSIBASE_SHIFT) | + ((u32)(dglort->vsi_l) << FM10K_DGLORTDEC_VSILENGTH_SHIFT) | + ((u32)(dglort->queue_l)); + if (dglort->inner_rss) + dglortdec |= FM10K_DGLORTDEC_INNERRSS_ENABLE; + + /* configure DGLORTMAP */ + dglortmap = (dglort->idx == fm10k_dglort_default) ? + FM10K_DGLORTMAP_ANY : FM10K_DGLORTMAP_ZERO; + dglortmap <<= dglort->vsi_l + dglort->queue_l + dglort->shared_l; + dglortmap |= dglort->glort; + + /* write values to hardware */ + FM10K_WRITE_REG(hw, FM10K_DGLORTDEC(dglort->idx), dglortdec); + FM10K_WRITE_REG(hw, FM10K_DGLORTMAP(dglort->idx), dglortmap); + + return FM10K_SUCCESS; +} + +u16 fm10k_queues_per_pool(struct fm10k_hw *hw) +{ + u16 num_pools = hw->iov.num_pools; + + return (num_pools > 32) ? 2 : (num_pools > 16) ? 4 : (num_pools > 8) ? + 8 : FM10K_MAX_QUEUES_POOL; +} + +u16 fm10k_vf_queue_index(struct fm10k_hw *hw, u16 vf_idx) +{ + u16 num_vfs = hw->iov.num_vfs; + u16 vf_q_idx = FM10K_MAX_QUEUES; + + vf_q_idx -= fm10k_queues_per_pool(hw) * (num_vfs - vf_idx); + + return vf_q_idx; +} + +STATIC u16 fm10k_vectors_per_pool(struct fm10k_hw *hw) +{ + u16 num_pools = hw->iov.num_pools; + + return (num_pools > 32) ? 8 : (num_pools > 16) ? 16 : + FM10K_MAX_VECTORS_POOL; +} + +STATIC u16 fm10k_vf_vector_index(struct fm10k_hw *hw, u16 vf_idx) +{ + u16 vf_v_idx = FM10K_MAX_VECTORS_PF; + + vf_v_idx += fm10k_vectors_per_pool(hw) * vf_idx; + + return vf_v_idx; +} + +/** + * fm10k_iov_assign_resources_pf - Assign pool resources for virtualization + * @hw: pointer to the HW structure + * @num_vfs: number of VFs to be allocated + * @num_pools: number of virtualization pools to be allocated + * + * Allocates queues and traffic classes to virtualization entities to prepare + * the PF for SR-IOV and VMDq + **/ +STATIC s32 fm10k_iov_assign_resources_pf(struct fm10k_hw *hw, u16 num_vfs, + u16 num_pools) +{ + u16 qmap_stride, qpp, vpp, vf_q_idx, vf_q_idx0, qmap_idx; + u32 vid = hw->mac.default_vid << FM10K_TXQCTL_VID_SHIFT; + int i, j; + + /* hardware only supports up to 64 pools */ + if (num_pools > 64) + return FM10K_ERR_PARAM; + + /* the number of VFs cannot exceed the number of pools */ + if ((num_vfs > num_pools) || (num_vfs > hw->iov.total_vfs)) + return FM10K_ERR_PARAM; + + /* record number of virtualization entities */ + hw->iov.num_vfs = num_vfs; + hw->iov.num_pools = num_pools; + + /* determine qmap offsets and counts */ + qmap_stride = (num_vfs > 8) ? 32 : 256; + qpp = fm10k_queues_per_pool(hw); + vpp = fm10k_vectors_per_pool(hw); + + /* calculate starting index for queues */ + vf_q_idx = fm10k_vf_queue_index(hw, 0); + qmap_idx = 0; + + /* establish TCs with -1 credits and no quanta to prevent transmit */ + for (i = 0; i < num_vfs; i++) { + FM10K_WRITE_REG(hw, FM10K_TC_MAXCREDIT(i), 0); + FM10K_WRITE_REG(hw, FM10K_TC_RATE(i), 0); + FM10K_WRITE_REG(hw, FM10K_TC_CREDIT(i), + FM10K_TC_CREDIT_CREDIT_MASK); + } + + /* zero out all mbmem registers */ + for (i = FM10K_VFMBMEM_LEN * num_vfs; i--;) + FM10K_WRITE_REG(hw, FM10K_MBMEM(i), 0); + + /* clear event notification of VF FLR */ + FM10K_WRITE_REG(hw, FM10K_PFVFLREC(0), ~0); + FM10K_WRITE_REG(hw, FM10K_PFVFLREC(1), ~0); + + /* loop through unallocated rings assigning them back to PF */ + for (i = FM10K_MAX_QUEUES_PF; i < vf_q_idx; i++) { + FM10K_WRITE_REG(hw, FM10K_TXDCTL(i), 0); + FM10K_WRITE_REG(hw, FM10K_TXQCTL(i), FM10K_TXQCTL_PF | vid); + FM10K_WRITE_REG(hw, FM10K_RXQCTL(i), FM10K_RXQCTL_PF); + } + + /* PF should have already updated VFITR2[0] */ + + /* update all ITR registers to flow to VFITR2[0] */ + for (i = FM10K_ITR_REG_COUNT_PF + 1; i < FM10K_ITR_REG_COUNT; i++) { + if (!(i & (vpp - 1))) + FM10K_WRITE_REG(hw, FM10K_ITR2(i), i - vpp); + else + FM10K_WRITE_REG(hw, FM10K_ITR2(i), i - 1); + } + + /* update PF ITR2[0] to reference the last vector */ + FM10K_WRITE_REG(hw, FM10K_ITR2(0), + fm10k_vf_vector_index(hw, num_vfs - 1)); + + /* loop through rings populating rings and TCs */ + for (i = 0; i < num_vfs; i++) { + /* record index for VF queue 0 for use in end of loop */ + vf_q_idx0 = vf_q_idx; + + for (j = 0; j < qpp; j++, qmap_idx++, vf_q_idx++) { + /* assign VF and locked TC to queues */ + FM10K_WRITE_REG(hw, FM10K_TXDCTL(vf_q_idx), 0); + FM10K_WRITE_REG(hw, FM10K_TXQCTL(vf_q_idx), + (i << FM10K_TXQCTL_TC_SHIFT) | i | + FM10K_TXQCTL_VF | vid); + FM10K_WRITE_REG(hw, FM10K_RXDCTL(vf_q_idx), + FM10K_RXDCTL_WRITE_BACK_MIN_DELAY | + FM10K_RXDCTL_DROP_ON_EMPTY); + FM10K_WRITE_REG(hw, FM10K_RXQCTL(vf_q_idx), + FM10K_RXQCTL_VF | + (i << FM10K_RXQCTL_VF_SHIFT)); + + /* map queue pair to VF */ + FM10K_WRITE_REG(hw, FM10K_TQMAP(qmap_idx), vf_q_idx); + FM10K_WRITE_REG(hw, FM10K_RQMAP(qmap_idx), vf_q_idx); + } + + /* repeat the first ring for all of the remaining VF rings */ + for (; j < qmap_stride; j++, qmap_idx++) { + FM10K_WRITE_REG(hw, FM10K_TQMAP(qmap_idx), vf_q_idx0); + FM10K_WRITE_REG(hw, FM10K_RQMAP(qmap_idx), vf_q_idx0); + } + } + + /* loop through remaining indexes assigning all to queue 0 */ + while (qmap_idx < FM10K_TQMAP_TABLE_SIZE) { + FM10K_WRITE_REG(hw, FM10K_TQMAP(qmap_idx), 0); + FM10K_WRITE_REG(hw, FM10K_RQMAP(qmap_idx), 0); + qmap_idx++; + } + + return FM10K_SUCCESS; +} + +/** + * fm10k_iov_configure_tc_pf - Configure the shaping group for VF + * @hw: pointer to the HW structure + * @vf_idx: index of VF receiving GLORT + * @rate: Rate indicated in Mb/s + * + * Configured the TC for a given VF to allow only up to a given number + * of Mb/s of outgoing Tx throughput. + **/ +STATIC s32 fm10k_iov_configure_tc_pf(struct fm10k_hw *hw, u16 vf_idx, int rate) +{ + /* configure defaults */ + u32 interval = FM10K_TC_RATE_INTERVAL_4US_GEN3; + u32 tc_rate = FM10K_TC_RATE_QUANTA_MASK; + + /* verify vf is in range */ + if (vf_idx >= hw->iov.num_vfs) + return FM10K_ERR_PARAM; + + /* set interval to align with 4.096 usec in all modes */ + switch (hw->bus.speed) { + case fm10k_bus_speed_2500: + interval = FM10K_TC_RATE_INTERVAL_4US_GEN1; + break; + case fm10k_bus_speed_5000: + interval = FM10K_TC_RATE_INTERVAL_4US_GEN2; + break; + default: + break; + } + + if (rate) { + if (rate > FM10K_VF_TC_MAX || rate < FM10K_VF_TC_MIN) + return FM10K_ERR_PARAM; + + /* The quanta is measured in Bytes per 4.096 or 8.192 usec + * The rate is provided in Mbits per second + * To tralslate from rate to quanta we need to multiply the + * rate by 8.192 usec and divide by 8 bits/byte. To avoid + * dealing with floating point we can round the values up + * to the nearest whole number ratio which gives us 128 / 125. + */ + tc_rate = (rate * 128) / 125; + + /* try to keep the rate limiting accurate by increasing + * the number of credits and interval for rates less than 4Gb/s + */ + if (rate < 4000) + interval <<= 1; + else + tc_rate >>= 1; + } + + /* update rate limiter with new values */ + FM10K_WRITE_REG(hw, FM10K_TC_RATE(vf_idx), tc_rate | interval); + FM10K_WRITE_REG(hw, FM10K_TC_MAXCREDIT(vf_idx), FM10K_TC_MAXCREDIT_64K); + FM10K_WRITE_REG(hw, FM10K_TC_CREDIT(vf_idx), FM10K_TC_MAXCREDIT_64K); + + return FM10K_SUCCESS; +} + +/** + * fm10k_iov_assign_int_moderator_pf - Add VF interrupts to moderator list + * @hw: pointer to the HW structure + * @vf_idx: index of VF receiving GLORT + * + * Update the interrupt moderator linked list to include any MSI-X + * interrupts which the VF has enabled in the MSI-X vector table. + **/ +STATIC s32 fm10k_iov_assign_int_moderator_pf(struct fm10k_hw *hw, u16 vf_idx) +{ + u16 vf_v_idx, vf_v_limit, i; + + /* verify vf is in range */ + if (vf_idx >= hw->iov.num_vfs) + return FM10K_ERR_PARAM; + + /* determine vector offset and count */ + vf_v_idx = fm10k_vf_vector_index(hw, vf_idx); + vf_v_limit = vf_v_idx + fm10k_vectors_per_pool(hw); + + /* search for first vector that is not masked */ + for (i = vf_v_limit - 1; i > vf_v_idx; i--) { + if (!FM10K_READ_REG(hw, FM10K_MSIX_VECTOR_MASK(i))) + break; + } + + /* reset linked list so it now includes our active vectors */ + if (vf_idx == (hw->iov.num_vfs - 1)) + FM10K_WRITE_REG(hw, FM10K_ITR2(0), i); + else + FM10K_WRITE_REG(hw, FM10K_ITR2(vf_v_limit), i); + + return FM10K_SUCCESS; +} + +/** + * fm10k_iov_assign_default_mac_vlan_pf - Assign a MAC and VLAN to VF + * @hw: pointer to the HW structure + * @vf_info: pointer to VF information structure + * + * Assign a MAC address and default VLAN to a VF and notify it of the update + **/ +STATIC s32 fm10k_iov_assign_default_mac_vlan_pf(struct fm10k_hw *hw, + struct fm10k_vf_info *vf_info) +{ + u16 qmap_stride, queues_per_pool, vf_q_idx, timeout, qmap_idx, i; + u32 msg[4], txdctl, txqctl, tdbal = 0, tdbah = 0; + s32 err = FM10K_SUCCESS; + u16 vf_idx, vf_vid; + + /* verify vf is in range */ + if (!vf_info || vf_info->vf_idx >= hw->iov.num_vfs) + return FM10K_ERR_PARAM; + + /* determine qmap offsets and counts */ + qmap_stride = (hw->iov.num_vfs > 8) ? 32 : 256; + queues_per_pool = fm10k_queues_per_pool(hw); + + /* calculate starting index for queues */ + vf_idx = vf_info->vf_idx; + vf_q_idx = fm10k_vf_queue_index(hw, vf_idx); + qmap_idx = qmap_stride * vf_idx; + + /* MAP Tx queue back to 0 temporarily, and disable it */ + FM10K_WRITE_REG(hw, FM10K_TQMAP(qmap_idx), 0); + FM10K_WRITE_REG(hw, FM10K_TXDCTL(vf_q_idx), 0); + + /* determine correct default VLAN ID */ + if (vf_info->pf_vid) + vf_vid = vf_info->pf_vid | FM10K_VLAN_CLEAR; + else + vf_vid = vf_info->sw_vid; + + /* generate MAC_ADDR request */ + fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN); + fm10k_tlv_attr_put_mac_vlan(msg, FM10K_MAC_VLAN_MSG_DEFAULT_MAC, + vf_info->mac, vf_vid); + + /* load onto outgoing mailbox, ignore any errors on enqueue */ + if (vf_info->mbx.ops.enqueue_tx) + vf_info->mbx.ops.enqueue_tx(hw, &vf_info->mbx, msg); + + /* verify ring has disabled before modifying base address registers */ + txdctl = FM10K_READ_REG(hw, FM10K_TXDCTL(vf_q_idx)); + for (timeout = 0; txdctl & FM10K_TXDCTL_ENABLE; timeout++) { + /* limit ourselves to a 1ms timeout */ + if (timeout == 10) { + err = FM10K_ERR_DMA_PENDING; + goto err_out; + } + + usec_delay(100); + txdctl = FM10K_READ_REG(hw, FM10K_TXDCTL(vf_q_idx)); + } + + /* Update base address registers to contain MAC address */ + if (FM10K_IS_VALID_ETHER_ADDR(vf_info->mac)) { + tdbal = (((u32)vf_info->mac[3]) << 24) | + (((u32)vf_info->mac[4]) << 16) | + (((u32)vf_info->mac[5]) << 8); + + tdbah = (((u32)0xFF) << 24) | + (((u32)vf_info->mac[0]) << 16) | + (((u32)vf_info->mac[1]) << 8) | + ((u32)vf_info->mac[2]); + } + + /* Record the base address into queue 0 */ + FM10K_WRITE_REG(hw, FM10K_TDBAL(vf_q_idx), tdbal); + FM10K_WRITE_REG(hw, FM10K_TDBAH(vf_q_idx), tdbah); + +err_out: + /* configure Queue control register */ + txqctl = ((u32)vf_vid << FM10K_TXQCTL_VID_SHIFT) & + FM10K_TXQCTL_VID_MASK; + txqctl |= (vf_idx << FM10K_TXQCTL_TC_SHIFT) | + FM10K_TXQCTL_VF | vf_idx; + + /* assign VID */ + for (i = 0; i < queues_per_pool; i++) + FM10K_WRITE_REG(hw, FM10K_TXQCTL(vf_q_idx + i), txqctl); + + /* restore the queue back to VF ownership */ + FM10K_WRITE_REG(hw, FM10K_TQMAP(qmap_idx), vf_q_idx); + return err; +} + +/** + * fm10k_iov_reset_resources_pf - Reassign queues and interrupts to a VF + * @hw: pointer to the HW structure + * @vf_info: pointer to VF information structure + * + * Reassign the interrupts and queues to a VF following an FLR + **/ +STATIC s32 fm10k_iov_reset_resources_pf(struct fm10k_hw *hw, + struct fm10k_vf_info *vf_info) +{ + u16 qmap_stride, queues_per_pool, vf_q_idx, qmap_idx; + u32 tdbal = 0, tdbah = 0, txqctl, rxqctl; + u16 vf_v_idx, vf_v_limit, vf_vid; + u8 vf_idx = vf_info->vf_idx; + int i; + + /* verify vf is in range */ + if (vf_idx >= hw->iov.num_vfs) + return FM10K_ERR_PARAM; + + /* clear event notification of VF FLR */ + FM10K_WRITE_REG(hw, FM10K_PFVFLREC(vf_idx / 32), 1 << (vf_idx % 32)); + + /* force timeout and then disconnect the mailbox */ + vf_info->mbx.timeout = 0; + if (vf_info->mbx.ops.disconnect) + vf_info->mbx.ops.disconnect(hw, &vf_info->mbx); + + /* determine vector offset and count */ + vf_v_idx = fm10k_vf_vector_index(hw, vf_idx); + vf_v_limit = vf_v_idx + fm10k_vectors_per_pool(hw); + + /* determine qmap offsets and counts */ + qmap_stride = (hw->iov.num_vfs > 8) ? 32 : 256; + queues_per_pool = fm10k_queues_per_pool(hw); + qmap_idx = qmap_stride * vf_idx; + + /* make all the queues inaccessible to the VF */ + for (i = qmap_idx; i < (qmap_idx + qmap_stride); i++) { + FM10K_WRITE_REG(hw, FM10K_TQMAP(i), 0); + FM10K_WRITE_REG(hw, FM10K_RQMAP(i), 0); + } + + /* calculate starting index for queues */ + vf_q_idx = fm10k_vf_queue_index(hw, vf_idx); + + /* determine correct default VLAN ID */ + if (vf_info->pf_vid) + vf_vid = vf_info->pf_vid; + else + vf_vid = vf_info->sw_vid; + + /* configure Queue control register */ + txqctl = ((u32)vf_vid << FM10K_TXQCTL_VID_SHIFT) | + (vf_idx << FM10K_TXQCTL_TC_SHIFT) | + FM10K_TXQCTL_VF | vf_idx; + rxqctl = FM10K_RXQCTL_VF | (vf_idx << FM10K_RXQCTL_VF_SHIFT); + + /* stop further DMA and reset queue ownership back to VF */ + for (i = vf_q_idx; i < (queues_per_pool + vf_q_idx); i++) { + FM10K_WRITE_REG(hw, FM10K_TXDCTL(i), 0); + FM10K_WRITE_REG(hw, FM10K_TXQCTL(i), txqctl); + FM10K_WRITE_REG(hw, FM10K_RXDCTL(i), + FM10K_RXDCTL_WRITE_BACK_MIN_DELAY | + FM10K_RXDCTL_DROP_ON_EMPTY); + FM10K_WRITE_REG(hw, FM10K_RXQCTL(i), rxqctl); + } + + /* reset TC with -1 credits and no quanta to prevent transmit */ + FM10K_WRITE_REG(hw, FM10K_TC_MAXCREDIT(vf_idx), 0); + FM10K_WRITE_REG(hw, FM10K_TC_RATE(vf_idx), 0); + FM10K_WRITE_REG(hw, FM10K_TC_CREDIT(vf_idx), + FM10K_TC_CREDIT_CREDIT_MASK); + + /* update our first entry in the table based on previous VF */ + if (!vf_idx) + hw->mac.ops.update_int_moderator(hw); + else + hw->iov.ops.assign_int_moderator(hw, vf_idx - 1); + + /* reset linked list so it now includes our active vectors */ + if (vf_idx == (hw->iov.num_vfs - 1)) + FM10K_WRITE_REG(hw, FM10K_ITR2(0), vf_v_idx); + else + FM10K_WRITE_REG(hw, FM10K_ITR2(vf_v_limit), vf_v_idx); + + /* link remaining vectors so that next points to previous */ + for (vf_v_idx++; vf_v_idx < vf_v_limit; vf_v_idx++) + FM10K_WRITE_REG(hw, FM10K_ITR2(vf_v_idx), vf_v_idx - 1); + + /* zero out MBMEM, VLAN_TABLE, RETA, RSSRK, and MRQC registers */ + for (i = FM10K_VFMBMEM_LEN; i--;) + FM10K_WRITE_REG(hw, FM10K_MBMEM_VF(vf_idx, i), 0); + for (i = FM10K_VLAN_TABLE_SIZE; i--;) + FM10K_WRITE_REG(hw, FM10K_VLAN_TABLE(vf_info->vsi, i), 0); + for (i = FM10K_RETA_SIZE; i--;) + FM10K_WRITE_REG(hw, FM10K_RETA(vf_info->vsi, i), 0); + for (i = FM10K_RSSRK_SIZE; i--;) + FM10K_WRITE_REG(hw, FM10K_RSSRK(vf_info->vsi, i), 0); + FM10K_WRITE_REG(hw, FM10K_MRQC(vf_info->vsi), 0); + + /* Update base address registers to contain MAC address */ + if (FM10K_IS_VALID_ETHER_ADDR(vf_info->mac)) { + tdbal = (((u32)vf_info->mac[3]) << 24) | + (((u32)vf_info->mac[4]) << 16) | + (((u32)vf_info->mac[5]) << 8); + tdbah = (((u32)0xFF) << 24) | + (((u32)vf_info->mac[0]) << 16) | + (((u32)vf_info->mac[1]) << 8) | + ((u32)vf_info->mac[2]); + } + + /* map queue pairs back to VF from last to first */ + for (i = queues_per_pool; i--;) { + FM10K_WRITE_REG(hw, FM10K_TDBAL(vf_q_idx + i), tdbal); + FM10K_WRITE_REG(hw, FM10K_TDBAH(vf_q_idx + i), tdbah); + FM10K_WRITE_REG(hw, FM10K_TQMAP(qmap_idx + i), vf_q_idx + i); + FM10K_WRITE_REG(hw, FM10K_RQMAP(qmap_idx + i), vf_q_idx + i); + } + + return FM10K_SUCCESS; +} + +/** + * fm10k_iov_set_lport_pf - Assign and enable a logical port for a given VF + * @hw: pointer to hardware structure + * @vf_info: pointer to VF information structure + * @lport_idx: Logical port offset from the hardware glort + * @flags: Set of capability flags to extend port beyond basic functionality + * + * This function allows enabling a VF port by assigning it a GLORT and + * setting the flags so that it can enable an Rx mode. + **/ +STATIC s32 fm10k_iov_set_lport_pf(struct fm10k_hw *hw, + struct fm10k_vf_info *vf_info, + u16 lport_idx, u8 flags) +{ + u16 glort = (hw->mac.dglort_map + lport_idx) & FM10K_DGLORTMAP_NONE; + + DEBUGFUNC("fm10k_iov_set_lport_state_pf"); + + /* if glort is not valid return error */ + if (!fm10k_glort_valid_pf(hw, glort)) + return FM10K_ERR_PARAM; + + vf_info->vf_flags = flags | FM10K_VF_FLAG_NONE_CAPABLE; + vf_info->glort = glort; + + return FM10K_SUCCESS; +} + +/** + * fm10k_iov_reset_lport_pf - Disable a logical port for a given VF + * @hw: pointer to hardware structure + * @vf_info: pointer to VF information structure + * + * This function disables a VF port by stripping it of a GLORT and + * setting the flags so that it cannot enable any Rx mode. + **/ +STATIC void fm10k_iov_reset_lport_pf(struct fm10k_hw *hw, + struct fm10k_vf_info *vf_info) +{ + u32 msg[1]; + + DEBUGFUNC("fm10k_iov_reset_lport_state_pf"); + + /* need to disable the port if it is already enabled */ + if (FM10K_VF_FLAG_ENABLED(vf_info)) { + /* notify switch that this port has been disabled */ + fm10k_update_lport_state_pf(hw, vf_info->glort, 1, false); + + /* generate port state response to notify VF it is not ready */ + fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE); + vf_info->mbx.ops.enqueue_tx(hw, &vf_info->mbx, msg); + } + + /* clear flags and glort if it exists */ + vf_info->vf_flags = 0; + vf_info->glort = 0; +} + +/** + * fm10k_iov_update_stats_pf - Updates hardware related statistics for VFs + * @hw: pointer to hardware structure + * @q: stats for all queues of a VF + * @vf_idx: index of VF + * + * This function collects queue stats for VFs. + **/ +STATIC void fm10k_iov_update_stats_pf(struct fm10k_hw *hw, + struct fm10k_hw_stats_q *q, + u16 vf_idx) +{ + u32 idx, qpp; + + /* get stats for all of the queues */ + qpp = fm10k_queues_per_pool(hw); + idx = fm10k_vf_queue_index(hw, vf_idx); + fm10k_update_hw_stats_q(hw, q, idx, qpp); +} + +STATIC s32 fm10k_iov_report_timestamp_pf(struct fm10k_hw *hw, + struct fm10k_vf_info *vf_info, + u64 timestamp) +{ + u32 msg[4]; + + /* generate port state response to notify VF it is not ready */ + fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_1588); + fm10k_tlv_attr_put_u64(msg, FM10K_1588_MSG_TIMESTAMP, timestamp); + + return vf_info->mbx.ops.enqueue_tx(hw, &vf_info->mbx, msg); +} + +/** + * fm10k_iov_msg_msix_pf - Message handler for MSI-X request from VF + * @hw: Pointer to hardware structure + * @results: Pointer array to message, results[0] is pointer to message + * @mbx: Pointer to mailbox information structure + * + * This function is a default handler for MSI-X requests from the VF. The + * assumption is that in this case it is acceptable to just directly + * hand off the message from the VF to the underlying shared code. + **/ +s32 fm10k_iov_msg_msix_pf(struct fm10k_hw *hw, u32 **results, + struct fm10k_mbx_info *mbx) +{ + struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx; + u8 vf_idx = vf_info->vf_idx; + + UNREFERENCED_1PARAMETER(results); + DEBUGFUNC("fm10k_iov_msg_msix_pf"); + + return hw->iov.ops.assign_int_moderator(hw, vf_idx); +} + +/** + * fm10k_iov_msg_mac_vlan_pf - Message handler for MAC/VLAN request from VF + * @hw: Pointer to hardware structure + * @results: Pointer array to message, results[0] is pointer to message + * @mbx: Pointer to mailbox information structure + * + * This function is a default handler for MAC/VLAN requests from the VF. + * The assumption is that in this case it is acceptable to just directly + * hand off the message from the VF to the underlying shared code. + **/ +s32 fm10k_iov_msg_mac_vlan_pf(struct fm10k_hw *hw, u32 **results, + struct fm10k_mbx_info *mbx) +{ + struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx; + int err = FM10K_SUCCESS; + u8 mac[ETH_ALEN]; + u32 *result; + u16 vlan; + u32 vid; + + DEBUGFUNC("fm10k_iov_msg_mac_vlan_pf"); + + /* we shouldn't be updating rules on a disabled interface */ + if (!FM10K_VF_FLAG_ENABLED(vf_info)) + err = FM10K_ERR_PARAM; + + if (!err && !!results[FM10K_MAC_VLAN_MSG_VLAN]) { + result = results[FM10K_MAC_VLAN_MSG_VLAN]; + + /* record VLAN id requested */ + err = fm10k_tlv_attr_get_u32(result, &vid); + if (err) + return err; + + /* if VLAN ID is 0, set the default VLAN ID instead of 0 */ + if (!vid || (vid == FM10K_VLAN_CLEAR)) { + if (vf_info->pf_vid) + vid |= vf_info->pf_vid; + else + vid |= vf_info->sw_vid; + } else if (vid != vf_info->pf_vid) { + return FM10K_ERR_PARAM; + } + + /* update VSI info for VF in regards to VLAN table */ + err = hw->mac.ops.update_vlan(hw, vid, vf_info->vsi, + !(vid & FM10K_VLAN_CLEAR)); + } + + if (!err && !!results[FM10K_MAC_VLAN_MSG_MAC]) { + result = results[FM10K_MAC_VLAN_MSG_MAC]; + + /* record unicast MAC address requested */ + err = fm10k_tlv_attr_get_mac_vlan(result, mac, &vlan); + if (err) + return err; + + /* block attempts to set MAC for a locked device */ + if (FM10K_IS_VALID_ETHER_ADDR(vf_info->mac) && + memcmp(mac, vf_info->mac, ETH_ALEN)) + return FM10K_ERR_PARAM; + + /* if VLAN ID is 0, set the default VLAN ID instead of 0 */ + if (!vlan || (vlan == FM10K_VLAN_CLEAR)) { + if (vf_info->pf_vid) + vlan |= vf_info->pf_vid; + else + vlan |= vf_info->sw_vid; + } else if (vf_info->pf_vid) { + return FM10K_ERR_PARAM; + } + + /* notify switch of request for new unicast address */ + err = hw->mac.ops.update_uc_addr(hw, vf_info->glort, mac, vlan, + !(vlan & FM10K_VLAN_CLEAR), 0); + } + + if (!err && !!results[FM10K_MAC_VLAN_MSG_MULTICAST]) { + result = results[FM10K_MAC_VLAN_MSG_MULTICAST]; + + /* record multicast MAC address requested */ + err = fm10k_tlv_attr_get_mac_vlan(result, mac, &vlan); + if (err) + return err; + + /* verify that the VF is allowed to request multicast */ + if (!(vf_info->vf_flags & FM10K_VF_FLAG_MULTI_ENABLED)) + return FM10K_ERR_PARAM; + + /* if VLAN ID is 0, set the default VLAN ID instead of 0 */ + if (!vlan || (vlan == FM10K_VLAN_CLEAR)) { + if (vf_info->pf_vid) + vlan |= vf_info->pf_vid; + else + vlan |= vf_info->sw_vid; + } else if (vf_info->pf_vid) { + return FM10K_ERR_PARAM; + } + + /* notify switch of request for new multicast address */ + err = hw->mac.ops.update_mc_addr(hw, vf_info->glort, mac, + !(vlan & FM10K_VLAN_CLEAR), 0); + } + + return err; +} + +/** + * fm10k_iov_supported_xcast_mode_pf - Determine best match for xcast mode + * @vf_info: VF info structure containing capability flags + * @mode: Requested xcast mode + * + * This function outputs the mode that most closely matches the requested + * mode. If not modes match it will request we disable the port + **/ +STATIC u8 fm10k_iov_supported_xcast_mode_pf(struct fm10k_vf_info *vf_info, + u8 mode) +{ + u8 vf_flags = vf_info->vf_flags; + + /* match up mode to capabilities as best as possible */ + switch (mode) { + case FM10K_XCAST_MODE_PROMISC: + if (vf_flags & FM10K_VF_FLAG_PROMISC_CAPABLE) + return FM10K_XCAST_MODE_PROMISC; + /* fallthough */ + case FM10K_XCAST_MODE_ALLMULTI: + if (vf_flags & FM10K_VF_FLAG_ALLMULTI_CAPABLE) + return FM10K_XCAST_MODE_ALLMULTI; + /* fallthough */ + case FM10K_XCAST_MODE_MULTI: + if (vf_flags & FM10K_VF_FLAG_MULTI_CAPABLE) + return FM10K_XCAST_MODE_MULTI; + /* fallthough */ + case FM10K_XCAST_MODE_NONE: + if (vf_flags & FM10K_VF_FLAG_NONE_CAPABLE) + return FM10K_XCAST_MODE_NONE; + /* fallthough */ + default: + break; + } + + /* disable interface as it should not be able to request any */ + return FM10K_XCAST_MODE_DISABLE; +} + +/** + * fm10k_iov_msg_lport_state_pf - Message handler for port state requests + * @hw: Pointer to hardware structure + * @results: Pointer array to message, results[0] is pointer to message + * @mbx: Pointer to mailbox information structure + * + * This function is a default handler for port state requests. The port + * state requests for now are basic and consist of enabling or disabling + * the port. + **/ +s32 fm10k_iov_msg_lport_state_pf(struct fm10k_hw *hw, u32 **results, + struct fm10k_mbx_info *mbx) +{ + struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx; + u32 *result; + s32 err = FM10K_SUCCESS; + u32 msg[2]; + u8 mode = 0; + + DEBUGFUNC("fm10k_iov_msg_lport_state_pf"); + + /* verify VF is allowed to enable even minimal mode */ + if (!(vf_info->vf_flags & FM10K_VF_FLAG_NONE_CAPABLE)) + return FM10K_ERR_PARAM; + + if (!!results[FM10K_LPORT_STATE_MSG_XCAST_MODE]) { + result = results[FM10K_LPORT_STATE_MSG_XCAST_MODE]; + + /* XCAST mode update requested */ + err = fm10k_tlv_attr_get_u8(result, &mode); + if (err) + return FM10K_ERR_PARAM; + + /* prep for possible demotion depending on capabilities */ + mode = fm10k_iov_supported_xcast_mode_pf(vf_info, mode); + + /* if mode is not currently enabled, enable it */ + if (!(FM10K_VF_FLAG_ENABLED(vf_info) & (1 << mode))) + fm10k_update_xcast_mode_pf(hw, vf_info->glort, mode); + + /* swap mode back to a bit flag */ + mode = FM10K_VF_FLAG_SET_MODE(mode); + } else if (!results[FM10K_LPORT_STATE_MSG_DISABLE]) { + /* need to disable the port if it is already enabled */ + if (FM10K_VF_FLAG_ENABLED(vf_info)) + err = fm10k_update_lport_state_pf(hw, vf_info->glort, + 1, false); + + /* when enabling the port we should reset the rate limiters */ + hw->iov.ops.configure_tc(hw, vf_info->vf_idx, vf_info->rate); + + /* set mode for minimal functionality */ + mode = FM10K_VF_FLAG_SET_MODE_NONE; + + /* generate port state response to notify VF it is ready */ + fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE); + fm10k_tlv_attr_put_bool(msg, FM10K_LPORT_STATE_MSG_READY); + mbx->ops.enqueue_tx(hw, mbx, msg); + } + + /* if enable state toggled note the update */ + if (!err && (!FM10K_VF_FLAG_ENABLED(vf_info) != !mode)) + err = fm10k_update_lport_state_pf(hw, vf_info->glort, 1, + !!mode); + + /* if state change succeeded, then update our stored state */ + mode |= FM10K_VF_FLAG_CAPABLE(vf_info); + if (!err) + vf_info->vf_flags = mode; + + return err; +} + +const struct fm10k_msg_data fm10k_iov_msg_data_pf[] = { + FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test), + FM10K_VF_MSG_MSIX_HANDLER(fm10k_iov_msg_msix_pf), + FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_iov_msg_mac_vlan_pf), + FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_iov_msg_lport_state_pf), + FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error), +}; + +/** + * fm10k_update_stats_hw_pf - Updates hardware related statistics of PF + * @hw: pointer to hardware structure + * @stats: pointer to the stats structure to update + * + * This function collects and aggregates global and per queue hardware + * statistics. + **/ +STATIC void fm10k_update_hw_stats_pf(struct fm10k_hw *hw, + struct fm10k_hw_stats *stats) +{ + u32 timeout, ur, ca, um, xec, vlan_drop, loopback_drop, nodesc_drop; + u32 id, id_prev; + + DEBUGFUNC("fm10k_update_hw_stats_pf"); + + /* Use Tx queue 0 as a canary to detect a reset */ + id = FM10K_READ_REG(hw, FM10K_TXQCTL(0)); + + /* Read Global Statistics */ + do { + timeout = fm10k_read_hw_stats_32b(hw, FM10K_STATS_TIMEOUT, + &stats->timeout); + ur = fm10k_read_hw_stats_32b(hw, FM10K_STATS_UR, &stats->ur); + ca = fm10k_read_hw_stats_32b(hw, FM10K_STATS_CA, &stats->ca); + um = fm10k_read_hw_stats_32b(hw, FM10K_STATS_UM, &stats->um); + xec = fm10k_read_hw_stats_32b(hw, FM10K_STATS_XEC, &stats->xec); + vlan_drop = fm10k_read_hw_stats_32b(hw, FM10K_STATS_VLAN_DROP, + &stats->vlan_drop); + loopback_drop = fm10k_read_hw_stats_32b(hw, + FM10K_STATS_LOOPBACK_DROP, + &stats->loopback_drop); + nodesc_drop = fm10k_read_hw_stats_32b(hw, + FM10K_STATS_NODESC_DROP, + &stats->nodesc_drop); + + /* if value has not changed then we have consistent data */ + id_prev = id; + id = FM10K_READ_REG(hw, FM10K_TXQCTL(0)); + } while ((id ^ id_prev) & FM10K_TXQCTL_ID_MASK); + + /* drop non-ID bits and set VALID ID bit */ + id &= FM10K_TXQCTL_ID_MASK; + id |= FM10K_STAT_VALID; + + /* Update Global Statistics */ + if (stats->stats_idx == id) { + stats->timeout.count += timeout; + stats->ur.count += ur; + stats->ca.count += ca; + stats->um.count += um; + stats->xec.count += xec; + stats->vlan_drop.count += vlan_drop; + stats->loopback_drop.count += loopback_drop; + stats->nodesc_drop.count += nodesc_drop; + } + + /* Update bases and record current PF id */ + fm10k_update_hw_base_32b(&stats->timeout, timeout); + fm10k_update_hw_base_32b(&stats->ur, ur); + fm10k_update_hw_base_32b(&stats->ca, ca); + fm10k_update_hw_base_32b(&stats->um, um); + fm10k_update_hw_base_32b(&stats->xec, xec); + fm10k_update_hw_base_32b(&stats->vlan_drop, vlan_drop); + fm10k_update_hw_base_32b(&stats->loopback_drop, loopback_drop); + fm10k_update_hw_base_32b(&stats->nodesc_drop, nodesc_drop); + stats->stats_idx = id; + + /* Update Queue Statistics */ + fm10k_update_hw_stats_q(hw, stats->q, 0, hw->mac.max_queues); +} + +/** + * fm10k_rebind_hw_stats_pf - Resets base for hardware statistics of PF + * @hw: pointer to hardware structure + * @stats: pointer to the stats structure to update + * + * This function resets the base for global and per queue hardware + * statistics. + **/ +STATIC void fm10k_rebind_hw_stats_pf(struct fm10k_hw *hw, + struct fm10k_hw_stats *stats) +{ + DEBUGFUNC("fm10k_rebind_hw_stats_pf"); + + /* Unbind Global Statistics */ + fm10k_unbind_hw_stats_32b(&stats->timeout); + fm10k_unbind_hw_stats_32b(&stats->ur); + fm10k_unbind_hw_stats_32b(&stats->ca); + fm10k_unbind_hw_stats_32b(&stats->um); + fm10k_unbind_hw_stats_32b(&stats->xec); + fm10k_unbind_hw_stats_32b(&stats->vlan_drop); + fm10k_unbind_hw_stats_32b(&stats->loopback_drop); + fm10k_unbind_hw_stats_32b(&stats->nodesc_drop); + + /* Unbind Queue Statistics */ + fm10k_unbind_hw_stats_q(stats->q, 0, hw->mac.max_queues); + + /* Reinitialize bases for all stats */ + fm10k_update_hw_stats_pf(hw, stats); +} + +/** + * fm10k_set_dma_mask_pf - Configures PhyAddrSpace to limit DMA to system + * @hw: pointer to hardware structure + * @dma_mask: 64 bit DMA mask required for platform + * + * This function sets the PHYADDR.PhyAddrSpace bits for the endpoint in order + * to limit the access to memory beyond what is physically in the system. + **/ +STATIC void fm10k_set_dma_mask_pf(struct fm10k_hw *hw, u64 dma_mask) +{ + /* we need to write the upper 32 bits of DMA mask to PhyAddrSpace */ + u32 phyaddr = (u32)(dma_mask >> 32); + + DEBUGFUNC("fm10k_set_dma_mask_pf"); + + FM10K_WRITE_REG(hw, FM10K_PHYADDR, phyaddr); +} + +/** + * fm10k_get_fault_pf - Record a fault in one of the interface units + * @hw: pointer to hardware structure + * @type: pointer to fault type register offset + * @fault: pointer to memory location to record the fault + * + * Record the fault register contents to the fault data structure and + * clear the entry from the register. + * + * Returns ERR_PARAM if invalid register is specified or no error is present. + **/ +STATIC s32 fm10k_get_fault_pf(struct fm10k_hw *hw, int type, + struct fm10k_fault *fault) +{ + u32 func; + + DEBUGFUNC("fm10k_get_fault_pf"); + + /* verify the fault register is in range and is aligned */ + switch (type) { + case FM10K_PCA_FAULT: + case FM10K_THI_FAULT: + case FM10K_FUM_FAULT: + break; + default: + return FM10K_ERR_PARAM; + } + + /* only service faults that are valid */ + func = FM10K_READ_REG(hw, type + FM10K_FAULT_FUNC); + if (!(func & FM10K_FAULT_FUNC_VALID)) + return FM10K_ERR_PARAM; + + /* read remaining fields */ + fault->address = FM10K_READ_REG(hw, type + FM10K_FAULT_ADDR_HI); + fault->address <<= 32; + fault->address = FM10K_READ_REG(hw, type + FM10K_FAULT_ADDR_LO); + fault->specinfo = FM10K_READ_REG(hw, type + FM10K_FAULT_SPECINFO); + + /* clear valid bit to allow for next error */ + FM10K_WRITE_REG(hw, type + FM10K_FAULT_FUNC, FM10K_FAULT_FUNC_VALID); + + /* Record which function triggered the error */ + if (func & FM10K_FAULT_FUNC_PF) + fault->func = 0; + else + fault->func = 1 + ((func & FM10K_FAULT_FUNC_VF_MASK) >> + FM10K_FAULT_FUNC_VF_SHIFT); + + /* record fault type */ + fault->type = func & FM10K_FAULT_FUNC_TYPE_MASK; + + return FM10K_SUCCESS; +} + +/** + * fm10k_request_lport_map_pf - Request LPORT map from the switch API + * @hw: pointer to hardware structure + * + **/ +STATIC s32 fm10k_request_lport_map_pf(struct fm10k_hw *hw) +{ + struct fm10k_mbx_info *mbx = &hw->mbx; + u32 msg[1]; + + DEBUGFUNC("fm10k_request_lport_pf"); + + /* issue request asking for LPORT map */ + fm10k_tlv_msg_init(msg, FM10K_PF_MSG_ID_LPORT_MAP); + + /* load onto outgoing mailbox */ + return mbx->ops.enqueue_tx(hw, mbx, msg); +} + +/** + * fm10k_get_host_state_pf - Returns the state of the switch and mailbox + * @hw: pointer to hardware structure + * @switch_ready: pointer to boolean value that will record switch state + * + * This funciton will check the DMA_CTRL2 register and mailbox in order + * to determine if the switch is ready for the PF to begin requesting + * addresses and mapping traffic to the local interface. + **/ +STATIC s32 fm10k_get_host_state_pf(struct fm10k_hw *hw, bool *switch_ready) +{ + s32 ret_val = FM10K_SUCCESS; + u32 dma_ctrl2; + + DEBUGFUNC("fm10k_get_host_state_pf"); + + /* verify the switch is ready for interaction */ + dma_ctrl2 = FM10K_READ_REG(hw, FM10K_DMA_CTRL2); + if (!(dma_ctrl2 & FM10K_DMA_CTRL2_SWITCH_READY)) + goto out; + + /* retrieve generic host state info */ + ret_val = fm10k_get_host_state_generic(hw, switch_ready); + if (ret_val) + goto out; + + /* interface cannot receive traffic without logical ports */ + if (hw->mac.dglort_map == FM10K_DGLORTMAP_NONE) + ret_val = fm10k_request_lport_map_pf(hw); + +out: + return ret_val; +} + +/* This structure defines the attibutes to be parsed below */ +const struct fm10k_tlv_attr fm10k_lport_map_msg_attr[] = { + FM10K_TLV_ATTR_U32(FM10K_PF_ATTR_ID_LPORT_MAP), + FM10K_TLV_ATTR_LAST +}; + +/** + * fm10k_msg_lport_map_pf - Message handler for lport_map message from SM + * @hw: Pointer to hardware structure + * @results: pointer array containing parsed data + * @mbx: Pointer to mailbox information structure + * + * This handler configures the lport mapping based on the reply from the + * switch API. + **/ +s32 fm10k_msg_lport_map_pf(struct fm10k_hw *hw, u32 **results, + struct fm10k_mbx_info *mbx) +{ + u16 glort, mask; + u32 dglort_map; + s32 err; + + UNREFERENCED_1PARAMETER(mbx); + DEBUGFUNC("fm10k_msg_lport_map_pf"); + + err = fm10k_tlv_attr_get_u32(results[FM10K_PF_ATTR_ID_LPORT_MAP], + &dglort_map); + if (err) + return err; + + /* extract values out of the header */ + glort = FM10K_MSG_HDR_FIELD_GET(dglort_map, LPORT_MAP_GLORT); + mask = FM10K_MSG_HDR_FIELD_GET(dglort_map, LPORT_MAP_MASK); + + /* verify mask is set and none of the masked bits in glort are set */ + if (!mask || (glort & ~mask)) + return FM10K_ERR_PARAM; + + /* verify the mask is contiguous, and that it is 1's followed by 0's */ + if (((~(mask - 1) & mask) + mask) & FM10K_DGLORTMAP_NONE) + return FM10K_ERR_PARAM; + + /* record the glort, mask, and port count */ + hw->mac.dglort_map = dglort_map; + + return FM10K_SUCCESS; +} + +const struct fm10k_tlv_attr fm10k_update_pvid_msg_attr[] = { + FM10K_TLV_ATTR_U32(FM10K_PF_ATTR_ID_UPDATE_PVID), + FM10K_TLV_ATTR_LAST +}; + +/** + * fm10k_msg_update_pvid_pf - Message handler for port VLAN message from SM + * @hw: Pointer to hardware structure + * @results: pointer array containing parsed data + * @mbx: Pointer to mailbox information structure + * + * This handler configures the default VLAN for the PF + **/ +s32 fm10k_msg_update_pvid_pf(struct fm10k_hw *hw, u32 **results, + struct fm10k_mbx_info *mbx) +{ + u16 glort, pvid; + u32 pvid_update; + s32 err; + + UNREFERENCED_1PARAMETER(mbx); + DEBUGFUNC("fm10k_msg_update_pvid_pf"); + + err = fm10k_tlv_attr_get_u32(results[FM10K_PF_ATTR_ID_UPDATE_PVID], + &pvid_update); + if (err) + return err; + + /* extract values from the pvid update */ + glort = FM10K_MSG_HDR_FIELD_GET(pvid_update, UPDATE_PVID_GLORT); + pvid = FM10K_MSG_HDR_FIELD_GET(pvid_update, UPDATE_PVID_PVID); + + /* if glort is not valid return error */ + if (!fm10k_glort_valid_pf(hw, glort)) + return FM10K_ERR_PARAM; + + /* verify VID is valid */ + if (pvid >= FM10K_VLAN_TABLE_VID_MAX) + return FM10K_ERR_PARAM; + + /* record the port VLAN ID value */ + hw->mac.default_vid = pvid; + + return FM10K_SUCCESS; +} + +/** + * fm10k_record_global_table_data - Move global table data to swapi table info + * @from: pointer to source table data structure + * @to: pointer to destination table info structure + * + * This function is will copy table_data to the table_info contained in + * the hw struct. + **/ +static void fm10k_record_global_table_data(struct fm10k_global_table_data *from, + struct fm10k_swapi_table_info *to) +{ + /* convert from le32 struct to CPU byte ordered values */ + to->used = FM10K_LE32_TO_CPU(from->used); + to->avail = FM10K_LE32_TO_CPU(from->avail); +} + +const struct fm10k_tlv_attr fm10k_err_msg_attr[] = { + FM10K_TLV_ATTR_LE_STRUCT(FM10K_PF_ATTR_ID_ERR, + sizeof(struct fm10k_swapi_error)), + FM10K_TLV_ATTR_LAST +}; + +/** + * fm10k_msg_err_pf - Message handler for error reply + * @hw: Pointer to hardware structure + * @results: pointer array containing parsed data + * @mbx: Pointer to mailbox information structure + * + * This handler will capture the data for any error replies to previous + * messages that the PF has sent. + **/ +s32 fm10k_msg_err_pf(struct fm10k_hw *hw, u32 **results, + struct fm10k_mbx_info *mbx) +{ + struct fm10k_swapi_error err_msg; + s32 err; + + UNREFERENCED_1PARAMETER(mbx); + DEBUGFUNC("fm10k_msg_err_pf"); + + /* extract structure from message */ + err = fm10k_tlv_attr_get_le_struct(results[FM10K_PF_ATTR_ID_ERR], + &err_msg, sizeof(err_msg)); + if (err) + return err; + + /* record table status */ + fm10k_record_global_table_data(&err_msg.mac, &hw->swapi.mac); + fm10k_record_global_table_data(&err_msg.nexthop, &hw->swapi.nexthop); + fm10k_record_global_table_data(&err_msg.ffu, &hw->swapi.ffu); + + /* record SW API status value */ + hw->swapi.status = FM10K_LE32_TO_CPU(err_msg.status); + + return FM10K_SUCCESS; +} + +const struct fm10k_tlv_attr fm10k_1588_timestamp_msg_attr[] = { + FM10K_TLV_ATTR_LE_STRUCT(FM10K_PF_ATTR_ID_1588_TIMESTAMP, + sizeof(struct fm10k_swapi_1588_timestamp)), + FM10K_TLV_ATTR_LAST +}; + +/* currently there is no shared 1588 timestamp handler */ + +/** + * fm10k_request_tx_timestamp_mode_pf - Request a specific Tx timestamping mode + * @hw: pointer to hardware structure + * @glort: base resource tag for this request + * @mode: integer value indicating the requested mode + * + * This function will attempt to request a specific timestamp mode for the + * port so that it can receive Tx timestamp messages. + **/ +STATIC s32 fm10k_request_tx_timestamp_mode_pf(struct fm10k_hw *hw, + u16 glort, + u8 mode) +{ + struct fm10k_mbx_info *mbx = &hw->mbx; + u32 msg[3], timestamp_mode; + + DEBUGFUNC("fm10k_request_timestamp_mode_pf"); + + if (mode > FM10K_TIMESTAMP_MODE_PEP_TO_ANY) + return FM10K_ERR_PARAM; + + /* if glort is not valid return error */ + if (!fm10k_glort_valid_pf(hw, glort)) + return FM10K_ERR_PARAM; + + /* write timestamp mode as a single u32 value, + * lower 16 bits: glort + * upper 16 bits: mode + */ + timestamp_mode = ((u32)mode << 16) | glort; + + /* generate message requesting change to xcast mode */ + fm10k_tlv_msg_init(msg, FM10K_PF_MSG_ID_TX_TIMESTAMP_MODE); + fm10k_tlv_attr_put_u32(msg, FM10K_PF_ATTR_ID_TIMESTAMP_MODE_REQ, timestamp_mode); + + /* load onto outgoing mailbox */ + return mbx->ops.enqueue_tx(hw, mbx, msg); +} + +/** + * fm10k_adjust_systime_pf - Adjust systime frequency + * @hw: pointer to hardware structure + * @ppb: adjustment rate in parts per billion + * + * This function will adjust the SYSTIME_CFG register contained in BAR 4 + * if this function is supported for BAR 4 access. The adjustment amount + * is based on the parts per billion value provided and adjusted to a + * value based on parts per 2^48 clock cycles. + * + * If adjustment is not supported or the requested value is too large + * we will return an error. + **/ +STATIC s32 fm10k_adjust_systime_pf(struct fm10k_hw *hw, s32 ppb) +{ + u64 systime_adjust; + + DEBUGFUNC("fm10k_adjust_systime_vf"); + + /* if sw_addr is not set we don't have switch register access */ + if (!hw->sw_addr) + return ppb ? FM10K_ERR_PARAM : FM10K_SUCCESS; + + /* we must convert the value from parts per billion to parts per + * 2^48 cycles. In addition I have opted to only use the 30 most + * significant bits of the adjustment value as the 8 least + * significant bits are located in another register and represent + * a value significantly less than a part per billion, the result + * of dropping the 8 least significant bits is that the adjustment + * value is effectively multiplied by 2^8 when we write it. + * + * As a result of all this the math for this breaks down as follows: + * ppb / 10^9 == adjust * 2^8 / 2^48 + * If we solve this for adjust, and simplify it comes out as: + * ppb * 2^31 / 5^9 == adjust + */ + systime_adjust = (ppb < 0) ? -ppb : ppb; + systime_adjust <<= 31; + do_div(systime_adjust, 1953125); + + /* verify the requested adjustment value is in range */ + if (systime_adjust > FM10K_SW_SYSTIME_ADJUST_MASK) + return FM10K_ERR_PARAM; + + if (ppb < 0) + systime_adjust |= FM10K_SW_SYSTIME_ADJUST_DIR_NEGATIVE; + + FM10K_WRITE_SW_REG(hw, FM10K_SW_SYSTIME_ADJUST, (u32)systime_adjust); + + return FM10K_SUCCESS; +} + +/** + * fm10k_read_systime_pf - Reads value of systime registers + * @hw: pointer to the hardware structure + * + * Function reads the content of 2 registers, combined to represent a 64 bit + * value measured in nanosecods. In order to guarantee the value is accurate + * we check the 32 most significant bits both before and after reading the + * 32 least significant bits to verify they didn't change as we were reading + * the registers. + **/ +static u64 fm10k_read_systime_pf(struct fm10k_hw *hw) +{ + u32 systime_l, systime_h, systime_tmp; + + systime_h = fm10k_read_reg(hw, FM10K_SYSTIME + 1); + + do { + systime_tmp = systime_h; + systime_l = fm10k_read_reg(hw, FM10K_SYSTIME); + systime_h = fm10k_read_reg(hw, FM10K_SYSTIME + 1); + } while (systime_tmp != systime_h); + + return ((u64)systime_h << 32) | systime_l; +} + +static const struct fm10k_msg_data fm10k_msg_data_pf[] = { + FM10K_PF_MSG_ERR_HANDLER(XCAST_MODES, fm10k_msg_err_pf), + FM10K_PF_MSG_ERR_HANDLER(UPDATE_MAC_FWD_RULE, fm10k_msg_err_pf), + FM10K_PF_MSG_LPORT_MAP_HANDLER(fm10k_msg_lport_map_pf), + FM10K_PF_MSG_ERR_HANDLER(LPORT_CREATE, fm10k_msg_err_pf), + FM10K_PF_MSG_ERR_HANDLER(LPORT_DELETE, fm10k_msg_err_pf), + FM10K_PF_MSG_UPDATE_PVID_HANDLER(fm10k_msg_update_pvid_pf), + FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error), +}; + +/** + * fm10k_init_ops_pf - Inits func ptrs and MAC type + * @hw: pointer to hardware structure + * + * Initialize the function pointers and assign the MAC type for PF. + * Does not touch the hardware. + **/ +s32 fm10k_init_ops_pf(struct fm10k_hw *hw) +{ + struct fm10k_mac_info *mac = &hw->mac; + struct fm10k_iov_info *iov = &hw->iov; + + DEBUGFUNC("fm10k_init_ops_pf"); + + fm10k_init_ops_generic(hw); + + mac->ops.reset_hw = &fm10k_reset_hw_pf; + mac->ops.init_hw = &fm10k_init_hw_pf; + mac->ops.start_hw = &fm10k_start_hw_generic; + mac->ops.stop_hw = &fm10k_stop_hw_generic; + mac->ops.is_slot_appropriate = &fm10k_is_slot_appropriate_pf; + mac->ops.update_vlan = &fm10k_update_vlan_pf; + mac->ops.read_mac_addr = &fm10k_read_mac_addr_pf; + mac->ops.update_uc_addr = &fm10k_update_uc_addr_pf; + mac->ops.update_mc_addr = &fm10k_update_mc_addr_pf; + mac->ops.update_xcast_mode = &fm10k_update_xcast_mode_pf; + mac->ops.update_int_moderator = &fm10k_update_int_moderator_pf; + mac->ops.update_lport_state = &fm10k_update_lport_state_pf; + mac->ops.update_hw_stats = &fm10k_update_hw_stats_pf; + mac->ops.rebind_hw_stats = &fm10k_rebind_hw_stats_pf; + mac->ops.configure_dglort_map = &fm10k_configure_dglort_map_pf; + mac->ops.set_dma_mask = &fm10k_set_dma_mask_pf; + mac->ops.get_fault = &fm10k_get_fault_pf; + mac->ops.get_host_state = &fm10k_get_host_state_pf; + mac->ops.adjust_systime = &fm10k_adjust_systime_pf; + mac->ops.read_systime = &fm10k_read_systime_pf; + mac->ops.request_tx_timestamp_mode = &fm10k_request_tx_timestamp_mode_pf; + + mac->max_msix_vectors = fm10k_get_pcie_msix_count_generic(hw); + + iov->ops.assign_resources = &fm10k_iov_assign_resources_pf; + iov->ops.configure_tc = &fm10k_iov_configure_tc_pf; + iov->ops.assign_int_moderator = &fm10k_iov_assign_int_moderator_pf; + iov->ops.assign_default_mac_vlan = fm10k_iov_assign_default_mac_vlan_pf; + iov->ops.reset_resources = &fm10k_iov_reset_resources_pf; + iov->ops.set_lport = &fm10k_iov_set_lport_pf; + iov->ops.reset_lport = &fm10k_iov_reset_lport_pf; + iov->ops.update_stats = &fm10k_iov_update_stats_pf; + iov->ops.report_timestamp = &fm10k_iov_report_timestamp_pf; + + return fm10k_sm_mbx_init(hw, &hw->mbx, fm10k_msg_data_pf); +} diff --git a/drivers/fm10k/base/fm10k_pf.h b/drivers/fm10k/base/fm10k_pf.h new file mode 100644 index 0000000..f6c290a --- /dev/null +++ b/drivers/fm10k/base/fm10k_pf.h @@ -0,0 +1,155 @@ +/******************************************************************************* + +Copyright (c) 2013 - 2015, 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. + +***************************************************************************/ + +#ifndef _FM10K_PF_H_ +#define _FM10K_PF_H_ + +#include "fm10k_type.h" +#include "fm10k_common.h" + +bool fm10k_glort_valid_pf(struct fm10k_hw *hw, u16 glort); +u16 fm10k_queues_per_pool(struct fm10k_hw *hw); +u16 fm10k_vf_queue_index(struct fm10k_hw *hw, u16 vf_idx); + +enum fm10k_pf_tlv_msg_id_v1 { + FM10K_PF_MSG_ID_TEST = 0x000, /* msg ID reserved */ + FM10K_PF_MSG_ID_XCAST_MODES = 0x001, + FM10K_PF_MSG_ID_UPDATE_MAC_FWD_RULE = 0x002, + FM10K_PF_MSG_ID_LPORT_MAP = 0x100, + FM10K_PF_MSG_ID_LPORT_CREATE = 0x200, + FM10K_PF_MSG_ID_LPORT_DELETE = 0x201, + FM10K_PF_MSG_ID_CONFIG = 0x300, + FM10K_PF_MSG_ID_UPDATE_PVID = 0x400, + FM10K_PF_MSG_ID_CREATE_FLOW_TABLE = 0x501, + FM10K_PF_MSG_ID_DELETE_FLOW_TABLE = 0x502, + FM10K_PF_MSG_ID_UPDATE_FLOW = 0x503, + FM10K_PF_MSG_ID_DELETE_FLOW = 0x504, + FM10K_PF_MSG_ID_SET_FLOW_STATE = 0x505, + FM10K_PF_MSG_ID_GET_1588_INFO = 0x506, + FM10K_PF_MSG_ID_1588_TIMESTAMP = 0x701, + FM10K_PF_MSG_ID_TX_TIMESTAMP_MODE = 0x702, +}; + +enum fm10k_pf_tlv_attr_id_v1 { + FM10K_PF_ATTR_ID_ERR = 0x00, + FM10K_PF_ATTR_ID_LPORT_MAP = 0x01, + FM10K_PF_ATTR_ID_XCAST_MODE = 0x02, + FM10K_PF_ATTR_ID_MAC_UPDATE = 0x03, + FM10K_PF_ATTR_ID_VLAN_UPDATE = 0x04, + FM10K_PF_ATTR_ID_CONFIG = 0x05, + FM10K_PF_ATTR_ID_CREATE_FLOW_TABLE = 0x06, + FM10K_PF_ATTR_ID_DELETE_FLOW_TABLE = 0x07, + FM10K_PF_ATTR_ID_UPDATE_FLOW = 0x08, + FM10K_PF_ATTR_ID_FLOW_STATE = 0x09, + FM10K_PF_ATTR_ID_FLOW_HANDLE = 0x0A, + FM10K_PF_ATTR_ID_DELETE_FLOW = 0x0B, + FM10K_PF_ATTR_ID_PORT = 0x0C, + FM10K_PF_ATTR_ID_UPDATE_PVID = 0x0D, + FM10K_PF_ATTR_ID_1588_TIMESTAMP = 0x10, + FM10K_PF_ATTR_ID_TIMESTAMP_MODE_REQ = 0x11, + FM10K_PF_ATTR_ID_TIMESTAMP_MODE_RESP = 0x12, +}; + +#define FM10K_MSG_LPORT_MAP_GLORT_SHIFT 0 +#define FM10K_MSG_LPORT_MAP_GLORT_SIZE 16 +#define FM10K_MSG_LPORT_MAP_MASK_SHIFT 16 +#define FM10K_MSG_LPORT_MAP_MASK_SIZE 16 + +#define FM10K_MSG_UPDATE_PVID_GLORT_SHIFT 0 +#define FM10K_MSG_UPDATE_PVID_GLORT_SIZE 16 +#define FM10K_MSG_UPDATE_PVID_PVID_SHIFT 16 +#define FM10K_MSG_UPDATE_PVID_PVID_SIZE 16 + +struct fm10k_mac_update { + __le32 mac_lower; + __le16 mac_upper; + __le16 vlan; + __le16 glort; + u8 flags; + u8 action; +}; + +struct fm10k_global_table_data { + __le32 used; + __le32 avail; +}; + +struct fm10k_swapi_error { + __le32 status; + struct fm10k_global_table_data mac; + struct fm10k_global_table_data nexthop; + struct fm10k_global_table_data ffu; +}; + +struct fm10k_swapi_1588_timestamp { + __le64 egress; + __le64 ingress; + __le16 dglort; + __le16 sglort; +}; + +#define FM10K_PF_MSG_LPORT_CREATE_HANDLER(func) \ + FM10K_MSG_HANDLER(FM10K_PF_MSG_ID_LPORT_CREATE, NULL, func) +#define FM10K_PF_MSG_LPORT_DELETE_HANDLER(func) \ + FM10K_MSG_HANDLER(FM10K_PF_MSG_ID_LPORT_DELETE, NULL, func) +s32 fm10k_msg_lport_map_pf(struct fm10k_hw *, u32 **, struct fm10k_mbx_info *); +extern const struct fm10k_tlv_attr fm10k_lport_map_msg_attr[]; +#define FM10K_PF_MSG_LPORT_MAP_HANDLER(func) \ + FM10K_MSG_HANDLER(FM10K_PF_MSG_ID_LPORT_MAP, \ + fm10k_lport_map_msg_attr, func) +s32 fm10k_msg_update_pvid_pf(struct fm10k_hw *, u32 **, + struct fm10k_mbx_info *); +extern const struct fm10k_tlv_attr fm10k_update_pvid_msg_attr[]; +#define FM10K_PF_MSG_UPDATE_PVID_HANDLER(func) \ + FM10K_MSG_HANDLER(FM10K_PF_MSG_ID_UPDATE_PVID, \ + fm10k_update_pvid_msg_attr, func) + +s32 fm10k_msg_err_pf(struct fm10k_hw *, u32 **, struct fm10k_mbx_info *); +extern const struct fm10k_tlv_attr fm10k_err_msg_attr[]; +#define FM10K_PF_MSG_ERR_HANDLER(msg, func) \ + FM10K_MSG_HANDLER(FM10K_PF_MSG_ID_##msg, fm10k_err_msg_attr, func) + +extern const struct fm10k_tlv_attr fm10k_1588_timestamp_msg_attr[]; +#define FM10K_PF_MSG_1588_TIMESTAMP_HANDLER(func) \ + FM10K_MSG_HANDLER(FM10K_PF_MSG_ID_1588_TIMESTAMP, \ + fm10k_1588_timestamp_msg_attr, func) + +s32 fm10k_iov_msg_msix_pf(struct fm10k_hw *, u32 **, struct fm10k_mbx_info *); +s32 fm10k_iov_msg_mac_vlan_pf(struct fm10k_hw *, u32 **, + struct fm10k_mbx_info *); +s32 fm10k_iov_msg_lport_state_pf(struct fm10k_hw *, u32 **, + struct fm10k_mbx_info *); +extern const struct fm10k_msg_data fm10k_iov_msg_data_pf[]; + +s32 fm10k_init_ops_pf(struct fm10k_hw *hw); +#endif /* _FM10K_PF_H */ diff --git a/drivers/fm10k/base/fm10k_tlv.c b/drivers/fm10k/base/fm10k_tlv.c new file mode 100644 index 0000000..1d9d7d8 --- /dev/null +++ b/drivers/fm10k/base/fm10k_tlv.c @@ -0,0 +1,914 @@ +/******************************************************************************* + +Copyright (c) 2013 - 2015, 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. + +***************************************************************************/ + +#include "fm10k_tlv.h" + +/** + * fm10k_tlv_msg_init - Initialize message block for TLV data storage + * @msg: Pointer to message block + * @msg_id: Message ID indicating message type + * + * This function return success if provided with a valid message pointer + **/ +s32 fm10k_tlv_msg_init(u32 *msg, u16 msg_id) +{ + DEBUGFUNC("fm10k_tlv_msg_init"); + + /* verify pointer is not NULL */ + if (!msg) + return FM10K_ERR_PARAM; + + *msg = (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT) | msg_id; + + return FM10K_SUCCESS; +} + +/** + * fm10k_tlv_attr_put_null_string - Place null terminated string on message + * @msg: Pointer to message block + * @attr_id: Attribute ID + * @string: Pointer to string to be stored in attribute + * + * This function will reorder a string to be CPU endian and store it in + * the attribute buffer. It will return success if provided with a valid + * pointers. + **/ +s32 fm10k_tlv_attr_put_null_string(u32 *msg, u16 attr_id, + const unsigned char *string) +{ + u32 attr_data = 0, len = 0; + u32 *attr; + + DEBUGFUNC("fm10k_tlv_attr_put_null_string"); + + /* verify pointers are not NULL */ + if (!string || !msg) + return FM10K_ERR_PARAM; + + attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; + + /* copy string into local variable and then write to msg */ + do { + /* write data to message */ + if (len && !(len % 4)) { + attr[len / 4] = attr_data; + attr_data = 0; + } + + /* record character to offset location */ + attr_data |= (u32)(*string) << (8 * (len % 4)); + len++; + + /* test for NULL and then increment */ + } while (*(string++)); + + /* write last piece of data to message */ + attr[(len + 3) / 4] = attr_data; + + /* record attribute header, update message length */ + len <<= FM10K_TLV_LEN_SHIFT; + attr[0] = len | attr_id; + + /* add header length to length */ + len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; + *msg += FM10K_TLV_LEN_ALIGN(len); + + return FM10K_SUCCESS; +} + +/** + * fm10k_tlv_attr_get_null_string - Get null terminated string from attribute + * @attr: Pointer to attribute + * @string: Pointer to location of destination string + * + * This function pulls the string back out of the attribute and will place + * it in the array pointed by by string. It will return success if provided + * with a valid pointers. + **/ +s32 fm10k_tlv_attr_get_null_string(u32 *attr, unsigned char *string) +{ + u32 len; + + DEBUGFUNC("fm10k_tlv_attr_get_null_string"); + + /* verify pointers are not NULL */ + if (!string || !attr) + return FM10K_ERR_PARAM; + + len = *attr >> FM10K_TLV_LEN_SHIFT; + attr++; + + while (len--) + string[len] = (u8)(attr[len / 4] >> (8 * (len % 4))); + + return FM10K_SUCCESS; +} + +/** + * fm10k_tlv_attr_put_mac_vlan - Store MAC/VLAN attribute in message + * @msg: Pointer to message block + * @attr_id: Attribute ID + * @mac_addr: MAC address to be stored + * + * This function will reorder a MAC address to be CPU endian and store it + * in the attribute buffer. It will return success if provided with a + * valid pointers. + **/ +s32 fm10k_tlv_attr_put_mac_vlan(u32 *msg, u16 attr_id, + const u8 *mac_addr, u16 vlan) +{ + u32 len = ETH_ALEN << FM10K_TLV_LEN_SHIFT; + u32 *attr; + + DEBUGFUNC("fm10k_tlv_attr_put_mac_vlan"); + + /* verify pointers are not NULL */ + if (!msg || !mac_addr) + return FM10K_ERR_PARAM; + + attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; + + /* record attribute header, update message length */ + attr[0] = len | attr_id; + + /* copy value into local variable and then write to msg */ + attr[1] = FM10K_LE32_TO_CPU(*(const __le32 *)&mac_addr[0]); + attr[2] = FM10K_LE16_TO_CPU(*(const __le16 *)&mac_addr[4]); + attr[2] |= (u32)vlan << 16; + + /* add header length to length */ + len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; + *msg += FM10K_TLV_LEN_ALIGN(len); + + return FM10K_SUCCESS; +} + +/** + * fm10k_tlv_attr_get_mac_vlan - Get MAC/VLAN stored in attribute + * @attr: Pointer to attribute + * @attr_id: Attribute ID + * @mac_addr: location of buffer to store MAC address + * + * This function pulls the MAC address back out of the attribute and will + * place it in the array pointed by by mac_addr. It will return success + * if provided with a valid pointers. + **/ +s32 fm10k_tlv_attr_get_mac_vlan(u32 *attr, u8 *mac_addr, u16 *vlan) +{ + DEBUGFUNC("fm10k_tlv_attr_get_mac_vlan"); + + /* verify pointers are not NULL */ + if (!mac_addr || !attr) + return FM10K_ERR_PARAM; + + *(__le32 *)&mac_addr[0] = FM10K_CPU_TO_LE32(attr[1]); + *(__le16 *)&mac_addr[4] = FM10K_CPU_TO_LE16((u16)(attr[2])); + *vlan = (u16)(attr[2] >> 16); + + return FM10K_SUCCESS; +} + +/** + * fm10k_tlv_attr_put_bool - Add header indicating value "true" + * @msg: Pointer to message block + * @attr_id: Attribute ID + * + * This function will simply add an attribute header, the fact + * that the header is here means the attribute value is true, else + * it is false. The function will return success if provided with a + * valid pointers. + **/ +s32 fm10k_tlv_attr_put_bool(u32 *msg, u16 attr_id) +{ + DEBUGFUNC("fm10k_tlv_attr_put_bool"); + + /* verify pointers are not NULL */ + if (!msg) + return FM10K_ERR_PARAM; + + /* record attribute header */ + msg[FM10K_TLV_DWORD_LEN(*msg)] = attr_id; + + /* add header length to length */ + *msg += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; + + return FM10K_SUCCESS; +} + +/** + * fm10k_tlv_attr_put_value - Store integer value attribute in message + * @msg: Pointer to message block + * @attr_id: Attribute ID + * @value: Value to be written + * @len: Size of value + * + * This function will place an integer value of up to 8 bytes in size + * in a message attribute. The function will return success provided + * that msg is a valid pointer, and len is 1, 2, 4, or 8. + **/ +s32 fm10k_tlv_attr_put_value(u32 *msg, u16 attr_id, s64 value, u32 len) +{ + u32 *attr; + + DEBUGFUNC("fm10k_tlv_attr_put_value"); + + /* verify non-null msg and len is 1, 2, 4, or 8 */ + if (!msg || !len || len > 8 || (len & (len - 1))) + return FM10K_ERR_PARAM; + + attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; + + if (len < 4) { + attr[1] = (u32)value & ((0x1ul << (8 * len)) - 1); + } else { + attr[1] = (u32)value; + if (len > 4) + attr[2] = (u32)(value >> 32); + } + + /* record attribute header, update message length */ + len <<= FM10K_TLV_LEN_SHIFT; + attr[0] = len | attr_id; + + /* add header length to length */ + len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; + *msg += FM10K_TLV_LEN_ALIGN(len); + + return FM10K_SUCCESS; +} + +/** + * fm10k_tlv_attr_get_value - Get integer value stored in attribute + * @attr: Pointer to attribute + * @value: Pointer to destination buffer + * @len: Size of value + * + * This function will place an integer value of up to 8 bytes in size + * in the offset pointed to by value. The function will return success + * provided that pointers are valid and the len value matches the + * attribute length. + **/ +s32 fm10k_tlv_attr_get_value(u32 *attr, void *value, u32 len) +{ + DEBUGFUNC("fm10k_tlv_attr_get_value"); + + /* verify pointers are not NULL */ + if (!attr || !value) + return FM10K_ERR_PARAM; + + if ((*attr >> FM10K_TLV_LEN_SHIFT) != len) + return FM10K_ERR_PARAM; + + if (len == 8) + *(u64 *)value = ((u64)attr[2] << 32) | attr[1]; + else if (len == 4) + *(u32 *)value = attr[1]; + else if (len == 2) + *(u16 *)value = (u16)attr[1]; + else + *(u8 *)value = (u8)attr[1]; + + return FM10K_SUCCESS; +} + +/** + * fm10k_tlv_attr_put_le_struct - Store little endian structure in message + * @msg: Pointer to message block + * @attr_id: Attribute ID + * @le_struct: Pointer to structure to be written + * @len: Size of le_struct + * + * This function will place a little endian structure value in a message + * attribute. The function will return success provided that all pointers + * are valid and length is a non-zero multiple of 4. + **/ +s32 fm10k_tlv_attr_put_le_struct(u32 *msg, u16 attr_id, + const void *le_struct, u32 len) +{ + const __le32 *le32_ptr = (const __le32 *)le_struct; + u32 *attr; + u32 i; + + DEBUGFUNC("fm10k_tlv_attr_put_le_struct"); + + /* verify non-null msg and len is in 32 bit words */ + if (!msg || !len || (len % 4)) + return FM10K_ERR_PARAM; + + attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; + + /* copy le32 structure into host byte order at 32b boundaries */ + for (i = 0; i < (len / 4); i++) + attr[i + 1] = FM10K_LE32_TO_CPU(le32_ptr[i]); + + /* record attribute header, update message length */ + len <<= FM10K_TLV_LEN_SHIFT; + attr[0] = len | attr_id; + + /* add header length to length */ + len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; + *msg += FM10K_TLV_LEN_ALIGN(len); + + return FM10K_SUCCESS; +} + +/** + * fm10k_tlv_attr_get_le_struct - Get little endian struct form attribute + * @attr: Pointer to attribute + * @le_struct: Pointer to structure to be written + * @len: Size of structure + * + * This function will place a little endian structure in the buffer + * pointed to by le_struct. The function will return success + * provided that pointers are valid and the len value matches the + * attribute length. + **/ +s32 fm10k_tlv_attr_get_le_struct(u32 *attr, void *le_struct, u32 len) +{ + __le32 *le32_ptr = (__le32 *)le_struct; + u32 i; + + DEBUGFUNC("fm10k_tlv_attr_get_le_struct"); + + /* verify pointers are not NULL */ + if (!le_struct || !attr) + return FM10K_ERR_PARAM; + + if ((*attr >> FM10K_TLV_LEN_SHIFT) != len) + return FM10K_ERR_PARAM; + + attr++; + + for (i = 0; len; i++, len -= 4) + le32_ptr[i] = FM10K_CPU_TO_LE32(attr[i]); + + return FM10K_SUCCESS; +} + +/** + * fm10k_tlv_attr_nest_start - Start a set of nested attributes + * @msg: Pointer to message block + * @attr_id: Attribute ID + * + * This function will mark off a new nested region for encapsulating + * a given set of attributes. The idea is if you wish to place a secondary + * structure within the message this mechanism allows for that. The + * function will return NULL on failure, and a pointer to the start + * of the nested attributes on success. + **/ +u32 *fm10k_tlv_attr_nest_start(u32 *msg, u16 attr_id) +{ + u32 *attr; + + DEBUGFUNC("fm10k_tlv_attr_nest_start"); + + /* verify pointer is not NULL */ + if (!msg) + return NULL; + + attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; + + attr[0] = attr_id; + + /* return pointer to nest header */ + return attr; +} + +/** + * fm10k_tlv_attr_nest_start - Start a set of nested attributes + * @msg: Pointer to message block + * + * This function closes off an existing set of nested attributes. The + * message pointer should be pointing to the parent of the nest. So in + * the case of a nest within the nest this would be the outer nest pointer. + * This function will return success provided all pointers are valid. + **/ +s32 fm10k_tlv_attr_nest_stop(u32 *msg) +{ + u32 *attr; + u32 len; + + DEBUGFUNC("fm10k_tlv_attr_nest_stop"); + + /* verify pointer is not NULL */ + if (!msg) + return FM10K_ERR_PARAM; + + /* locate the nested header and retrieve its length */ + attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; + len = (attr[0] >> FM10K_TLV_LEN_SHIFT) << FM10K_TLV_LEN_SHIFT; + + /* only include nest if data was added to it */ + if (len) { + len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; + *msg += len; + } + + return FM10K_SUCCESS; +} + +/** + * fm10k_tlv_attr_validate - Validate attribute metadata + * @attr: Pointer to attribute + * @tlv_attr: Type and length info for attribute + * + * This function does some basic validation of the input TLV. It + * verifies the length, and in the case of null terminated strings + * it verifies that the last byte is null. The function will + * return FM10K_ERR_PARAM if any attribute is malformed, otherwise + * it returns 0. + **/ +STATIC s32 fm10k_tlv_attr_validate(u32 *attr, + const struct fm10k_tlv_attr *tlv_attr) +{ + u32 attr_id = *attr & FM10K_TLV_ID_MASK; + u16 len = *attr >> FM10K_TLV_LEN_SHIFT; + + DEBUGFUNC("fm10k_tlv_attr_validate"); + + /* verify this is an attribute and not a message */ + if (*attr & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT)) + return FM10K_ERR_PARAM; + + /* search through the list of attributes to find a matching ID */ + while (tlv_attr->id < attr_id) + tlv_attr++; + + /* if didn't find a match then we should exit */ + if (tlv_attr->id != attr_id) + return FM10K_NOT_IMPLEMENTED; + + /* move to start of attribute data */ + attr++; + + switch (tlv_attr->type) { + case FM10K_TLV_NULL_STRING: + if (!len || + (attr[(len - 1) / 4] & (0xFF << (8 * ((len - 1) % 4))))) + return FM10K_ERR_PARAM; + if (len > tlv_attr->len) + return FM10K_ERR_PARAM; + break; + case FM10K_TLV_MAC_ADDR: + if (len != ETH_ALEN) + return FM10K_ERR_PARAM; + break; + case FM10K_TLV_BOOL: + if (len) + return FM10K_ERR_PARAM; + break; + case FM10K_TLV_UNSIGNED: + case FM10K_TLV_SIGNED: + if (len != tlv_attr->len) + return FM10K_ERR_PARAM; + break; + case FM10K_TLV_LE_STRUCT: + /* struct must be 4 byte aligned */ + if ((len % 4) || len != tlv_attr->len) + return FM10K_ERR_PARAM; + break; + case FM10K_TLV_NESTED: + /* nested attributes must be 4 byte aligned */ + if (len % 4) + return FM10K_ERR_PARAM; + break; + default: + /* attribute id is mapped to bad value */ + return FM10K_ERR_PARAM; + } + + return FM10K_SUCCESS; +} + +/** + * fm10k_tlv_attr_parse - Parses stream of attribute data + * @attr: Pointer to attribute list + * @results: Pointer array to store pointers to attributes + * @tlv_attr: Type and length info for attributes + * + * This function validates a stream of attributes and parses them + * up into an array of pointers stored in results. The function will + * return FM10K_ERR_PARAM on any input or message error, + * FM10K_NOT_IMPLEMENTED for any attribute that is outside of the array + * and 0 on success. + **/ +s32 fm10k_tlv_attr_parse(u32 *attr, u32 **results, + const struct fm10k_tlv_attr *tlv_attr) +{ + u32 i, attr_id, offset = 0; + s32 err = 0; + u16 len; + + DEBUGFUNC("fm10k_tlv_attr_parse"); + + /* verify pointers are not NULL */ + if (!attr || !results) + return FM10K_ERR_PARAM; + + /* initialize results to NULL */ + for (i = 0; i < FM10K_TLV_RESULTS_MAX; i++) + results[i] = NULL; + + /* pull length from the message header */ + len = *attr >> FM10K_TLV_LEN_SHIFT; + + /* no attributes to parse if there is no length */ + if (!len) + return FM10K_SUCCESS; + + /* no attributes to parse, just raw data, message becomes attribute */ + if (!tlv_attr) { + results[0] = attr; + return FM10K_SUCCESS; + } + + /* move to start of attribute data */ + attr++; + + /* run through list parsing all attributes */ + while (offset < len) { + attr_id = *attr & FM10K_TLV_ID_MASK; + + if (attr_id < FM10K_TLV_RESULTS_MAX) + err = fm10k_tlv_attr_validate(attr, tlv_attr); + else + err = FM10K_NOT_IMPLEMENTED; + + if (err < 0) + return err; + if (!err) + results[attr_id] = attr; + + /* update offset */ + offset += FM10K_TLV_DWORD_LEN(*attr) * 4; + + /* move to next attribute */ + attr = &attr[FM10K_TLV_DWORD_LEN(*attr)]; + } + + /* we should find ourselves at the end of the list */ + if (offset != len) + return FM10K_ERR_PARAM; + + return FM10K_SUCCESS; +} + +/** + * fm10k_tlv_msg_parse - Parses message header and calls function handler + * @hw: Pointer to hardware structure + * @msg: Pointer to message + * @mbx: Pointer to mailbox information structure + * @func: Function array containing list of message handling functions + * + * This function should be the first function called upon receiving a + * message. The handler will identify the message type and call the correct + * handler for the given message. It will return the value from the function + * call on a recognized message type, otherwise it will return + * FM10K_NOT_IMPLEMENTED on an unrecognized type. + **/ +s32 fm10k_tlv_msg_parse(struct fm10k_hw *hw, u32 *msg, + struct fm10k_mbx_info *mbx, + const struct fm10k_msg_data *data) +{ + u32 *results[FM10K_TLV_RESULTS_MAX]; + u32 msg_id; + s32 err; + + DEBUGFUNC("fm10k_tlv_msg_parse"); + + /* verify pointer is not NULL */ + if (!msg || !data) + return FM10K_ERR_PARAM; + + /* verify this is a message and not an attribute */ + if (!(*msg & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT))) + return FM10K_ERR_PARAM; + + /* grab message ID */ + msg_id = *msg & FM10K_TLV_ID_MASK; + + while (data->id < msg_id) + data++; + + /* if we didn't find it then pass it up as an error */ + if (data->id != msg_id) { + while (data->id != FM10K_TLV_ERROR) + data++; + } + + /* parse the attributes into the results list */ + err = fm10k_tlv_attr_parse(msg, results, data->attr); + if (err < 0) + return err; + + return data->func(hw, results, mbx); +} + +/** + * fm10k_tlv_msg_error - Default handler for unrecognized TLV message IDs + * @hw: Pointer to hardware structure + * @results: Pointer array to message, results[0] is pointer to message + * @mbx: Unused mailbox pointer + * + * This function is a default handler for unrecognized messages. At a + * a minimum it just indicates that the message requested was + * unimplemented. + **/ +s32 fm10k_tlv_msg_error(struct fm10k_hw *hw, u32 **results, + struct fm10k_mbx_info *mbx) +{ + UNREFERENCED_3PARAMETER(hw, results, mbx); + DEBUGOUT1("Unknown message ID %u\n", **results & FM10K_TLV_ID_MASK); + return FM10K_NOT_IMPLEMENTED; +} + +STATIC const unsigned char test_str[] = "fm10k"; +STATIC const unsigned char test_mac[ETH_ALEN] = { 0x12, 0x34, 0x56, + 0x78, 0x9a, 0xbc }; +STATIC const u16 test_vlan = 0x0FED; +STATIC const u64 test_u64 = 0xfedcba9876543210ull; +STATIC const u32 test_u32 = 0x87654321; +STATIC const u16 test_u16 = 0x8765; +STATIC const u8 test_u8 = 0x87; +STATIC const s64 test_s64 = -0x123456789abcdef0ll; +STATIC const s32 test_s32 = -0x1235678; +STATIC const s16 test_s16 = -0x1234; +STATIC const s8 test_s8 = -0x12; +STATIC const __le32 test_le[2] = { FM10K_CPU_TO_LE32(0x12345678), + FM10K_CPU_TO_LE32(0x9abcdef0)}; + +/* The message below is meant to be used as a test message to demonstrate + * how to use the TLV interface and to test the types. Normally this code + * be compiled out by stripping the code wrapped in FM10K_TLV_TEST_MSG + */ +const struct fm10k_tlv_attr fm10k_tlv_msg_test_attr[] = { + FM10K_TLV_ATTR_NULL_STRING(FM10K_TEST_MSG_STRING, 80), + FM10K_TLV_ATTR_MAC_ADDR(FM10K_TEST_MSG_MAC_ADDR), + FM10K_TLV_ATTR_U8(FM10K_TEST_MSG_U8), + FM10K_TLV_ATTR_U16(FM10K_TEST_MSG_U16), + FM10K_TLV_ATTR_U32(FM10K_TEST_MSG_U32), + FM10K_TLV_ATTR_U64(FM10K_TEST_MSG_U64), + FM10K_TLV_ATTR_S8(FM10K_TEST_MSG_S8), + FM10K_TLV_ATTR_S16(FM10K_TEST_MSG_S16), + FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_S32), + FM10K_TLV_ATTR_S64(FM10K_TEST_MSG_S64), + FM10K_TLV_ATTR_LE_STRUCT(FM10K_TEST_MSG_LE_STRUCT, 8), + FM10K_TLV_ATTR_NESTED(FM10K_TEST_MSG_NESTED), + FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_RESULT), + FM10K_TLV_ATTR_LAST +}; + +/** + * fm10k_tlv_msg_test_generate_data - Stuff message with data + * @msg: Pointer to message + * @attr_flags: List of flags indicating what attributes to add + * + * This function is meant to load a message buffer with attribute data + **/ +STATIC void fm10k_tlv_msg_test_generate_data(u32 *msg, u32 attr_flags) +{ + DEBUGFUNC("fm10k_tlv_msg_test_generate_data"); + + if (attr_flags & (1 << FM10K_TEST_MSG_STRING)) + fm10k_tlv_attr_put_null_string(msg, FM10K_TEST_MSG_STRING, + test_str); + if (attr_flags & (1 << FM10K_TEST_MSG_MAC_ADDR)) + fm10k_tlv_attr_put_mac_vlan(msg, FM10K_TEST_MSG_MAC_ADDR, + test_mac, test_vlan); + if (attr_flags & (1 << FM10K_TEST_MSG_U8)) + fm10k_tlv_attr_put_u8(msg, FM10K_TEST_MSG_U8, test_u8); + if (attr_flags & (1 << FM10K_TEST_MSG_U16)) + fm10k_tlv_attr_put_u16(msg, FM10K_TEST_MSG_U16, test_u16); + if (attr_flags & (1 << FM10K_TEST_MSG_U32)) + fm10k_tlv_attr_put_u32(msg, FM10K_TEST_MSG_U32, test_u32); + if (attr_flags & (1 << FM10K_TEST_MSG_U64)) + fm10k_tlv_attr_put_u64(msg, FM10K_TEST_MSG_U64, test_u64); + if (attr_flags & (1 << FM10K_TEST_MSG_S8)) + fm10k_tlv_attr_put_s8(msg, FM10K_TEST_MSG_S8, test_s8); + if (attr_flags & (1 << FM10K_TEST_MSG_S16)) + fm10k_tlv_attr_put_s16(msg, FM10K_TEST_MSG_S16, test_s16); + if (attr_flags & (1 << FM10K_TEST_MSG_S32)) + fm10k_tlv_attr_put_s32(msg, FM10K_TEST_MSG_S32, test_s32); + if (attr_flags & (1 << FM10K_TEST_MSG_S64)) + fm10k_tlv_attr_put_s64(msg, FM10K_TEST_MSG_S64, test_s64); + if (attr_flags & (1 << FM10K_TEST_MSG_LE_STRUCT)) + fm10k_tlv_attr_put_le_struct(msg, FM10K_TEST_MSG_LE_STRUCT, + test_le, 8); +} + +/** + * fm10k_tlv_msg_test_create - Create a test message testing all attributes + * @msg: Pointer to message + * @attr_flags: List of flags indicating what attributes to add + * + * This function is meant to load a message buffer with all attribute types + * including a nested attribute. + **/ +void fm10k_tlv_msg_test_create(u32 *msg, u32 attr_flags) +{ + u32 *nest = NULL; + + DEBUGFUNC("fm10k_tlv_msg_test_create"); + + fm10k_tlv_msg_init(msg, FM10K_TLV_MSG_ID_TEST); + + fm10k_tlv_msg_test_generate_data(msg, attr_flags); + + /* check for nested attributes */ + attr_flags >>= FM10K_TEST_MSG_NESTED; + + if (attr_flags) { + nest = fm10k_tlv_attr_nest_start(msg, FM10K_TEST_MSG_NESTED); + + fm10k_tlv_msg_test_generate_data(nest, attr_flags); + + fm10k_tlv_attr_nest_stop(msg); + } +} + +/** + * fm10k_tlv_msg_test - Validate all results on test message receive + * @hw: Pointer to hardware structure + * @results: Pointer array to attributes in the message + * @mbx: Pointer to mailbox information structure + * + * This function does a check to verify all attributes match what the test + * message placed in the message buffer. It is the default handler + * for TLV test messages. + **/ +s32 fm10k_tlv_msg_test(struct fm10k_hw *hw, u32 **results, + struct fm10k_mbx_info *mbx) +{ + u32 *nest_results[FM10K_TLV_RESULTS_MAX]; + unsigned char result_str[80]; + unsigned char result_mac[ETH_ALEN]; + s32 err = FM10K_SUCCESS; + __le32 result_le[2]; + u16 result_vlan; + u64 result_u64; + u32 result_u32; + u16 result_u16; + u8 result_u8; + s64 result_s64; + s32 result_s32; + s16 result_s16; + s8 result_s8; + u32 reply[3]; + + DEBUGFUNC("fm10k_tlv_msg_test"); + + /* retrieve results of a previous test */ + if (!!results[FM10K_TEST_MSG_RESULT]) + return fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_RESULT], + &mbx->test_result); + +parse_nested: + if (!!results[FM10K_TEST_MSG_STRING]) { + err = fm10k_tlv_attr_get_null_string( + results[FM10K_TEST_MSG_STRING], + result_str); + if (!err && memcmp(test_str, result_str, sizeof(test_str))) + err = FM10K_ERR_INVALID_VALUE; + if (err) + goto report_result; + } + if (!!results[FM10K_TEST_MSG_MAC_ADDR]) { + err = fm10k_tlv_attr_get_mac_vlan( + results[FM10K_TEST_MSG_MAC_ADDR], + result_mac, &result_vlan); + if (!err && memcmp(test_mac, result_mac, ETH_ALEN)) + err = FM10K_ERR_INVALID_VALUE; + if (!err && test_vlan != result_vlan) + err = FM10K_ERR_INVALID_VALUE; + if (err) + goto report_result; + } + if (!!results[FM10K_TEST_MSG_U8]) { + err = fm10k_tlv_attr_get_u8(results[FM10K_TEST_MSG_U8], + &result_u8); + if (!err && test_u8 != result_u8) + err = FM10K_ERR_INVALID_VALUE; + if (err) + goto report_result; + } + if (!!results[FM10K_TEST_MSG_U16]) { + err = fm10k_tlv_attr_get_u16(results[FM10K_TEST_MSG_U16], + &result_u16); + if (!err && test_u16 != result_u16) + err = FM10K_ERR_INVALID_VALUE; + if (err) + goto report_result; + } + if (!!results[FM10K_TEST_MSG_U32]) { + err = fm10k_tlv_attr_get_u32(results[FM10K_TEST_MSG_U32], + &result_u32); + if (!err && test_u32 != result_u32) + err = FM10K_ERR_INVALID_VALUE; + if (err) + goto report_result; + } + if (!!results[FM10K_TEST_MSG_U64]) { + err = fm10k_tlv_attr_get_u64(results[FM10K_TEST_MSG_U64], + &result_u64); + if (!err && test_u64 != result_u64) + err = FM10K_ERR_INVALID_VALUE; + if (err) + goto report_result; + } + if (!!results[FM10K_TEST_MSG_S8]) { + err = fm10k_tlv_attr_get_s8(results[FM10K_TEST_MSG_S8], + &result_s8); + if (!err && test_s8 != result_s8) + err = FM10K_ERR_INVALID_VALUE; + if (err) + goto report_result; + } + if (!!results[FM10K_TEST_MSG_S16]) { + err = fm10k_tlv_attr_get_s16(results[FM10K_TEST_MSG_S16], + &result_s16); + if (!err && test_s16 != result_s16) + err = FM10K_ERR_INVALID_VALUE; + if (err) + goto report_result; + } + if (!!results[FM10K_TEST_MSG_S32]) { + err = fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_S32], + &result_s32); + if (!err && test_s32 != result_s32) + err = FM10K_ERR_INVALID_VALUE; + if (err) + goto report_result; + } + if (!!results[FM10K_TEST_MSG_S64]) { + err = fm10k_tlv_attr_get_s64(results[FM10K_TEST_MSG_S64], + &result_s64); + if (!err && test_s64 != result_s64) + err = FM10K_ERR_INVALID_VALUE; + if (err) + goto report_result; + } + if (!!results[FM10K_TEST_MSG_LE_STRUCT]) { + err = fm10k_tlv_attr_get_le_struct( + results[FM10K_TEST_MSG_LE_STRUCT], + result_le, + sizeof(result_le)); + if (!err && memcmp(test_le, result_le, sizeof(test_le))) + err = FM10K_ERR_INVALID_VALUE; + if (err) + goto report_result; + } + + if (!!results[FM10K_TEST_MSG_NESTED]) { + /* clear any pointers */ + memset(nest_results, 0, sizeof(nest_results)); + + /* parse the nested attributes into the nest results list */ + err = fm10k_tlv_attr_parse(results[FM10K_TEST_MSG_NESTED], + nest_results, + fm10k_tlv_msg_test_attr); + if (err) + goto report_result; + + /* loop back through to the start */ + results = nest_results; + goto parse_nested; + } + +report_result: + /* generate reply with test result */ + fm10k_tlv_msg_init(reply, FM10K_TLV_MSG_ID_TEST); + fm10k_tlv_attr_put_s32(reply, FM10K_TEST_MSG_RESULT, err); + + /* load onto outgoing mailbox */ + return mbx->ops.enqueue_tx(hw, mbx, reply); +} diff --git a/drivers/fm10k/base/fm10k_tlv.h b/drivers/fm10k/base/fm10k_tlv.h new file mode 100644 index 0000000..ad97236 --- /dev/null +++ b/drivers/fm10k/base/fm10k_tlv.h @@ -0,0 +1,199 @@ +/******************************************************************************* + +Copyright (c) 2013 - 2015, 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. + +***************************************************************************/ + +#ifndef _FM10K_TLV_H_ +#define _FM10K_TLV_H_ + +/* forward declaration */ +struct fm10k_msg_data; + +#include "fm10k_type.h" + +/* Message / Argument header format + * 3 2 1 0 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Length | Flags | Type / ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * The message header format described here is used for messages that are + * passed between the PF and the VF. To allow for messages larger then + * mailbox size we will provide a message with the above header and it + * will be segmented and transported to the mailbox to the other side where + * it is reassembled. It contains the following fields: + * Len: Length of the message in bytes excluding the message header + * Flags: TBD + * Rule: These will be the message/argument types we pass + */ +/* message data header */ +#define FM10K_TLV_ID_SHIFT 0 +#define FM10K_TLV_ID_SIZE 16 +#define FM10K_TLV_ID_MASK ((1u << FM10K_TLV_ID_SIZE) - 1) +#define FM10K_TLV_FLAGS_SHIFT 16 +#define FM10K_TLV_FLAGS_MSG 0x1 +#define FM10K_TLV_FLAGS_SIZE 4 +#define FM10K_TLV_LEN_SHIFT 20 +#define FM10K_TLV_LEN_SIZE 12 + +#define FM10K_TLV_HDR_LEN 4ul +#define FM10K_TLV_LEN_ALIGN_MASK \ + ((FM10K_TLV_HDR_LEN - 1) << FM10K_TLV_LEN_SHIFT) +#define FM10K_TLV_LEN_ALIGN(tlv) \ + (((tlv) + FM10K_TLV_LEN_ALIGN_MASK) & ~FM10K_TLV_LEN_ALIGN_MASK) +#define FM10K_TLV_DWORD_LEN(tlv) \ + ((u16)((FM10K_TLV_LEN_ALIGN(tlv)) >> (FM10K_TLV_LEN_SHIFT + 2)) + 1) + +#define FM10K_TLV_RESULTS_MAX 32 + +enum fm10k_tlv_type { + FM10K_TLV_NULL_STRING, + FM10K_TLV_MAC_ADDR, + FM10K_TLV_BOOL, + FM10K_TLV_UNSIGNED, + FM10K_TLV_SIGNED, + FM10K_TLV_LE_STRUCT, + FM10K_TLV_NESTED, + FM10K_TLV_MAX_TYPE +}; + +#define FM10K_TLV_ERROR (~0u) + +struct fm10k_tlv_attr { + unsigned int id; + enum fm10k_tlv_type type; + u16 len; +}; + +#define FM10K_TLV_ATTR_NULL_STRING(id, len) { id, FM10K_TLV_NULL_STRING, len } +#define FM10K_TLV_ATTR_MAC_ADDR(id) { id, FM10K_TLV_MAC_ADDR, 6 } +#define FM10K_TLV_ATTR_BOOL(id) { id, FM10K_TLV_BOOL, 0 } +#define FM10K_TLV_ATTR_U8(id) { id, FM10K_TLV_UNSIGNED, 1 } +#define FM10K_TLV_ATTR_U16(id) { id, FM10K_TLV_UNSIGNED, 2 } +#define FM10K_TLV_ATTR_U32(id) { id, FM10K_TLV_UNSIGNED, 4 } +#define FM10K_TLV_ATTR_U64(id) { id, FM10K_TLV_UNSIGNED, 8 } +#define FM10K_TLV_ATTR_S8(id) { id, FM10K_TLV_SIGNED, 1 } +#define FM10K_TLV_ATTR_S16(id) { id, FM10K_TLV_SIGNED, 2 } +#define FM10K_TLV_ATTR_S32(id) { id, FM10K_TLV_SIGNED, 4 } +#define FM10K_TLV_ATTR_S64(id) { id, FM10K_TLV_SIGNED, 8 } +#define FM10K_TLV_ATTR_LE_STRUCT(id, len) { id, FM10K_TLV_LE_STRUCT, len } +#define FM10K_TLV_ATTR_NESTED(id) { id, FM10K_TLV_NESTED } +#define FM10K_TLV_ATTR_LAST { FM10K_TLV_ERROR } + +struct fm10k_msg_data { + unsigned int id; + const struct fm10k_tlv_attr *attr; + s32 (*func)(struct fm10k_hw *, u32 **, + struct fm10k_mbx_info *); +}; + +#define FM10K_MSG_HANDLER(id, attr, func) { id, attr, func } + +s32 fm10k_tlv_msg_init(u32 *, u16); +s32 fm10k_tlv_attr_put_null_string(u32 *, u16, const unsigned char *); +s32 fm10k_tlv_attr_get_null_string(u32 *, unsigned char *); +s32 fm10k_tlv_attr_put_mac_vlan(u32 *, u16, const u8 *, u16); +s32 fm10k_tlv_attr_get_mac_vlan(u32 *, u8 *, u16 *); +s32 fm10k_tlv_attr_put_bool(u32 *, u16); +s32 fm10k_tlv_attr_put_value(u32 *, u16, s64, u32); +#define fm10k_tlv_attr_put_u8(msg, attr_id, val) \ + fm10k_tlv_attr_put_value(msg, attr_id, val, 1) +#define fm10k_tlv_attr_put_u16(msg, attr_id, val) \ + fm10k_tlv_attr_put_value(msg, attr_id, val, 2) +#define fm10k_tlv_attr_put_u32(msg, attr_id, val) \ + fm10k_tlv_attr_put_value(msg, attr_id, val, 4) +#define fm10k_tlv_attr_put_u64(msg, attr_id, val) \ + fm10k_tlv_attr_put_value(msg, attr_id, val, 8) +#define fm10k_tlv_attr_put_s8(msg, attr_id, val) \ + fm10k_tlv_attr_put_value(msg, attr_id, val, 1) +#define fm10k_tlv_attr_put_s16(msg, attr_id, val) \ + fm10k_tlv_attr_put_value(msg, attr_id, val, 2) +#define fm10k_tlv_attr_put_s32(msg, attr_id, val) \ + fm10k_tlv_attr_put_value(msg, attr_id, val, 4) +#define fm10k_tlv_attr_put_s64(msg, attr_id, val) \ + fm10k_tlv_attr_put_value(msg, attr_id, val, 8) +s32 fm10k_tlv_attr_get_value(u32 *, void *, u32); +#define fm10k_tlv_attr_get_u8(attr, ptr) \ + fm10k_tlv_attr_get_value(attr, ptr, sizeof(u8)) +#define fm10k_tlv_attr_get_u16(attr, ptr) \ + fm10k_tlv_attr_get_value(attr, ptr, sizeof(u16)) +#define fm10k_tlv_attr_get_u32(attr, ptr) \ + fm10k_tlv_attr_get_value(attr, ptr, sizeof(u32)) +#define fm10k_tlv_attr_get_u64(attr, ptr) \ + fm10k_tlv_attr_get_value(attr, ptr, sizeof(u64)) +#define fm10k_tlv_attr_get_s8(attr, ptr) \ + fm10k_tlv_attr_get_value(attr, ptr, sizeof(s8)) +#define fm10k_tlv_attr_get_s16(attr, ptr) \ + fm10k_tlv_attr_get_value(attr, ptr, sizeof(s16)) +#define fm10k_tlv_attr_get_s32(attr, ptr) \ + fm10k_tlv_attr_get_value(attr, ptr, sizeof(s32)) +#define fm10k_tlv_attr_get_s64(attr, ptr) \ + fm10k_tlv_attr_get_value(attr, ptr, sizeof(s64)) +s32 fm10k_tlv_attr_put_le_struct(u32 *, u16, const void *, u32); +s32 fm10k_tlv_attr_get_le_struct(u32 *, void *, u32); +u32 *fm10k_tlv_attr_nest_start(u32 *, u16); +s32 fm10k_tlv_attr_nest_stop(u32 *); +s32 fm10k_tlv_attr_parse(u32 *, u32 **, const struct fm10k_tlv_attr *); +s32 fm10k_tlv_msg_parse(struct fm10k_hw *, u32 *, struct fm10k_mbx_info *, + const struct fm10k_msg_data *); +s32 fm10k_tlv_msg_error(struct fm10k_hw *hw, u32 **results, + struct fm10k_mbx_info *); + +#define FM10K_TLV_MSG_ID_TEST 0 + +enum fm10k_tlv_test_attr_id { + FM10K_TEST_MSG_UNSET, + FM10K_TEST_MSG_STRING, + FM10K_TEST_MSG_MAC_ADDR, + FM10K_TEST_MSG_U8, + FM10K_TEST_MSG_U16, + FM10K_TEST_MSG_U32, + FM10K_TEST_MSG_U64, + FM10K_TEST_MSG_S8, + FM10K_TEST_MSG_S16, + FM10K_TEST_MSG_S32, + FM10K_TEST_MSG_S64, + FM10K_TEST_MSG_LE_STRUCT, + FM10K_TEST_MSG_NESTED, + FM10K_TEST_MSG_RESULT, + FM10K_TEST_MSG_MAX +}; + +extern const struct fm10k_tlv_attr fm10k_tlv_msg_test_attr[]; +void fm10k_tlv_msg_test_create(u32 *, u32); +s32 fm10k_tlv_msg_test(struct fm10k_hw *, u32 **, struct fm10k_mbx_info *); + +#define FM10K_TLV_MSG_TEST_HANDLER(func) \ + FM10K_MSG_HANDLER(FM10K_TLV_MSG_ID_TEST, fm10k_tlv_msg_test_attr, func) +#define FM10K_TLV_MSG_ERROR_HANDLER(func) \ + FM10K_MSG_HANDLER(FM10K_TLV_ERROR, NULL, func) +#endif /* _FM10K_MSG_H_ */ diff --git a/drivers/fm10k/base/fm10k_type.h b/drivers/fm10k/base/fm10k_type.h new file mode 100644 index 0000000..534fab4 --- /dev/null +++ b/drivers/fm10k/base/fm10k_type.h @@ -0,0 +1,937 @@ +/******************************************************************************* + +Copyright (c) 2013 - 2015, 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. + +***************************************************************************/ + +#ifndef _FM10K_TYPE_H_ +#define _FM10K_TYPE_H_ + +/* forward declaration */ +struct fm10k_hw; + +#include "fm10k_osdep.h" +#include "fm10k_mbx.h" + +#define FM10K_INTEL_VENDOR_ID 0x8086 +#define FM10K_DEV_ID_PF 0x15A4 +#define FM10K_DEV_ID_VF 0x15A5 + +#define FM10K_MAX_QUEUES 256 +#define FM10K_MAX_QUEUES_PF 128 +#define FM10K_MAX_QUEUES_POOL 16 + +#define FM10K_48_BIT_MASK 0x0000FFFFFFFFFFFFull +#define FM10K_STAT_VALID 0x80000000 + +/* PCI Bus Info */ +#define FM10K_PCIE_LINK_CAP 0x7C +#define FM10K_PCIE_LINK_STATUS 0x82 +#define FM10K_PCIE_LINK_WIDTH 0x3F0 +#define FM10K_PCIE_LINK_WIDTH_1 0x10 +#define FM10K_PCIE_LINK_WIDTH_2 0x20 +#define FM10K_PCIE_LINK_WIDTH_4 0x40 +#define FM10K_PCIE_LINK_WIDTH_8 0x80 +#define FM10K_PCIE_LINK_SPEED 0xF +#define FM10K_PCIE_LINK_SPEED_2500 0x1 +#define FM10K_PCIE_LINK_SPEED_5000 0x2 +#define FM10K_PCIE_LINK_SPEED_8000 0x3 + +/* PCIe payload size */ +#define FM10K_PCIE_DEV_CAP 0x74 +#define FM10K_PCIE_DEV_CAP_PAYLOAD 0x07 +#define FM10K_PCIE_DEV_CAP_PAYLOAD_128 0x00 +#define FM10K_PCIE_DEV_CAP_PAYLOAD_256 0x01 +#define FM10K_PCIE_DEV_CAP_PAYLOAD_512 0x02 +#define FM10K_PCIE_DEV_CTRL 0x78 +#define FM10K_PCIE_DEV_CTRL_PAYLOAD 0xE0 +#define FM10K_PCIE_DEV_CTRL_PAYLOAD_128 0x00 +#define FM10K_PCIE_DEV_CTRL_PAYLOAD_256 0x20 +#define FM10K_PCIE_DEV_CTRL_PAYLOAD_512 0x40 + +/* PCIe MSI-X Capability info */ +#define FM10K_PCI_MSIX_MSG_CTRL 0xB2 +#define FM10K_PCI_MSIX_MSG_CTRL_TBL_SZ_MASK 0x7FF +#define FM10K_MAX_MSIX_VECTORS 256 +#define FM10K_MAX_VECTORS_PF 256 +#define FM10K_MAX_VECTORS_POOL 32 + +/* PCIe SR-IOV Info */ +#define FM10K_PCIE_SRIOV_CTRL 0x190 +#define FM10K_PCIE_SRIOV_CTRL_VFARI 0x10 + +#define FM10K_SUCCESS 0 +#define FM10K_ERR_DEVICE_NOT_SUPPORTED -1 +#define FM10K_ERR_PARAM -2 +#define FM10K_ERR_NO_RESOURCES -3 +#define FM10K_ERR_REQUESTS_PENDING -4 +#define FM10K_ERR_RESET_REQUESTED -5 +#define FM10K_ERR_DMA_PENDING -6 +#define FM10K_ERR_RESET_FAILED -7 +#define FM10K_ERR_INVALID_MAC_ADDR -8 +#define FM10K_ERR_INVALID_VALUE -9 +#define FM10K_NOT_IMPLEMENTED 0x7FFFFFFF + +#define UNREFERENCED_XPARAMETER +#define UNREFERENCED_1PARAMETER(_p) (_p) +#define UNREFERENCED_2PARAMETER(_p, _q) do { (_p); (_q); } while (0) +#define UNREFERENCED_3PARAMETER(_p, _q, _r) do { (_p); (_q); (_r); } while (0) + +/* Start of PF registers */ +#define FM10K_CTRL 0x0000 +#define FM10K_CTRL_BAR4_ALLOWED 0x00000004 + +#define FM10K_CTRL_EXT 0x0001 +#define FM10K_CTRL_EXT_NS_DIS 0x00000001 +#define FM10K_CTRL_EXT_RO_DIS 0x00000002 +#define FM10K_CTRL_EXT_SWITCH_LOOPBACK 0x00000004 +#define FM10K_EXVET 0x0002 +#define FM10K_EXVET_ETHERTYPE_MASK 0x000000FF +#define FM10K_EXVET_TAG_SIZE_SHIFT 16 +#define FM10K_EXVET_AFTER_VLAN 0x00040000 +#define FM10K_GCR 0x0003 +#define FM10K_FACTPS 0x0004 +#define FM10K_GCR_EXT 0x0005 + +/* Interrupt control registers */ +#define FM10K_EICR 0x0006 +#define FM10K_EICR_PCA_FAULT 0x00000001 +#define FM10K_EICR_THI_FAULT 0x00000004 +#define FM10K_EICR_FUM_FAULT 0x00000020 +#define FM10K_EICR_FAULT_MASK 0x0000003F +#define FM10K_EICR_MAILBOX 0x00000040 +#define FM10K_EICR_SWITCHREADY 0x00000080 +#define FM10K_EICR_SWITCHNOTREADY 0x00000100 +#define FM10K_EICR_SWITCHINTERRUPT 0x00000200 +#define FM10K_EICR_SRAMERROR 0x00000400 +#define FM10K_EICR_VFLR 0x00000800 +#define FM10K_EICR_MAXHOLDTIME 0x00001000 +#define FM10K_EIMR 0x0007 +#define FM10K_EIMR_PCA_FAULT 0x00000001 +#define FM10K_EIMR_THI_FAULT 0x00000010 +#define FM10K_EIMR_FUM_FAULT 0x00000400 +#define FM10K_EIMR_MAILBOX 0x00001000 +#define FM10K_EIMR_SWITCHREADY 0x00004000 +#define FM10K_EIMR_SWITCHNOTREADY 0x00010000 +#define FM10K_EIMR_SWITCHINTERRUPT 0x00040000 +#define FM10K_EIMR_SRAMERROR 0x00100000 +#define FM10K_EIMR_VFLR 0x00400000 +#define FM10K_EIMR_MAXHOLDTIME 0x01000000 +#define FM10K_EIMR_ALL 0x55555555 +#define FM10K_EIMR_DISABLE(NAME) ((FM10K_EIMR_ ## NAME) << 0) +#define FM10K_EIMR_ENABLE(NAME) ((FM10K_EIMR_ ## NAME) << 1) +#define FM10K_FAULT_ADDR_LO 0x0 +#define FM10K_FAULT_ADDR_HI 0x1 +#define FM10K_FAULT_SPECINFO 0x2 +#define FM10K_FAULT_FUNC 0x3 +#define FM10K_FAULT_SIZE 0x4 +#define FM10K_FAULT_FUNC_VALID 0x00008000 +#define FM10K_FAULT_FUNC_PF 0x00004000 +#define FM10K_FAULT_FUNC_VF_MASK 0x00003F00 +#define FM10K_FAULT_FUNC_VF_SHIFT 8 +#define FM10K_FAULT_FUNC_TYPE_MASK 0x000000FF + +#define FM10K_PCA_FAULT 0x0008 +#define FM10K_THI_FAULT 0x0010 +#define FM10K_FUM_FAULT 0x001C + +/* Rx queue timeout indicator */ +#define FM10K_MAXHOLDQ(_n) ((_n) + 0x0020) + +/* Switch Manager info */ +#define FM10K_SM_AREA(_n) ((_n) + 0x0028) + +/* GLORT mapping registers */ +#define FM10K_DGLORTMAP(_n) ((_n) + 0x0030) +#define FM10K_DGLORT_COUNT 8 +#define FM10K_DGLORTMAP_MASK_SHIFT 16 +#define FM10K_DGLORTMAP_ANY 0x00000000 +#define FM10K_DGLORTMAP_NONE 0x0000FFFF +#define FM10K_DGLORTMAP_ZERO 0xFFFF0000 +#define FM10K_DGLORTDEC(_n) ((_n) + 0x0038) +#define FM10K_DGLORTDEC_VSILENGTH_SHIFT 4 +#define FM10K_DGLORTDEC_VSIBASE_SHIFT 7 +#define FM10K_DGLORTDEC_PCLENGTH_SHIFT 14 +#define FM10K_DGLORTDEC_QBASE_SHIFT 16 +#define FM10K_DGLORTDEC_RSSLENGTH_SHIFT 24 +#define FM10K_DGLORTDEC_INNERRSS_ENABLE 0x08000000 +#define FM10K_TUNNEL_CFG 0x0040 +#define FM10K_TUNNEL_CFG_NVGRE_SHIFT 16 +#define FM10K_TUNNEL_CFG_GENEVE 0x0041 +#define FM10K_SWPRI_MAP(_n) ((_n) + 0x0050) +#define FM10K_SWPRI_MAX 16 +#define FM10K_RSSRK(_n, _m) (((_n) * 0x10) + (_m) + 0x0800) +#define FM10K_RSSRK_SIZE 10 +#define FM10K_RSSRK_ENTRIES_PER_REG 4 +#define FM10K_RETA(_n, _m) (((_n) * 0x20) + (_m) + 0x1000) +#define FM10K_RETA_SIZE 32 +#define FM10K_RETA_ENTRIES_PER_REG 4 +#define FM10K_MAX_RSS_INDICES 128 + +/* Rate limiting registers */ +#define FM10K_TC_CREDIT(_n) ((_n) + 0x2000) +#define FM10K_TC_CREDIT_CREDIT_MASK 0x001FFFFF +#define FM10K_TC_MAXCREDIT(_n) ((_n) + 0x2040) +#define FM10K_TC_MAXCREDIT_64K 0x00010000 +#define FM10K_TC_RATE(_n) ((_n) + 0x2080) +#define FM10K_TC_RATE_QUANTA_MASK 0x0000FFFF +#define FM10K_TC_RATE_INTERVAL_4US_GEN1 0x00020000 +#define FM10K_TC_RATE_INTERVAL_4US_GEN2 0x00040000 +#define FM10K_TC_RATE_INTERVAL_4US_GEN3 0x00080000 +#define FM10K_TC_RATE_STATUS 0x20C0 +#define FM10K_PAUSE 0x20C2 + +/* DMA control registers */ +#define FM10K_DMA_CTRL 0x20C3 +#define FM10K_DMA_CTRL_TX_ENABLE 0x00000001 +#define FM10K_DMA_CTRL_TX_HOST_PENDING 0x00000002 +#define FM10K_DMA_CTRL_TX_DATA 0x00000004 +#define FM10K_DMA_CTRL_TX_ACTIVE 0x00000008 +#define FM10K_DMA_CTRL_RX_ENABLE 0x00000010 +#define FM10K_DMA_CTRL_RX_HOST_PENDING 0x00000020 +#define FM10K_DMA_CTRL_RX_DATA 0x00000040 +#define FM10K_DMA_CTRL_RX_ACTIVE 0x00000080 +#define FM10K_DMA_CTRL_RX_DESC_SIZE 0x00000100 +#define FM10K_DMA_CTRL_MINMSS_SHIFT 9 +#define FM10K_DMA_CTRL_MINMSS_64 0x00008000 +#define FM10K_DMA_CTRL_MAX_HOLD_TIME_SHIFT 23 +#define FM10K_DMA_CTRL_MAX_HOLD_1US_GEN3 0x04800000 +#define FM10K_DMA_CTRL_MAX_HOLD_1US_GEN2 0x04000000 +#define FM10K_DMA_CTRL_MAX_HOLD_1US_GEN1 0x03800000 +#define FM10K_DMA_CTRL_DATAPATH_RESET 0x20000000 +#define FM10K_DMA_CTRL_MAXNUMOFQ_MASK 0xC0000000 +#define FM10K_DMA_CTRL_32_DESC 0x00000000 +#define FM10K_DMA_CTRL_64_DESC 0x40000000 +#define FM10K_DMA_CTRL_128_DESC 0x80000000 + +#define FM10K_DMA_CTRL2 0x20C4 +#define FM10K_DMA_CTRL2_TX_FRAME_SPACING_SHIFT 5 +#define FM10K_DMA_CTRL2_SWITCH_READY 0x00002000 +#define FM10K_DMA_CTRL2_RX_DESC_READ_PRIO_SHIFT 14 +#define FM10K_DMA_CTRL2_TX_DESC_READ_PRIO_SHIFT 17 +#define FM10K_DMA_CTRL2_TX_DATA_READ_PRIO_SHIFT 20 + +/* TSO flags configuration + * First packet contains all flags except for fin and psh + * Middle packet contains only urg and ack + * Last packet contains urg, ack, fin, and psh + */ +#define FM10K_TSO_FLAGS_LOW 0x00300FF6 +#define FM10K_TSO_FLAGS_HI 0x00000039 +#define FM10K_DTXTCPFLGL 0x20C5 +#define FM10K_DTXTCPFLGH 0x20C6 + +#define FM10K_TPH_CTRL 0x20C7 +#define FM10K_TPH_CTRL_DISABLE_READ_HINT 0x00000080 +#define FM10K_MRQC(_n) ((_n) + 0x2100) +#define FM10K_MRQC_TCP_IPV4 0x00000001 +#define FM10K_MRQC_IPV4 0x00000002 +#define FM10K_MRQC_IPV6 0x00000010 +#define FM10K_MRQC_TCP_IPV6 0x00000020 +#define FM10K_MRQC_UDP_IPV4 0x00000040 +#define FM10K_MRQC_UDP_IPV6 0x00000080 + +#define FM10K_TQMAP(_n) ((_n) + 0x2800) +#define FM10K_TQMAP_TABLE_SIZE 2048 +#define FM10K_RQMAP(_n) ((_n) + 0x3000) +#define FM10K_RQMAP_TABLE_SIZE 2048 + +/* Hardware Statistics */ +#define FM10K_STATS_TIMEOUT 0x3800 +#define FM10K_STATS_UR 0x3801 +#define FM10K_STATS_CA 0x3802 +#define FM10K_STATS_UM 0x3803 +#define FM10K_STATS_XEC 0x3804 +#define FM10K_STATS_VLAN_DROP 0x3805 +#define FM10K_STATS_LOOPBACK_DROP 0x3806 +#define FM10K_STATS_NODESC_DROP 0x3807 + +/* Timesync registers */ +#define FM10K_RRTIME_CFG 0x3808 +#define FM10K_RRTIME_LIMIT(_n) ((_n) + 0x380C) +#define FM10K_RRTIME_COUNT(_n) ((_n) + 0x3810) +#define FM10K_SYSTIME 0x3814 +#define FM10K_SYSTIME0 0x3816 +#define FM10K_SYSTIME_CFG 0x3818 +#define FM10K_SYSTIME_CFG_STEP_MASK 0x0000000F + +/* PCIe state registers */ +#define FM10K_PFVFBME(_n) ((_n) + 0x381A) +#define FM10K_PHYADDR 0x381C + +/* Rx ring registers */ +#define FM10K_RDBAL(_n) ((0x40 * (_n)) + 0x4000) +#define FM10K_RDBAH(_n) ((0x40 * (_n)) + 0x4001) +#define FM10K_RDLEN(_n) ((0x40 * (_n)) + 0x4002) +#define FM10K_TPH_RXCTRL(_n) ((0x40 * (_n)) + 0x4003) +#define FM10K_TPH_RXCTRL_DESC_TPHEN 0x00000020 +#define FM10K_TPH_RXCTRL_HDR_TPHEN 0x00000040 +#define FM10K_TPH_RXCTRL_DATA_TPHEN 0x00000080 +#define FM10K_TPH_RXCTRL_DESC_RROEN 0x00000200 +#define FM10K_TPH_RXCTRL_DATA_WROEN 0x00002000 +#define FM10K_TPH_RXCTRL_HDR_WROEN 0x00008000 +#define FM10K_RDH(_n) ((0x40 * (_n)) + 0x4004) +#define FM10K_RDT(_n) ((0x40 * (_n)) + 0x4005) +#define FM10K_RXQCTL(_n) ((0x40 * (_n)) + 0x4006) +#define FM10K_RXQCTL_ENABLE 0x00000001 +#define FM10K_RXQCTL_PF 0x000000FC +#define FM10K_RXQCTL_VF_SHIFT 2 +#define FM10K_RXQCTL_VF 0x00000100 +#define FM10K_RXQCTL_ID_MASK (FM10K_RXQCTL_PF | FM10K_RXQCTL_VF) +#define FM10K_RXDCTL(_n) ((0x40 * (_n)) + 0x4007) +#define FM10K_RXDCTL_WRITE_BACK_MIN_DELAY 0x00000001 +#define FM10K_RXDCTL_WRITE_BACK_IMM 0x00000100 +#define FM10K_RXDCTL_DROP_ON_EMPTY 0x00000200 +#define FM10K_RXINT(_n) ((0x40 * (_n)) + 0x4008) +#define FM10K_RXINT_TIMER_SHIFT 8 +#define FM10K_SRRCTL(_n) ((0x40 * (_n)) + 0x4009) +#define FM10K_SRRCTL_BSIZEPKT_SHIFT 8 /* shift _right_ */ +#define FM10K_SRRCTL_BSIZEHDR_SHIFT 2 /* shift _left_ */ +#define FM10K_SRRCTL_BSIZEHDR_MASK 0x00003F00 +#define FM10K_SRRCTL_DESCTYPE_HDR_SPLIT 0x00004000 +#define FM10K_SRRCTL_DESCTYPE_SIZE_SPLIT 0x00008000 +#define FM10K_SRRCTL_PSRTYPE_INNER_TCPHDR 0x00010000 +#define FM10K_SRRCTL_PSRTYPE_INNER_UDPHDR 0x00020000 +#define FM10K_SRRCTL_PSRTYPE_INNER_IPV4HDR 0x00040000 +#define FM10K_SRRCTL_PSRTYPE_INNER_IPV6HDR 0x00080000 +#define FM10K_SRRCTL_PSRTYPE_INNER_L2HDR 0x00100000 +#define FM10K_SRRCTL_PSRTYPE_ENCAPHDR 0x00200000 +#define FM10K_SRRCTL_PSRTYPE_TCPHDR 0x00400000 +#define FM10K_SRRCTL_PSRTYPE_UDPHDR 0x00800000 +#define FM10K_SRRCTL_PSRTYPE_IPV4HDR 0x01000000 +#define FM10K_SRRCTL_PSRTYPE_IPV6HDR 0x02000000 +#define FM10K_SRRCTL_PSRTYPE_L2HDR 0x04000000 +#define FM10K_SRRCTL_LOOPBACK_SUPPRESS 0x40000000 +#define FM10K_SRRCTL_BUFFER_CHAINING_EN 0x80000000 + +/* Rx Statistics */ +#define FM10K_QPRC(_n) ((0x40 * (_n)) + 0x400A) +#define FM10K_QPRDC(_n) ((0x40 * (_n)) + 0x400B) +#define FM10K_QBRC_L(_n) ((0x40 * (_n)) + 0x400C) +#define FM10K_QBRC_H(_n) ((0x40 * (_n)) + 0x400D) + +/* Rx GLORT register */ +#define FM10K_RX_SGLORT(_n) ((0x40 * (_n)) + 0x400E) + +/* Tx ring registers */ +#define FM10K_TDBAL(_n) ((0x40 * (_n)) + 0x8000) +#define FM10K_TDBAH(_n) ((0x40 * (_n)) + 0x8001) +#define FM10K_TDLEN(_n) ((0x40 * (_n)) + 0x8002) +#define FM10K_TPH_TXCTRL(_n) ((0x40 * (_n)) + 0x8003) +#define FM10K_TPH_TXCTRL_DESC_TPHEN 0x00000020 +#define FM10K_TPH_TXCTRL_DESC_RROEN 0x00000200 +#define FM10K_TPH_TXCTRL_DESC_WROEN 0x00000800 +#define FM10K_TPH_TXCTRL_DATA_RROEN 0x00002000 +#define FM10K_TDH(_n) ((0x40 * (_n)) + 0x8004) +#define FM10K_TDT(_n) ((0x40 * (_n)) + 0x8005) +#define FM10K_TXDCTL(_n) ((0x40 * (_n)) + 0x8006) +#define FM10K_TXDCTL_ENABLE 0x00004000 +#define FM10K_TXDCTL_MAX_TIME_SHIFT 16 +#define FM10K_TXDCTL_PUSH_DESC 0x10000000 +#define FM10K_TXQCTL(_n) ((0x40 * (_n)) + 0x8007) +#define FM10K_TXQCTL_PF 0x0000003F +#define FM10K_TXQCTL_VF 0x00000040 +#define FM10K_TXQCTL_ID_MASK (FM10K_TXQCTL_PF | FM10K_TXQCTL_VF) +#define FM10K_TXQCTL_PC_SHIFT 7 +#define FM10K_TXQCTL_PC_MASK 0x00000380 +#define FM10K_TXQCTL_TC_SHIFT 10 +#define FM10K_TXQCTL_TC_MASK 0x0000FC00 +#define FM10K_TXQCTL_VID_SHIFT 16 +#define FM10K_TXQCTL_VID_MASK 0x0FFF0000 +#define FM10K_TXQCTL_UNLIMITED_BW 0x10000000 +#define FM10K_TXQCTL_PUSHMODEDIS 0x20000000 +#define FM10K_TXINT(_n) ((0x40 * (_n)) + 0x8008) +#define FM10K_TXINT_TIMER_SHIFT 8 + +/* Tx Statistics */ +#define FM10K_QPTC(_n) ((0x40 * (_n)) + 0x8009) +#define FM10K_QBTC_L(_n) ((0x40 * (_n)) + 0x800A) +#define FM10K_QBTC_H(_n) ((0x40 * (_n)) + 0x800B) + +/* Tx Push registers */ +#define FM10K_TQDLOC(_n) ((0x40 * (_n)) + 0x800C) +#define FM10K_TQDLOC_BASE_32_DESC 0x08 +#define FM10K_TQDLOC_BASE_64_DESC 0x10 +#define FM10K_TQDLOC_BASE_128_DESC 0x20 +#define FM10K_TQDLOC_SIZE_32_DESC 0x00050000 +#define FM10K_TQDLOC_SIZE_64_DESC 0x00060000 +#define FM10K_TQDLOC_SIZE_128_DESC 0x00070000 +#define FM10K_TQDLOC_SIZE_SHIFT 16 +#define FM10K_TX_DCACHE(_n, _m) ((0x400 * (_n)) + (0x4 * (_m)) + 0x40000) + +/* Tx GLORT registers */ +#define FM10K_TX_SGLORT(_n) ((0x40 * (_n)) + 0x800D) +#define FM10K_PFVTCTL(_n) ((0x40 * (_n)) + 0x800E) +#define FM10K_PFVTCTL_FTAG_DESC_ENABLE 0x00000001 + +/* Interrupt moderation and control registers */ +#define FM10K_PBACL(_n) ((_n) + 0x10000) +#define FM10K_INT_MAP(_n) ((_n) + 0x10080) +#define FM10K_INT_MAP_TIMER0 0x00000000 +#define FM10K_INT_MAP_TIMER1 0x00000100 +#define FM10K_INT_MAP_IMMEDIATE 0x00000200 +#define FM10K_INT_MAP_DISABLE 0x00000300 +#define FM10K_MSIX_VECTOR_ADDR_LO(_n) ((0x4 * (_n)) + 0x11000) +#define FM10K_MSIX_VECTOR_ADDR_HI(_n) ((0x4 * (_n)) + 0x11001) +#define FM10K_MSIX_VECTOR_DATA(_n) ((0x4 * (_n)) + 0x11002) +#define FM10K_MSIX_VECTOR_MASK(_n) ((0x4 * (_n)) + 0x11003) +#define FM10K_INT_CTRL 0x12000 +#define FM10K_INT_CTRL_ENABLEMODERATOR 0x00000400 +#define FM10K_ITR(_n) ((_n) + 0x12400) +#define FM10K_ITR_INTERVAL1_SHIFT 12 +#define FM10K_ITR_TIMER0_EXPIRED 0x01000000 +#define FM10K_ITR_TIMER1_EXPIRED 0x02000000 +#define FM10K_ITR_PENDING0 0x04000000 +#define FM10K_ITR_PENDING1 0x08000000 +#define FM10K_ITR_PENDING2 0x10000000 +#define FM10K_ITR_AUTOMASK 0x20000000 +#define FM10K_ITR_MASK_SET 0x40000000 +#define FM10K_ITR_MASK_CLEAR 0x80000000 +#define FM10K_ITR2(_n) ((0x2 * (_n)) + 0x12800) +#define FM10K_ITR2_LP(_n) ((0x2 * (_n)) + 0x12801) +#define FM10K_ITR_REG_COUNT 768 +#define FM10K_ITR_REG_COUNT_PF 256 + +/* Switch manager interrupt registers */ +#define FM10K_IP 0x13000 +#define FM10K_IP_HOT_RESET 0x00000001 +#define FM10K_IP_DEVICE_STATE_CHANGE 0x00000002 +#define FM10K_IP_MAILBOX 0x00000004 +#define FM10K_IP_VPD_REQUEST 0x00000008 +#define FM10K_IP_SRAMERROR 0x00000010 +#define FM10K_IP_PFLR 0x00000020 +#define FM10K_IP_DATAPATHRESET 0x00000040 +#define FM10K_IP_OUTOFRESET 0x00000080 +#define FM10K_IP_NOTINRESET 0x00000100 +#define FM10K_IP_TIMEOUT 0x00000200 +#define FM10K_IP_VFLR 0x00000400 +#define FM10K_IM 0x13001 +#define FM10K_IB 0x13002 +#define FM10K_SRAM_IP 0x13003 +#define FM10K_SRAM_IM 0x13004 + +/* VLAN registers */ +#define FM10K_VLAN_TABLE(_n, _m) ((0x80 * (_n)) + (_m) + 0x14000) +#define FM10K_VLAN_TABLE_SIZE 128 + +/* VLAN specific message offsets */ +#define FM10K_VLAN_TABLE_VID_MAX 4096 +#define FM10K_VLAN_TABLE_VSI_MAX 64 +#define FM10K_VLAN_LENGTH_SHIFT 16 +#define FM10K_VLAN_CLEAR (1 << 15) +#define FM10K_VLAN_ALL \ + ((FM10K_VLAN_TABLE_VID_MAX - 1) << FM10K_VLAN_LENGTH_SHIFT) + +/* VF FLR event notification registers */ +#define FM10K_PFVFLRE(_n) ((0x1 * (_n)) + 0x18844) +#define FM10K_PFVFLREC(_n) ((0x1 * (_n)) + 0x18846) + +/* Defines for size of uncacheable and write-combining memories */ +#define FM10K_UC_ADDR_START 0x000000 /* start of standard regs */ +#define FM10K_WC_ADDR_START 0x100000 /* start of Tx Desc Cache */ +#define FM10K_DBI_ADDR_START 0x200000 /* start of debug registers */ +#define FM10K_UC_ADDR_SIZE (FM10K_WC_ADDR_START - FM10K_UC_ADDR_START) +#define FM10K_WC_ADDR_SIZE (FM10K_DBI_ADDR_START - FM10K_WC_ADDR_START) + +/* Define timeouts for resets and disables */ +#define FM10K_QUEUE_DISABLE_TIMEOUT 100 +#define FM10K_RESET_TIMEOUT 150 + +/* Maximum supported combined inner and outer header length for encapsulation */ +#define FM10K_TUNNEL_HEADER_LENGTH 184 + +/* VF registers */ +#define FM10K_VFCTRL 0x00000 +#define FM10K_VFCTRL_RST 0x00000008 +#define FM10K_VFINT_MAP 0x00030 +#define FM10K_VFSYSTIME 0x00040 +#define FM10K_VFITR(_n) ((_n) + 0x00060) +#define FM10K_VFPBACL(_n) ((_n) + 0x00008) + +/* Registers contained in BAR 4 for Switch management */ +#define FM10K_SW_SYSTIME_CFG 0x0224C +#define FM10K_SW_SYSTIME_CFG_STEP_SHIFT 4 +#define FM10K_SW_SYSTIME_CFG_ADJUST_MASK 0xFF000000 +#define FM10K_SW_SYSTIME_ADJUST 0x0224D +#define FM10K_SW_SYSTIME_ADJUST_MASK 0x3FFFFFFF +#define FM10K_SW_SYSTIME_ADJUST_DIR_NEGATIVE 0x80000000 +#define FM10K_SW_SYSTIME_PULSE(_n) ((_n) + 0x02252) + +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif /* ETH_ALEN */ + + + + +enum fm10k_int_source { + fm10k_int_Mailbox = 0, + fm10k_int_PCIeFault = 1, + fm10k_int_SwitchUpDown = 2, + fm10k_int_SwitchEvent = 3, + fm10k_int_SRAM = 4, + fm10k_int_VFLR = 5, + fm10k_int_MaxHoldTime = 6, + fm10k_int_sources_max_pf +}; + +/* PCIe bus speeds */ +enum fm10k_bus_speed { + fm10k_bus_speed_unknown = 0, + fm10k_bus_speed_2500 = 2500, + fm10k_bus_speed_5000 = 5000, + fm10k_bus_speed_8000 = 8000, + fm10k_bus_speed_reserved +}; + +/* PCIe bus widths */ +enum fm10k_bus_width { + fm10k_bus_width_unknown = 0, + fm10k_bus_width_pcie_x1 = 1, + fm10k_bus_width_pcie_x2 = 2, + fm10k_bus_width_pcie_x4 = 4, + fm10k_bus_width_pcie_x8 = 8, + fm10k_bus_width_reserved +}; + +/* PCIe payload sizes */ +enum fm10k_bus_payload { + fm10k_bus_payload_unknown = 0, + fm10k_bus_payload_128 = 1, + fm10k_bus_payload_256 = 2, + fm10k_bus_payload_512 = 3, + fm10k_bus_payload_reserved +}; + +/* Bus parameters */ +struct fm10k_bus_info { + enum fm10k_bus_speed speed; + enum fm10k_bus_width width; + enum fm10k_bus_payload payload; +}; + +/* Statistics related declarations */ +struct fm10k_hw_stat { + u64 count; + u32 base_l; + u32 base_h; +}; + +struct fm10k_hw_stats_q { + struct fm10k_hw_stat tx_bytes; + struct fm10k_hw_stat tx_packets; +#define tx_stats_idx tx_packets.base_h + struct fm10k_hw_stat rx_bytes; + struct fm10k_hw_stat rx_packets; +#define rx_stats_idx rx_packets.base_h + struct fm10k_hw_stat rx_drops; +}; + +struct fm10k_hw_stats { + struct fm10k_hw_stat timeout; +#define stats_idx timeout.base_h + struct fm10k_hw_stat ur; + struct fm10k_hw_stat ca; + struct fm10k_hw_stat um; + struct fm10k_hw_stat xec; + struct fm10k_hw_stat vlan_drop; + struct fm10k_hw_stat loopback_drop; + struct fm10k_hw_stat nodesc_drop; + struct fm10k_hw_stats_q q[FM10K_MAX_QUEUES_PF]; +}; + +/* Establish DGLORT feature priority */ +enum fm10k_dglortdec_idx { + fm10k_dglort_default = 0, + fm10k_dglort_vf_rsvd0 = 1, + fm10k_dglort_vf_rss = 2, + fm10k_dglort_pf_rsvd0 = 3, + fm10k_dglort_pf_queue = 4, + fm10k_dglort_pf_vsi = 5, + fm10k_dglort_pf_rsvd1 = 6, + fm10k_dglort_pf_rss = 7 +}; + +struct fm10k_dglort_cfg { + u16 glort; /* GLORT base */ + u16 queue_b; /* Base value for queue */ + u8 vsi_b; /* Base value for VSI */ + u8 idx; /* index of DGLORTDEC entry */ + u8 rss_l; /* RSS indices */ + u8 pc_l; /* Priority Class indices */ + u8 vsi_l; /* Number of bits from GLORT used to determine VSI */ + u8 queue_l; /* Number of bits from GLORT used to determine queue */ + u8 shared_l; /* Ignored bits from GLORT resulting in shared VSI */ + u8 inner_rss; /* Boolean value if inner header is used for RSS */ +}; + +enum fm10k_pca_fault { + PCA_NO_FAULT, + PCA_UNMAPPED_ADDR, + PCA_BAD_QACCESS_PF, + PCA_BAD_QACCESS_VF, + PCA_MALICIOUS_REQ, + PCA_POISONED_TLP, + PCA_TLP_ABORT, + __PCA_MAX +}; + +enum fm10k_thi_fault { + THI_NO_FAULT, + THI_MAL_DIS_Q_FAULT, + __THI_MAX +}; + +enum fm10k_fum_fault { + FUM_NO_FAULT, + FUM_UNMAPPED_ADDR, + FUM_POISONED_TLP, + FUM_BAD_VF_QACCESS, + FUM_ADD_DECODE_ERR, + FUM_RO_ERROR, + FUM_QPRC_CRC_ERROR, + FUM_CSR_TIMEOUT, + FUM_INVALID_TYPE, + FUM_INVALID_LENGTH, + FUM_INVALID_BE, + FUM_INVALID_ALIGN, + __FUM_MAX +}; + +struct fm10k_fault { + u64 address; /* Address at the time fault was detected */ + u32 specinfo; /* Extra info on this fault (fault dependent) */ + u8 type; /* Fault value dependent on subunit */ + u8 func; /* Function number of the fault */ +}; + +struct fm10k_mac_ops { + /* basic bring-up and tear-down */ + s32 (*reset_hw)(struct fm10k_hw *); + s32 (*init_hw)(struct fm10k_hw *); + s32 (*start_hw)(struct fm10k_hw *); + s32 (*stop_hw)(struct fm10k_hw *); + s32 (*get_bus_info)(struct fm10k_hw *); + s32 (*get_host_state)(struct fm10k_hw *, bool *); + bool (*is_slot_appropriate)(struct fm10k_hw *); + s32 (*update_vlan)(struct fm10k_hw *, u32, u8, bool); + s32 (*read_mac_addr)(struct fm10k_hw *); + s32 (*update_uc_addr)(struct fm10k_hw *, u16, const u8 *, + u16, bool, u8); + s32 (*update_mc_addr)(struct fm10k_hw *, u16, const u8 *, u16, bool); + s32 (*update_xcast_mode)(struct fm10k_hw *, u16, u8); + void (*update_int_moderator)(struct fm10k_hw *); + s32 (*update_lport_state)(struct fm10k_hw *, u16, u16, bool); + void (*update_hw_stats)(struct fm10k_hw *, struct fm10k_hw_stats *); + void (*rebind_hw_stats)(struct fm10k_hw *, struct fm10k_hw_stats *); + s32 (*configure_dglort_map)(struct fm10k_hw *, + struct fm10k_dglort_cfg *); + void (*set_dma_mask)(struct fm10k_hw *, u64); + s32 (*get_fault)(struct fm10k_hw *, int, struct fm10k_fault *); + void (*request_lport_map)(struct fm10k_hw *); + s32 (*adjust_systime)(struct fm10k_hw *, s32 ppb); + u64 (*read_systime)(struct fm10k_hw *); + s32 (*request_tx_timestamp_mode)(struct fm10k_hw *, u16, u8); +}; + +enum fm10k_mac_type { + fm10k_mac_unknown = 0, + fm10k_mac_pf, + fm10k_mac_vf, + fm10k_num_macs +}; + +struct fm10k_mac_info { + struct fm10k_mac_ops ops; + enum fm10k_mac_type type; + u8 addr[ETH_ALEN]; + u8 perm_addr[ETH_ALEN]; + u16 default_vid; + u16 max_msix_vectors; + u16 max_queues; + bool vlan_override; + bool get_host_state; + bool tx_ready; + u32 dglort_map; +}; + +struct fm10k_swapi_table_info { + u32 used; + u32 avail; +}; + +struct fm10k_swapi_info { + u32 status; + struct fm10k_swapi_table_info mac; + struct fm10k_swapi_table_info nexthop; + struct fm10k_swapi_table_info ffu; +}; + +enum fm10k_xcast_modes { + FM10K_XCAST_MODE_ALLMULTI = 0, + FM10K_XCAST_MODE_MULTI = 1, + FM10K_XCAST_MODE_PROMISC = 2, + FM10K_XCAST_MODE_NONE = 3, + FM10K_XCAST_MODE_DISABLE = 4 +}; + +enum fm10k_timestamp_modes { + FM10K_TIMESTAMP_MODE_NONE = 0, + FM10K_TIMESTAMP_MODE_PEP_TO_PEP = 1, + FM10K_TIMESTAMP_MODE_PEP_TO_ANY = 2, +}; + +#define FM10K_VF_TC_MAX 100000 /* 100,000 Mb/s aka 100Gb/s */ +#define FM10K_VF_TC_MIN 1 /* 1 Mb/s is the slowest rate */ + +struct fm10k_vf_info { + /* mbx must be first field in struct unless all default IOV message + * handlers are redone as the assumption is that vf_info starts + * at the same offset as the mailbox + */ + struct fm10k_mbx_info mbx; /* PF side of VF mailbox */ + int rate; /* Tx BW cap as defined by OS */ + u16 glort; /* resource tag for this VF */ + u16 sw_vid; /* Switch API assigned VLAN */ + u16 pf_vid; /* PF assigned Default VLAN */ + u8 mac[ETH_ALEN]; /* PF Default MAC address */ + u8 vsi; /* VSI identifier */ + u8 vf_idx; /* which VF this is */ + u8 vf_flags; /* flags indicating what modes + * are supported for the port + */ +}; + +#define FM10K_VF_FLAG_ALLMULTI_CAPABLE ((u8)1 << FM10K_XCAST_MODE_ALLMULTI) +#define FM10K_VF_FLAG_MULTI_CAPABLE ((u8)1 << FM10K_XCAST_MODE_MULTI) +#define FM10K_VF_FLAG_PROMISC_CAPABLE ((u8)1 << FM10K_XCAST_MODE_PROMISC) +#define FM10K_VF_FLAG_NONE_CAPABLE ((u8)1 << FM10K_XCAST_MODE_NONE) +#define FM10K_VF_FLAG_CAPABLE(vf_info) ((vf_info)->vf_flags & (u8)0xF) +#define FM10K_VF_FLAG_ENABLED(vf_info) ((vf_info)->vf_flags >> 4) +#define FM10K_VF_FLAG_SET_MODE(mode) ((u8)0x10 << (mode)) +#define FM10K_VF_FLAG_ENABLED_MODE_SHIFT 4 +#define FM10K_VF_FLAG_SET_MODE_MASK ((u8)0xF0) +#define FM10K_VF_FLAG_SET_MODE_NONE \ + FM10K_VF_FLAG_SET_MODE(FM10K_XCAST_MODE_NONE) +#define FM10K_VF_FLAG_MULTI_ENABLED \ + (FM10K_VF_FLAG_SET_MODE(FM10K_XCAST_MODE_ALLMULTI) | \ + FM10K_VF_FLAG_SET_MODE(FM10K_XCAST_MODE_MULTI) | \ + FM10K_VF_FLAG_SET_MODE(FM10K_XCAST_MODE_PROMISC)) + +struct fm10k_iov_ops { + /* IOV related bring-up and tear-down */ + s32 (*assign_resources)(struct fm10k_hw *, u16, u16); + s32 (*configure_tc)(struct fm10k_hw *, u16, int); + s32 (*assign_int_moderator)(struct fm10k_hw *, u16); + s32 (*assign_default_mac_vlan)(struct fm10k_hw *, + struct fm10k_vf_info *); + s32 (*reset_resources)(struct fm10k_hw *, + struct fm10k_vf_info *); + s32 (*set_lport)(struct fm10k_hw *, struct fm10k_vf_info *, u16, u8); + void (*reset_lport)(struct fm10k_hw *, struct fm10k_vf_info *); + void (*update_stats)(struct fm10k_hw *, struct fm10k_hw_stats_q *, u16); + s32 (*report_timestamp)(struct fm10k_hw *, struct fm10k_vf_info *, u64); +}; + +struct fm10k_iov_info { + struct fm10k_iov_ops ops; + u16 total_vfs; + u16 num_vfs; + u16 num_pools; +}; + +struct fm10k_hw { + u32 *hw_addr; + u32 *sw_addr; + void *back; + struct fm10k_mac_info mac; + struct fm10k_bus_info bus; + struct fm10k_bus_info bus_caps; + struct fm10k_iov_info iov; + struct fm10k_mbx_info mbx; + struct fm10k_swapi_info swapi; + u16 device_id; + u16 vendor_id; + u16 subsystem_device_id; + u16 subsystem_vendor_id; + u8 revision_id; +}; + +/* Number of Transmit and Receive Descriptors must be a multiple of 8 */ +#define FM10K_REQ_TX_DESCRIPTOR_MULTIPLE 8 +#define FM10K_REQ_RX_DESCRIPTOR_MULTIPLE 8 + +/* Transmit Descriptor */ +struct fm10k_tx_desc { + __le64 buffer_addr; /* Address of the descriptor's data buffer */ + __le16 buflen; /* Length of data to be DMAed */ + __le16 vlan; /* VLAN_ID and VPRI to be inserted in FTAG */ + __le16 mss; /* MSS for segmentation offload */ + u8 hdrlen; /* Header size for segmentation offload */ + u8 flags; /* Status and offload request flags */ +}; + +/* Transmit Descriptor Cache Structure */ +struct fm10k_tx_desc_cache { + struct fm10k_tx_desc tx_desc[256]; +}; + +#define FM10K_TXD_FLAG_INT 0x01 +#define FM10K_TXD_FLAG_TIME 0x02 +#define FM10K_TXD_FLAG_CSUM 0x04 +#define FM10K_TXD_FLAG_CSUM2 0x08 +#define FM10K_TXD_FLAG_FTAG 0x10 +#define FM10K_TXD_FLAG_RS 0x20 +#define FM10K_TXD_FLAG_LAST 0x40 +#define FM10K_TXD_FLAG_DONE 0x80 + +#define FM10K_TXD_VLAN_PRI_SHIFT 12 + +/* These macros are meant to enable optimal placement of the RS and INT + * bits. It will point us to the last descriptor in the cache for either the + * start of the packet, or the end of the packet. If the index is actually + * at the start of the FIFO it will point to the offset for the last index + * in the FIFO to prevent an unnecessary write. + */ +#define FM10K_TXD_WB_FIFO_SIZE 4 +#define FM10K_TXD_WB_IDX(idx) \ + (((idx) - 1) | (FM10K_TXD_WB_FIFO_SIZE - 1)) + +/* Receive Descriptor - 32B */ +union fm10k_rx_desc { + struct { + __le64 pkt_addr; /* Packet buffer address */ + __le64 hdr_addr; /* Header buffer address */ + __le64 reserved; /* Empty space, RSS hash */ + __le64 timestamp; + } q; /* Read, Writeback, 64b quad-words */ + struct { + __le32 data; /* RSS and header data */ + __le32 rss; /* RSS Hash */ + __le32 staterr; + __le32 vlan_len; + __le32 glort; /* sglort/dglort */ + } d; /* Writeback, 32b double-words */ + struct { + __le16 pkt_info; /* RSS, Pkt type */ + __le16 hdr_info; /* Splithdr, hdrlen, xC */ + __le16 rss_lower; + __le16 rss_upper; + __le16 status; /* status/error */ + __le16 csum_err; /* checksum or extended error value */ + __le16 length; /* Packet length */ + __le16 vlan; /* VLAN tag */ + __le16 dglort; + __le16 sglort; + } w; /* Writeback, 16b words */ +}; + +#define FM10K_RXD_RSSTYPE_MASK 0x000F +enum fm10k_rdesc_rss_type { + FM10K_RSSTYPE_NONE = 0x0, + FM10K_RSSTYPE_IPV4_TCP = 0x1, + FM10K_RSSTYPE_IPV4 = 0x2, + FM10K_RSSTYPE_IPV6_TCP = 0x3, + /* Reserved 0x4 */ + FM10K_RSSTYPE_IPV6 = 0x5, + /* Reserved 0x6 */ + FM10K_RSSTYPE_IPV4_UDP = 0x7, + FM10K_RSSTYPE_IPV6_UDP = 0x8 + /* Reserved 0x9 - 0xF */ +}; + +#define FM10K_RXD_PKTTYPE_MASK 0x03F0 +#define FM10K_RXD_PKTTYPE_MASK_L3 0x0070 +#define FM10K_RXD_PKTTYPE_MASK_L4 0x0380 +#define FM10K_RXD_PKTTYPE_SHIFT 4 +#define FM10K_RXD_PKTTYPE_INNER_MASK_L3 0x1C00 +#define FM10K_RXD_PKTTYPE_INNER_MASK_L4 0xE000 +#define FM10K_RXD_PKTTYPE_INNER_SHIFT 10 +enum fm10k_rdesc_pkt_type { + /* L3 type */ + FM10K_PKTTYPE_OTHER = 0x00, + FM10K_PKTTYPE_IPV4 = 0x01, + FM10K_PKTTYPE_IPV4_EX = 0x02, + FM10K_PKTTYPE_IPV6 = 0x03, + FM10K_PKTTYPE_IPV6_EX = 0x04, + + /* L4 type */ + FM10K_PKTTYPE_TCP = 0x08, + FM10K_PKTTYPE_UDP = 0x10, + FM10K_PKTTYPE_GRE = 0x18, + FM10K_PKTTYPE_VXLAN = 0x20, + FM10K_PKTTYPE_NVGRE = 0x28, + FM10K_PKTTYPE_GENEVE = 0x30 +}; + +#define FM10K_RXD_HDR_INFO_XC_MASK 0x0006 +enum fm10k_rxdesc_xc { + FM10K_XC_UNICAST = 0x0, + FM10K_XC_MULTICAST = 0x4, + FM10K_XC_BROADCAST = 0x6 +}; + +#define FM10K_RXD_HDR_INFO_LEN_SHIFT 5 +#define FM10K_RXD_HDR_INFO_SPH 0x8000 + +#define FM10K_RXD_STATUS_DD 0x0001 /* Descriptor done */ +#define FM10K_RXD_STATUS_EOP 0x0002 /* End of packet */ +#define FM10K_RXD_STATUS_VEXT 0x0004 /* A VLAN tag is present */ +#define FM10K_RXD_STATUS_IPCS 0x0008 /* Indicates IPv4 csum */ +#define FM10K_RXD_STATUS_L4CS 0x0010 /* Indicates an L4 csum */ +#define FM10K_RXD_STATUS_IPCS2 0x0020 /* Inner header IPv4 csum */ +#define FM10K_RXD_STATUS_L4CS2 0x0040 /* Inner header L4 csum */ +#define FM10K_RXD_STATUS_IPFRAG_MASK 0x0180 /* Fragment mask */ +#define FM10K_RXD_STATUS_IPFRAG_CSUM 0x0100 /* Fragment w/ CSUM field */ +#define FM10K_RXD_STATUS_VEXT2 0x0200 /* A custom tag is present */ +#define FM10K_RXD_STATUS_HBO 0x0400 /* header buffer overrun */ +#define FM10K_RXD_STATUS_L4E2 0x0800 /* Inner header L4 csum err */ +#define FM10K_RXD_STATUS_IPE2 0x1000 /* Inner header IPv4 csum err */ +#define FM10K_RXD_STATUS_RXE 0x2000 /* Generic Rx error */ +#define FM10K_RXD_STATUS_L4E 0x4000 /* L4 csum error */ +#define FM10K_RXD_STATUS_IPE 0x8000 /* IPv4 csum error */ + +#define FM10K_RXD_ERR_SWITCH_ERROR 0x0001 /* Switch found bad packet */ +#define FM10K_RXD_ERR_NO_DESCRIPTOR 0x0002 /* No descriptor available */ +#define FM10K_RXD_ERR_PP_ERROR 0x0004 /* RAM error during processing */ +#define FM10K_RXD_ERR_SWITCH_READY 0x0008 /* Link transition mid-packet */ +#define FM10K_RXD_ERR_TOO_BIG 0x0010 /* Pkt too big for single buf */ + +#define FM10K_RXD_VLAN_ID_MASK 0x0FFF +#define FM10K_RXD_VLAN_PRI_SHIFT FM10K_TXD_VLAN_PRI_SHIFT + +struct fm10k_ftag { + __be16 swpri_type_user; + __be16 vlan; + __be16 sglort; + __be16 dglort; +}; + +#endif /* _FM10K_TYPE_H */ diff --git a/drivers/fm10k/base/fm10k_vf.c b/drivers/fm10k/base/fm10k_vf.c new file mode 100644 index 0000000..2246688 --- /dev/null +++ b/drivers/fm10k/base/fm10k_vf.c @@ -0,0 +1,641 @@ +/******************************************************************************* + +Copyright (c) 2013 - 2015, 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. + +***************************************************************************/ + +#include "fm10k_vf.h" + +/** + * fm10k_stop_hw_vf - Stop Tx/Rx units + * @hw: pointer to hardware structure + * + **/ +STATIC s32 fm10k_stop_hw_vf(struct fm10k_hw *hw) +{ + u8 *perm_addr = hw->mac.perm_addr; + u32 bal = 0, bah = 0; + s32 err; + u16 i; + + DEBUGFUNC("fm10k_stop_hw_vf"); + + /* we need to disable the queues before taking further steps */ + err = fm10k_stop_hw_generic(hw); + if (err) + return err; + + /* If permanent address is set then we need to restore it */ + if (FM10K_IS_VALID_ETHER_ADDR(perm_addr)) { + bal = (((u32)perm_addr[3]) << 24) | + (((u32)perm_addr[4]) << 16) | + (((u32)perm_addr[5]) << 8); + bah = (((u32)0xFF) << 24) | + (((u32)perm_addr[0]) << 16) | + (((u32)perm_addr[1]) << 8) | + ((u32)perm_addr[2]); + } + + /* The queues have already been disabled so we just need to + * update their base address registers + */ + for (i = 0; i < hw->mac.max_queues; i++) { + FM10K_WRITE_REG(hw, FM10K_TDBAL(i), bal); + FM10K_WRITE_REG(hw, FM10K_TDBAH(i), bah); + FM10K_WRITE_REG(hw, FM10K_RDBAL(i), bal); + FM10K_WRITE_REG(hw, FM10K_RDBAH(i), bah); + } + + return FM10K_SUCCESS; +} + +/** + * fm10k_reset_hw_vf - VF hardware reset + * @hw: pointer to hardware structure + * + * This function should return the hardware to a state similar to the + * one it is in after just being initialized. + **/ +STATIC s32 fm10k_reset_hw_vf(struct fm10k_hw *hw) +{ + s32 err; + + DEBUGFUNC("fm10k_reset_hw_vf"); + + /* shut down queues we own and reset DMA configuration */ + err = fm10k_stop_hw_vf(hw); + if (err) + return err; + + /* Inititate VF reset */ + FM10K_WRITE_REG(hw, FM10K_VFCTRL, FM10K_VFCTRL_RST); + + /* Flush write and allow 100us for reset to complete */ + FM10K_WRITE_FLUSH(hw); + usec_delay(FM10K_RESET_TIMEOUT); + + /* Clear reset bit and verify it was cleared */ + FM10K_WRITE_REG(hw, FM10K_VFCTRL, 0); + if (FM10K_READ_REG(hw, FM10K_VFCTRL) & FM10K_VFCTRL_RST) + err = FM10K_ERR_RESET_FAILED; + + return err; +} + +/** + * fm10k_init_hw_vf - VF hardware initialization + * @hw: pointer to hardware structure + * + **/ +STATIC s32 fm10k_init_hw_vf(struct fm10k_hw *hw) +{ + u32 tqdloc, tqdloc0 = ~FM10K_READ_REG(hw, FM10K_TQDLOC(0)); + s32 err; + u16 i; + + DEBUGFUNC("fm10k_init_hw_vf"); + + /* assume we always have at least 1 queue */ + for (i = 1; tqdloc0 && (i < FM10K_MAX_QUEUES_POOL); i++) { + /* verify the Descriptor cache offsets are increasing */ + tqdloc = ~FM10K_READ_REG(hw, FM10K_TQDLOC(i)); + if (!tqdloc || (tqdloc == tqdloc0)) + break; + + /* check to verify the PF doesn't own any of our queues */ + if (!~FM10K_READ_REG(hw, FM10K_TXQCTL(i)) || + !~FM10K_READ_REG(hw, FM10K_RXQCTL(i))) + break; + } + + /* shut down queues we own and reset DMA configuration */ + err = fm10k_disable_queues_generic(hw, i); + if (err) + return err; + + /* record maximum queue count */ + hw->mac.max_queues = i; + + /* fetch default VLAN */ + hw->mac.default_vid = (FM10K_READ_REG(hw, FM10K_TXQCTL(0)) & + FM10K_TXQCTL_VID_MASK) >> FM10K_TXQCTL_VID_SHIFT; + + return FM10K_SUCCESS; +} + +/** + * fm10k_is_slot_appropriate_vf - Indicate appropriate slot for this SKU + * @hw: pointer to hardware structure + * + * Looks at the PCIe bus info to confirm whether or not this slot can support + * the necessary bandwidth for this device. Since the VF has no control over + * the "slot" it is in, always indicate that the slot is appropriate. + **/ +STATIC bool fm10k_is_slot_appropriate_vf(struct fm10k_hw *hw) +{ + UNREFERENCED_1PARAMETER(hw); + DEBUGFUNC("fm10k_is_slot_appropriate_vf"); + + return TRUE; +} + +/* This structure defines the attibutes to be parsed below */ +const struct fm10k_tlv_attr fm10k_mac_vlan_msg_attr[] = { + FM10K_TLV_ATTR_U32(FM10K_MAC_VLAN_MSG_VLAN), + FM10K_TLV_ATTR_BOOL(FM10K_MAC_VLAN_MSG_SET), + FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_MAC), + FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_DEFAULT_MAC), + FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_MULTICAST), + FM10K_TLV_ATTR_LAST +}; + +/** + * fm10k_update_vlan_vf - Update status of VLAN ID in VLAN filter table + * @hw: pointer to hardware structure + * @vid: VLAN ID to add to table + * @vsi: Reserved, should always be 0 + * @set: Indicates if this is a set or clear operation + * + * This function adds or removes the corresponding VLAN ID from the VLAN + * filter table for this VF. + **/ +STATIC s32 fm10k_update_vlan_vf(struct fm10k_hw *hw, u32 vid, u8 vsi, bool set) +{ + struct fm10k_mbx_info *mbx = &hw->mbx; + u32 msg[4]; + + /* verify the index is not set */ + if (vsi) + return FM10K_ERR_PARAM; + + /* verify upper 4 bits of vid and length are 0 */ + if ((vid << 16 | vid) >> 28) + return FM10K_ERR_PARAM; + + /* encode set bit into the VLAN ID */ + if (!set) + vid |= FM10K_VLAN_CLEAR; + + /* generate VLAN request */ + fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN); + fm10k_tlv_attr_put_u32(msg, FM10K_MAC_VLAN_MSG_VLAN, vid); + + /* load onto outgoing mailbox */ + return mbx->ops.enqueue_tx(hw, mbx, msg); +} + +/** + * fm10k_msg_mac_vlan_vf - Read device MAC address from mailbox message + * @hw: pointer to the HW structure + * @results: Attributes for message + * @mbx: unused mailbox data + * + * This function should determine the MAC address for the VF + **/ +s32 fm10k_msg_mac_vlan_vf(struct fm10k_hw *hw, u32 **results, + struct fm10k_mbx_info *mbx) +{ + u8 perm_addr[ETH_ALEN]; + u16 vid; + s32 err; + + UNREFERENCED_1PARAMETER(mbx); + DEBUGFUNC("fm10k_msg_mac_vlan_vf"); + + /* record MAC address requested */ + err = fm10k_tlv_attr_get_mac_vlan( + results[FM10K_MAC_VLAN_MSG_DEFAULT_MAC], + perm_addr, &vid); + if (err) + return err; + + memcpy(hw->mac.perm_addr, perm_addr, ETH_ALEN); + hw->mac.default_vid = vid & (FM10K_VLAN_TABLE_VID_MAX - 1); + hw->mac.vlan_override = !!(vid & FM10K_VLAN_CLEAR); + + return FM10K_SUCCESS; +} + +/** + * fm10k_read_mac_addr_vf - Read device MAC address + * @hw: pointer to the HW structure + * + * This function should determine the MAC address for the VF + **/ +STATIC s32 fm10k_read_mac_addr_vf(struct fm10k_hw *hw) +{ + u8 perm_addr[ETH_ALEN]; + u32 base_addr; + + DEBUGFUNC("fm10k_read_mac_addr_vf"); + + base_addr = FM10K_READ_REG(hw, FM10K_TDBAL(0)); + + /* last byte should be 0 */ + if (base_addr << 24) + return FM10K_ERR_INVALID_MAC_ADDR; + + perm_addr[3] = (u8)(base_addr >> 24); + perm_addr[4] = (u8)(base_addr >> 16); + perm_addr[5] = (u8)(base_addr >> 8); + + base_addr = FM10K_READ_REG(hw, FM10K_TDBAH(0)); + + /* first byte should be all 1's */ + if ((~base_addr) >> 24) + return FM10K_ERR_INVALID_MAC_ADDR; + + perm_addr[0] = (u8)(base_addr >> 16); + perm_addr[1] = (u8)(base_addr >> 8); + perm_addr[2] = (u8)(base_addr); + + memcpy(hw->mac.perm_addr, perm_addr, ETH_ALEN); + memcpy(hw->mac.addr, perm_addr, ETH_ALEN); + + return FM10K_SUCCESS; +} + +/** + * fm10k_update_uc_addr_vf - Update device unicast addresses + * @hw: pointer to the HW structure + * @glort: unused + * @mac: MAC address to add/remove from table + * @vid: VLAN ID to add/remove from table + * @add: Indicates if this is an add or remove operation + * @flags: flags field to indicate add and secure - unused + * + * This function is used to add or remove unicast MAC addresses for + * the VF. + **/ +STATIC s32 fm10k_update_uc_addr_vf(struct fm10k_hw *hw, u16 glort, + const u8 *mac, u16 vid, bool add, u8 flags) +{ + struct fm10k_mbx_info *mbx = &hw->mbx; + u32 msg[7]; + + DEBUGFUNC("fm10k_update_uc_addr_vf"); + + UNREFERENCED_2PARAMETER(glort, flags); + + /* verify VLAN ID is valid */ + if (vid >= FM10K_VLAN_TABLE_VID_MAX) + return FM10K_ERR_PARAM; + + /* verify MAC address is valid */ + if (!FM10K_IS_VALID_ETHER_ADDR(mac)) + return FM10K_ERR_PARAM; + + /* verify we are not locked down on the MAC address */ + if (FM10K_IS_VALID_ETHER_ADDR(hw->mac.perm_addr) && + memcmp(hw->mac.perm_addr, mac, ETH_ALEN)) + return FM10K_ERR_PARAM; + + /* add bit to notify us if this is a set or clear operation */ + if (!add) + vid |= FM10K_VLAN_CLEAR; + + /* generate VLAN request */ + fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN); + fm10k_tlv_attr_put_mac_vlan(msg, FM10K_MAC_VLAN_MSG_MAC, mac, vid); + + /* load onto outgoing mailbox */ + return mbx->ops.enqueue_tx(hw, mbx, msg); +} + +/** + * fm10k_update_mc_addr_vf - Update device multicast addresses + * @hw: pointer to the HW structure + * @glort: unused + * @mac: MAC address to add/remove from table + * @vid: VLAN ID to add/remove from table + * @add: Indicates if this is an add or remove operation + * + * This function is used to add or remove multicast MAC addresses for + * the VF. + **/ +STATIC s32 fm10k_update_mc_addr_vf(struct fm10k_hw *hw, u16 glort, + const u8 *mac, u16 vid, bool add) +{ + struct fm10k_mbx_info *mbx = &hw->mbx; + u32 msg[7]; + + DEBUGFUNC("fm10k_update_uc_addr_vf"); + + UNREFERENCED_1PARAMETER(glort); + + /* verify VLAN ID is valid */ + if (vid >= FM10K_VLAN_TABLE_VID_MAX) + return FM10K_ERR_PARAM; + + /* verify multicast address is valid */ + if (!FM10K_IS_MULTICAST_ETHER_ADDR(mac)) + return FM10K_ERR_PARAM; + + /* add bit to notify us if this is a set or clear operation */ + if (!add) + vid |= FM10K_VLAN_CLEAR; + + /* generate VLAN request */ + fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN); + fm10k_tlv_attr_put_mac_vlan(msg, FM10K_MAC_VLAN_MSG_MULTICAST, + mac, vid); + + /* load onto outgoing mailbox */ + return mbx->ops.enqueue_tx(hw, mbx, msg); +} + +/** + * fm10k_update_int_moderator_vf - Request update of interrupt moderator list + * @hw: pointer to hardware structure + * + * This function will issue a request to the PF to rescan our MSI-X table + * and to update the interrupt moderator linked list. + **/ +STATIC void fm10k_update_int_moderator_vf(struct fm10k_hw *hw) +{ + struct fm10k_mbx_info *mbx = &hw->mbx; + u32 msg[1]; + + /* generate MSI-X request */ + fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MSIX); + + /* load onto outgoing mailbox */ + mbx->ops.enqueue_tx(hw, mbx, msg); +} + +/* This structure defines the attibutes to be parsed below */ +const struct fm10k_tlv_attr fm10k_lport_state_msg_attr[] = { + FM10K_TLV_ATTR_BOOL(FM10K_LPORT_STATE_MSG_DISABLE), + FM10K_TLV_ATTR_U8(FM10K_LPORT_STATE_MSG_XCAST_MODE), + FM10K_TLV_ATTR_BOOL(FM10K_LPORT_STATE_MSG_READY), + FM10K_TLV_ATTR_LAST +}; + +/** + * fm10k_msg_lport_state_vf - Message handler for lport_state message from PF + * @hw: Pointer to hardware structure + * @results: pointer array containing parsed data + * @mbx: Pointer to mailbox information structure + * + * This handler is meant to capture the indication from the PF that we + * are ready to bring up the interface. + **/ +s32 fm10k_msg_lport_state_vf(struct fm10k_hw *hw, u32 **results, + struct fm10k_mbx_info *mbx) +{ + UNREFERENCED_1PARAMETER(mbx); + DEBUGFUNC("fm10k_msg_lport_state_vf"); + + hw->mac.dglort_map = !results[FM10K_LPORT_STATE_MSG_READY] ? + FM10K_DGLORTMAP_NONE : FM10K_DGLORTMAP_ZERO; + + return FM10K_SUCCESS; +} + +/** + * fm10k_update_lport_state_vf - Update device state in lower device + * @hw: pointer to the HW structure + * @glort: unused + * @count: number of logical ports to enable - unused (always 1) + * @enable: boolean value indicating if this is an enable or disable request + * + * Notify the lower device of a state change. If the lower device is + * enabled we can add filters, if it is disabled all filters for this + * logical port are flushed. + **/ +STATIC s32 fm10k_update_lport_state_vf(struct fm10k_hw *hw, u16 glort, + u16 count, bool enable) +{ + struct fm10k_mbx_info *mbx = &hw->mbx; + u32 msg[2]; + + UNREFERENCED_2PARAMETER(glort, count); + DEBUGFUNC("fm10k_update_lport_state_vf"); + + /* reset glort mask 0 as we have to wait to be enabled */ + hw->mac.dglort_map = FM10K_DGLORTMAP_NONE; + + /* generate port state request */ + fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE); + if (!enable) + fm10k_tlv_attr_put_bool(msg, FM10K_LPORT_STATE_MSG_DISABLE); + + /* load onto outgoing mailbox */ + return mbx->ops.enqueue_tx(hw, mbx, msg); +} + +/** + * fm10k_update_xcast_mode_vf - Request update of multicast mode + * @hw: pointer to hardware structure + * @glort: unused + * @mode: integer value indicating mode being requested + * + * This function will attempt to request a higher mode for the port + * so that it can enable either multicast, multicast promiscuous, or + * promiscuous mode of operation. + **/ +STATIC s32 fm10k_update_xcast_mode_vf(struct fm10k_hw *hw, u16 glort, u8 mode) +{ + struct fm10k_mbx_info *mbx = &hw->mbx; + u32 msg[3]; + + UNREFERENCED_1PARAMETER(glort); + DEBUGFUNC("fm10k_update_xcast_mode_vf"); + + if (mode > FM10K_XCAST_MODE_NONE) + return FM10K_ERR_PARAM; + + /* generate message requesting to change xcast mode */ + fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE); + fm10k_tlv_attr_put_u8(msg, FM10K_LPORT_STATE_MSG_XCAST_MODE, mode); + + /* load onto outgoing mailbox */ + return mbx->ops.enqueue_tx(hw, mbx, msg); +} + +const struct fm10k_tlv_attr fm10k_1588_msg_attr[] = { + FM10K_TLV_ATTR_U64(FM10K_1588_MSG_TIMESTAMP), + FM10K_TLV_ATTR_LAST +}; + +/* currently there is no shared 1588 timestamp handler */ + +/** + * fm10k_update_hw_stats_vf - Updates hardware related statistics of VF + * @hw: pointer to hardware structure + * @stats: pointer to statistics structure + * + * This function collects and aggregates per queue hardware statistics. + **/ +STATIC void fm10k_update_hw_stats_vf(struct fm10k_hw *hw, + struct fm10k_hw_stats *stats) +{ + DEBUGFUNC("fm10k_update_hw_stats_vf"); + + fm10k_update_hw_stats_q(hw, stats->q, 0, hw->mac.max_queues); +} + +/** + * fm10k_rebind_hw_stats_vf - Resets base for hardware statistics of VF + * @hw: pointer to hardware structure + * @stats: pointer to the stats structure to update + * + * This function resets the base for queue hardware statistics. + **/ +STATIC void fm10k_rebind_hw_stats_vf(struct fm10k_hw *hw, + struct fm10k_hw_stats *stats) +{ + DEBUGFUNC("fm10k_rebind_hw_stats_vf"); + + /* Unbind Queue Statistics */ + fm10k_unbind_hw_stats_q(stats->q, 0, hw->mac.max_queues); + + /* Reinitialize bases for all stats */ + fm10k_update_hw_stats_vf(hw, stats); +} + +/** + * fm10k_configure_dglort_map_vf - Configures GLORT entry and queues + * @hw: pointer to hardware structure + * @dglort: pointer to dglort configuration structure + * + * Reads the configuration structure contained in dglort_cfg and uses + * that information to then populate a DGLORTMAP/DEC entry and the queues + * to which it has been assigned. + **/ +STATIC s32 fm10k_configure_dglort_map_vf(struct fm10k_hw *hw, + struct fm10k_dglort_cfg *dglort) +{ + UNREFERENCED_1PARAMETER(hw); + DEBUGFUNC("fm10k_configure_dglort_map_vf"); + + /* verify the dglort pointer */ + if (!dglort) + return FM10K_ERR_PARAM; + + /* stub for now until we determine correct message for this */ + + return FM10K_SUCCESS; +} + +/** + * fm10k_adjust_systime_vf - Adjust systime frequency + * @hw: pointer to hardware structure + * @ppb: adjustment rate in parts per billion + * + * This function takes an adjustment rate in parts per billion and will + * verify that this value is 0 as the VF cannot support adjusting the + * systime clock. + * + * If the ppb value is non-zero the return is ERR_PARAM else success + **/ +STATIC s32 fm10k_adjust_systime_vf(struct fm10k_hw *hw, s32 ppb) +{ + UNREFERENCED_1PARAMETER(hw); + DEBUGFUNC("fm10k_adjust_systime_vf"); + + /* The VF cannot adjust the clock frequency, however it should + * already have a syntonic clock with whichever host interface is + * running as the master for the host interface clock domain so + * there should be not frequency adjustment necessary. + */ + return ppb ? FM10K_ERR_PARAM : FM10K_SUCCESS; +} + +/** + * fm10k_read_systime_vf - Reads value of systime registers + * @hw: pointer to the hardware structure + * + * Function reads the content of 2 registers, combined to represent a 64 bit + * value measured in nanoseconds. In order to guarantee the value is accurate + * we check the 32 most significant bits both before and after reading the + * 32 least significant bits to verify they didn't change as we were reading + * the registers. + **/ +static u64 fm10k_read_systime_vf(struct fm10k_hw *hw) +{ + u32 systime_l, systime_h, systime_tmp; + + systime_h = fm10k_read_reg(hw, FM10K_VFSYSTIME + 1); + + do { + systime_tmp = systime_h; + systime_l = fm10k_read_reg(hw, FM10K_VFSYSTIME); + systime_h = fm10k_read_reg(hw, FM10K_VFSYSTIME + 1); + } while (systime_tmp != systime_h); + + return ((u64)systime_h << 32) | systime_l; +} + +static const struct fm10k_msg_data fm10k_msg_data_vf[] = { + FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test), + FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_msg_mac_vlan_vf), + FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_msg_lport_state_vf), + FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error), +}; + +/** + * fm10k_init_ops_vf - Inits func ptrs and MAC type + * @hw: pointer to hardware structure + * + * Initialize the function pointers and assign the MAC type for VF. + * Does not touch the hardware. + **/ +s32 fm10k_init_ops_vf(struct fm10k_hw *hw) +{ + struct fm10k_mac_info *mac = &hw->mac; + + DEBUGFUNC("fm10k_init_ops_vf"); + + fm10k_init_ops_generic(hw); + + mac->ops.reset_hw = &fm10k_reset_hw_vf; + mac->ops.init_hw = &fm10k_init_hw_vf; + mac->ops.start_hw = &fm10k_start_hw_generic; + mac->ops.stop_hw = &fm10k_stop_hw_vf; + mac->ops.is_slot_appropriate = &fm10k_is_slot_appropriate_vf; + mac->ops.update_vlan = &fm10k_update_vlan_vf; + mac->ops.read_mac_addr = &fm10k_read_mac_addr_vf; + mac->ops.update_uc_addr = &fm10k_update_uc_addr_vf; + mac->ops.update_mc_addr = &fm10k_update_mc_addr_vf; + mac->ops.update_xcast_mode = &fm10k_update_xcast_mode_vf; + mac->ops.update_int_moderator = &fm10k_update_int_moderator_vf; + mac->ops.update_lport_state = &fm10k_update_lport_state_vf; + mac->ops.update_hw_stats = &fm10k_update_hw_stats_vf; + mac->ops.rebind_hw_stats = &fm10k_rebind_hw_stats_vf; + mac->ops.configure_dglort_map = &fm10k_configure_dglort_map_vf; + mac->ops.get_host_state = &fm10k_get_host_state_generic; + mac->ops.adjust_systime = &fm10k_adjust_systime_vf; + mac->ops.read_systime = &fm10k_read_systime_vf, + + mac->max_msix_vectors = fm10k_get_pcie_msix_count_generic(hw); + + return fm10k_pfvf_mbx_init(hw, &hw->mbx, fm10k_msg_data_vf, 0); +} diff --git a/drivers/fm10k/base/fm10k_vf.h b/drivers/fm10k/base/fm10k_vf.h new file mode 100644 index 0000000..0438542 --- /dev/null +++ b/drivers/fm10k/base/fm10k_vf.h @@ -0,0 +1,91 @@ +/******************************************************************************* + +Copyright (c) 2013 - 2015, 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. + +***************************************************************************/ + +#ifndef _FM10K_VF_H_ +#define _FM10K_VF_H_ + +#include "fm10k_type.h" +#include "fm10k_common.h" + +enum fm10k_vf_tlv_msg_id { + FM10K_VF_MSG_ID_TEST = 0, /* msg ID reserved for testing */ + FM10K_VF_MSG_ID_MSIX, + FM10K_VF_MSG_ID_MAC_VLAN, + FM10K_VF_MSG_ID_LPORT_STATE, + FM10K_VF_MSG_ID_1588, + FM10K_VF_MSG_ID_MAX, +}; + +enum fm10k_tlv_mac_vlan_attr_id { + FM10K_MAC_VLAN_MSG_VLAN, + FM10K_MAC_VLAN_MSG_SET, + FM10K_MAC_VLAN_MSG_MAC, + FM10K_MAC_VLAN_MSG_DEFAULT_MAC, + FM10K_MAC_VLAN_MSG_MULTICAST, + FM10K_MAC_VLAN_MSG_ID_MAX +}; + +enum fm10k_tlv_lport_state_attr_id { + FM10K_LPORT_STATE_MSG_DISABLE, + FM10K_LPORT_STATE_MSG_XCAST_MODE, + FM10K_LPORT_STATE_MSG_READY, + FM10K_LPORT_STATE_MSG_MAX +}; + +enum fm10k_tlv_1588_attr_id { + FM10K_1588_MSG_TIMESTAMP, + FM10K_1588_MSG_MAX +}; + +#define FM10K_VF_MSG_MSIX_HANDLER(func) \ + FM10K_MSG_HANDLER(FM10K_VF_MSG_ID_MSIX, NULL, func) + +s32 fm10k_msg_mac_vlan_vf(struct fm10k_hw *, u32 **, struct fm10k_mbx_info *); +extern const struct fm10k_tlv_attr fm10k_mac_vlan_msg_attr[]; +#define FM10K_VF_MSG_MAC_VLAN_HANDLER(func) \ + FM10K_MSG_HANDLER(FM10K_VF_MSG_ID_MAC_VLAN, \ + fm10k_mac_vlan_msg_attr, func) + +s32 fm10k_msg_lport_state_vf(struct fm10k_hw *, u32 **, + struct fm10k_mbx_info *); +extern const struct fm10k_tlv_attr fm10k_lport_state_msg_attr[]; +#define FM10K_VF_MSG_LPORT_STATE_HANDLER(func) \ + FM10K_MSG_HANDLER(FM10K_VF_MSG_ID_LPORT_STATE, \ + fm10k_lport_state_msg_attr, func) + +extern const struct fm10k_tlv_attr fm10k_1588_msg_attr[]; +#define FM10K_VF_MSG_1588_HANDLER(func) \ + FM10K_MSG_HANDLER(FM10K_VF_MSG_ID_1588, fm10k_1588_msg_attr, func) + +s32 fm10k_init_ops_vf(struct fm10k_hw *hw); +#endif /* _FM10K_VF_H */ diff --git a/drivers/fm10k/fm10k.h b/drivers/fm10k/fm10k.h new file mode 100644 index 0000000..0e31796 --- /dev/null +++ b/drivers/fm10k/fm10k.h @@ -0,0 +1,292 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of 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. + */ + +#ifndef _FM10K_H_ +#define _FM10K_H_ + +#include +#include +#include +#include +#include +#include "fm10k_logs.h" +#include "base/fm10k_type.h" + +/* descriptor ring base addresses must be aligned to the following */ +#define FM10K_ALIGN_RX_DESC 128 +#define FM10K_ALIGN_TX_DESC 128 + +/* The maximum packet size that FM10K supports */ +#define FM10K_MAX_PKT_SIZE (15 * 1024) + +/* Minimum size of RX buffer FM10K supported */ +#define FM10K_MIN_RX_BUF_SIZE 256 + +/* The maximum of SRIOV VFs per port supported */ +#define FM10K_MAX_VF_NUM 64 + +/* number of descriptors must be a multiple of the following */ +#define FM10K_MULT_RX_DESC FM10K_REQ_RX_DESCRIPTOR_MULTIPLE +#define FM10K_MULT_TX_DESC FM10K_REQ_TX_DESCRIPTOR_MULTIPLE + +/* maximum size of descriptor rings */ +#define FM10K_MAX_RX_RING_SZ (512 * 1024) +#define FM10K_MAX_TX_RING_SZ (512 * 1024) + +/* minimum and maximum number of descriptors in a ring */ +#define FM10K_MIN_RX_DESC 32 +#define FM10K_MIN_TX_DESC 32 +#define FM10K_MAX_RX_DESC (FM10K_MAX_RX_RING_SZ / sizeof(union fm10k_rx_desc)) +#define FM10K_MAX_TX_DESC (FM10K_MAX_TX_RING_SZ / sizeof(struct fm10k_tx_desc)) + +/* + * byte aligment for HW RX data buffer + * Datasheet requires RX buffer addresses shall either be 512-byte aligned or + * be 8-byte aligned but without crossing host memory pages (4KB alignment + * boundaries). Satisfy first option. + */ +#define FM10K_RX_DATABUF_ALIGN 512 + +/* + * threshold default, min, max, and divisor constraints + * the configured values must satisfy the following: + * MIN <= value <= MAX + * DIV % value == 0 + */ +#define FM10K_RX_FREE_THRESH_DEFAULT(rxq) 32 +#define FM10K_RX_FREE_THRESH_MIN(rxq) 1 +#define FM10K_RX_FREE_THRESH_MAX(rxq) ((rxq)->nb_desc - 1) +#define FM10K_RX_FREE_THRESH_DIV(rxq) ((rxq)->nb_desc) + +#define FM10K_TX_FREE_THRESH_DEFAULT(txq) 32 +#define FM10K_TX_FREE_THRESH_MIN(txq) 1 +#define FM10K_TX_FREE_THRESH_MAX(txq) ((txq)->nb_desc - 3) +#define FM10K_TX_FREE_THRESH_DIV(txq) 0 + +#define FM10K_DEFAULT_RX_PTHRESH 8 +#define FM10K_DEFAULT_RX_HTHRESH 8 +#define FM10K_DEFAULT_RX_WTHRESH 0 + +#define FM10K_DEFAULT_TX_PTHRESH 32 +#define FM10K_DEFAULT_TX_HTHRESH 0 +#define FM10K_DEFAULT_TX_WTHRESH 0 + +#define FM10K_TX_RS_THRESH_DEFAULT(txq) 32 +#define FM10K_TX_RS_THRESH_MIN(txq) 1 +#define FM10K_TX_RS_THRESH_MAX(txq) \ + RTE_MIN(((txq)->nb_desc - 2), (txq)->free_thresh) +#define FM10K_TX_RS_THRESH_DIV(txq) ((txq)->nb_desc) + +#define FM10K_VLAN_TAG_SIZE 4 + +struct fm10k_dev_info { + volatile uint32_t enable; + volatile uint32_t glort; + /* Protect the mailbox to avoid race condition */ + rte_spinlock_t mbx_lock; +}; + +/* + * Structure to store private data for each driver instance. + */ +struct fm10k_adapter { + struct fm10k_hw hw; + struct fm10k_hw_stats stats; + struct fm10k_dev_info info; +}; + +#define FM10K_DEV_PRIVATE_TO_HW(adapter) \ + (&((struct fm10k_adapter *)adapter)->hw) + +#define FM10K_DEV_PRIVATE_TO_STATS(adapter) \ + (&((struct fm10k_adapter *)adapter)->stats) + +#define FM10K_DEV_PRIVATE_TO_INFO(adapter) \ + (&((struct fm10k_adapter *)adapter)->info) + +#define FM10K_DEV_PRIVATE_TO_MBXLOCK(adapter) \ + (&(((struct fm10k_adapter *)adapter)->info.mbx_lock)) + +struct fm10k_rx_queue { + struct rte_mempool *mp; + struct rte_mbuf **sw_ring; + volatile union fm10k_rx_desc *hw_ring; + struct rte_mbuf *pkt_first_seg; /**< First segment of current packet. */ + struct rte_mbuf *pkt_last_seg; /**< Last segment of current packet. */ + uint64_t hw_ring_phys_addr; + uint16_t next_dd; + uint16_t next_alloc; + uint16_t next_trigger; + uint16_t alloc_thresh; + volatile uint32_t *tail_ptr; + uint16_t nb_desc; + uint16_t queue_id; + uint8_t port_id; + uint8_t drop_en; + uint8_t rx_deferred_start; /**< don't start this queue in dev start. */ +}; + +/* + * a FIFO is used to track which descriptors have their RS bit set for Tx + * queues which are configured to allow multiple descriptors per packet + */ +struct fifo { + uint16_t *list; + uint16_t *head; + uint16_t *tail; + uint16_t *endp; +}; + +struct fm10k_tx_queue { + struct rte_mbuf **sw_ring; + struct fm10k_tx_desc *hw_ring; + uint64_t hw_ring_phys_addr; + struct fifo rs_tracker; + uint16_t last_free; + uint16_t next_free; + uint16_t nb_free; + uint16_t nb_used; + uint16_t free_trigger; + uint16_t free_thresh; + uint16_t rs_thresh; + volatile uint32_t *tail_ptr; + uint16_t nb_desc; + uint8_t port_id; + uint8_t tx_deferred_start; /** < don't start this queue in dev start. */ + uint16_t queue_id; +}; + +#define MBUF_DMA_ADDR(mb) \ + ((uint64_t) ((mb)->buf_physaddr + (mb)->data_off)) + +/* enforce 512B alignment on default Rx DMA addresses */ +#define MBUF_DMA_ADDR_DEFAULT(mb) \ + ((uint64_t) RTE_ALIGN(((mb)->buf_physaddr + RTE_PKTMBUF_HEADROOM), 512)) + +static inline void fifo_reset(struct fifo *fifo, uint32_t len) +{ + fifo->head = fifo->tail = fifo->list; + fifo->endp = fifo->list + len; +} + +static inline void fifo_insert(struct fifo *fifo, uint16_t val) +{ + *fifo->head = val; + if (++fifo->head == fifo->endp) + fifo->head = fifo->list; +} + +/* do not worry about list being empty since we only check it once we know + * we have used enough descriptors to set the RS bit at least once */ +static inline uint16_t fifo_peek(struct fifo *fifo) +{ + return *fifo->tail; +} + +static inline uint16_t fifo_remove(struct fifo *fifo) +{ + uint16_t val; + val = *fifo->tail; + if (++fifo->tail == fifo->endp) + fifo->tail = fifo->list; + return val; +} + +static inline void +fm10k_pktmbuf_reset(struct rte_mbuf *mb, uint8_t in_port) +{ + rte_mbuf_refcnt_set(mb, 1); + mb->next = NULL; + mb->nb_segs = 1; + + /* enforce 512B alignment on default Rx virtual addresses */ + mb->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb->buf_addr + + RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN) + - (char *)mb->buf_addr); + mb->port = in_port; +} + +/* + * Verify Rx packet buffer alignment is valid. + * + * Hardware requires specific alignment for Rx packet buffers. At + * least one of the following two conditions must be satisfied. + * 1. Address is 512B aligned + * 2. Address is 8B aligned and buffer does not cross 4K boundary. + * + * Return 1 if buffer alignment satisfies at least one condition, + * otherwise return 0. + * + * Note: Alignment is checked by the driver when the Rx queue is reset. It + * is assumed that if an entire descriptor ring can be filled with + * buffers containing valid alignment, then all buffers in that mempool + * have valid address alignment. It is the responsibility of the user + * to ensure all buffers have valid alignment, as it is the user who + * creates the mempool. + * Note: It is assumed the buffer needs only to store a maximum size Ethernet + * frame. + */ +static inline int +fm10k_addr_alignment_valid(struct rte_mbuf *mb) +{ + uint64_t addr = MBUF_DMA_ADDR_DEFAULT(mb); + uint64_t boundary1, boundary2; + + /* 512B aligned? */ + if (RTE_ALIGN(addr, 512) == addr) + return 1; + + /* 8B aligned, and max Ethernet frame would not cross a 4KB boundary? */ + if (RTE_ALIGN(addr, 8) == addr) { + boundary1 = RTE_ALIGN_FLOOR(addr, 4096); + boundary2 = RTE_ALIGN_FLOOR(addr + ETHER_MAX_VLAN_FRAME_LEN, + 4096); + if (boundary1 == boundary2) + return 1; + } + + PMD_INIT_LOG(ERR, "Error: Invalid buffer alignment!"); + + return 0; +} + +/* Rx and Tx prototypes */ +uint16_t fm10k_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, + uint16_t nb_pkts); + +uint16_t fm10k_recv_scattered_pkts(void *rx_queue, + struct rte_mbuf **rx_pkts, uint16_t nb_pkts); + +uint16_t fm10k_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, + uint16_t nb_pkts); +#endif diff --git a/drivers/fm10k/fm10k_ethdev.c b/drivers/fm10k/fm10k_ethdev.c new file mode 100644 index 0000000..275c19c --- /dev/null +++ b/drivers/fm10k/fm10k_ethdev.c @@ -0,0 +1,1872 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of 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. + */ + +#include +#include +#include +#include +#include +#include + +#include "fm10k.h" +#include "base/fm10k_api.h" + +#define FM10K_RX_BUFF_ALIGN 512 +/* Default delay to acquire mailbox lock */ +#define FM10K_MBXLOCK_DELAY_US 20 +#define UINT64_LOWER_32BITS_MASK 0x00000000ffffffffULL + +/* Number of chars per uint32 type */ +#define CHARS_PER_UINT32 (sizeof(uint32_t)) +#define BIT_MASK_PER_UINT32 ((1 << CHARS_PER_UINT32) - 1) + +static void fm10k_close_mbx_service(struct fm10k_hw *hw); + +static void +fm10k_mbx_initlock(struct fm10k_hw *hw) +{ + rte_spinlock_init(FM10K_DEV_PRIVATE_TO_MBXLOCK(hw->back)); +} + +static void +fm10k_mbx_lock(struct fm10k_hw *hw) +{ + while (!rte_spinlock_trylock(FM10K_DEV_PRIVATE_TO_MBXLOCK(hw->back))) + rte_delay_us(FM10K_MBXLOCK_DELAY_US); +} + +static void +fm10k_mbx_unlock(struct fm10k_hw *hw) +{ + rte_spinlock_unlock(FM10K_DEV_PRIVATE_TO_MBXLOCK(hw->back)); +} + +/* + * reset queue to initial state, allocate software buffers used when starting + * device. + * return 0 on success + * return -ENOMEM if buffers cannot be allocated + * return -EINVAL if buffers do not satisfy alignment condition + */ +static inline int +rx_queue_reset(struct fm10k_rx_queue *q) +{ + uint64_t dma_addr; + int i, diag; + PMD_INIT_FUNC_TRACE(); + + diag = rte_mempool_get_bulk(q->mp, (void **)q->sw_ring, q->nb_desc); + if (diag != 0) + return -ENOMEM; + + for (i = 0; i < q->nb_desc; ++i) { + fm10k_pktmbuf_reset(q->sw_ring[i], q->port_id); + if (!fm10k_addr_alignment_valid(q->sw_ring[i])) { + rte_mempool_put_bulk(q->mp, (void **)q->sw_ring, + q->nb_desc); + return -EINVAL; + } + dma_addr = MBUF_DMA_ADDR_DEFAULT(q->sw_ring[i]); + q->hw_ring[i].q.pkt_addr = dma_addr; + q->hw_ring[i].q.hdr_addr = dma_addr; + } + + q->next_dd = 0; + q->next_alloc = 0; + q->next_trigger = q->alloc_thresh - 1; + FM10K_PCI_REG_WRITE(q->tail_ptr, q->nb_desc - 1); + return 0; +} + +/* + * clean queue, descriptor rings, free software buffers used when stopping + * device. + */ +static inline void +rx_queue_clean(struct fm10k_rx_queue *q) +{ + union fm10k_rx_desc zero = {.q = {0, 0, 0, 0} }; + uint32_t i; + PMD_INIT_FUNC_TRACE(); + + /* zero descriptor rings */ + for (i = 0; i < q->nb_desc; ++i) + q->hw_ring[i] = zero; + + /* free software buffers */ + for (i = 0; i < q->nb_desc; ++i) { + if (q->sw_ring[i]) { + rte_pktmbuf_free_seg(q->sw_ring[i]); + q->sw_ring[i] = NULL; + } + } +} + +/* + * free all queue memory used when releasing the queue (i.e. configure) + */ +static inline void +rx_queue_free(struct fm10k_rx_queue *q) +{ + PMD_INIT_FUNC_TRACE(); + if (q) { + PMD_INIT_LOG(DEBUG, "Freeing rx queue %p", q); + rx_queue_clean(q); + if (q->sw_ring) { + rte_free(q->sw_ring); + q->sw_ring = NULL; + } + rte_free(q); + q = NULL; + } +} + +/* + * disable RX queue, wait unitl HW finished necessary flush operation + */ +static inline int +rx_queue_disable(struct fm10k_hw *hw, uint16_t qnum) +{ + uint32_t reg, i; + + reg = FM10K_READ_REG(hw, FM10K_RXQCTL(qnum)); + FM10K_WRITE_REG(hw, FM10K_RXQCTL(qnum), + reg & ~FM10K_RXQCTL_ENABLE); + + /* Wait 100us at most */ + for (i = 0; i < FM10K_QUEUE_DISABLE_TIMEOUT; i++) { + rte_delay_us(1); + reg = FM10K_READ_REG(hw, FM10K_RXQCTL(i)); + if (!(reg & FM10K_RXQCTL_ENABLE)) + break; + } + + if (i == FM10K_QUEUE_DISABLE_TIMEOUT) + return -1; + + return 0; +} + +/* + * reset queue to initial state, allocate software buffers used when starting + * device + */ +static inline void +tx_queue_reset(struct fm10k_tx_queue *q) +{ + PMD_INIT_FUNC_TRACE(); + q->last_free = 0; + q->next_free = 0; + q->nb_used = 0; + q->nb_free = q->nb_desc - 1; + q->free_trigger = q->nb_free - q->free_thresh; + fifo_reset(&q->rs_tracker, (q->nb_desc + 1) / q->rs_thresh); + FM10K_PCI_REG_WRITE(q->tail_ptr, 0); +} + +/* + * clean queue, descriptor rings, free software buffers used when stopping + * device + */ +static inline void +tx_queue_clean(struct fm10k_tx_queue *q) +{ + struct fm10k_tx_desc zero = {0, 0, 0, 0, 0, 0}; + uint32_t i; + PMD_INIT_FUNC_TRACE(); + + /* zero descriptor rings */ + for (i = 0; i < q->nb_desc; ++i) + q->hw_ring[i] = zero; + + /* free software buffers */ + for (i = 0; i < q->nb_desc; ++i) { + if (q->sw_ring[i]) { + rte_pktmbuf_free_seg(q->sw_ring[i]); + q->sw_ring[i] = NULL; + } + } +} + +/* + * free all queue memory used when releasing the queue (i.e. configure) + */ +static inline void +tx_queue_free(struct fm10k_tx_queue *q) +{ + PMD_INIT_FUNC_TRACE(); + if (q) { + PMD_INIT_LOG(DEBUG, "Freeing tx queue %p", q); + tx_queue_clean(q); + if (q->rs_tracker.list) { + rte_free(q->rs_tracker.list); + q->rs_tracker.list = NULL; + } + if (q->sw_ring) { + rte_free(q->sw_ring); + q->sw_ring = NULL; + } + rte_free(q); + q = NULL; + } +} + +/* + * disable TX queue, wait unitl HW finished necessary flush operation + */ +static inline int +tx_queue_disable(struct fm10k_hw *hw, uint16_t qnum) +{ + uint32_t reg, i; + + reg = FM10K_READ_REG(hw, FM10K_TXDCTL(qnum)); + FM10K_WRITE_REG(hw, FM10K_TXDCTL(qnum), + reg & ~FM10K_TXDCTL_ENABLE); + + /* Wait 100us at most */ + for (i = 0; i < FM10K_QUEUE_DISABLE_TIMEOUT; i++) { + rte_delay_us(1); + reg = FM10K_READ_REG(hw, FM10K_TXDCTL(i)); + if (!(reg & FM10K_TXDCTL_ENABLE)) + break; + } + + if (i == FM10K_QUEUE_DISABLE_TIMEOUT) + return -1; + + return 0; +} + +static int +fm10k_dev_configure(struct rte_eth_dev *dev) +{ + PMD_INIT_FUNC_TRACE(); + + if (dev->data->dev_conf.rxmode.hw_strip_crc == 0) + PMD_INIT_LOG(WARNING, "fm10k always strip CRC"); + + return 0; +} + +static void +fm10k_dev_mq_rx_configure(struct rte_eth_dev *dev) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct rte_eth_conf *dev_conf = &dev->data->dev_conf; + uint32_t mrqc, *key, i, reta, j; + uint64_t hf; + +#define RSS_KEY_SIZE 40 + static uint8_t rss_intel_key[RSS_KEY_SIZE] = { + 0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2, + 0x41, 0x67, 0x25, 0x3D, 0x43, 0xA3, 0x8F, 0xB0, + 0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4, + 0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C, + 0x6A, 0x42, 0xB7, 0x3B, 0xBE, 0xAC, 0x01, 0xFA, + }; + + if (dev->data->nb_rx_queues == 1 || + dev_conf->rxmode.mq_mode != ETH_MQ_RX_RSS || + dev_conf->rx_adv_conf.rss_conf.rss_hf == 0) + return; + + /* random key is rss_intel_key (default) or user provided (rss_key) */ + if (dev_conf->rx_adv_conf.rss_conf.rss_key == NULL) + key = (uint32_t *)rss_intel_key; + else + key = (uint32_t *)dev_conf->rx_adv_conf.rss_conf.rss_key; + + /* Now fill our hash function seeds, 4 bytes at a time */ + for (i = 0; i < RSS_KEY_SIZE / sizeof(*key); ++i) + FM10K_WRITE_REG(hw, FM10K_RSSRK(0, i), key[i]); + + /* + * Fill in redirection table + * The byte-swap is needed because NIC registers are in + * little-endian order. + */ + reta = 0; + for (i = 0, j = 0; i < FM10K_RETA_SIZE; i++, j++) { + if (j == dev->data->nb_rx_queues) + j = 0; + reta = (reta << CHAR_BIT) | j; + if ((i & 3) == 3) + FM10K_WRITE_REG(hw, FM10K_RETA(0, i >> 2), + rte_bswap32(reta)); + } + + /* + * Generate RSS hash based on packet types, TCP/UDP + * port numbers and/or IPv4/v6 src and dst addresses + */ + hf = dev_conf->rx_adv_conf.rss_conf.rss_hf; + mrqc = 0; + mrqc |= (hf & ETH_RSS_IPV4) ? FM10K_MRQC_IPV4 : 0; + mrqc |= (hf & ETH_RSS_IPV6) ? FM10K_MRQC_IPV6 : 0; + mrqc |= (hf & ETH_RSS_IPV6_EX) ? FM10K_MRQC_IPV6 : 0; + mrqc |= (hf & ETH_RSS_NONFRAG_IPV4_TCP) ? FM10K_MRQC_TCP_IPV4 : 0; + mrqc |= (hf & ETH_RSS_NONFRAG_IPV6_TCP) ? FM10K_MRQC_TCP_IPV6 : 0; + mrqc |= (hf & ETH_RSS_IPV6_TCP_EX) ? FM10K_MRQC_TCP_IPV6 : 0; + mrqc |= (hf & ETH_RSS_NONFRAG_IPV4_UDP) ? FM10K_MRQC_UDP_IPV4 : 0; + mrqc |= (hf & ETH_RSS_NONFRAG_IPV6_UDP) ? FM10K_MRQC_UDP_IPV6 : 0; + mrqc |= (hf & ETH_RSS_IPV6_UDP_EX) ? FM10K_MRQC_UDP_IPV6 : 0; + + if (mrqc == 0) { + PMD_INIT_LOG(ERR, "Specified RSS mode 0x%"PRIx64"is not" + "supported", hf); + return; + } + + FM10K_WRITE_REG(hw, FM10K_MRQC(0), mrqc); +} + +static int +fm10k_dev_tx_init(struct rte_eth_dev *dev) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int i, ret; + struct fm10k_tx_queue *txq; + uint64_t base_addr; + uint32_t size; + + /* Disable TXINT to avoid possible interrupt */ + for (i = 0; i < hw->mac.max_queues; i++) + FM10K_WRITE_REG(hw, FM10K_TXINT(i), + 3 << FM10K_TXINT_TIMER_SHIFT); + + /* Setup TX queue */ + for (i = 0; i < dev->data->nb_tx_queues; ++i) { + txq = dev->data->tx_queues[i]; + base_addr = txq->hw_ring_phys_addr; + size = txq->nb_desc * sizeof(struct fm10k_tx_desc); + + /* disable queue to avoid issues while updating state */ + ret = tx_queue_disable(hw, i); + if (ret) { + PMD_INIT_LOG(ERR, "failed to disable queue %d", i); + return -1; + } + + /* set location and size for descriptor ring */ + FM10K_WRITE_REG(hw, FM10K_TDBAL(i), + base_addr & UINT64_LOWER_32BITS_MASK); + FM10K_WRITE_REG(hw, FM10K_TDBAH(i), + base_addr >> (CHAR_BIT * sizeof(uint32_t))); + FM10K_WRITE_REG(hw, FM10K_TDLEN(i), size); + } + return 0; +} + +static int +fm10k_dev_rx_init(struct rte_eth_dev *dev) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int i, ret; + struct fm10k_rx_queue *rxq; + uint64_t base_addr; + uint32_t size; + uint32_t rxdctl = FM10K_RXDCTL_WRITE_BACK_MIN_DELAY; + uint16_t buf_size; + + /* Disable RXINT to avoid possible interrupt */ + for (i = 0; i < hw->mac.max_queues; i++) + FM10K_WRITE_REG(hw, FM10K_RXINT(i), + 3 << FM10K_RXINT_TIMER_SHIFT); + + /* Setup RX queues */ + for (i = 0; i < dev->data->nb_rx_queues; ++i) { + rxq = dev->data->rx_queues[i]; + base_addr = rxq->hw_ring_phys_addr; + size = rxq->nb_desc * sizeof(union fm10k_rx_desc); + + /* disable queue to avoid issues while updating state */ + ret = rx_queue_disable(hw, i); + if (ret) { + PMD_INIT_LOG(ERR, "failed to disable queue %d", i); + return -1; + } + + /* Setup the Base and Length of the Rx Descriptor Ring */ + FM10K_WRITE_REG(hw, FM10K_RDBAL(i), + base_addr & UINT64_LOWER_32BITS_MASK); + FM10K_WRITE_REG(hw, FM10K_RDBAH(i), + base_addr >> (CHAR_BIT * sizeof(uint32_t))); + FM10K_WRITE_REG(hw, FM10K_RDLEN(i), size); + + /* Configure the Rx buffer size for one buff without split */ + buf_size = (uint16_t)(rte_pktmbuf_data_room_size(rxq->mp) - + RTE_PKTMBUF_HEADROOM); + FM10K_WRITE_REG(hw, FM10K_SRRCTL(i), + buf_size >> FM10K_SRRCTL_BSIZEPKT_SHIFT); + + /* It adds dual VLAN length for supporting dual VLAN */ + if ((dev->data->dev_conf.rxmode.max_rx_pkt_len + + 2 * FM10K_VLAN_TAG_SIZE) > buf_size){ + dev->data->scattered_rx = 1; + dev->rx_pkt_burst = fm10k_recv_scattered_pkts; + } + + /* Enable drop on empty, it's RO for VF */ + if (hw->mac.type == fm10k_mac_pf && rxq->drop_en) + rxdctl |= FM10K_RXDCTL_DROP_ON_EMPTY; + + FM10K_WRITE_REG(hw, FM10K_RXDCTL(i), rxdctl); + FM10K_WRITE_FLUSH(hw); + } + + if (dev->data->dev_conf.rxmode.enable_scatter) { + dev->rx_pkt_burst = fm10k_recv_scattered_pkts; + dev->data->scattered_rx = 1; + } + + /* Configure RSS if applicable */ + fm10k_dev_mq_rx_configure(dev); + return 0; +} + +static int +fm10k_dev_rx_queue_start(struct rte_eth_dev *dev, uint16_t rx_queue_id) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int err = -1; + uint32_t reg; + struct fm10k_rx_queue *rxq; + + PMD_INIT_FUNC_TRACE(); + + if (rx_queue_id < dev->data->nb_rx_queues) { + rxq = dev->data->rx_queues[rx_queue_id]; + err = rx_queue_reset(rxq); + if (err == -ENOMEM) { + PMD_INIT_LOG(ERR, "Failed to alloc memory : %d", err); + return err; + } else if (err == -EINVAL) { + PMD_INIT_LOG(ERR, "Invalid buffer address alignment :" + " %d", err); + return err; + } + + /* Setup the HW Rx Head and Tail Descriptor Pointers + * Note: this must be done AFTER the queue is enabled on real + * hardware, but BEFORE the queue is enabled when using the + * emulation platform. Do it in both places for now and remove + * this comment and the following two register writes when the + * emulation platform is no longer being used. + */ + FM10K_WRITE_REG(hw, FM10K_RDH(rx_queue_id), 0); + FM10K_WRITE_REG(hw, FM10K_RDT(rx_queue_id), rxq->nb_desc - 1); + + /* Set PF ownership flag for PF devices */ + reg = FM10K_READ_REG(hw, FM10K_RXQCTL(rx_queue_id)); + if (hw->mac.type == fm10k_mac_pf) + reg |= FM10K_RXQCTL_PF; + reg |= FM10K_RXQCTL_ENABLE; + /* enable RX queue */ + FM10K_WRITE_REG(hw, FM10K_RXQCTL(rx_queue_id), reg); + FM10K_WRITE_FLUSH(hw); + + /* Setup the HW Rx Head and Tail Descriptor Pointers + * Note: this must be done AFTER the queue is enabled + */ + FM10K_WRITE_REG(hw, FM10K_RDH(rx_queue_id), 0); + FM10K_WRITE_REG(hw, FM10K_RDT(rx_queue_id), rxq->nb_desc - 1); + } + + return err; +} + +static int +fm10k_dev_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rx_queue_id) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + PMD_INIT_FUNC_TRACE(); + + if (rx_queue_id < dev->data->nb_rx_queues) { + /* Disable RX queue */ + rx_queue_disable(hw, rx_queue_id); + + /* Free mbuf and clean HW ring */ + rx_queue_clean(dev->data->rx_queues[rx_queue_id]); + } + + return 0; +} + +static int +fm10k_dev_tx_queue_start(struct rte_eth_dev *dev, uint16_t tx_queue_id) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + /** @todo - this should be defined in the shared code */ +#define FM10K_TXDCTL_WRITE_BACK_MIN_DELAY 0x00010000 + uint32_t txdctl = FM10K_TXDCTL_WRITE_BACK_MIN_DELAY; + int err = 0; + + PMD_INIT_FUNC_TRACE(); + + if (tx_queue_id < dev->data->nb_tx_queues) { + tx_queue_reset(dev->data->tx_queues[tx_queue_id]); + + /* reset head and tail pointers */ + FM10K_WRITE_REG(hw, FM10K_TDH(tx_queue_id), 0); + FM10K_WRITE_REG(hw, FM10K_TDT(tx_queue_id), 0); + + /* enable TX queue */ + FM10K_WRITE_REG(hw, FM10K_TXDCTL(tx_queue_id), + FM10K_TXDCTL_ENABLE | txdctl); + FM10K_WRITE_FLUSH(hw); + } else + err = -1; + + return err; +} + +static int +fm10k_dev_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + PMD_INIT_FUNC_TRACE(); + + if (tx_queue_id < dev->data->nb_tx_queues) { + tx_queue_disable(hw, tx_queue_id); + tx_queue_clean(dev->data->tx_queues[tx_queue_id]); + } + + return 0; +} + +/* fls = find last set bit = 32 minus the number of leading zeros */ +#ifndef fls +#define fls(x) (((x) == 0) ? 0 : (32 - __builtin_clz((x)))) +#endif +#define BSIZEPKT_ROUNDUP ((1 << FM10K_SRRCTL_BSIZEPKT_SHIFT) - 1) +static int +fm10k_dev_start(struct rte_eth_dev *dev) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int i, diag; + + PMD_INIT_FUNC_TRACE(); + + /* stop, init, then start the hw */ + diag = fm10k_stop_hw(hw); + if (diag != FM10K_SUCCESS) { + PMD_INIT_LOG(ERR, "Hardware stop failed: %d", diag); + return -EIO; + } + + diag = fm10k_init_hw(hw); + if (diag != FM10K_SUCCESS) { + PMD_INIT_LOG(ERR, "Hardware init failed: %d", diag); + return -EIO; + } + + diag = fm10k_start_hw(hw); + if (diag != FM10K_SUCCESS) { + PMD_INIT_LOG(ERR, "Hardware start failed: %d", diag); + return -EIO; + } + + diag = fm10k_dev_tx_init(dev); + if (diag) { + PMD_INIT_LOG(ERR, "TX init failed: %d", diag); + return diag; + } + + diag = fm10k_dev_rx_init(dev); + if (diag) { + PMD_INIT_LOG(ERR, "RX init failed: %d", diag); + return diag; + } + + if (hw->mac.type == fm10k_mac_pf) { + /* Establish only VSI 0 as valid */ + FM10K_WRITE_REG(hw, FM10K_DGLORTMAP(0), FM10K_DGLORTMAP_ANY); + + /* Configure RSS bits used in RETA table */ + FM10K_WRITE_REG(hw, FM10K_DGLORTDEC(0), + fls(dev->data->nb_rx_queues - 1) << + FM10K_DGLORTDEC_RSSLENGTH_SHIFT); + + /* Invalidate all other GLORT entries */ + for (i = 1; i < FM10K_DGLORT_COUNT; i++) + FM10K_WRITE_REG(hw, FM10K_DGLORTMAP(i), + FM10K_DGLORTMAP_NONE); + } + + for (i = 0; i < dev->data->nb_rx_queues; i++) { + struct fm10k_rx_queue *rxq; + rxq = dev->data->rx_queues[i]; + + if (rxq->rx_deferred_start) + continue; + diag = fm10k_dev_rx_queue_start(dev, i); + if (diag != 0) { + int j; + for (j = 0; j < i; ++j) + rx_queue_clean(dev->data->rx_queues[j]); + return diag; + } + } + + for (i = 0; i < dev->data->nb_tx_queues; i++) { + struct fm10k_tx_queue *txq; + txq = dev->data->tx_queues[i]; + + if (txq->tx_deferred_start) + continue; + diag = fm10k_dev_tx_queue_start(dev, i); + if (diag != 0) { + int j; + for (j = 0; j < dev->data->nb_rx_queues; ++j) + rx_queue_clean(dev->data->rx_queues[j]); + return diag; + } + } + + return 0; +} + +static void +fm10k_dev_stop(struct rte_eth_dev *dev) +{ + int i; + + PMD_INIT_FUNC_TRACE(); + + for (i = 0; i < dev->data->nb_tx_queues; i++) + fm10k_dev_tx_queue_stop(dev, i); + + for (i = 0; i < dev->data->nb_rx_queues; i++) + fm10k_dev_rx_queue_stop(dev, i); +} + +static void +fm10k_dev_close(struct rte_eth_dev *dev) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + PMD_INIT_FUNC_TRACE(); + + /* Stop mailbox service first */ + fm10k_close_mbx_service(hw); + fm10k_dev_stop(dev); + fm10k_stop_hw(hw); +} + +static int +fm10k_link_update(struct rte_eth_dev *dev, + __rte_unused int wait_to_complete) +{ + PMD_INIT_FUNC_TRACE(); + + /* The host-interface link is always up. The speed is ~50Gbps per Gen3 + * x8 PCIe interface. For now, we leave the speed undefined since there + * is no 50Gbps Ethernet. */ + dev->data->dev_link.link_speed = 0; + dev->data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX; + dev->data->dev_link.link_status = 1; + + return 0; +} + +static void +fm10k_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) +{ + uint64_t ipackets, opackets, ibytes, obytes; + struct fm10k_hw *hw = + FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct fm10k_hw_stats *hw_stats = + FM10K_DEV_PRIVATE_TO_STATS(dev->data->dev_private); + int i; + + PMD_INIT_FUNC_TRACE(); + + fm10k_update_hw_stats(hw, hw_stats); + + ipackets = opackets = ibytes = obytes = 0; + for (i = 0; (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) && + (i < FM10K_MAX_QUEUES_PF); ++i) { + stats->q_ipackets[i] = hw_stats->q[i].rx_packets.count; + stats->q_opackets[i] = hw_stats->q[i].tx_packets.count; + stats->q_ibytes[i] = hw_stats->q[i].rx_bytes.count; + stats->q_obytes[i] = hw_stats->q[i].tx_bytes.count; + ipackets += stats->q_ipackets[i]; + opackets += stats->q_opackets[i]; + ibytes += stats->q_ibytes[i]; + obytes += stats->q_obytes[i]; + } + stats->ipackets = ipackets; + stats->opackets = opackets; + stats->ibytes = ibytes; + stats->obytes = obytes; +} + +static void +fm10k_stats_reset(struct rte_eth_dev *dev) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct fm10k_hw_stats *hw_stats = + FM10K_DEV_PRIVATE_TO_STATS(dev->data->dev_private); + + PMD_INIT_FUNC_TRACE(); + + memset(hw_stats, 0, sizeof(*hw_stats)); + fm10k_rebind_hw_stats(hw, hw_stats); +} + +static void +fm10k_dev_infos_get(struct rte_eth_dev *dev, + struct rte_eth_dev_info *dev_info) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + PMD_INIT_FUNC_TRACE(); + + dev_info->min_rx_bufsize = FM10K_MIN_RX_BUF_SIZE; + dev_info->max_rx_pktlen = FM10K_MAX_PKT_SIZE; + dev_info->max_rx_queues = hw->mac.max_queues; + dev_info->max_tx_queues = hw->mac.max_queues; + dev_info->max_mac_addrs = 1; + dev_info->max_hash_mac_addrs = 0; + dev_info->max_vfs = FM10K_MAX_VF_NUM; + dev_info->max_vmdq_pools = ETH_64_POOLS; + dev_info->rx_offload_capa = + DEV_RX_OFFLOAD_IPV4_CKSUM | + DEV_RX_OFFLOAD_UDP_CKSUM | + DEV_RX_OFFLOAD_TCP_CKSUM; + dev_info->tx_offload_capa = 0; + dev_info->reta_size = FM10K_MAX_RSS_INDICES; + + dev_info->default_rxconf = (struct rte_eth_rxconf) { + .rx_thresh = { + .pthresh = FM10K_DEFAULT_RX_PTHRESH, + .hthresh = FM10K_DEFAULT_RX_HTHRESH, + .wthresh = FM10K_DEFAULT_RX_WTHRESH, + }, + .rx_free_thresh = FM10K_RX_FREE_THRESH_DEFAULT(0), + .rx_drop_en = 0, + }; + + dev_info->default_txconf = (struct rte_eth_txconf) { + .tx_thresh = { + .pthresh = FM10K_DEFAULT_TX_PTHRESH, + .hthresh = FM10K_DEFAULT_TX_HTHRESH, + .wthresh = FM10K_DEFAULT_TX_WTHRESH, + }, + .tx_free_thresh = FM10K_TX_FREE_THRESH_DEFAULT(0), + .tx_rs_thresh = FM10K_TX_RS_THRESH_DEFAULT(0), + .txq_flags = ETH_TXQ_FLAGS_NOMULTSEGS | + ETH_TXQ_FLAGS_NOOFFLOADS, + }; + +} + +static int +fm10k_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + PMD_INIT_FUNC_TRACE(); + + /* @todo - add support for the VF */ + if (hw->mac.type != fm10k_mac_pf) + return -ENOTSUP; + + return fm10k_update_vlan(hw, vlan_id, 0, on); +} + +static inline int +check_nb_desc(uint16_t min, uint16_t max, uint16_t mult, uint16_t request) +{ + if ((request < min) || (request > max) || ((request % mult) != 0)) + return -1; + else + return 0; +} + +/* + * Create a memzone for hardware descriptor rings. Malloc cannot be used since + * the physical address is required. If the memzone is already created, then + * this function returns a pointer to the existing memzone. + */ +static inline const struct rte_memzone * +allocate_hw_ring(const char *driver_name, const char *ring_name, + uint8_t port_id, uint16_t queue_id, int socket_id, + uint32_t size, uint32_t align) +{ + char name[RTE_MEMZONE_NAMESIZE]; + const struct rte_memzone *mz; + + snprintf(name, sizeof(name), "%s_%s_%d_%d_%d", + driver_name, ring_name, port_id, queue_id, socket_id); + + /* return the memzone if it already exists */ + mz = rte_memzone_lookup(name); + if (mz) + return mz; + +#ifdef RTE_LIBRTE_XEN_DOM0 + return rte_memzone_reserve_bounded(name, size, socket_id, 0, align, + RTE_PGSIZE_2M); +#else + return rte_memzone_reserve_aligned(name, size, socket_id, 0, align); +#endif +} + +static inline int +check_thresh(uint16_t min, uint16_t max, uint16_t div, uint16_t request) +{ + if ((request < min) || (request > max) || ((div % request) != 0)) + return -1; + else + return 0; +} + +static inline int +handle_rxconf(struct fm10k_rx_queue *q, const struct rte_eth_rxconf *conf) +{ + uint16_t rx_free_thresh; + + if (conf->rx_free_thresh == 0) + rx_free_thresh = FM10K_RX_FREE_THRESH_DEFAULT(q); + else + rx_free_thresh = conf->rx_free_thresh; + + /* make sure the requested threshold satisfies the constraints */ + if (check_thresh(FM10K_RX_FREE_THRESH_MIN(q), + FM10K_RX_FREE_THRESH_MAX(q), + FM10K_RX_FREE_THRESH_DIV(q), + rx_free_thresh)) { + PMD_INIT_LOG(ERR, "rx_free_thresh (%u) must be " + "less than or equal to %u, " + "greater than or equal to %u, " + "and a divisor of %u", + rx_free_thresh, FM10K_RX_FREE_THRESH_MAX(q), + FM10K_RX_FREE_THRESH_MIN(q), + FM10K_RX_FREE_THRESH_DIV(q)); + return (-EINVAL); + } + + q->alloc_thresh = rx_free_thresh; + q->drop_en = conf->rx_drop_en; + q->rx_deferred_start = conf->rx_deferred_start; + + return 0; +} + +/* + * Hardware requires specific alignment for Rx packet buffers. At + * least one of the following two conditions must be satisfied. + * 1. Address is 512B aligned + * 2. Address is 8B aligned and buffer does not cross 4K boundary. + * + * As such, the driver may need to adjust the DMA address within the + * buffer by up to 512B. The mempool element size is checked here + * to make sure a maximally sized Ethernet frame can still be wholly + * contained within the buffer after 512B alignment. + * + * return 1 if the element size is valid, otherwise return 0. + */ +static int +mempool_element_size_valid(struct rte_mempool *mp) +{ + uint32_t min_size; + + /* elt_size includes mbuf header and headroom */ + min_size = mp->elt_size - sizeof(struct rte_mbuf) - + RTE_PKTMBUF_HEADROOM; + + /* account for up to 512B of alignment */ + min_size -= FM10K_RX_BUFF_ALIGN; + + /* sanity check for overflow */ + if (min_size > mp->elt_size) + return 0; + + if (min_size < ETHER_MAX_VLAN_FRAME_LEN) + return 0; + + /* size is valid */ + return 1; +} + +static int +fm10k_rx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_id, + uint16_t nb_desc, unsigned int socket_id, + const struct rte_eth_rxconf *conf, struct rte_mempool *mp) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct fm10k_rx_queue *q; + const struct rte_memzone *mz; + + PMD_INIT_FUNC_TRACE(); + + /* make sure the mempool element size can account for alignment. */ + if (!mempool_element_size_valid(mp)) { + PMD_INIT_LOG(ERR, "Error : Mempool element size is too small"); + return (-EINVAL); + } + + /* make sure a valid number of descriptors have been requested */ + if (check_nb_desc(FM10K_MIN_RX_DESC, FM10K_MAX_RX_DESC, + FM10K_MULT_RX_DESC, nb_desc)) { + PMD_INIT_LOG(ERR, "Number of Rx descriptors (%u) must be " + "less than or equal to %"PRIu32", " + "greater than or equal to %u, " + "and a multiple of %u", + nb_desc, (uint32_t)FM10K_MAX_RX_DESC, FM10K_MIN_RX_DESC, + FM10K_MULT_RX_DESC); + return (-EINVAL); + } + + /* + * if this queue existed already, free the associated memory. The + * queue cannot be reused in case we need to allocate memory on + * different socket than was previously used. + */ + if (dev->data->rx_queues[queue_id] != NULL) { + rx_queue_free(dev->data->rx_queues[queue_id]); + dev->data->rx_queues[queue_id] = NULL; + } + + /* allocate memory for the queue structure */ + q = rte_zmalloc_socket("fm10k", sizeof(*q), RTE_CACHE_LINE_SIZE, + socket_id); + if (q == NULL) { + PMD_INIT_LOG(ERR, "Cannot allocate queue structure"); + return (-ENOMEM); + } + + /* setup queue */ + q->mp = mp; + q->nb_desc = nb_desc; + q->port_id = dev->data->port_id; + q->queue_id = queue_id; + q->tail_ptr = (volatile uint32_t *) + &((uint32_t *)hw->hw_addr)[FM10K_RDT(queue_id)]; + if (handle_rxconf(q, conf)) + return (-EINVAL); + + /* allocate memory for the software ring */ + q->sw_ring = rte_zmalloc_socket("fm10k sw ring", + nb_desc * sizeof(struct rte_mbuf *), + RTE_CACHE_LINE_SIZE, socket_id); + if (q->sw_ring == NULL) { + PMD_INIT_LOG(ERR, "Cannot allocate software ring"); + rte_free(q); + return (-ENOMEM); + } + + /* + * allocate memory for the hardware descriptor ring. A memzone large + * enough to hold the maximum ring size is requested to allow for + * resizing in later calls to the queue setup function. + */ + mz = allocate_hw_ring(dev->driver->pci_drv.name, "rx_ring", + dev->data->port_id, queue_id, socket_id, + FM10K_MAX_RX_RING_SZ, FM10K_ALIGN_RX_DESC); + if (mz == NULL) { + PMD_INIT_LOG(ERR, "Cannot allocate hardware ring"); + rte_free(q->sw_ring); + rte_free(q); + return (-ENOMEM); + } + q->hw_ring = mz->addr; + q->hw_ring_phys_addr = mz->phys_addr; + + dev->data->rx_queues[queue_id] = q; + return 0; +} + +static void +fm10k_rx_queue_release(void *queue) +{ + PMD_INIT_FUNC_TRACE(); + + rx_queue_free(queue); +} + +static inline int +handle_txconf(struct fm10k_tx_queue *q, const struct rte_eth_txconf *conf) +{ + uint16_t tx_free_thresh; + uint16_t tx_rs_thresh; + + /* constraint MACROs require that tx_free_thresh is configured + * before tx_rs_thresh */ + if (conf->tx_free_thresh == 0) + tx_free_thresh = FM10K_TX_FREE_THRESH_DEFAULT(q); + else + tx_free_thresh = conf->tx_free_thresh; + + /* make sure the requested threshold satisfies the constraints */ + if (check_thresh(FM10K_TX_FREE_THRESH_MIN(q), + FM10K_TX_FREE_THRESH_MAX(q), + FM10K_TX_FREE_THRESH_DIV(q), + tx_free_thresh)) { + PMD_INIT_LOG(ERR, "tx_free_thresh (%u) must be " + "less than or equal to %u, " + "greater than or equal to %u, " + "and a divisor of %u", + tx_free_thresh, FM10K_TX_FREE_THRESH_MAX(q), + FM10K_TX_FREE_THRESH_MIN(q), + FM10K_TX_FREE_THRESH_DIV(q)); + return (-EINVAL); + } + + q->free_thresh = tx_free_thresh; + + if (conf->tx_rs_thresh == 0) + tx_rs_thresh = FM10K_TX_RS_THRESH_DEFAULT(q); + else + tx_rs_thresh = conf->tx_rs_thresh; + + q->tx_deferred_start = conf->tx_deferred_start; + + /* make sure the requested threshold satisfies the constraints */ + if (check_thresh(FM10K_TX_RS_THRESH_MIN(q), + FM10K_TX_RS_THRESH_MAX(q), + FM10K_TX_RS_THRESH_DIV(q), + tx_rs_thresh)) { + PMD_INIT_LOG(ERR, "tx_rs_thresh (%u) must be " + "less than or equal to %u, " + "greater than or equal to %u, " + "and a divisor of %u", + tx_rs_thresh, FM10K_TX_RS_THRESH_MAX(q), + FM10K_TX_RS_THRESH_MIN(q), + FM10K_TX_RS_THRESH_DIV(q)); + return (-EINVAL); + } + + q->rs_thresh = tx_rs_thresh; + + return 0; +} + +static int +fm10k_tx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_id, + uint16_t nb_desc, unsigned int socket_id, + const struct rte_eth_txconf *conf) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct fm10k_tx_queue *q; + const struct rte_memzone *mz; + + PMD_INIT_FUNC_TRACE(); + + /* make sure a valid number of descriptors have been requested */ + if (check_nb_desc(FM10K_MIN_TX_DESC, FM10K_MAX_TX_DESC, + FM10K_MULT_TX_DESC, nb_desc)) { + PMD_INIT_LOG(ERR, "Number of Tx descriptors (%u) must be " + "less than or equal to %"PRIu32", " + "greater than or equal to %u, " + "and a multiple of %u", + nb_desc, (uint32_t)FM10K_MAX_TX_DESC, FM10K_MIN_TX_DESC, + FM10K_MULT_TX_DESC); + return (-EINVAL); + } + + /* + * if this queue existed already, free the associated memory. The + * queue cannot be reused in case we need to allocate memory on + * different socket than was previously used. + */ + if (dev->data->tx_queues[queue_id] != NULL) { + tx_queue_free(dev->data->tx_queues[queue_id]); + dev->data->tx_queues[queue_id] = NULL; + } + + /* allocate memory for the queue structure */ + q = rte_zmalloc_socket("fm10k", sizeof(*q), RTE_CACHE_LINE_SIZE, + socket_id); + if (q == NULL) { + PMD_INIT_LOG(ERR, "Cannot allocate queue structure"); + return (-ENOMEM); + } + + /* setup queue */ + q->nb_desc = nb_desc; + q->port_id = dev->data->port_id; + q->queue_id = queue_id; + q->tail_ptr = (volatile uint32_t *) + &((uint32_t *)hw->hw_addr)[FM10K_TDT(queue_id)]; + if (handle_txconf(q, conf)) + return (-EINVAL); + + /* allocate memory for the software ring */ + q->sw_ring = rte_zmalloc_socket("fm10k sw ring", + nb_desc * sizeof(struct rte_mbuf *), + RTE_CACHE_LINE_SIZE, socket_id); + if (q->sw_ring == NULL) { + PMD_INIT_LOG(ERR, "Cannot allocate software ring"); + rte_free(q); + return (-ENOMEM); + } + + /* + * allocate memory for the hardware descriptor ring. A memzone large + * enough to hold the maximum ring size is requested to allow for + * resizing in later calls to the queue setup function. + */ + mz = allocate_hw_ring(dev->driver->pci_drv.name, "tx_ring", + dev->data->port_id, queue_id, socket_id, + FM10K_MAX_TX_RING_SZ, FM10K_ALIGN_TX_DESC); + if (mz == NULL) { + PMD_INIT_LOG(ERR, "Cannot allocate hardware ring"); + rte_free(q->sw_ring); + rte_free(q); + return (-ENOMEM); + } + q->hw_ring = mz->addr; + q->hw_ring_phys_addr = mz->phys_addr; + + /* + * allocate memory for the RS bit tracker. Enough slots to hold the + * descriptor index for each RS bit needing to be set are required. + */ + q->rs_tracker.list = rte_zmalloc_socket("fm10k rs tracker", + ((nb_desc + 1) / q->rs_thresh) * + sizeof(uint16_t), + RTE_CACHE_LINE_SIZE, socket_id); + if (q->rs_tracker.list == NULL) { + PMD_INIT_LOG(ERR, "Cannot allocate RS bit tracker"); + rte_free(q->sw_ring); + rte_free(q); + return (-ENOMEM); + } + + dev->data->tx_queues[queue_id] = q; + return 0; +} + +static void +fm10k_tx_queue_release(void *queue) +{ + PMD_INIT_FUNC_TRACE(); + + tx_queue_free(queue); +} + +static int +fm10k_reta_update(struct rte_eth_dev *dev, + struct rte_eth_rss_reta_entry64 *reta_conf, + uint16_t reta_size) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint16_t i, j, idx, shift; + uint8_t mask; + uint32_t reta; + + PMD_INIT_FUNC_TRACE(); + + if (reta_size > FM10K_MAX_RSS_INDICES) { + PMD_INIT_LOG(ERR, "The size of hash lookup table configured " + "(%d) doesn't match the number hardware can supported " + "(%d)", reta_size, FM10K_MAX_RSS_INDICES); + return -EINVAL; + } + + /* + * Update Redirection Table RETA[n], n=0..31. The redirection table has + * 128-entries in 32 registers + */ + for (i = 0; i < FM10K_MAX_RSS_INDICES; i += CHARS_PER_UINT32) { + idx = i / RTE_RETA_GROUP_SIZE; + shift = i % RTE_RETA_GROUP_SIZE; + mask = (uint8_t)((reta_conf[idx].mask >> shift) & + BIT_MASK_PER_UINT32); + if (mask == 0) + continue; + + reta = 0; + if (mask != BIT_MASK_PER_UINT32) + reta = FM10K_READ_REG(hw, FM10K_RETA(0, i >> 2)); + + for (j = 0; j < CHARS_PER_UINT32; j++) { + if (mask & (0x1 << j)) { + if (mask != 0xF) + reta &= ~(UINT8_MAX << CHAR_BIT * j); + reta |= reta_conf[idx].reta[shift + j] << + (CHAR_BIT * j); + } + } + FM10K_WRITE_REG(hw, FM10K_RETA(0, i >> 2), reta); + } + + return 0; +} + +static int +fm10k_reta_query(struct rte_eth_dev *dev, + struct rte_eth_rss_reta_entry64 *reta_conf, + uint16_t reta_size) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint16_t i, j, idx, shift; + uint8_t mask; + uint32_t reta; + + PMD_INIT_FUNC_TRACE(); + + if (reta_size < FM10K_MAX_RSS_INDICES) { + PMD_INIT_LOG(ERR, "The size of hash lookup table configured " + "(%d) doesn't match the number hardware can supported " + "(%d)", reta_size, FM10K_MAX_RSS_INDICES); + return -EINVAL; + } + + /* + * Read Redirection Table RETA[n], n=0..31. The redirection table has + * 128-entries in 32 registers + */ + for (i = 0; i < FM10K_MAX_RSS_INDICES; i += CHARS_PER_UINT32) { + idx = i / RTE_RETA_GROUP_SIZE; + shift = i % RTE_RETA_GROUP_SIZE; + mask = (uint8_t)((reta_conf[idx].mask >> shift) & + BIT_MASK_PER_UINT32); + if (mask == 0) + continue; + + reta = FM10K_READ_REG(hw, FM10K_RETA(0, i >> 2)); + for (j = 0; j < CHARS_PER_UINT32; j++) { + if (mask & (0x1 << j)) + reta_conf[idx].reta[shift + j] = ((reta >> + CHAR_BIT * j) & UINT8_MAX); + } + } + + return 0; +} + +static int +fm10k_rss_hash_update(struct rte_eth_dev *dev, + struct rte_eth_rss_conf *rss_conf) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t *key = (uint32_t *)rss_conf->rss_key; + uint32_t mrqc; + uint64_t hf = rss_conf->rss_hf; + int i; + + PMD_INIT_FUNC_TRACE(); + + if (rss_conf->rss_key_len < FM10K_RSSRK_SIZE * + FM10K_RSSRK_ENTRIES_PER_REG) + return -EINVAL; + + if (hf == 0) + return -EINVAL; + + mrqc = 0; + mrqc |= (hf & ETH_RSS_IPV4) ? FM10K_MRQC_IPV4 : 0; + mrqc |= (hf & ETH_RSS_IPV6) ? FM10K_MRQC_IPV6 : 0; + mrqc |= (hf & ETH_RSS_IPV6_EX) ? FM10K_MRQC_IPV6 : 0; + mrqc |= (hf & ETH_RSS_NONFRAG_IPV4_TCP) ? FM10K_MRQC_TCP_IPV4 : 0; + mrqc |= (hf & ETH_RSS_NONFRAG_IPV6_TCP) ? FM10K_MRQC_TCP_IPV6 : 0; + mrqc |= (hf & ETH_RSS_IPV6_TCP_EX) ? FM10K_MRQC_TCP_IPV6 : 0; + mrqc |= (hf & ETH_RSS_NONFRAG_IPV4_UDP) ? FM10K_MRQC_UDP_IPV4 : 0; + mrqc |= (hf & ETH_RSS_NONFRAG_IPV6_UDP) ? FM10K_MRQC_UDP_IPV6 : 0; + mrqc |= (hf & ETH_RSS_IPV6_UDP_EX) ? FM10K_MRQC_UDP_IPV6 : 0; + + /* If the mapping doesn't fit any supported, return */ + if (mrqc == 0) + return -EINVAL; + + if (key != NULL) + for (i = 0; i < FM10K_RSSRK_SIZE; ++i) + FM10K_WRITE_REG(hw, FM10K_RSSRK(0, i), key[i]); + + FM10K_WRITE_REG(hw, FM10K_MRQC(0), mrqc); + + return 0; +} + +static int +fm10k_rss_hash_conf_get(struct rte_eth_dev *dev, + struct rte_eth_rss_conf *rss_conf) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t *key = (uint32_t *)rss_conf->rss_key; + uint32_t mrqc; + uint64_t hf; + int i; + + PMD_INIT_FUNC_TRACE(); + + if (rss_conf->rss_key_len < FM10K_RSSRK_SIZE * + FM10K_RSSRK_ENTRIES_PER_REG) + return -EINVAL; + + if (key != NULL) + for (i = 0; i < FM10K_RSSRK_SIZE; ++i) + key[i] = FM10K_READ_REG(hw, FM10K_RSSRK(0, i)); + + mrqc = FM10K_READ_REG(hw, FM10K_MRQC(0)); + hf = 0; + hf |= (mrqc & FM10K_MRQC_IPV4) ? ETH_RSS_IPV4 : 0; + hf |= (mrqc & FM10K_MRQC_IPV6) ? ETH_RSS_IPV6 : 0; + hf |= (mrqc & FM10K_MRQC_IPV6) ? ETH_RSS_IPV6_EX : 0; + hf |= (mrqc & FM10K_MRQC_TCP_IPV4) ? ETH_RSS_NONFRAG_IPV4_TCP : 0; + hf |= (mrqc & FM10K_MRQC_TCP_IPV6) ? ETH_RSS_NONFRAG_IPV6_TCP : 0; + hf |= (mrqc & FM10K_MRQC_TCP_IPV6) ? ETH_RSS_IPV6_TCP_EX : 0; + hf |= (mrqc & FM10K_MRQC_UDP_IPV4) ? ETH_RSS_NONFRAG_IPV4_UDP : 0; + hf |= (mrqc & FM10K_MRQC_UDP_IPV6) ? ETH_RSS_NONFRAG_IPV6_UDP : 0; + hf |= (mrqc & FM10K_MRQC_UDP_IPV6) ? ETH_RSS_IPV6_UDP_EX : 0; + + rss_conf->rss_hf = hf; + + return 0; +} + +static void +fm10k_dev_enable_intr_pf(struct rte_eth_dev *dev) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t int_map = FM10K_INT_MAP_IMMEDIATE; + + /* Bind all local non-queue interrupt to vector 0 */ + int_map |= 0; + + FM10K_WRITE_REG(hw, FM10K_INT_MAP(fm10k_int_Mailbox), int_map); + FM10K_WRITE_REG(hw, FM10K_INT_MAP(fm10k_int_PCIeFault), int_map); + FM10K_WRITE_REG(hw, FM10K_INT_MAP(fm10k_int_SwitchUpDown), int_map); + FM10K_WRITE_REG(hw, FM10K_INT_MAP(fm10k_int_SwitchEvent), int_map); + FM10K_WRITE_REG(hw, FM10K_INT_MAP(fm10k_int_SRAM), int_map); + FM10K_WRITE_REG(hw, FM10K_INT_MAP(fm10k_int_VFLR), int_map); + + /* Enable misc causes */ + FM10K_WRITE_REG(hw, FM10K_EIMR, FM10K_EIMR_ENABLE(PCA_FAULT) | + FM10K_EIMR_ENABLE(THI_FAULT) | + FM10K_EIMR_ENABLE(FUM_FAULT) | + FM10K_EIMR_ENABLE(MAILBOX) | + FM10K_EIMR_ENABLE(SWITCHREADY) | + FM10K_EIMR_ENABLE(SWITCHNOTREADY) | + FM10K_EIMR_ENABLE(SRAMERROR) | + FM10K_EIMR_ENABLE(VFLR)); + + /* Enable ITR 0 */ + FM10K_WRITE_REG(hw, FM10K_ITR(0), FM10K_ITR_AUTOMASK | + FM10K_ITR_MASK_CLEAR); + FM10K_WRITE_FLUSH(hw); +} + +static void +fm10k_dev_enable_intr_vf(struct rte_eth_dev *dev) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t int_map = FM10K_INT_MAP_IMMEDIATE; + + /* Bind all local non-queue interrupt to vector 0 */ + int_map |= 0; + + /* Only INT 0 available, other 15 are reserved. */ + FM10K_WRITE_REG(hw, FM10K_VFINT_MAP, int_map); + + /* Enable ITR 0 */ + FM10K_WRITE_REG(hw, FM10K_VFITR(0), FM10K_ITR_AUTOMASK | + FM10K_ITR_MASK_CLEAR); + FM10K_WRITE_FLUSH(hw); +} + +static int +fm10k_dev_handle_fault(struct fm10k_hw *hw, uint32_t eicr) +{ + struct fm10k_fault fault; + int err; + const char *estr = "Unknown error"; + + /* Process PCA fault */ + if (eicr & FM10K_EIMR_PCA_FAULT) { + err = fm10k_get_fault(hw, FM10K_PCA_FAULT, &fault); + if (err) + goto error; + switch (fault.type) { + case PCA_NO_FAULT: + estr = "PCA_NO_FAULT"; break; + case PCA_UNMAPPED_ADDR: + estr = "PCA_UNMAPPED_ADDR"; break; + case PCA_BAD_QACCESS_PF: + estr = "PCA_BAD_QACCESS_PF"; break; + case PCA_BAD_QACCESS_VF: + estr = "PCA_BAD_QACCESS_VF"; break; + case PCA_MALICIOUS_REQ: + estr = "PCA_MALICIOUS_REQ"; break; + case PCA_POISONED_TLP: + estr = "PCA_POISONED_TLP"; break; + case PCA_TLP_ABORT: + estr = "PCA_TLP_ABORT"; break; + default: + goto error; + } + PMD_INIT_LOG(ERR, "%s: %s(%d) Addr:0x%"PRIx64" Spec: 0x%x", + estr, fault.func ? "VF" : "PF", fault.func, + fault.address, fault.specinfo); + } + + /* Process THI fault */ + if (eicr & FM10K_EIMR_THI_FAULT) { + err = fm10k_get_fault(hw, FM10K_THI_FAULT, &fault); + if (err) + goto error; + switch (fault.type) { + case THI_NO_FAULT: + estr = "THI_NO_FAULT"; break; + case THI_MAL_DIS_Q_FAULT: + estr = "THI_MAL_DIS_Q_FAULT"; break; + default: + goto error; + } + PMD_INIT_LOG(ERR, "%s: %s(%d) Addr:0x%"PRIx64" Spec: 0x%x", + estr, fault.func ? "VF" : "PF", fault.func, + fault.address, fault.specinfo); + } + + /* Process FUM fault */ + if (eicr & FM10K_EIMR_FUM_FAULT) { + err = fm10k_get_fault(hw, FM10K_FUM_FAULT, &fault); + if (err) + goto error; + switch (fault.type) { + case FUM_NO_FAULT: + estr = "FUM_NO_FAULT"; break; + case FUM_UNMAPPED_ADDR: + estr = "FUM_UNMAPPED_ADDR"; break; + case FUM_POISONED_TLP: + estr = "FUM_POISONED_TLP"; break; + case FUM_BAD_VF_QACCESS: + estr = "FUM_BAD_VF_QACCESS"; break; + case FUM_ADD_DECODE_ERR: + estr = "FUM_ADD_DECODE_ERR"; break; + case FUM_RO_ERROR: + estr = "FUM_RO_ERROR"; break; + case FUM_QPRC_CRC_ERROR: + estr = "FUM_QPRC_CRC_ERROR"; break; + case FUM_CSR_TIMEOUT: + estr = "FUM_CSR_TIMEOUT"; break; + case FUM_INVALID_TYPE: + estr = "FUM_INVALID_TYPE"; break; + case FUM_INVALID_LENGTH: + estr = "FUM_INVALID_LENGTH"; break; + case FUM_INVALID_BE: + estr = "FUM_INVALID_BE"; break; + case FUM_INVALID_ALIGN: + estr = "FUM_INVALID_ALIGN"; break; + default: + goto error; + } + PMD_INIT_LOG(ERR, "%s: %s(%d) Addr:0x%"PRIx64" Spec: 0x%x", + estr, fault.func ? "VF" : "PF", fault.func, + fault.address, fault.specinfo); + } + + if (estr) + return 0; + return 0; +error: + PMD_INIT_LOG(ERR, "Failed to handle fault event."); + return err; +} + +/** + * PF interrupt handler triggered by NIC for handling specific interrupt. + * + * @param handle + * Pointer to interrupt handle. + * @param param + * The address of parameter (struct rte_eth_dev *) regsitered before. + * + * @return + * void + */ +static void +fm10k_dev_interrupt_handler_pf( + __rte_unused struct rte_intr_handle *handle, + void *param) +{ + struct rte_eth_dev *dev = (struct rte_eth_dev *)param; + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t cause, status; + + if (hw->mac.type != fm10k_mac_pf) + return; + + cause = FM10K_READ_REG(hw, FM10K_EICR); + + /* Handle PCI fault cases */ + if (cause & FM10K_EICR_FAULT_MASK) { + PMD_INIT_LOG(ERR, "INT: find fault!"); + fm10k_dev_handle_fault(hw, cause); + } + + /* Handle switch up/down */ + if (cause & FM10K_EICR_SWITCHNOTREADY) + PMD_INIT_LOG(ERR, "INT: Switch is not ready"); + + if (cause & FM10K_EICR_SWITCHREADY) + PMD_INIT_LOG(INFO, "INT: Switch is ready"); + + /* Handle mailbox message */ + fm10k_mbx_lock(hw); + hw->mbx.ops.process(hw, &hw->mbx); + fm10k_mbx_unlock(hw); + + /* Handle SRAM error */ + if (cause & FM10K_EICR_SRAMERROR) { + PMD_INIT_LOG(ERR, "INT: SRAM error on PEP"); + + status = FM10K_READ_REG(hw, FM10K_SRAM_IP); + /* Write to clear pending bits */ + FM10K_WRITE_REG(hw, FM10K_SRAM_IP, status); + + /* Todo: print out error message after shared code updates */ + } + + /* Clear these 3 events if having any */ + cause &= FM10K_EICR_SWITCHNOTREADY | FM10K_EICR_MAILBOX | + FM10K_EICR_SWITCHREADY; + if (cause) + FM10K_WRITE_REG(hw, FM10K_EICR, cause); + + /* Re-enable interrupt from device side */ + FM10K_WRITE_REG(hw, FM10K_ITR(0), FM10K_ITR_AUTOMASK | + FM10K_ITR_MASK_CLEAR); + /* Re-enable interrupt from host side */ + rte_intr_enable(&(dev->pci_dev->intr_handle)); +} + +/** + * VF interrupt handler triggered by NIC for handling specific interrupt. + * + * @param handle + * Pointer to interrupt handle. + * @param param + * The address of parameter (struct rte_eth_dev *) regsitered before. + * + * @return + * void + */ +static void +fm10k_dev_interrupt_handler_vf( + __rte_unused struct rte_intr_handle *handle, + void *param) +{ + struct rte_eth_dev *dev = (struct rte_eth_dev *)param; + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + if (hw->mac.type != fm10k_mac_vf) + return; + + /* Handle mailbox message if lock is acquired */ + fm10k_mbx_lock(hw); + hw->mbx.ops.process(hw, &hw->mbx); + fm10k_mbx_unlock(hw); + + /* Re-enable interrupt from device side */ + FM10K_WRITE_REG(hw, FM10K_VFITR(0), FM10K_ITR_AUTOMASK | + FM10K_ITR_MASK_CLEAR); + /* Re-enable interrupt from host side */ + rte_intr_enable(&(dev->pci_dev->intr_handle)); +} + +/* Mailbox message handler in VF */ +static const struct fm10k_msg_data fm10k_msgdata_vf[] = { + FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test), + FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_msg_mac_vlan_vf), + FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_msg_lport_state_vf), + FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error), +}; + +/* Mailbox message handler in PF */ +static const struct fm10k_msg_data fm10k_msgdata_pf[] = { + FM10K_PF_MSG_ERR_HANDLER(XCAST_MODES, fm10k_msg_err_pf), + FM10K_PF_MSG_ERR_HANDLER(UPDATE_MAC_FWD_RULE, fm10k_msg_err_pf), + FM10K_PF_MSG_LPORT_MAP_HANDLER(fm10k_msg_lport_map_pf), + FM10K_PF_MSG_ERR_HANDLER(LPORT_CREATE, fm10k_msg_err_pf), + FM10K_PF_MSG_ERR_HANDLER(LPORT_DELETE, fm10k_msg_err_pf), + FM10K_PF_MSG_UPDATE_PVID_HANDLER(fm10k_msg_update_pvid_pf), + FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error), +}; + +static int +fm10k_setup_mbx_service(struct fm10k_hw *hw) +{ + int err; + + /* Initialize mailbox lock */ + fm10k_mbx_initlock(hw); + + /* Replace default message handler with new ones */ + if (hw->mac.type == fm10k_mac_pf) + err = hw->mbx.ops.register_handlers(&hw->mbx, fm10k_msgdata_pf); + else + err = hw->mbx.ops.register_handlers(&hw->mbx, fm10k_msgdata_vf); + + if (err) { + PMD_INIT_LOG(ERR, "Failed to register mailbox handler.err:%d", + err); + return err; + } + /* Connect to SM for PF device or PF for VF device */ + return hw->mbx.ops.connect(hw, &hw->mbx); +} + +static void +fm10k_close_mbx_service(struct fm10k_hw *hw) +{ + /* Disconnect from SM for PF device or PF for VF device */ + hw->mbx.ops.disconnect(hw, &hw->mbx); +} + +static const struct eth_dev_ops fm10k_eth_dev_ops = { + .dev_configure = fm10k_dev_configure, + .dev_start = fm10k_dev_start, + .dev_stop = fm10k_dev_stop, + .dev_close = fm10k_dev_close, + .stats_get = fm10k_stats_get, + .stats_reset = fm10k_stats_reset, + .link_update = fm10k_link_update, + .dev_infos_get = fm10k_dev_infos_get, + .vlan_filter_set = fm10k_vlan_filter_set, + .rx_queue_start = fm10k_dev_rx_queue_start, + .rx_queue_stop = fm10k_dev_rx_queue_stop, + .tx_queue_start = fm10k_dev_tx_queue_start, + .tx_queue_stop = fm10k_dev_tx_queue_stop, + .rx_queue_setup = fm10k_rx_queue_setup, + .rx_queue_release = fm10k_rx_queue_release, + .tx_queue_setup = fm10k_tx_queue_setup, + .tx_queue_release = fm10k_tx_queue_release, + .reta_update = fm10k_reta_update, + .reta_query = fm10k_reta_query, + .rss_hash_update = fm10k_rss_hash_update, + .rss_hash_conf_get = fm10k_rss_hash_conf_get, +}; + +static int +eth_fm10k_dev_init(struct rte_eth_dev *dev) +{ + struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int diag; + + PMD_INIT_FUNC_TRACE(); + + dev->dev_ops = &fm10k_eth_dev_ops; + dev->rx_pkt_burst = &fm10k_recv_pkts; + dev->tx_pkt_burst = &fm10k_xmit_pkts; + + if (dev->data->scattered_rx) + dev->rx_pkt_burst = &fm10k_recv_scattered_pkts; + + /* only initialize in the primary process */ + if (rte_eal_process_type() != RTE_PROC_PRIMARY) + return 0; + + /* Vendor and Device ID need to be set before init of shared code */ + memset(hw, 0, sizeof(*hw)); + hw->device_id = dev->pci_dev->id.device_id; + hw->vendor_id = dev->pci_dev->id.vendor_id; + hw->subsystem_device_id = dev->pci_dev->id.subsystem_device_id; + hw->subsystem_vendor_id = dev->pci_dev->id.subsystem_vendor_id; + hw->revision_id = 0; + hw->hw_addr = (void *)dev->pci_dev->mem_resource[0].addr; + if (hw->hw_addr == NULL) { + PMD_INIT_LOG(ERR, "Bad mem resource." + " Try to blacklist unused devices."); + return -EIO; + } + + /* Store fm10k_adapter pointer */ + hw->back = dev->data->dev_private; + + /* Initialize the shared code */ + diag = fm10k_init_shared_code(hw); + if (diag != FM10K_SUCCESS) { + PMD_INIT_LOG(ERR, "Shared code init failed: %d", diag); + return -EIO; + } + + /* + * Inialize bus info. Normally we would call fm10k_get_bus_info(), but + * there is no way to get link status without reading BAR4. Until this + * works, assume we have maximum bandwidth. + * @todo - fix bus info + */ + hw->bus_caps.speed = fm10k_bus_speed_8000; + hw->bus_caps.width = fm10k_bus_width_pcie_x8; + hw->bus_caps.payload = fm10k_bus_payload_512; + hw->bus.speed = fm10k_bus_speed_8000; + hw->bus.width = fm10k_bus_width_pcie_x8; + hw->bus.payload = fm10k_bus_payload_256; + + /* Initialize the hw */ + diag = fm10k_init_hw(hw); + if (diag != FM10K_SUCCESS) { + PMD_INIT_LOG(ERR, "Hardware init failed: %d", diag); + return -EIO; + } + + /* Initialize MAC address(es) */ + dev->data->mac_addrs = rte_zmalloc("fm10k", ETHER_ADDR_LEN, 0); + if (dev->data->mac_addrs == NULL) { + PMD_INIT_LOG(ERR, "Cannot allocate memory for MAC addresses"); + return -ENOMEM; + } + + diag = fm10k_read_mac_addr(hw); + if (diag != FM10K_SUCCESS) { + /* + * TODO: remove special handling on VF. Need shared code to + * fix first. + */ + if (hw->mac.type == fm10k_mac_pf) { + PMD_INIT_LOG(ERR, "Read MAC addr failed: %d", diag); + return -EIO; + } else { + /* Generate a random addr */ + eth_random_addr(hw->mac.addr); + memcpy(hw->mac.perm_addr, hw->mac.addr, ETH_ALEN); + } + } + + ether_addr_copy((const struct ether_addr *)hw->mac.addr, + &dev->data->mac_addrs[0]); + + /* Reset the hw statistics */ + fm10k_stats_reset(dev); + + /* Reset the hw */ + diag = fm10k_reset_hw(hw); + if (diag != FM10K_SUCCESS) { + PMD_INIT_LOG(ERR, "Hardware reset failed: %d", diag); + return -EIO; + } + + /* Setup mailbox service */ + diag = fm10k_setup_mbx_service(hw); + if (diag != FM10K_SUCCESS) { + PMD_INIT_LOG(ERR, "Failed to setup mailbox: %d", diag); + return -EIO; + } + + /*PF/VF has different interrupt handling mechanism */ + if (hw->mac.type == fm10k_mac_pf) { + /* register callback func to eal lib */ + rte_intr_callback_register(&(dev->pci_dev->intr_handle), + fm10k_dev_interrupt_handler_pf, (void *)dev); + + /* enable MISC interrupt */ + fm10k_dev_enable_intr_pf(dev); + } else { /* VF */ + rte_intr_callback_register(&(dev->pci_dev->intr_handle), + fm10k_dev_interrupt_handler_vf, (void *)dev); + + fm10k_dev_enable_intr_vf(dev); + } + + /* + * Below function will trigger operations on mailbox, acquire lock to + * avoid race condition from interrupt handler. Operations on mailbox + * FIFO will trigger interrupt to PF/SM, in which interrupt handler + * will handle and generate an interrupt to our side. Then, FIFO in + * mailbox will be touched. + */ + fm10k_mbx_lock(hw); + /* Enable port first */ + hw->mac.ops.update_lport_state(hw, 0, 0, 1); + + /* Update default vlan */ + hw->mac.ops.update_vlan(hw, hw->mac.default_vid, 0, true); + + /* + * Add default mac/vlan filter. glort is assigned by SM for PF, while is + * unused for VF. PF will assign correct glort for VF. + */ + hw->mac.ops.update_uc_addr(hw, hw->mac.dglort_map, hw->mac.addr, + hw->mac.default_vid, 1, 0); + + /* Set unicast mode by default. App can change to other mode in other + * API func. + */ + hw->mac.ops.update_xcast_mode(hw, hw->mac.dglort_map, + FM10K_XCAST_MODE_MULTI); + + fm10k_mbx_unlock(hw); + + /* enable uio intr after callback registered */ + rte_intr_enable(&(dev->pci_dev->intr_handle)); + + return 0; +} + +/* + * The set of PCI devices this driver supports. This driver will enable both PF + * and SRIOV-VF devices. + */ +static const struct rte_pci_id pci_id_fm10k_map[] = { +#define RTE_PCI_DEV_ID_DECL_FM10K(vend, dev) { RTE_PCI_DEVICE(vend, dev) }, +#define RTE_PCI_DEV_ID_DECL_FM10KVF(vend, dev) { RTE_PCI_DEVICE(vend, dev) }, +#include "rte_pci_dev_ids.h" + { .vendor_id = 0, /* sentinel */ }, +}; + +static struct eth_driver rte_pmd_fm10k = { + { + .name = "rte_pmd_fm10k", + .id_table = pci_id_fm10k_map, + .drv_flags = RTE_PCI_DRV_NEED_MAPPING, + }, + .eth_dev_init = eth_fm10k_dev_init, + .dev_private_size = sizeof(struct fm10k_adapter), +}; + +/* + * Driver initialization routine. + * Invoked once at EAL init time. + * Register itself as the [Poll Mode] Driver of PCI FM10K devices. + */ +static int +rte_pmd_fm10k_init(__rte_unused const char *name, + __rte_unused const char *params) +{ + PMD_INIT_FUNC_TRACE(); + rte_eth_driver_register(&rte_pmd_fm10k); + return 0; +} + +static struct rte_driver rte_fm10k_driver = { + .type = PMD_PDEV, + .init = rte_pmd_fm10k_init, +}; + +PMD_REGISTER_DRIVER(rte_fm10k_driver); diff --git a/drivers/fm10k/fm10k_logs.h b/drivers/fm10k/fm10k_logs.h new file mode 100644 index 0000000..41a45ce --- /dev/null +++ b/drivers/fm10k/fm10k_logs.h @@ -0,0 +1,80 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of 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. + */ + +#ifndef _FM10K_LOGS_H_ +#define _FM10K_LOGS_H_ + +#include + +#define PMD_INIT_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, RTE_LOGTYPE_PMD, \ + "PMD: %s(): " fmt "\n", __func__, ##args) + +#ifdef RTE_LIBRTE_FM10K_DEBUG_INIT +#define PMD_INIT_FUNC_TRACE() PMD_INIT_LOG(DEBUG, " >>") +#else +#define PMD_INIT_FUNC_TRACE() do { } while (0) +#endif + +#ifdef RTE_LIBRTE_FM10K_DEBUG_RX +#define PMD_RX_LOG(level, fmt, args...) \ + RTE_LOG(level, PMD, "%s(): " fmt "\n", __func__, ## args) +#else +#define PMD_RX_LOG(level, fmt, args...) do { } while (0) +#endif + +#ifdef RTE_LIBRTE_FM10K_DEBUG_TX +#define PMD_TX_LOG(level, fmt, args...) \ + RTE_LOG(level, PMD, "%s(): " fmt "\n", __func__, ## args) +#else +#define PMD_TX_LOG(level, fmt, args...) do { } while (0) +#endif + +#ifdef RTE_LIBRTE_FM10K_DEBUG_TX_FREE +#define PMD_TX_FREE_LOG(level, fmt, args...) \ + RTE_LOG(level, PMD, "%s(): " fmt "\n", __func__, ## args) +#else +#define PMD_TX_FREE_LOG(level, fmt, args...) do { } while (0) +#endif + +#ifdef RTE_LIBRTE_FM10K_DEBUG_DRIVER +#define PMD_DRV_LOG_RAW(level, fmt, args...) \ + RTE_LOG(level, PMD, "%s(): " fmt, __func__, ## args) +#else +#define PMD_DRV_LOG_RAW(level, fmt, args...) do { } while (0) +#endif + +#define PMD_DRV_LOG(level, fmt, args...) \ + PMD_DRV_LOG_RAW(level, fmt "\n", ## args) + +#endif /* _FM10K_LOGS_H_ */ diff --git a/drivers/fm10k/fm10k_rxtx.c b/drivers/fm10k/fm10k_rxtx.c new file mode 100644 index 0000000..83bddfc --- /dev/null +++ b/drivers/fm10k/fm10k_rxtx.c @@ -0,0 +1,461 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of 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. + */ +#include +#include +#include "fm10k.h" +#include "base/fm10k_type.h" + +#ifdef RTE_PMD_PACKET_PREFETCH +#define rte_packet_prefetch(p) rte_prefetch1(p) +#else +#define rte_packet_prefetch(p) do {} while (0) +#endif + +#ifdef RTE_LIBRTE_FM10K_DEBUG_RX +static inline void dump_rxd(union fm10k_rx_desc *rxd) +{ + PMD_RX_LOG(DEBUG, "+----------------|----------------+"); + PMD_RX_LOG(DEBUG, "| GLORT | PKT HDR & TYPE |"); + PMD_RX_LOG(DEBUG, "| 0x%08x | 0x%08x |", rxd->d.glort, + rxd->d.data); + PMD_RX_LOG(DEBUG, "+----------------|----------------+"); + PMD_RX_LOG(DEBUG, "| VLAN & LEN | STATUS |"); + PMD_RX_LOG(DEBUG, "| 0x%08x | 0x%08x |", rxd->d.vlan_len, + rxd->d.staterr); + PMD_RX_LOG(DEBUG, "+----------------|----------------+"); + PMD_RX_LOG(DEBUG, "| RESERVED | RSS_HASH |"); + PMD_RX_LOG(DEBUG, "| 0x%08x | 0x%08x |", 0, rxd->d.rss); + PMD_RX_LOG(DEBUG, "+----------------|----------------+"); + PMD_RX_LOG(DEBUG, "| TIME TAG |"); + PMD_RX_LOG(DEBUG, "| 0x%016lx |", rxd->q.timestamp); + PMD_RX_LOG(DEBUG, "+----------------|----------------+"); +} +#endif + +static inline void +rx_desc_to_ol_flags(struct rte_mbuf *m, const union fm10k_rx_desc *d) +{ + uint16_t ptype; + static const uint16_t pt_lut[] = { 0, + PKT_RX_IPV4_HDR, PKT_RX_IPV4_HDR_EXT, + PKT_RX_IPV6_HDR, PKT_RX_IPV6_HDR_EXT, + 0, 0, 0 + }; + + if (d->w.pkt_info & FM10K_RXD_RSSTYPE_MASK) + m->ol_flags |= PKT_RX_RSS_HASH; + + if (unlikely((d->d.staterr & + (FM10K_RXD_STATUS_IPCS | FM10K_RXD_STATUS_IPE)) == + (FM10K_RXD_STATUS_IPCS | FM10K_RXD_STATUS_IPE))) + m->ol_flags |= PKT_RX_IP_CKSUM_BAD; + + if (unlikely((d->d.staterr & + (FM10K_RXD_STATUS_L4CS | FM10K_RXD_STATUS_L4E)) == + (FM10K_RXD_STATUS_L4CS | FM10K_RXD_STATUS_L4E))) + m->ol_flags |= PKT_RX_L4_CKSUM_BAD; + + if (d->d.staterr & FM10K_RXD_STATUS_VEXT) + m->ol_flags |= PKT_RX_VLAN_PKT; + + if (unlikely(d->d.staterr & FM10K_RXD_STATUS_HBO)) + m->ol_flags |= PKT_RX_HBUF_OVERFLOW; + + if (unlikely(d->d.staterr & FM10K_RXD_STATUS_RXE)) + m->ol_flags |= PKT_RX_RECIP_ERR; + + ptype = (d->d.data & FM10K_RXD_PKTTYPE_MASK_L3) >> + FM10K_RXD_PKTTYPE_SHIFT; + m->ol_flags |= pt_lut[(uint8_t)ptype]; +} + +uint16_t +fm10k_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, + uint16_t nb_pkts) +{ + struct rte_mbuf *mbuf; + union fm10k_rx_desc desc; + struct fm10k_rx_queue *q = rx_queue; + uint16_t count = 0; + int alloc = 0; + uint16_t next_dd; + int ret; + + next_dd = q->next_dd; + + nb_pkts = RTE_MIN(nb_pkts, q->alloc_thresh); + for (count = 0; count < nb_pkts; ++count) { + mbuf = q->sw_ring[next_dd]; + desc = q->hw_ring[next_dd]; + if (!(desc.d.staterr & FM10K_RXD_STATUS_DD)) + break; +#ifdef RTE_LIBRTE_FM10K_DEBUG_RX + dump_rxd(&desc); +#endif + rte_pktmbuf_pkt_len(mbuf) = desc.w.length; + rte_pktmbuf_data_len(mbuf) = desc.w.length; + + mbuf->ol_flags = 0; +#ifdef RTE_LIBRTE_FM10K_RX_OLFLAGS_ENABLE + rx_desc_to_ol_flags(mbuf, &desc); +#endif + + mbuf->hash.rss = desc.d.rss; + + rx_pkts[count] = mbuf; + if (++next_dd == q->nb_desc) { + next_dd = 0; + alloc = 1; + } + + /* Prefetch next mbuf while processing current one. */ + rte_prefetch0(q->sw_ring[next_dd]); + + /* + * When next RX descriptor is on a cache-line boundary, + * prefetch the next 4 RX descriptors and the next 8 pointers + * to mbufs. + */ + if ((next_dd & 0x3) == 0) { + rte_prefetch0(&q->hw_ring[next_dd]); + rte_prefetch0(&q->sw_ring[next_dd]); + } + } + + q->next_dd = next_dd; + + if ((q->next_dd > q->next_trigger) || (alloc == 1)) { + ret = rte_mempool_get_bulk(q->mp, + (void **)&q->sw_ring[q->next_alloc], + q->alloc_thresh); + + if (unlikely(ret != 0)) { + uint8_t port = q->port_id; + PMD_RX_LOG(ERR, "Failed to alloc mbuf"); + /* + * Need to restore next_dd if we cannot allocate new + * buffers to replenish the old ones. + */ + q->next_dd = (q->next_dd + q->nb_desc - count) % + q->nb_desc; + rte_eth_devices[port].data->rx_mbuf_alloc_failed++; + return 0; + } + + for (; q->next_alloc <= q->next_trigger; ++q->next_alloc) { + mbuf = q->sw_ring[q->next_alloc]; + + /* setup static mbuf fields */ + fm10k_pktmbuf_reset(mbuf, q->port_id); + + /* write descriptor */ + desc.q.pkt_addr = MBUF_DMA_ADDR_DEFAULT(mbuf); + desc.q.hdr_addr = MBUF_DMA_ADDR_DEFAULT(mbuf); + q->hw_ring[q->next_alloc] = desc; + } + FM10K_PCI_REG_WRITE(q->tail_ptr, q->next_trigger); + q->next_trigger += q->alloc_thresh; + if (q->next_trigger >= q->nb_desc) { + q->next_trigger = q->alloc_thresh - 1; + q->next_alloc = 0; + } + } + + return count; +} + +uint16_t +fm10k_recv_scattered_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, + uint16_t nb_pkts) +{ + struct rte_mbuf *mbuf; + union fm10k_rx_desc desc; + struct fm10k_rx_queue *q = rx_queue; + uint16_t count = 0; + uint16_t nb_rcv, nb_seg; + int alloc = 0; + uint16_t next_dd; + struct rte_mbuf *first_seg = q->pkt_first_seg; + struct rte_mbuf *last_seg = q->pkt_last_seg; + int ret; + + next_dd = q->next_dd; + nb_rcv = 0; + + nb_seg = RTE_MIN(nb_pkts, q->alloc_thresh); + for (count = 0; count < nb_seg; count++) { + mbuf = q->sw_ring[next_dd]; + desc = q->hw_ring[next_dd]; + if (!(desc.d.staterr & FM10K_RXD_STATUS_DD)) + break; +#ifdef RTE_LIBRTE_FM10K_DEBUG_RX + dump_rxd(&desc); +#endif + + if (++next_dd == q->nb_desc) { + next_dd = 0; + alloc = 1; + } + + /* Prefetch next mbuf while processing current one. */ + rte_prefetch0(q->sw_ring[next_dd]); + + /* + * When next RX descriptor is on a cache-line boundary, + * prefetch the next 4 RX descriptors and the next 8 pointers + * to mbufs. + */ + if ((next_dd & 0x3) == 0) { + rte_prefetch0(&q->hw_ring[next_dd]); + rte_prefetch0(&q->sw_ring[next_dd]); + } + + /* Fill data length */ + rte_pktmbuf_data_len(mbuf) = desc.w.length; + + /* + * If this is the first buffer of the received packet, + * set the pointer to the first mbuf of the packet and + * initialize its context. + * Otherwise, update the total length and the number of segments + * of the current scattered packet, and update the pointer to + * the last mbuf of the current packet. + */ + if (!first_seg) { + first_seg = mbuf; + first_seg->pkt_len = desc.w.length; + } else { + first_seg->pkt_len = + (uint16_t)(first_seg->pkt_len + + rte_pktmbuf_data_len(mbuf)); + first_seg->nb_segs++; + last_seg->next = mbuf; + } + + /* + * If this is not the last buffer of the received packet, + * update the pointer to the last mbuf of the current scattered + * packet and continue to parse the RX ring. + */ + if (!(desc.d.staterr & FM10K_RXD_STATUS_EOP)) { + last_seg = mbuf; + continue; + } + + first_seg->ol_flags = 0; +#ifdef RTE_LIBRTE_FM10K_RX_OLFLAGS_ENABLE + rx_desc_to_ol_flags(first_seg, &desc); +#endif + first_seg->hash.rss = desc.d.rss; + + /* Prefetch data of first segment, if configured to do so. */ + rte_packet_prefetch((char *)first_seg->buf_addr + + first_seg->data_off); + + /* + * Store the mbuf address into the next entry of the array + * of returned packets. + */ + rx_pkts[nb_rcv++] = first_seg; + + /* + * Setup receipt context for a new packet. + */ + first_seg = NULL; + } + + q->next_dd = next_dd; + + if ((q->next_dd > q->next_trigger) || (alloc == 1)) { + ret = rte_mempool_get_bulk(q->mp, + (void **)&q->sw_ring[q->next_alloc], + q->alloc_thresh); + + if (unlikely(ret != 0)) { + uint8_t port = q->port_id; + PMD_RX_LOG(ERR, "Failed to alloc mbuf"); + /* + * Need to restore next_dd if we cannot allocate new + * buffers to replenish the old ones. + */ + q->next_dd = (q->next_dd + q->nb_desc - count) % + q->nb_desc; + rte_eth_devices[port].data->rx_mbuf_alloc_failed++; + return 0; + } + + for (; q->next_alloc <= q->next_trigger; ++q->next_alloc) { + mbuf = q->sw_ring[q->next_alloc]; + + /* setup static mbuf fields */ + fm10k_pktmbuf_reset(mbuf, q->port_id); + + /* write descriptor */ + desc.q.pkt_addr = MBUF_DMA_ADDR_DEFAULT(mbuf); + desc.q.hdr_addr = MBUF_DMA_ADDR_DEFAULT(mbuf); + q->hw_ring[q->next_alloc] = desc; + } + FM10K_PCI_REG_WRITE(q->tail_ptr, q->next_trigger); + q->next_trigger += q->alloc_thresh; + if (q->next_trigger >= q->nb_desc) { + q->next_trigger = q->alloc_thresh - 1; + q->next_alloc = 0; + } + } + + q->pkt_first_seg = first_seg; + q->pkt_last_seg = last_seg; + + return nb_rcv; +} + +static inline void tx_free_descriptors(struct fm10k_tx_queue *q) +{ + uint16_t next_rs, count = 0; + + next_rs = fifo_peek(&q->rs_tracker); + if (!(q->hw_ring[next_rs].flags & FM10K_TXD_FLAG_DONE)) + return; + + /* the DONE flag is set on this descriptor so remove the ID + * from the RS bit tracker and free the buffers */ + fifo_remove(&q->rs_tracker); + + /* wrap around? if so, free buffers from last_free up to but NOT + * including nb_desc */ + if (q->last_free > next_rs) { + count = q->nb_desc - q->last_free; + while (q->last_free < q->nb_desc) { + rte_pktmbuf_free_seg(q->sw_ring[q->last_free]); + q->sw_ring[q->last_free] = NULL; + ++q->last_free; + } + q->last_free = 0; + } + + /* adjust free descriptor count before the next loop */ + q->nb_free += count + (next_rs + 1 - q->last_free); + + /* free buffers from last_free, up to and including next_rs */ + while (q->last_free <= next_rs) { + rte_pktmbuf_free_seg(q->sw_ring[q->last_free]); + q->sw_ring[q->last_free] = NULL; + ++q->last_free; + } + + if (q->last_free == q->nb_desc) + q->last_free = 0; +} + +static inline void tx_xmit_pkt(struct fm10k_tx_queue *q, struct rte_mbuf *mb) +{ + uint16_t last_id; + uint8_t flags; + + /* always set the LAST flag on the last descriptor used to + * transmit the packet */ + flags = FM10K_TXD_FLAG_LAST; + last_id = q->next_free + mb->nb_segs - 1; + if (last_id >= q->nb_desc) + last_id = last_id - q->nb_desc; + + /* but only set the RS flag on the last descriptor if rs_thresh + * descriptors will be used since the RS flag was last set */ + if ((q->nb_used + mb->nb_segs) >= q->rs_thresh) { + flags |= FM10K_TXD_FLAG_RS; + fifo_insert(&q->rs_tracker, last_id); + q->nb_used = 0; + } else { + q->nb_used = q->nb_used + mb->nb_segs; + } + + q->hw_ring[last_id].flags = flags; + q->nb_free -= mb->nb_segs; + + /* set checksum flags on first descriptor of packet. SCTP checksum + * offload is not supported, but we do not explicitly check for this + * case in favor of greatly simplified processing. */ + if (mb->ol_flags & (PKT_TX_IP_CKSUM | PKT_TX_L4_MASK)) + q->hw_ring[q->next_free].flags |= FM10K_TXD_FLAG_CSUM; + + /* set vlan if requested */ + if (mb->ol_flags & PKT_TX_VLAN_PKT) + q->hw_ring[q->next_free].vlan = mb->vlan_tci; + + /* fill up the rings */ + for (; mb != NULL; mb = mb->next) { + q->sw_ring[q->next_free] = mb; + q->hw_ring[q->next_free].buffer_addr = + rte_cpu_to_le_64(MBUF_DMA_ADDR(mb)); + q->hw_ring[q->next_free].buflen = + rte_cpu_to_le_16(rte_pktmbuf_data_len(mb)); + if (++q->next_free == q->nb_desc) + q->next_free = 0; + } +} + +uint16_t +fm10k_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, + uint16_t nb_pkts) +{ + struct fm10k_tx_queue *q = tx_queue; + struct rte_mbuf *mb; + uint16_t count; + + for (count = 0; count < nb_pkts; ++count) { + mb = tx_pkts[count]; + + /* running low on descriptors? try to free some... */ + if (q->nb_free < q->free_trigger) + tx_free_descriptors(q); + + /* make sure there are enough free descriptors to transmit the + * entire packet before doing anything */ + if (q->nb_free < mb->nb_segs) + break; + + /* sanity check to make sure the mbuf is valid */ + if ((mb->nb_segs == 0) || + ((mb->nb_segs > 1) && (mb->next == NULL))) + break; + + /* process the packet */ + tx_xmit_pkt(q, mb); + } + + /* update the tail pointer if any packets were processed */ + if (likely(count > 0)) + FM10K_PCI_REG_WRITE(q->tail_ptr, q->next_free); + + return count; +} diff --git a/drivers/fm10k/rte_pmd_fm10k_version.map b/drivers/fm10k/rte_pmd_fm10k_version.map new file mode 100644 index 0000000..ef35398 --- /dev/null +++ b/drivers/fm10k/rte_pmd_fm10k_version.map @@ -0,0 +1,4 @@ +DPDK_2.0 { + + local: *; +}; diff --git a/lib/Makefile b/lib/Makefile index 305a105..6e8056f 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -43,7 +43,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether DIRS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += librte_pmd_ixgbe DIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += librte_pmd_i40e -DIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += librte_pmd_fm10k DIRS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) += librte_pmd_mlx4 DIRS-$(CONFIG_RTE_LIBRTE_PMD_RING) += librte_pmd_ring DIRS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += librte_pmd_pcap diff --git a/lib/librte_pmd_fm10k/Makefile b/lib/librte_pmd_fm10k/Makefile deleted file mode 100644 index 7395933..0000000 --- a/lib/librte_pmd_fm10k/Makefile +++ /dev/null @@ -1,102 +0,0 @@ -# BSD LICENSE -# -# Copyright(c) 2013-2015 Intel Corporation. All rights reserved. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of 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. - -include $(RTE_SDK)/mk/rte.vars.mk - -# -# library name -# -LIB = librte_pmd_fm10k.a - -CFLAGS += -O3 -CFLAGS += $(WERROR_FLAGS) - -EXPORT_MAP := rte_pmd_fm10k_version.map - -LIBABIVER := 1 - -ifeq ($(CC), icc) -# -# CFLAGS for icc -# -CFLAGS_BASE_DRIVER = -wd174 -wd593 -wd869 -wd981 -wd2259 - -else ifeq ($(CC), clang) -# -## CFLAGS for clang -# -CFLAGS_BASE_DRIVER = -Wno-unused-parameter -Wno-unused-value -CFLAGS_BASE_DRIVER += -Wno-strict-aliasing -Wno-format-extra-args -CFLAGS_BASE_DRIVER += -Wno-unused-variable -CFLAGS_BASE_DRIVER += -Wno-missing-field-initializers - -else -# -# CFLAGS for gcc -# -CFLAGS_BASE_DRIVER = -Wno-unused-parameter -Wno-unused-value -CFLAGS_BASE_DRIVER += -Wno-strict-aliasing -Wno-format-extra-args -CFLAGS_BASE_DRIVER += -Wno-unused-variable -CFLAGS_BASE_DRIVER += -Wno-missing-field-initializers - -ifeq ($(shell test $(GCC_VERSION) -ge 44 && echo 1), 1) -CFLAGS += -Wno-deprecated -CFLAGS_BASE_DRIVER += -Wno-unused-but-set-variable -endif -endif - -# -# Add extra flags for base driver source files to disable warnings in them -# -BASE_DRIVER_OBJS=$(patsubst %.c,%.o,$(notdir $(wildcard $(SRCDIR)/base/*.c))) -$(foreach obj, $(BASE_DRIVER_OBJS), $(eval CFLAGS_$(obj)+=$(CFLAGS_BASE_DRIVER))) - -VPATH += $(SRCDIR)/base - -# -# all source are stored in SRCS-y -# -SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_ethdev.c -SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_rxtx.c - -SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_pf.c -SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_tlv.c -SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_common.c -SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_mbx.c -SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_vf.c -SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_api.c - -# this lib depends upon: -DEPDIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += lib/librte_eal lib/librte_ether -DEPDIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += lib/librte_mempool lib/librte_mbuf -DEPDIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += lib/librte_net lib/librte_malloc - -include $(RTE_SDK)/mk/rte.lib.mk diff --git a/lib/librte_pmd_fm10k/base/fm10k_api.c b/lib/librte_pmd_fm10k/base/fm10k_api.c deleted file mode 100644 index c0f555c..0000000 --- a/lib/librte_pmd_fm10k/base/fm10k_api.c +++ /dev/null @@ -1,341 +0,0 @@ -/******************************************************************************* - -Copyright (c) 2013 - 2015, 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. - -***************************************************************************/ - -#include "fm10k_api.h" -#include "fm10k_common.h" - -/** - * fm10k_set_mac_type - Sets MAC type - * @hw: pointer to the HW structure - * - * This function sets the mac type of the adapter based on the - * vendor ID and device ID stored in the hw structure. - **/ -s32 fm10k_set_mac_type(struct fm10k_hw *hw) -{ - s32 ret_val = FM10K_SUCCESS; - - DEBUGFUNC("fm10k_set_mac_type"); - - if (hw->vendor_id != FM10K_INTEL_VENDOR_ID) { - ERROR_REPORT2(FM10K_ERROR_UNSUPPORTED, - "Unsupported vendor id: %x\n", hw->vendor_id); - return FM10K_ERR_DEVICE_NOT_SUPPORTED; - } - - switch (hw->device_id) { - case FM10K_DEV_ID_PF: - hw->mac.type = fm10k_mac_pf; - break; - case FM10K_DEV_ID_VF: - hw->mac.type = fm10k_mac_vf; - break; - default: - ret_val = FM10K_ERR_DEVICE_NOT_SUPPORTED; - ERROR_REPORT2(FM10K_ERROR_UNSUPPORTED, - "Unsupported device id: %x\n", - hw->device_id); - break; - } - - DEBUGOUT2("fm10k_set_mac_type found mac: %d, returns: %d\n", - hw->mac.type, ret_val); - - return ret_val; -} - -/** - * fm10k_init_shared_code - Initialize the shared code - * @hw: pointer to hardware structure - * - * This will assign function pointers and assign the MAC type and PHY code. - * Does not touch the hardware. This function must be called prior to any - * other function in the shared code. The fm10k_hw structure should be - * memset to 0 prior to calling this function. The following fields in - * hw structure should be filled in prior to calling this function: - * hw_addr, back, device_id, vendor_id, subsystem_device_id, - * subsystem_vendor_id, and revision_id - **/ -s32 fm10k_init_shared_code(struct fm10k_hw *hw) -{ - s32 status; - - DEBUGFUNC("fm10k_init_shared_code"); - - /* Set the mac type */ - fm10k_set_mac_type(hw); - - switch (hw->mac.type) { - case fm10k_mac_pf: - status = fm10k_init_ops_pf(hw); - break; - case fm10k_mac_vf: - status = fm10k_init_ops_vf(hw); - break; - default: - status = FM10K_ERR_DEVICE_NOT_SUPPORTED; - break; - } - - return status; -} - -#define fm10k_call_func(hw, func, params, error) \ - ((func) ? (func params) : (error)) - -/** - * fm10k_reset_hw - Reset the hardware to known good state - * @hw: pointer to hardware structure - * - * This function should return the hardware to a state similar to the - * one it is in after being powered on. - **/ -s32 fm10k_reset_hw(struct fm10k_hw *hw) -{ - return fm10k_call_func(hw, hw->mac.ops.reset_hw, (hw), - FM10K_NOT_IMPLEMENTED); -} - -/** - * fm10k_init_hw - Initialize the hardware - * @hw: pointer to hardware structure - * - * Initialize the hardware by resetting and then starting the hardware - **/ -s32 fm10k_init_hw(struct fm10k_hw *hw) -{ - return fm10k_call_func(hw, hw->mac.ops.init_hw, (hw), - FM10K_NOT_IMPLEMENTED); -} - -/** - * fm10k_stop_hw - Prepares hardware to shutdown Rx/Tx - * @hw: pointer to hardware structure - * - * Disables Rx/Tx queues and disables the DMA engine. - **/ -s32 fm10k_stop_hw(struct fm10k_hw *hw) -{ - return fm10k_call_func(hw, hw->mac.ops.stop_hw, (hw), - FM10K_NOT_IMPLEMENTED); -} - -/** - * fm10k_start_hw - Prepares hardware for Rx/Tx - * @hw: pointer to hardware structure - * - * This function sets the flags indicating that the hardware is ready to - * begin operation. - **/ -s32 fm10k_start_hw(struct fm10k_hw *hw) -{ - return fm10k_call_func(hw, hw->mac.ops.start_hw, (hw), - FM10K_NOT_IMPLEMENTED); -} - -/** - * fm10k_get_bus_info - Set PCI bus info - * @hw: pointer to hardware structure - * - * Sets the PCI bus info (speed, width, type) within the fm10k_hw structure - **/ -s32 fm10k_get_bus_info(struct fm10k_hw *hw) -{ - return fm10k_call_func(hw, hw->mac.ops.get_bus_info, (hw), - FM10K_NOT_IMPLEMENTED); -} - -/** - * fm10k_is_slot_appropriate - Indicate appropriate slot for this SKU - * @hw: pointer to hardware structure - * - * Looks at the PCIe bus info to confirm whether or not this slot can support - * the necessary bandwidth for this device. - **/ -bool fm10k_is_slot_appropriate(struct fm10k_hw *hw) -{ - if (hw->mac.ops.is_slot_appropriate) - return hw->mac.ops.is_slot_appropriate(hw); - return true; -} - -/** - * fm10k_update_vlan - Clear VLAN ID to VLAN filter table - * @hw: pointer to hardware structure - * @vid: VLAN ID to add to table - * @idx: Index indicating VF ID or PF ID in table - * @set: Indicates if this is a set or clear operation - * - * This function adds or removes the corresponding VLAN ID from the VLAN - * filter table for the corresponding function. - **/ -s32 fm10k_update_vlan(struct fm10k_hw *hw, u32 vid, u8 idx, bool set) -{ - return fm10k_call_func(hw, hw->mac.ops.update_vlan, (hw, vid, idx, set), - FM10K_NOT_IMPLEMENTED); -} - -/** - * fm10k_read_mac_addr - Reads MAC address - * @hw: pointer to hardware structure - * - * Reads the MAC address out of the interface and stores it in the HW - * structures. - **/ -s32 fm10k_read_mac_addr(struct fm10k_hw *hw) -{ - return fm10k_call_func(hw, hw->mac.ops.read_mac_addr, (hw), - FM10K_NOT_IMPLEMENTED); -} - -/** - * fm10k_update_hw_stats - Update hw statistics - * @hw: pointer to hardware structure - * - * This function updates statistics that are related to hardware. - * */ -void fm10k_update_hw_stats(struct fm10k_hw *hw, struct fm10k_hw_stats *stats) -{ - if (hw->mac.ops.update_hw_stats) - hw->mac.ops.update_hw_stats(hw, stats); -} - -/** - * fm10k_rebind_hw_stats - Reset base for hw statistics - * @hw: pointer to hardware structure - * - * This function resets the base for statistics that are related to hardware. - * */ -void fm10k_rebind_hw_stats(struct fm10k_hw *hw, struct fm10k_hw_stats *stats) -{ - if (hw->mac.ops.rebind_hw_stats) - hw->mac.ops.rebind_hw_stats(hw, stats); -} - -/** - * fm10k_configure_dglort_map - Configures GLORT entry and queues - * @hw: pointer to hardware structure - * @dglort: pointer to dglort configuration structure - * - * Reads the configuration structure contained in dglort_cfg and uses - * that information to then populate a DGLORTMAP/DEC entry and the queues - * to which it has been assigned. - **/ -s32 fm10k_configure_dglort_map(struct fm10k_hw *hw, - struct fm10k_dglort_cfg *dglort) -{ - return fm10k_call_func(hw, hw->mac.ops.configure_dglort_map, - (hw, dglort), FM10K_NOT_IMPLEMENTED); -} - -/** - * fm10k_set_dma_mask - Configures PhyAddrSpace to limit DMA to system - * @hw: pointer to hardware structure - * @dma_mask: 64 bit DMA mask required for platform - * - * This function configures the endpoint to limit the access to memory - * beyond what is physically in the system. - **/ -void fm10k_set_dma_mask(struct fm10k_hw *hw, u64 dma_mask) -{ - if (hw->mac.ops.set_dma_mask) - hw->mac.ops.set_dma_mask(hw, dma_mask); -} - -/** - * fm10k_get_fault - Record a fault in one of the interface units - * @hw: pointer to hardware structure - * @type: pointer to fault type register offset - * @fault: pointer to memory location to record the fault - * - * Record the fault register contents to the fault data structure and - * clear the entry from the register. - * - * Returns ERR_PARAM if invalid register is specified or no error is present. - **/ -s32 fm10k_get_fault(struct fm10k_hw *hw, int type, struct fm10k_fault *fault) -{ - return fm10k_call_func(hw, hw->mac.ops.get_fault, (hw, type, fault), - FM10K_NOT_IMPLEMENTED); -} - -/** - * fm10k_update_uc_addr - Update device unicast address - * @hw: pointer to the HW structure - * @lport: logical port ID to update - unused - * @mac: MAC address to add/remove from table - * @vid: VLAN ID to add/remove from table - * @add: Indicates if this is an add or remove operation - * @flags: flags field to indicate add and secure - unused - * - * This function is used to add or remove unicast MAC addresses - **/ -s32 fm10k_update_uc_addr(struct fm10k_hw *hw, u16 lport, - const u8 *mac, u16 vid, bool add, u8 flags) -{ - return fm10k_call_func(hw, hw->mac.ops.update_uc_addr, - (hw, lport, mac, vid, add, flags), - FM10K_NOT_IMPLEMENTED); -} - -/** - * fm10k_update_mc_addr - Update device multicast address - * @hw: pointer to the HW structure - * @lport: logical port ID to update - unused - * @mac: MAC address to add/remove from table - * @vid: VLAN ID to add/remove from table - * @add: Indicates if this is an add or remove operation - * - * This function is used to add or remove multicast MAC addresses - **/ -s32 fm10k_update_mc_addr(struct fm10k_hw *hw, u16 lport, - const u8 *mac, u16 vid, bool add) -{ - return fm10k_call_func(hw, hw->mac.ops.update_mc_addr, - (hw, lport, mac, vid, add), - FM10K_NOT_IMPLEMENTED); -} - -/** - * fm10k_adjust_systime - Adjust systime frequency - * @hw: pointer to hardware structure - * @ppb: adjustment rate in parts per billion - * - * This function is meant to update the frequency of the clock represented - * by the SYSTIME register. - **/ -s32 fm10k_adjust_systime(struct fm10k_hw *hw, s32 ppb) -{ - return fm10k_call_func(hw, hw->mac.ops.adjust_systime, - (hw, ppb), FM10K_NOT_IMPLEMENTED); -} diff --git a/lib/librte_pmd_fm10k/base/fm10k_api.h b/lib/librte_pmd_fm10k/base/fm10k_api.h deleted file mode 100644 index 343d750..0000000 --- a/lib/librte_pmd_fm10k/base/fm10k_api.h +++ /dev/null @@ -1,61 +0,0 @@ -/******************************************************************************* - -Copyright (c) 2013 - 2015, 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. - -***************************************************************************/ - -#ifndef _FM10K_API_H_ -#define _FM10K_API_H_ - -#include "fm10k_pf.h" -#include "fm10k_vf.h" - -s32 fm10k_set_mac_type(struct fm10k_hw *hw); -s32 fm10k_reset_hw(struct fm10k_hw *hw); -s32 fm10k_init_hw(struct fm10k_hw *hw); -s32 fm10k_stop_hw(struct fm10k_hw *hw); -s32 fm10k_start_hw(struct fm10k_hw *hw); -s32 fm10k_init_shared_code(struct fm10k_hw *hw); -s32 fm10k_get_bus_info(struct fm10k_hw *hw); -bool fm10k_is_slot_appropriate(struct fm10k_hw *hw); -s32 fm10k_update_vlan(struct fm10k_hw *hw, u32 vid, u8 idx, bool set); -s32 fm10k_read_mac_addr(struct fm10k_hw *hw); -void fm10k_update_hw_stats(struct fm10k_hw *hw, struct fm10k_hw_stats *stats); -void fm10k_rebind_hw_stats(struct fm10k_hw *hw, struct fm10k_hw_stats *stats); -s32 fm10k_configure_dglort_map(struct fm10k_hw *hw, - struct fm10k_dglort_cfg *dglort); -void fm10k_set_dma_mask(struct fm10k_hw *hw, u64 dma_mask); -s32 fm10k_get_fault(struct fm10k_hw *hw, int type, struct fm10k_fault *fault); -s32 fm10k_update_uc_addr(struct fm10k_hw *hw, u16 lport, - const u8 *mac, u16 vid, bool add, u8 flags); -s32 fm10k_update_mc_addr(struct fm10k_hw *hw, u16 lport, - const u8 *mac, u16 vid, bool add); -s32 fm10k_adjust_systime(struct fm10k_hw *hw, s32 ppb); -#endif /* _FM10K_API_H_ */ diff --git a/lib/librte_pmd_fm10k/base/fm10k_common.c b/lib/librte_pmd_fm10k/base/fm10k_common.c deleted file mode 100644 index a90d2f0..0000000 --- a/lib/librte_pmd_fm10k/base/fm10k_common.c +++ /dev/null @@ -1,572 +0,0 @@ -/******************************************************************************* - -Copyright (c) 2013 - 2015, 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. - -***************************************************************************/ - -#include "fm10k_common.h" - -/** - * fm10k_get_bus_info_generic - Generic set PCI bus info - * @hw: pointer to hardware structure - * - * Gets the PCI bus info (speed, width, type) then calls helper function to - * store this data within the fm10k_hw structure. - **/ -STATIC s32 fm10k_get_bus_info_generic(struct fm10k_hw *hw) -{ - u16 link_cap, link_status, device_cap, device_control; - - DEBUGFUNC("fm10k_get_bus_info_generic"); - - /* Get the maximum link width and speed from PCIe config space */ - link_cap = FM10K_READ_PCI_WORD(hw, FM10K_PCIE_LINK_CAP); - - switch (link_cap & FM10K_PCIE_LINK_WIDTH) { - case FM10K_PCIE_LINK_WIDTH_1: - hw->bus_caps.width = fm10k_bus_width_pcie_x1; - break; - case FM10K_PCIE_LINK_WIDTH_2: - hw->bus_caps.width = fm10k_bus_width_pcie_x2; - break; - case FM10K_PCIE_LINK_WIDTH_4: - hw->bus_caps.width = fm10k_bus_width_pcie_x4; - break; - case FM10K_PCIE_LINK_WIDTH_8: - hw->bus_caps.width = fm10k_bus_width_pcie_x8; - break; - default: - hw->bus_caps.width = fm10k_bus_width_unknown; - break; - } - - switch (link_cap & FM10K_PCIE_LINK_SPEED) { - case FM10K_PCIE_LINK_SPEED_2500: - hw->bus_caps.speed = fm10k_bus_speed_2500; - break; - case FM10K_PCIE_LINK_SPEED_5000: - hw->bus_caps.speed = fm10k_bus_speed_5000; - break; - case FM10K_PCIE_LINK_SPEED_8000: - hw->bus_caps.speed = fm10k_bus_speed_8000; - break; - default: - hw->bus_caps.speed = fm10k_bus_speed_unknown; - break; - } - - /* Get the PCIe maximum payload size for the PCIe function */ - device_cap = FM10K_READ_PCI_WORD(hw, FM10K_PCIE_DEV_CAP); - - switch (device_cap & FM10K_PCIE_DEV_CAP_PAYLOAD) { - case FM10K_PCIE_DEV_CAP_PAYLOAD_128: - hw->bus_caps.payload = fm10k_bus_payload_128; - break; - case FM10K_PCIE_DEV_CAP_PAYLOAD_256: - hw->bus_caps.payload = fm10k_bus_payload_256; - break; - case FM10K_PCIE_DEV_CAP_PAYLOAD_512: - hw->bus_caps.payload = fm10k_bus_payload_512; - break; - default: - hw->bus_caps.payload = fm10k_bus_payload_unknown; - break; - } - - /* Get the negotiated link width and speed from PCIe config space */ - link_status = FM10K_READ_PCI_WORD(hw, FM10K_PCIE_LINK_STATUS); - - switch (link_status & FM10K_PCIE_LINK_WIDTH) { - case FM10K_PCIE_LINK_WIDTH_1: - hw->bus.width = fm10k_bus_width_pcie_x1; - break; - case FM10K_PCIE_LINK_WIDTH_2: - hw->bus.width = fm10k_bus_width_pcie_x2; - break; - case FM10K_PCIE_LINK_WIDTH_4: - hw->bus.width = fm10k_bus_width_pcie_x4; - break; - case FM10K_PCIE_LINK_WIDTH_8: - hw->bus.width = fm10k_bus_width_pcie_x8; - break; - default: - hw->bus.width = fm10k_bus_width_unknown; - break; - } - - switch (link_status & FM10K_PCIE_LINK_SPEED) { - case FM10K_PCIE_LINK_SPEED_2500: - hw->bus.speed = fm10k_bus_speed_2500; - break; - case FM10K_PCIE_LINK_SPEED_5000: - hw->bus.speed = fm10k_bus_speed_5000; - break; - case FM10K_PCIE_LINK_SPEED_8000: - hw->bus.speed = fm10k_bus_speed_8000; - break; - default: - hw->bus.speed = fm10k_bus_speed_unknown; - break; - } - - /* Get the negotiated PCIe maximum payload size for the PCIe function */ - device_control = FM10K_READ_PCI_WORD(hw, FM10K_PCIE_DEV_CTRL); - - switch (device_control & FM10K_PCIE_DEV_CTRL_PAYLOAD) { - case FM10K_PCIE_DEV_CTRL_PAYLOAD_128: - hw->bus.payload = fm10k_bus_payload_128; - break; - case FM10K_PCIE_DEV_CTRL_PAYLOAD_256: - hw->bus.payload = fm10k_bus_payload_256; - break; - case FM10K_PCIE_DEV_CTRL_PAYLOAD_512: - hw->bus.payload = fm10k_bus_payload_512; - break; - default: - hw->bus.payload = fm10k_bus_payload_unknown; - break; - } - - return FM10K_SUCCESS; -} - -u16 fm10k_get_pcie_msix_count_generic(struct fm10k_hw *hw) -{ - u16 msix_count; - - DEBUGFUNC("fm10k_get_pcie_msix_count_generic"); - - /* read in value from MSI-X capability register */ - msix_count = FM10K_READ_PCI_WORD(hw, FM10K_PCI_MSIX_MSG_CTRL); - msix_count &= FM10K_PCI_MSIX_MSG_CTRL_TBL_SZ_MASK; - - /* MSI-X count is zero-based in HW */ - msix_count++; - - if (msix_count > FM10K_MAX_MSIX_VECTORS) - msix_count = FM10K_MAX_MSIX_VECTORS; - - return msix_count; -} - -/** - * fm10k_init_ops_generic - Inits function ptrs - * @hw: pointer to the hardware structure - * - * Initialize the function pointers. - **/ -s32 fm10k_init_ops_generic(struct fm10k_hw *hw) -{ - struct fm10k_mac_info *mac = &hw->mac; - - DEBUGFUNC("fm10k_init_ops_generic"); - - /* MAC */ - mac->ops.get_bus_info = &fm10k_get_bus_info_generic; - - /* initialize GLORT state to avoid any false hits */ - mac->dglort_map = FM10K_DGLORTMAP_NONE; - - return FM10K_SUCCESS; -} - -/** - * fm10k_start_hw_generic - Prepare hardware for Tx/Rx - * @hw: pointer to hardware structure - * - * This function sets the Tx ready flag to indicate that the Tx path has - * been initialized. - **/ -s32 fm10k_start_hw_generic(struct fm10k_hw *hw) -{ - DEBUGFUNC("fm10k_start_hw_generic"); - - /* set flag indicating we are beginning Tx */ - hw->mac.tx_ready = true; - - return FM10K_SUCCESS; -} - -/** - * fm10k_disable_queues_generic - Stop Tx/Rx queues - * @hw: pointer to hardware structure - * @q_cnt: number of queues to be disabled - * - **/ -s32 fm10k_disable_queues_generic(struct fm10k_hw *hw, u16 q_cnt) -{ - u32 reg; - u16 i, time; - - DEBUGFUNC("fm10k_disable_queues_generic"); - - /* clear tx_ready to prevent any false hits for reset */ - hw->mac.tx_ready = false; - - /* clear the enable bit for all rings */ - for (i = 0; i < q_cnt; i++) { - reg = FM10K_READ_REG(hw, FM10K_TXDCTL(i)); - FM10K_WRITE_REG(hw, FM10K_TXDCTL(i), - reg & ~FM10K_TXDCTL_ENABLE); - reg = FM10K_READ_REG(hw, FM10K_RXQCTL(i)); - FM10K_WRITE_REG(hw, FM10K_RXQCTL(i), - reg & ~FM10K_RXQCTL_ENABLE); - } - - FM10K_WRITE_FLUSH(hw); - usec_delay(1); - - /* loop through all queues to verify that they are all disabled */ - for (i = 0, time = FM10K_QUEUE_DISABLE_TIMEOUT; time;) { - /* if we are at end of rings all rings are disabled */ - if (i == q_cnt) - return FM10K_SUCCESS; - - /* if queue enables cleared, then move to next ring pair */ - reg = FM10K_READ_REG(hw, FM10K_TXDCTL(i)); - if (!~reg || !(reg & FM10K_TXDCTL_ENABLE)) { - reg = FM10K_READ_REG(hw, FM10K_RXQCTL(i)); - if (!~reg || !(reg & FM10K_RXQCTL_ENABLE)) { - i++; - continue; - } - } - - /* decrement time and wait 1 usec */ - time--; - if (time) - usec_delay(1); - } - - return FM10K_ERR_REQUESTS_PENDING; -} - -/** - * fm10k_stop_hw_generic - Stop Tx/Rx units - * @hw: pointer to hardware structure - * - **/ -s32 fm10k_stop_hw_generic(struct fm10k_hw *hw) -{ - DEBUGFUNC("fm10k_stop_hw_generic"); - - return fm10k_disable_queues_generic(hw, hw->mac.max_queues); -} - -/** - * fm10k_read_hw_stats_32b - Reads value of 32-bit registers - * @hw: pointer to the hardware structure - * @addr: address of register containing a 32-bit value - * - * Function reads the content of the register and returns the delta - * between the base and the current value. - * **/ -u32 fm10k_read_hw_stats_32b(struct fm10k_hw *hw, u32 addr, - struct fm10k_hw_stat *stat) -{ - u32 delta = FM10K_READ_REG(hw, addr) - stat->base_l; - - DEBUGFUNC("fm10k_read_hw_stats_32b"); - - if (FM10K_REMOVED(hw->hw_addr)) - stat->base_h = 0; - - return delta; -} - -/** - * fm10k_read_hw_stats_48b - Reads value of 48-bit registers - * @hw: pointer to the hardware structure - * @addr: address of register containing the lower 32-bit value - * - * Function reads the content of 2 registers, combined to represent a 48-bit - * statistical value. Extra processing is required to handle overflowing. - * Finally, a delta value is returned representing the difference between the - * values stored in registers and values stored in the statistic counters. - * **/ -STATIC u64 fm10k_read_hw_stats_48b(struct fm10k_hw *hw, u32 addr, - struct fm10k_hw_stat *stat) -{ - u32 count_l; - u32 count_h; - u32 count_tmp; - u64 delta; - - DEBUGFUNC("fm10k_read_hw_stats_48b"); - - count_h = FM10K_READ_REG(hw, addr + 1); - - /* Check for overflow */ - do { - count_tmp = count_h; - count_l = FM10K_READ_REG(hw, addr); - count_h = FM10K_READ_REG(hw, addr + 1); - } while (count_h != count_tmp); - - delta = ((u64)(count_h - stat->base_h) << 32) + count_l; - delta -= stat->base_l; - - return delta & FM10K_48_BIT_MASK; -} - -/** - * fm10k_update_hw_base_48b - Updates 48-bit statistic base value - * @stat: pointer to the hardware statistic structure - * @delta: value to be updated into the hardware statistic structure - * - * Function receives a value and determines if an update is required based on - * a delta calculation. Only the base value will be updated. - **/ -STATIC void fm10k_update_hw_base_48b(struct fm10k_hw_stat *stat, u64 delta) -{ - DEBUGFUNC("fm10k_update_hw_base_48b"); - - if (!delta) - return; - - /* update lower 32 bits */ - delta += stat->base_l; - stat->base_l = (u32)delta; - - /* update upper 32 bits */ - stat->base_h += (u32)(delta >> 32); -} - -/** - * fm10k_update_hw_stats_tx_q - Updates TX queue statistics counters - * @hw: pointer to the hardware structure - * @q: pointer to the ring of hardware statistics queue - * @idx: index pointing to the start of the ring iteration - * - * Function updates the TX queue statistics counters that are related to the - * hardware. - **/ -STATIC void fm10k_update_hw_stats_tx_q(struct fm10k_hw *hw, - struct fm10k_hw_stats_q *q, - u32 idx) -{ - u32 id_tx, id_tx_prev, tx_packets; - u64 tx_bytes = 0; - - DEBUGFUNC("fm10k_update_hw_stats_tx_q"); - - /* Retrieve TX Owner Data */ - id_tx = FM10K_READ_REG(hw, FM10K_TXQCTL(idx)); - - /* Process TX Ring */ - do { - tx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPTC(idx), - &q->tx_packets); - - if (tx_packets) - tx_bytes = fm10k_read_hw_stats_48b(hw, - FM10K_QBTC_L(idx), - &q->tx_bytes); - - /* Re-Check Owner Data */ - id_tx_prev = id_tx; - id_tx = FM10K_READ_REG(hw, FM10K_TXQCTL(idx)); - } while ((id_tx ^ id_tx_prev) & FM10K_TXQCTL_ID_MASK); - - /* drop non-ID bits and set VALID ID bit */ - id_tx &= FM10K_TXQCTL_ID_MASK; - id_tx |= FM10K_STAT_VALID; - - /* update packet counts */ - if (q->tx_stats_idx == id_tx) { - q->tx_packets.count += tx_packets; - q->tx_bytes.count += tx_bytes; - } - - /* update bases and record ID */ - fm10k_update_hw_base_32b(&q->tx_packets, tx_packets); - fm10k_update_hw_base_48b(&q->tx_bytes, tx_bytes); - - q->tx_stats_idx = id_tx; -} - -/** - * fm10k_update_hw_stats_rx_q - Updates RX queue statistics counters - * @hw: pointer to the hardware structure - * @q: pointer to the ring of hardware statistics queue - * @idx: index pointing to the start of the ring iteration - * - * Function updates the RX queue statistics counters that are related to the - * hardware. - **/ -STATIC void fm10k_update_hw_stats_rx_q(struct fm10k_hw *hw, - struct fm10k_hw_stats_q *q, - u32 idx) -{ - u32 id_rx, id_rx_prev, rx_packets, rx_drops; - u64 rx_bytes = 0; - - DEBUGFUNC("fm10k_update_hw_stats_rx_q"); - - /* Retrieve RX Owner Data */ - id_rx = FM10K_READ_REG(hw, FM10K_RXQCTL(idx)); - - /* Process RX Ring */ - do { - rx_drops = fm10k_read_hw_stats_32b(hw, FM10K_QPRDC(idx), - &q->rx_drops); - - rx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPRC(idx), - &q->rx_packets); - - if (rx_packets) - rx_bytes = fm10k_read_hw_stats_48b(hw, - FM10K_QBRC_L(idx), - &q->rx_bytes); - - /* Re-Check Owner Data */ - id_rx_prev = id_rx; - id_rx = FM10K_READ_REG(hw, FM10K_RXQCTL(idx)); - } while ((id_rx ^ id_rx_prev) & FM10K_RXQCTL_ID_MASK); - - /* drop non-ID bits and set VALID ID bit */ - id_rx &= FM10K_RXQCTL_ID_MASK; - id_rx |= FM10K_STAT_VALID; - - /* update packet counts */ - if (q->rx_stats_idx == id_rx) { - q->rx_drops.count += rx_drops; - q->rx_packets.count += rx_packets; - q->rx_bytes.count += rx_bytes; - } - - /* update bases and record ID */ - fm10k_update_hw_base_32b(&q->rx_drops, rx_drops); - fm10k_update_hw_base_32b(&q->rx_packets, rx_packets); - fm10k_update_hw_base_48b(&q->rx_bytes, rx_bytes); - - q->rx_stats_idx = id_rx; -} - -/** - * fm10k_update_hw_stats_q - Updates queue statistics counters - * @hw: pointer to the hardware structure - * @q: pointer to the ring of hardware statistics queue - * @idx: index pointing to the start of the ring iteration - * @count: number of queues to iterate over - * - * Function updates the queue statistics counters that are related to the - * hardware. - **/ -void fm10k_update_hw_stats_q(struct fm10k_hw *hw, struct fm10k_hw_stats_q *q, - u32 idx, u32 count) -{ - u32 i; - - DEBUGFUNC("fm10k_update_hw_stats_q"); - - for (i = 0; i < count; i++, idx++, q++) { - fm10k_update_hw_stats_tx_q(hw, q, idx); - fm10k_update_hw_stats_rx_q(hw, q, idx); - } -} - -/** - * fm10k_unbind_hw_stats_q - Unbind the queue counters from their queues - * @hw: pointer to the hardware structure - * @q: pointer to the ring of hardware statistics queue - * @idx: index pointing to the start of the ring iteration - * @count: number of queues to iterate over - * - * Function invalidates the index values for the queues so any updates that - * may have happened are ignored and the base for the queue stats is reset. - **/ -void fm10k_unbind_hw_stats_q(struct fm10k_hw_stats_q *q, u32 idx, u32 count) -{ - u32 i; - - for (i = 0; i < count; i++, idx++, q++) { - q->rx_stats_idx = 0; - q->tx_stats_idx = 0; - } -} - -/** - * fm10k_get_host_state_generic - Returns the state of the host - * @hw: pointer to hardware structure - * @host_ready: pointer to boolean value that will record host state - * - * This function will check the health of the mailbox and Tx queue 0 - * in order to determine if we should report that the link is up or not. - **/ -s32 fm10k_get_host_state_generic(struct fm10k_hw *hw, bool *host_ready) -{ - struct fm10k_mbx_info *mbx = &hw->mbx; - struct fm10k_mac_info *mac = &hw->mac; - s32 ret_val = FM10K_SUCCESS; - u32 txdctl = FM10K_READ_REG(hw, FM10K_TXDCTL(0)); - - DEBUGFUNC("fm10k_get_host_state_generic"); - - /* process upstream mailbox in case interrupts were disabled */ - mbx->ops.process(hw, mbx); - - /* If Tx is no longer enabled link should come down */ - if (!(~txdctl) || !(txdctl & FM10K_TXDCTL_ENABLE)) - mac->get_host_state = true; - - /* exit if not checking for link, or link cannot be changed */ - if (!mac->get_host_state || !(~txdctl)) - goto out; - - /* if we somehow dropped the Tx enable we should reset */ - if (hw->mac.tx_ready && !(txdctl & FM10K_TXDCTL_ENABLE)) { - ret_val = FM10K_ERR_RESET_REQUESTED; - goto out; - } - - /* if Mailbox timed out we should request reset */ - if (!mbx->timeout) { - ret_val = FM10K_ERR_RESET_REQUESTED; - goto out; - } - - /* verify Mailbox is still valid */ - if (!mbx->ops.tx_ready(mbx, FM10K_VFMBX_MSG_MTU)) - goto out; - - /* interface cannot receive traffic without logical ports */ - if (mac->dglort_map == FM10K_DGLORTMAP_NONE) - goto out; - - /* if we passed all the tests above then the switch is ready and we no - * longer need to check for link - */ - mac->get_host_state = false; - -out: - *host_ready = !mac->get_host_state; - return ret_val; -} diff --git a/lib/librte_pmd_fm10k/base/fm10k_common.h b/lib/librte_pmd_fm10k/base/fm10k_common.h deleted file mode 100644 index 45fbbc0..0000000 --- a/lib/librte_pmd_fm10k/base/fm10k_common.h +++ /dev/null @@ -1,52 +0,0 @@ -/******************************************************************************* - -Copyright (c) 2013 - 2015, 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. - -***************************************************************************/ - -#ifndef _FM10K_COMMON_H_ -#define _FM10K_COMMON_H_ - -#include "fm10k_type.h" - -u16 fm10k_get_pcie_msix_count_generic(struct fm10k_hw *hw); -s32 fm10k_init_ops_generic(struct fm10k_hw *hw); -s32 fm10k_disable_queues_generic(struct fm10k_hw *hw, u16 q_cnt); -s32 fm10k_start_hw_generic(struct fm10k_hw *hw); -s32 fm10k_stop_hw_generic(struct fm10k_hw *hw); -u32 fm10k_read_hw_stats_32b(struct fm10k_hw *hw, u32 addr, - struct fm10k_hw_stat *stat); -#define fm10k_update_hw_base_32b(stat, delta) ((stat)->base_l += (delta)) -void fm10k_update_hw_stats_q(struct fm10k_hw *hw, struct fm10k_hw_stats_q *q, - u32 idx, u32 count); -#define fm10k_unbind_hw_stats_32b(s) ((s)->base_h = 0) -void fm10k_unbind_hw_stats_q(struct fm10k_hw_stats_q *q, u32 idx, u32 count); -s32 fm10k_get_host_state_generic(struct fm10k_hw *hw, bool *host_ready); -#endif /* _FM10K_COMMON_H_ */ diff --git a/lib/librte_pmd_fm10k/base/fm10k_mbx.c b/lib/librte_pmd_fm10k/base/fm10k_mbx.c deleted file mode 100644 index 2081414..0000000 --- a/lib/librte_pmd_fm10k/base/fm10k_mbx.c +++ /dev/null @@ -1,2185 +0,0 @@ -/******************************************************************************* - -Copyright (c) 2013 - 2015, 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. - -***************************************************************************/ - -#include "fm10k_common.h" - -/** - * fm10k_fifo_init - Initialize a message FIFO - * @fifo: pointer to FIFO - * @buffer: pointer to memory to be used to store FIFO - * @size: maximum message size to store in FIFO, must be 2^n - 1 - **/ -STATIC void fm10k_fifo_init(struct fm10k_mbx_fifo *fifo, u32 *buffer, u16 size) -{ - fifo->buffer = buffer; - fifo->size = size; - fifo->head = 0; - fifo->tail = 0; -} - -/** - * fm10k_fifo_used - Retrieve used space in FIFO - * @fifo: pointer to FIFO - * - * This function returns the number of DWORDs used in the FIFO - **/ -STATIC u16 fm10k_fifo_used(struct fm10k_mbx_fifo *fifo) -{ - return fifo->tail - fifo->head; -} - -/** - * fm10k_fifo_unused - Retrieve unused space in FIFO - * @fifo: pointer to FIFO - * - * This function returns the number of unused DWORDs in the FIFO - **/ -STATIC u16 fm10k_fifo_unused(struct fm10k_mbx_fifo *fifo) -{ - return fifo->size + fifo->head - fifo->tail; -} - -/** - * fm10k_fifo_empty - Test to verify if fifo is empty - * @fifo: pointer to FIFO - * - * This function returns true if the FIFO is empty, else false - **/ -STATIC bool fm10k_fifo_empty(struct fm10k_mbx_fifo *fifo) -{ - return fifo->head == fifo->tail; -} - -/** - * fm10k_fifo_head_offset - returns indices of head with given offset - * @fifo: pointer to FIFO - * @offset: offset to add to head - * - * This function returns the indices into the fifo based on head + offset - **/ -STATIC u16 fm10k_fifo_head_offset(struct fm10k_mbx_fifo *fifo, u16 offset) -{ - return (fifo->head + offset) & (fifo->size - 1); -} - -/** - * fm10k_fifo_tail_offset - returns indices of tail with given offset - * @fifo: pointer to FIFO - * @offset: offset to add to tail - * - * This function returns the indices into the fifo based on tail + offset - **/ -STATIC u16 fm10k_fifo_tail_offset(struct fm10k_mbx_fifo *fifo, u16 offset) -{ - return (fifo->tail + offset) & (fifo->size - 1); -} - -/** - * fm10k_fifo_head_len - Retrieve length of first message in FIFO - * @fifo: pointer to FIFO - * - * This function returns the size of the first message in the FIFO - **/ -STATIC u16 fm10k_fifo_head_len(struct fm10k_mbx_fifo *fifo) -{ - u32 *head = fifo->buffer + fm10k_fifo_head_offset(fifo, 0); - - /* verify there is at least 1 DWORD in the fifo so *head is valid */ - if (fm10k_fifo_empty(fifo)) - return 0; - - /* retieve the message length */ - return FM10K_TLV_DWORD_LEN(*head); -} - -/** - * fm10k_fifo_head_drop - Drop the first message in FIFO - * @fifo: pointer to FIFO - * - * This function returns the size of the message dropped from the FIFO - **/ -STATIC u16 fm10k_fifo_head_drop(struct fm10k_mbx_fifo *fifo) -{ - u16 len = fm10k_fifo_head_len(fifo); - - /* update head so it is at the start of next frame */ - fifo->head += len; - - return len; -} - -/** - * fm10k_mbx_index_len - Convert a head/tail index into a length value - * @mbx: pointer to mailbox - * @head: head index - * @tail: head index - * - * This function takes the head and tail index and determines the length - * of the data indicated by this pair. - **/ -STATIC u16 fm10k_mbx_index_len(struct fm10k_mbx_info *mbx, u16 head, u16 tail) -{ - u16 len = tail - head; - - /* we wrapped so subtract 2, one for index 0, one for all 1s index */ - if (len > tail) - len -= 2; - - return len & ((mbx->mbmem_len << 1) - 1); -} - -/** - * fm10k_mbx_tail_add - Determine new tail value with added offset - * @mbx: pointer to mailbox - * @offset: length to add to head offset - * - * This function takes the local tail index and recomputes it for - * a given length added as an offset. - **/ -STATIC u16 fm10k_mbx_tail_add(struct fm10k_mbx_info *mbx, u16 offset) -{ - u16 tail = (mbx->tail + offset + 1) & ((mbx->mbmem_len << 1) - 1); - - /* add/sub 1 because we cannot have offset 0 or all 1s */ - return (tail > mbx->tail) ? --tail : ++tail; -} - -/** - * fm10k_mbx_tail_sub - Determine new tail value with subtracted offset - * @mbx: pointer to mailbox - * @offset: length to add to head offset - * - * This function takes the local tail index and recomputes it for - * a given length added as an offset. - **/ -STATIC u16 fm10k_mbx_tail_sub(struct fm10k_mbx_info *mbx, u16 offset) -{ - u16 tail = (mbx->tail - offset - 1) & ((mbx->mbmem_len << 1) - 1); - - /* sub/add 1 because we cannot have offset 0 or all 1s */ - return (tail < mbx->tail) ? ++tail : --tail; -} - -/** - * fm10k_mbx_head_add - Determine new head value with added offset - * @mbx: pointer to mailbox - * @offset: length to add to head offset - * - * This function takes the local head index and recomputes it for - * a given length added as an offset. - **/ -STATIC u16 fm10k_mbx_head_add(struct fm10k_mbx_info *mbx, u16 offset) -{ - u16 head = (mbx->head + offset + 1) & ((mbx->mbmem_len << 1) - 1); - - /* add/sub 1 because we cannot have offset 0 or all 1s */ - return (head > mbx->head) ? --head : ++head; -} - -/** - * fm10k_mbx_head_sub - Determine new head value with subtracted offset - * @mbx: pointer to mailbox - * @offset: length to add to head offset - * - * This function takes the local head index and recomputes it for - * a given length added as an offset. - **/ -STATIC u16 fm10k_mbx_head_sub(struct fm10k_mbx_info *mbx, u16 offset) -{ - u16 head = (mbx->head - offset - 1) & ((mbx->mbmem_len << 1) - 1); - - /* sub/add 1 because we cannot have offset 0 or all 1s */ - return (head < mbx->head) ? ++head : --head; -} - -/** - * fm10k_mbx_pushed_tail_len - Retrieve the length of message being pushed - * @mbx: pointer to mailbox - * - * This function will return the length of the message currently being - * pushed onto the tail of the Rx queue. - **/ -STATIC u16 fm10k_mbx_pushed_tail_len(struct fm10k_mbx_info *mbx) -{ - u32 *tail = mbx->rx.buffer + fm10k_fifo_tail_offset(&mbx->rx, 0); - - /* pushed tail is only valid if pushed is set */ - if (!mbx->pushed) - return 0; - - return FM10K_TLV_DWORD_LEN(*tail); -} - -/** - * fm10k_fifo_write_copy - pulls data off of msg and places it in fifo - * @fifo: pointer to FIFO - * @msg: message array to populate - * @tail_offset: additional offset to add to tail pointer - * @len: length of FIFO to copy into message header - * - * This function will take a message and copy it into a section of the - * FIFO. In order to get something into a location other than just - * the tail you can use tail_offset to adjust the pointer. - **/ -STATIC void fm10k_fifo_write_copy(struct fm10k_mbx_fifo *fifo, - const u32 *msg, u16 tail_offset, u16 len) -{ - u16 end = fm10k_fifo_tail_offset(fifo, tail_offset); - u32 *tail = fifo->buffer + end; - - /* track when we should cross the end of the FIFO */ - end = fifo->size - end; - - /* copy end of message before start of message */ - if (end < len) - memcpy(fifo->buffer, msg + end, (len - end) << 2); - else - end = len; - - /* Copy remaining message into Tx FIFO */ - memcpy(tail, msg, end << 2); -} - -/** - * fm10k_fifo_enqueue - Enqueues the message to the tail of the FIFO - * @fifo: pointer to FIFO - * @msg: message array to read - * - * This function enqueues a message up to the size specified by the length - * contained in the first DWORD of the message and will place at the tail - * of the FIFO. It will return 0 on success, or a negative value on error. - **/ -STATIC s32 fm10k_fifo_enqueue(struct fm10k_mbx_fifo *fifo, const u32 *msg) -{ - u16 len = FM10K_TLV_DWORD_LEN(*msg); - - DEBUGFUNC("fm10k_fifo_enqueue"); - - /* verify parameters */ - if (len > fifo->size) - return FM10K_MBX_ERR_SIZE; - - /* verify there is room for the message */ - if (len > fm10k_fifo_unused(fifo)) - return FM10K_MBX_ERR_NO_SPACE; - - /* Copy message into FIFO */ - fm10k_fifo_write_copy(fifo, msg, 0, len); - - /* memory barrier to guarantee FIFO is written before tail update */ - FM10K_WMB(); - - /* Update Tx FIFO tail */ - fifo->tail += len; - - return FM10K_SUCCESS; -} - -/** - * fm10k_mbx_validate_msg_size - Validate incoming message based on size - * @mbx: pointer to mailbox - * @len: length of data pushed onto buffer - * - * This function analyzes the frame and will return a non-zero value when - * the start of a message larger than the mailbox is detected. - **/ -STATIC u16 fm10k_mbx_validate_msg_size(struct fm10k_mbx_info *mbx, u16 len) -{ - struct fm10k_mbx_fifo *fifo = &mbx->rx; - u16 total_len = 0, msg_len; - u32 *msg; - - DEBUGFUNC("fm10k_mbx_validate_msg"); - - /* length should include previous amounts pushed */ - len += mbx->pushed; - - /* offset in message is based off of current message size */ - do { - msg = fifo->buffer + fm10k_fifo_tail_offset(fifo, total_len); - msg_len = FM10K_TLV_DWORD_LEN(*msg); - total_len += msg_len; - } while (total_len < len); - - /* message extends out of pushed section, but fits in FIFO */ - if ((len < total_len) && (msg_len <= mbx->rx.size)) - return 0; - - /* return length of invalid section */ - return (len < total_len) ? len : (len - total_len); -} - -/** - * fm10k_mbx_write_copy - pulls data off of Tx FIFO and places it in mbmem - * @mbx: pointer to mailbox - * - * This function will take a section of the Rx FIFO and copy it into the - mbx->tail--; - * mailbox memory. The offset in mbmem is based on the lower bits of the - * tail and len determines the length to copy. - **/ -STATIC void fm10k_mbx_write_copy(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx) -{ - struct fm10k_mbx_fifo *fifo = &mbx->tx; - u32 mbmem = mbx->mbmem_reg; - u32 *head = fifo->buffer; - u16 end, len, tail, mask; - - DEBUGFUNC("fm10k_mbx_write_copy"); - - if (!mbx->tail_len) - return; - - /* determine data length and mbmem tail index */ - mask = mbx->mbmem_len - 1; - len = mbx->tail_len; - tail = fm10k_mbx_tail_sub(mbx, len); - if (tail > mask) - tail++; - - /* determine offset in the ring */ - end = fm10k_fifo_head_offset(fifo, mbx->pulled); - head += end; - - /* memory barrier to guarantee data is ready to be read */ - FM10K_RMB(); - - /* Copy message from Tx FIFO */ - for (end = fifo->size - end; len; head = fifo->buffer) { - do { - /* adjust tail to match offset for FIFO */ - tail &= mask; - if (!tail) - tail++; - - /* write message to hardware FIFO */ - FM10K_WRITE_MBX(hw, mbmem + tail++, *(head++)); - } while (--len && --end); - } -} - -/** - * fm10k_mbx_pull_head - Pulls data off of head of Tx FIFO - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * @head: acknowledgement number last received - * - * This function will push the tail index forward based on the remote - * head index. It will then pull up to mbmem_len DWORDs off of the - * head of the FIFO and will place it in the MBMEM registers - * associated with the mailbox. - **/ -STATIC void fm10k_mbx_pull_head(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx, u16 head) -{ - u16 mbmem_len, len, ack = fm10k_mbx_index_len(mbx, head, mbx->tail); - struct fm10k_mbx_fifo *fifo = &mbx->tx; - - /* update number of bytes pulled and update bytes in transit */ - mbx->pulled += mbx->tail_len - ack; - - /* determine length of data to pull, reserve space for mbmem header */ - mbmem_len = mbx->mbmem_len - 1; - len = fm10k_fifo_used(fifo) - mbx->pulled; - if (len > mbmem_len) - len = mbmem_len; - - /* update tail and record number of bytes in transit */ - mbx->tail = fm10k_mbx_tail_add(mbx, len - ack); - mbx->tail_len = len; - - /* drop pulled messages from the FIFO */ - for (len = fm10k_fifo_head_len(fifo); - len && (mbx->pulled >= len); - len = fm10k_fifo_head_len(fifo)) { - mbx->pulled -= fm10k_fifo_head_drop(fifo); - mbx->tx_messages++; - mbx->tx_dwords += len; - } - - /* Copy message out from the Tx FIFO */ - fm10k_mbx_write_copy(hw, mbx); -} - -/** - * fm10k_mbx_read_copy - pulls data off of mbmem and places it in Rx FIFO - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * - * This function will take a section of the mailbox memory and copy it - * into the Rx FIFO. The offset is based on the lower bits of the - * head and len determines the length to copy. - **/ -STATIC void fm10k_mbx_read_copy(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx) -{ - struct fm10k_mbx_fifo *fifo = &mbx->rx; - u32 mbmem = mbx->mbmem_reg ^ mbx->mbmem_len; - u32 *tail = fifo->buffer; - u16 end, len, head; - - DEBUGFUNC("fm10k_mbx_read_copy"); - - /* determine data length and mbmem head index */ - len = mbx->head_len; - head = fm10k_mbx_head_sub(mbx, len); - if (head >= mbx->mbmem_len) - head++; - - /* determine offset in the ring */ - end = fm10k_fifo_tail_offset(fifo, mbx->pushed); - tail += end; - - /* Copy message into Rx FIFO */ - for (end = fifo->size - end; len; tail = fifo->buffer) { - do { - /* adjust head to match offset for FIFO */ - head &= mbx->mbmem_len - 1; - if (!head) - head++; - - /* read message from hardware FIFO */ - *(tail++) = FM10K_READ_MBX(hw, mbmem + head++); - } while (--len && --end); - } - - /* memory barrier to guarantee FIFO is written before tail update */ - FM10K_WMB(); -} - -/** - * fm10k_mbx_push_tail - Pushes up to 15 DWORDs on to tail of FIFO - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * @tail: tail index of message - * - * This function will first validate the tail index and size for the - * incoming message. It then updates the acknowledgment number and - * copies the data into the FIFO. It will return the number of messages - * dequeued on success and a negative value on error. - **/ -STATIC s32 fm10k_mbx_push_tail(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx, - u16 tail) -{ - struct fm10k_mbx_fifo *fifo = &mbx->rx; - u16 len, seq = fm10k_mbx_index_len(mbx, mbx->head, tail); - - DEBUGFUNC("fm10k_mbx_push_tail"); - - /* determine length of data to push */ - len = fm10k_fifo_unused(fifo) - mbx->pushed; - if (len > seq) - len = seq; - - /* update head and record bytes received */ - mbx->head = fm10k_mbx_head_add(mbx, len); - mbx->head_len = len; - - /* nothing to do if there is no data */ - if (!len) - return FM10K_SUCCESS; - - /* Copy msg into Rx FIFO */ - fm10k_mbx_read_copy(hw, mbx); - - /* determine if there are any invalid lengths in message */ - if (fm10k_mbx_validate_msg_size(mbx, len)) - return FM10K_MBX_ERR_SIZE; - - /* Update pushed */ - mbx->pushed += len; - - /* flush any completed messages */ - for (len = fm10k_mbx_pushed_tail_len(mbx); - len && (mbx->pushed >= len); - len = fm10k_mbx_pushed_tail_len(mbx)) { - fifo->tail += len; - mbx->pushed -= len; - mbx->rx_messages++; - mbx->rx_dwords += len; - } - - return FM10K_SUCCESS; -} - -/* pre-generated data for generating the CRC based on the poly 0xAC9A. */ -static const u16 fm10k_crc_16b_table[256] = { - 0x0000, 0x7956, 0xF2AC, 0x8BFA, 0xBC6D, 0xC53B, 0x4EC1, 0x3797, - 0x21EF, 0x58B9, 0xD343, 0xAA15, 0x9D82, 0xE4D4, 0x6F2E, 0x1678, - 0x43DE, 0x3A88, 0xB172, 0xC824, 0xFFB3, 0x86E5, 0x0D1F, 0x7449, - 0x6231, 0x1B67, 0x909D, 0xE9CB, 0xDE5C, 0xA70A, 0x2CF0, 0x55A6, - 0x87BC, 0xFEEA, 0x7510, 0x0C46, 0x3BD1, 0x4287, 0xC97D, 0xB02B, - 0xA653, 0xDF05, 0x54FF, 0x2DA9, 0x1A3E, 0x6368, 0xE892, 0x91C4, - 0xC462, 0xBD34, 0x36CE, 0x4F98, 0x780F, 0x0159, 0x8AA3, 0xF3F5, - 0xE58D, 0x9CDB, 0x1721, 0x6E77, 0x59E0, 0x20B6, 0xAB4C, 0xD21A, - 0x564D, 0x2F1B, 0xA4E1, 0xDDB7, 0xEA20, 0x9376, 0x188C, 0x61DA, - 0x77A2, 0x0EF4, 0x850E, 0xFC58, 0xCBCF, 0xB299, 0x3963, 0x4035, - 0x1593, 0x6CC5, 0xE73F, 0x9E69, 0xA9FE, 0xD0A8, 0x5B52, 0x2204, - 0x347C, 0x4D2A, 0xC6D0, 0xBF86, 0x8811, 0xF147, 0x7ABD, 0x03EB, - 0xD1F1, 0xA8A7, 0x235D, 0x5A0B, 0x6D9C, 0x14CA, 0x9F30, 0xE666, - 0xF01E, 0x8948, 0x02B2, 0x7BE4, 0x4C73, 0x3525, 0xBEDF, 0xC789, - 0x922F, 0xEB79, 0x6083, 0x19D5, 0x2E42, 0x5714, 0xDCEE, 0xA5B8, - 0xB3C0, 0xCA96, 0x416C, 0x383A, 0x0FAD, 0x76FB, 0xFD01, 0x8457, - 0xAC9A, 0xD5CC, 0x5E36, 0x2760, 0x10F7, 0x69A1, 0xE25B, 0x9B0D, - 0x8D75, 0xF423, 0x7FD9, 0x068F, 0x3118, 0x484E, 0xC3B4, 0xBAE2, - 0xEF44, 0x9612, 0x1DE8, 0x64BE, 0x5329, 0x2A7F, 0xA185, 0xD8D3, - 0xCEAB, 0xB7FD, 0x3C07, 0x4551, 0x72C6, 0x0B90, 0x806A, 0xF93C, - 0x2B26, 0x5270, 0xD98A, 0xA0DC, 0x974B, 0xEE1D, 0x65E7, 0x1CB1, - 0x0AC9, 0x739F, 0xF865, 0x8133, 0xB6A4, 0xCFF2, 0x4408, 0x3D5E, - 0x68F8, 0x11AE, 0x9A54, 0xE302, 0xD495, 0xADC3, 0x2639, 0x5F6F, - 0x4917, 0x3041, 0xBBBB, 0xC2ED, 0xF57A, 0x8C2C, 0x07D6, 0x7E80, - 0xFAD7, 0x8381, 0x087B, 0x712D, 0x46BA, 0x3FEC, 0xB416, 0xCD40, - 0xDB38, 0xA26E, 0x2994, 0x50C2, 0x6755, 0x1E03, 0x95F9, 0xECAF, - 0xB909, 0xC05F, 0x4BA5, 0x32F3, 0x0564, 0x7C32, 0xF7C8, 0x8E9E, - 0x98E6, 0xE1B0, 0x6A4A, 0x131C, 0x248B, 0x5DDD, 0xD627, 0xAF71, - 0x7D6B, 0x043D, 0x8FC7, 0xF691, 0xC106, 0xB850, 0x33AA, 0x4AFC, - 0x5C84, 0x25D2, 0xAE28, 0xD77E, 0xE0E9, 0x99BF, 0x1245, 0x6B13, - 0x3EB5, 0x47E3, 0xCC19, 0xB54F, 0x82D8, 0xFB8E, 0x7074, 0x0922, - 0x1F5A, 0x660C, 0xEDF6, 0x94A0, 0xA337, 0xDA61, 0x519B, 0x28CD }; - -/** - * fm10k_crc_16b - Generate a 16 bit CRC for a region of 16 bit data - * @data: pointer to data to process - * @seed: seed value for CRC - * @len: length measured in 16 bits words - * - * This function will generate a CRC based on the polynomial 0xAC9A and - * whatever value is stored in the seed variable. Note that this - * value inverts the local seed and the result in order to capture all - * leading and trailing zeros. - */ -STATIC u16 fm10k_crc_16b(const u32 *data, u16 seed, u16 len) -{ - u32 result = seed; - - while (len--) { - result ^= *(data++); - result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF]; - result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF]; - - if (!(len--)) - break; - - result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF]; - result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF]; - } - - return (u16)result; -} - -/** - * fm10k_fifo_crc - generate a CRC based off of FIFO data - * @fifo: pointer to FIFO - * @offset: offset point for start of FIFO - * @len: number of DWORDS words to process - * @seed: seed value for CRC - * - * This function generates a CRC for some region of the FIFO - **/ -STATIC u16 fm10k_fifo_crc(struct fm10k_mbx_fifo *fifo, u16 offset, - u16 len, u16 seed) -{ - u32 *data = fifo->buffer + offset; - - /* track when we should cross the end of the FIFO */ - offset = fifo->size - offset; - - /* if we are in 2 blocks process the end of the FIFO first */ - if (offset < len) { - seed = fm10k_crc_16b(data, seed, offset * 2); - data = fifo->buffer; - len -= offset; - } - - /* process any remaining bits */ - return fm10k_crc_16b(data, seed, len * 2); -} - -/** - * fm10k_mbx_update_local_crc - Update the local CRC for outgoing data - * @mbx: pointer to mailbox - * @head: head index provided by remote mailbox - * - * This function will generate the CRC for all data from the end of the - * last head update to the current one. It uses the result of the - * previous CRC as the seed for this update. The result is stored in - * mbx->local. - **/ -STATIC void fm10k_mbx_update_local_crc(struct fm10k_mbx_info *mbx, u16 head) -{ - u16 len = mbx->tail_len - fm10k_mbx_index_len(mbx, head, mbx->tail); - - /* determine the offset for the start of the region to be pulled */ - head = fm10k_fifo_head_offset(&mbx->tx, mbx->pulled); - - /* update local CRC to include all of the pulled data */ - mbx->local = fm10k_fifo_crc(&mbx->tx, head, len, mbx->local); -} - -/** - * fm10k_mbx_verify_remote_crc - Verify the CRC is correct for current data - * @mbx: pointer to mailbox - * - * This function will take all data that has been provided from the remote - * end and generate a CRC for it. This is stored in mbx->remote. The - * CRC for the header is then computed and if the result is non-zero this - * is an error and we signal an error dropping all data and resetting the - * connection. - */ -STATIC s32 fm10k_mbx_verify_remote_crc(struct fm10k_mbx_info *mbx) -{ - struct fm10k_mbx_fifo *fifo = &mbx->rx; - u16 len = mbx->head_len; - u16 offset = fm10k_fifo_tail_offset(fifo, mbx->pushed) - len; - u16 crc; - - /* update the remote CRC if new data has been received */ - if (len) - mbx->remote = fm10k_fifo_crc(fifo, offset, len, mbx->remote); - - /* process the full header as we have to validate the CRC */ - crc = fm10k_crc_16b(&mbx->mbx_hdr, mbx->remote, 1); - - /* notify other end if we have a problem */ - return crc ? FM10K_MBX_ERR_CRC : FM10K_SUCCESS; -} - -/** - * fm10k_mbx_rx_ready - Indicates that a message is ready in the Rx FIFO - * @mbx: pointer to mailbox - * - * This function returns true if there is a message in the Rx FIFO to dequeue. - **/ -STATIC bool fm10k_mbx_rx_ready(struct fm10k_mbx_info *mbx) -{ - u16 msg_size = fm10k_fifo_head_len(&mbx->rx); - - return msg_size && (fm10k_fifo_used(&mbx->rx) >= msg_size); -} - -/** - * fm10k_mbx_tx_ready - Indicates that the mailbox is in state ready for Tx - * @mbx: pointer to mailbox - * @len: verify free space is >= this value - * - * This function returns true if the mailbox is in a state ready to transmit. - **/ -STATIC bool fm10k_mbx_tx_ready(struct fm10k_mbx_info *mbx, u16 len) -{ - u16 fifo_unused = fm10k_fifo_unused(&mbx->tx); - - return (mbx->state == FM10K_STATE_OPEN) && (fifo_unused >= len); -} - -/** - * fm10k_mbx_tx_complete - Indicates that the Tx FIFO has been emptied - * @mbx: pointer to mailbox - * - * This function returns true if the Tx FIFO is empty. - **/ -STATIC bool fm10k_mbx_tx_complete(struct fm10k_mbx_info *mbx) -{ - return fm10k_fifo_empty(&mbx->tx); -} - -/** - * fm10k_mbx_deqeueue_rx - Dequeues the message from the head in the Rx FIFO - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * - * This function dequeues messages and hands them off to the tlv parser. - * It will return the number of messages processed when called. - **/ -STATIC u16 fm10k_mbx_dequeue_rx(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx) -{ - struct fm10k_mbx_fifo *fifo = &mbx->rx; - s32 err; - u16 cnt; - - /* parse Rx messages out of the Rx FIFO to empty it */ - for (cnt = 0; !fm10k_fifo_empty(fifo); cnt++) { - err = fm10k_tlv_msg_parse(hw, fifo->buffer + fifo->head, - mbx, mbx->msg_data); - if (err < 0) - mbx->rx_parse_err++; - - fm10k_fifo_head_drop(fifo); - } - - /* shift remaining bytes back to start of FIFO */ - memmove(fifo->buffer, fifo->buffer + fifo->tail, mbx->pushed << 2); - - /* shift head and tail based on the memory we moved */ - fifo->tail -= fifo->head; - fifo->head = 0; - - return cnt; -} - -/** - * fm10k_mbx_enqueue_tx - Enqueues the message to the tail of the Tx FIFO - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * @msg: message array to read - * - * This function enqueues a message up to the size specified by the length - * contained in the first DWORD of the message and will place at the tail - * of the FIFO. It will return 0 on success, or a negative value on error. - **/ -STATIC s32 fm10k_mbx_enqueue_tx(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx, const u32 *msg) -{ - u32 countdown = mbx->timeout; - s32 err; - - switch (mbx->state) { - case FM10K_STATE_CLOSED: - case FM10K_STATE_DISCONNECT: - return FM10K_MBX_ERR_NO_MBX; - default: - break; - } - - /* enqueue the message on the Tx FIFO */ - err = fm10k_fifo_enqueue(&mbx->tx, msg); - - /* if it failed give the FIFO a chance to drain */ - while (err && countdown) { - countdown--; - usec_delay(mbx->usec_delay); - mbx->ops.process(hw, mbx); - err = fm10k_fifo_enqueue(&mbx->tx, msg); - } - - /* if we failed treat the error */ - if (err) { - mbx->timeout = 0; - mbx->tx_busy++; - } - - /* begin processing message, ignore errors as this is just meant - * to start the mailbox flow so we are not concerned if there - * is a bad error, or the mailbox is already busy with a request - */ - if (!mbx->tail_len) - mbx->ops.process(hw, mbx); - - return FM10K_SUCCESS; -} - -/** - * fm10k_mbx_read - Copies the mbmem to local message buffer - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * - * This function copies the message from the mbmem to the message array - **/ -STATIC s32 fm10k_mbx_read(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx) -{ - DEBUGFUNC("fm10k_mbx_read"); - - /* only allow one reader in here at a time */ - if (mbx->mbx_hdr) - return FM10K_MBX_ERR_BUSY; - - /* read to capture initial interrupt bits */ - if (FM10K_READ_MBX(hw, mbx->mbx_reg) & FM10K_MBX_REQ_INTERRUPT) - mbx->mbx_lock = FM10K_MBX_ACK; - - /* write back interrupt bits to clear */ - FM10K_WRITE_MBX(hw, mbx->mbx_reg, - FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT); - - /* read remote header */ - mbx->mbx_hdr = FM10K_READ_MBX(hw, mbx->mbmem_reg ^ mbx->mbmem_len); - - return FM10K_SUCCESS; -} - -/** - * fm10k_mbx_write - Copies the local message buffer to mbmem - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * - * This function copies the message from the the message array to mbmem - **/ -STATIC void fm10k_mbx_write(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx) -{ - u32 mbmem = mbx->mbmem_reg; - - DEBUGFUNC("fm10k_mbx_write"); - - /* write new msg header to notify recipient of change */ - FM10K_WRITE_MBX(hw, mbmem, mbx->mbx_hdr); - - /* write mailbox to send interrupt */ - if (mbx->mbx_lock) - FM10K_WRITE_MBX(hw, mbx->mbx_reg, mbx->mbx_lock); - - /* we no longer are using the header so free it */ - mbx->mbx_hdr = 0; - mbx->mbx_lock = 0; -} - -/** - * fm10k_mbx_create_connect_hdr - Generate a connect mailbox header - * @mbx: pointer to mailbox - * - * This function returns a connection mailbox header - **/ -STATIC void fm10k_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx) -{ - mbx->mbx_lock |= FM10K_MBX_REQ; - - mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_CONNECT, TYPE) | - FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD) | - FM10K_MSG_HDR_FIELD_SET(mbx->rx.size - 1, CONNECT_SIZE); -} - -/** - * fm10k_mbx_create_data_hdr - Generate a data mailbox header - * @mbx: pointer to mailbox - * - * This function returns a data mailbox header - **/ -STATIC void fm10k_mbx_create_data_hdr(struct fm10k_mbx_info *mbx) -{ - u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DATA, TYPE) | - FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) | - FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD); - struct fm10k_mbx_fifo *fifo = &mbx->tx; - u16 crc; - - if (mbx->tail_len) - mbx->mbx_lock |= FM10K_MBX_REQ; - - /* generate CRC for data in flight and header */ - crc = fm10k_fifo_crc(fifo, fm10k_fifo_head_offset(fifo, mbx->pulled), - mbx->tail_len, mbx->local); - crc = fm10k_crc_16b(&hdr, crc, 1); - - /* load header to memory to be written */ - mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC); -} - -/** - * fm10k_mbx_create_disconnect_hdr - Generate a disconnect mailbox header - * @mbx: pointer to mailbox - * - * This function returns a disconnect mailbox header - **/ -STATIC void fm10k_mbx_create_disconnect_hdr(struct fm10k_mbx_info *mbx) -{ - u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) | - FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) | - FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD); - u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1); - - mbx->mbx_lock |= FM10K_MBX_ACK; - - /* load header to memory to be written */ - mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC); -} - -/** - * fm10k_mbx_create_error_msg - Generate a error message - * @mbx: pointer to mailbox - * @err: local error encountered - * - * This function will interpret the error provided by err, and based on - * that it may shift the message by 1 DWORD and then place an error header - * at the start of the message. - **/ -STATIC void fm10k_mbx_create_error_msg(struct fm10k_mbx_info *mbx, s32 err) -{ - /* only generate an error message for these types */ - switch (err) { - case FM10K_MBX_ERR_TAIL: - case FM10K_MBX_ERR_HEAD: - case FM10K_MBX_ERR_TYPE: - case FM10K_MBX_ERR_SIZE: - case FM10K_MBX_ERR_RSVD0: - case FM10K_MBX_ERR_CRC: - break; - default: - return; - } - - mbx->mbx_lock |= FM10K_MBX_REQ; - - mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_ERROR, TYPE) | - FM10K_MSG_HDR_FIELD_SET(err, ERR_NO) | - FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD); -} - -/** - * fm10k_mbx_validate_msg_hdr - Validate common fields in the message header - * @mbx: pointer to mailbox - * @msg: message array to read - * - * This function will parse up the fields in the mailbox header and return - * an error if the header contains any of a number of invalid configurations - * including unrecognized type, invalid route, or a malformed message. - **/ -STATIC s32 fm10k_mbx_validate_msg_hdr(struct fm10k_mbx_info *mbx) -{ - u16 type, rsvd0, head, tail, size; - const u32 *hdr = &mbx->mbx_hdr; - - DEBUGFUNC("fm10k_mbx_validate_msg_hdr"); - - type = FM10K_MSG_HDR_FIELD_GET(*hdr, TYPE); - rsvd0 = FM10K_MSG_HDR_FIELD_GET(*hdr, RSVD0); - tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL); - head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD); - size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE); - - if (rsvd0) - return FM10K_MBX_ERR_RSVD0; - - switch (type) { - case FM10K_MSG_DISCONNECT: - /* validate that all data has been received */ - if (tail != mbx->head) - return FM10K_MBX_ERR_TAIL; - - /* fall through */ - case FM10K_MSG_DATA: - /* validate that head is moving correctly */ - if (!head || (head == FM10K_MSG_HDR_MASK(HEAD))) - return FM10K_MBX_ERR_HEAD; - if (fm10k_mbx_index_len(mbx, head, mbx->tail) > mbx->tail_len) - return FM10K_MBX_ERR_HEAD; - - /* validate that tail is moving correctly */ - if (!tail || (tail == FM10K_MSG_HDR_MASK(TAIL))) - return FM10K_MBX_ERR_TAIL; - if (fm10k_mbx_index_len(mbx, mbx->head, tail) < mbx->mbmem_len) - break; - - return FM10K_MBX_ERR_TAIL; - case FM10K_MSG_CONNECT: - /* validate size is in range and is power of 2 mask */ - if ((size < FM10K_VFMBX_MSG_MTU) || (size & (size + 1))) - return FM10K_MBX_ERR_SIZE; - - /* fall through */ - case FM10K_MSG_ERROR: - if (!head || (head == FM10K_MSG_HDR_MASK(HEAD))) - return FM10K_MBX_ERR_HEAD; - /* neither create nor error include a tail offset */ - if (tail) - return FM10K_MBX_ERR_TAIL; - - break; - default: - return FM10K_MBX_ERR_TYPE; - } - - return FM10K_SUCCESS; -} - -/** - * fm10k_mbx_create_reply - Generate reply based on state and remote head - * @mbx: pointer to mailbox - * @head: acknowledgement number - * - * This function will generate an outgoing message based on the current - * mailbox state and the remote fifo head. It will return the length - * of the outgoing message excluding header on success, and a negative value - * on error. - **/ -STATIC s32 fm10k_mbx_create_reply(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx, u16 head) -{ - switch (mbx->state) { - case FM10K_STATE_OPEN: - case FM10K_STATE_DISCONNECT: - /* update our checksum for the outgoing data */ - fm10k_mbx_update_local_crc(mbx, head); - - /* as long as other end recognizes us keep sending data */ - fm10k_mbx_pull_head(hw, mbx, head); - - /* generate new header based on data */ - if (mbx->tail_len || (mbx->state == FM10K_STATE_OPEN)) - fm10k_mbx_create_data_hdr(mbx); - else - fm10k_mbx_create_disconnect_hdr(mbx); - break; - case FM10K_STATE_CONNECT: - /* send disconnect even if we aren't connected */ - fm10k_mbx_create_connect_hdr(mbx); - break; - case FM10K_STATE_CLOSED: - /* generate new header based on data */ - fm10k_mbx_create_disconnect_hdr(mbx); - default: - break; - } - - return FM10K_SUCCESS; -} - -/** - * fm10k_mbx_reset_work- Reset internal pointers for any pending work - * @mbx: pointer to mailbox - * - * This function will reset all internal pointers so any work in progress - * is dropped. This call should occur every time we transition from the - * open state to the connect state. - **/ -STATIC void fm10k_mbx_reset_work(struct fm10k_mbx_info *mbx) -{ - /* reset our outgoing max size back to Rx limits */ - mbx->max_size = mbx->rx.size - 1; - - /* just do a quick resysnc to start of message */ - mbx->pushed = 0; - mbx->pulled = 0; - mbx->tail_len = 0; - mbx->head_len = 0; - mbx->rx.tail = 0; - mbx->rx.head = 0; -} - -/** - * fm10k_mbx_update_max_size - Update the max_size and drop any large messages - * @mbx: pointer to mailbox - * @size: new value for max_size - * - * This function will update the max_size value and drop any outgoing messages - * from the head of the Tx FIFO that are larger than max_size. - **/ -STATIC void fm10k_mbx_update_max_size(struct fm10k_mbx_info *mbx, u16 size) -{ - u16 len; - - DEBUGFUNC("fm10k_mbx_update_max_size_hdr"); - - mbx->max_size = size; - - /* flush any oversized messages from the queue */ - for (len = fm10k_fifo_head_len(&mbx->tx); - len > size; - len = fm10k_fifo_head_len(&mbx->tx)) { - fm10k_fifo_head_drop(&mbx->tx); - mbx->tx_dropped++; - } -} - -/** - * fm10k_mbx_connect_reset - Reset following request for reset - * @mbx: pointer to mailbox - * - * This function resets the mailbox to either a disconnected state - * or a connect state depending on the current mailbox state - **/ -STATIC void fm10k_mbx_connect_reset(struct fm10k_mbx_info *mbx) -{ - /* just do a quick resysnc to start of frame */ - fm10k_mbx_reset_work(mbx); - - /* reset CRC seeds */ - mbx->local = FM10K_MBX_CRC_SEED; - mbx->remote = FM10K_MBX_CRC_SEED; - - /* we cannot exit connect until the size is good */ - if (mbx->state == FM10K_STATE_OPEN) - mbx->state = FM10K_STATE_CONNECT; - else - mbx->state = FM10K_STATE_CLOSED; -} - -/** - * fm10k_mbx_process_connect - Process connect header - * @mbx: pointer to mailbox - * @msg: message array to process - * - * This function will read an incoming connect header and reply with the - * appropriate message. It will return a value indicating the number of - * data DWORDs on success, or will return a negative value on failure. - **/ -STATIC s32 fm10k_mbx_process_connect(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx) -{ - const enum fm10k_mbx_state state = mbx->state; - const u32 *hdr = &mbx->mbx_hdr; - u16 size, head; - - /* we will need to pull all of the fields for verification */ - size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE); - head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD); - - switch (state) { - case FM10K_STATE_DISCONNECT: - case FM10K_STATE_OPEN: - /* reset any in-progress work */ - fm10k_mbx_connect_reset(mbx); - break; - case FM10K_STATE_CONNECT: - /* we cannot exit connect until the size is good */ - if (size > mbx->rx.size) { - mbx->max_size = mbx->rx.size - 1; - } else { - /* record the remote system requesting connection */ - mbx->state = FM10K_STATE_OPEN; - - fm10k_mbx_update_max_size(mbx, size); - } - break; - default: - break; - } - - /* align our tail index to remote head index */ - mbx->tail = head; - - return fm10k_mbx_create_reply(hw, mbx, head); -} - -/** - * fm10k_mbx_process_data - Process data header - * @mbx: pointer to mailbox - * - * This function will read an incoming data header and reply with the - * appropriate message. It will return a value indicating the number of - * data DWORDs on success, or will return a negative value on failure. - **/ -STATIC s32 fm10k_mbx_process_data(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx) -{ - const u32 *hdr = &mbx->mbx_hdr; - u16 head, tail; - s32 err; - - DEBUGFUNC("fm10k_mbx_process_data"); - - /* we will need to pull all of the fields for verification */ - head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD); - tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL); - - /* if we are in connect just update our data and go */ - if (mbx->state == FM10K_STATE_CONNECT) { - mbx->tail = head; - mbx->state = FM10K_STATE_OPEN; - } - - /* abort on message size errors */ - err = fm10k_mbx_push_tail(hw, mbx, tail); - if (err < 0) - return err; - - /* verify the checksum on the incoming data */ - err = fm10k_mbx_verify_remote_crc(mbx); - if (err) - return err; - - /* process messages if we have received any */ - fm10k_mbx_dequeue_rx(hw, mbx); - - return fm10k_mbx_create_reply(hw, mbx, head); -} - -/** - * fm10k_mbx_process_disconnect - Process disconnect header - * @mbx: pointer to mailbox - * - * This function will read an incoming disconnect header and reply with the - * appropriate message. It will return a value indicating the number of - * data DWORDs on success, or will return a negative value on failure. - **/ -STATIC s32 fm10k_mbx_process_disconnect(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx) -{ - const enum fm10k_mbx_state state = mbx->state; - const u32 *hdr = &mbx->mbx_hdr; - u16 head; - s32 err; - - /* we will need to pull the header field for verification */ - head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD); - - /* We should not be receiving disconnect if Rx is incomplete */ - if (mbx->pushed) - return FM10K_MBX_ERR_TAIL; - - /* we have already verified mbx->head == tail so we know this is 0 */ - mbx->head_len = 0; - - /* verify the checksum on the incoming header is correct */ - err = fm10k_mbx_verify_remote_crc(mbx); - if (err) - return err; - - switch (state) { - case FM10K_STATE_DISCONNECT: - case FM10K_STATE_OPEN: - /* state doesn't change if we still have work to do */ - if (!fm10k_mbx_tx_complete(mbx)) - break; - - /* verify the head indicates we completed all transmits */ - if (head != mbx->tail) - return FM10K_MBX_ERR_HEAD; - - /* reset any in-progress work */ - fm10k_mbx_connect_reset(mbx); - break; - default: - break; - } - - return fm10k_mbx_create_reply(hw, mbx, head); -} - -/** - * fm10k_mbx_process_error - Process error header - * @mbx: pointer to mailbox - * - * This function will read an incoming error header and reply with the - * appropriate message. It will return a value indicating the number of - * data DWORDs on success, or will return a negative value on failure. - **/ -STATIC s32 fm10k_mbx_process_error(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx) -{ - const u32 *hdr = &mbx->mbx_hdr; - s32 err_no; - u16 head; - - /* we will need to pull all of the fields for verification */ - head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD); - - /* we only have lower 10 bits of error number so add upper bits */ - err_no = FM10K_MSG_HDR_FIELD_GET(*hdr, ERR_NO); - err_no |= ~FM10K_MSG_HDR_MASK(ERR_NO); - - switch (mbx->state) { - case FM10K_STATE_OPEN: - case FM10K_STATE_DISCONNECT: - /* flush any uncompleted work */ - fm10k_mbx_reset_work(mbx); - - /* reset CRC seeds */ - mbx->local = FM10K_MBX_CRC_SEED; - mbx->remote = FM10K_MBX_CRC_SEED; - - /* reset tail index and size to prepare for reconnect */ - mbx->tail = head; - - /* if open then reset max_size and go back to connect */ - if (mbx->state == FM10K_STATE_OPEN) { - mbx->state = FM10K_STATE_CONNECT; - break; - } - - /* send a connect message to get data flowing again */ - fm10k_mbx_create_connect_hdr(mbx); - return FM10K_SUCCESS; - default: - break; - } - - return fm10k_mbx_create_reply(hw, mbx, mbx->tail); -} - -/** - * fm10k_mbx_process - Process mailbox interrupt - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * - * This function will process incoming mailbox events and generate mailbox - * replies. It will return a value indicating the number of DWORDs - * transmitted excluding header on success or a negative value on error. - **/ -STATIC s32 fm10k_mbx_process(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx) -{ - s32 err; - - DEBUGFUNC("fm10k_mbx_process"); - - /* we do not read mailbox if closed */ - if (mbx->state == FM10K_STATE_CLOSED) - return FM10K_SUCCESS; - - /* copy data from mailbox */ - err = fm10k_mbx_read(hw, mbx); - if (err) - return err; - - /* validate type, source, and destination */ - err = fm10k_mbx_validate_msg_hdr(mbx); - if (err < 0) - goto msg_err; - - switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, TYPE)) { - case FM10K_MSG_CONNECT: - err = fm10k_mbx_process_connect(hw, mbx); - break; - case FM10K_MSG_DATA: - err = fm10k_mbx_process_data(hw, mbx); - break; - case FM10K_MSG_DISCONNECT: - err = fm10k_mbx_process_disconnect(hw, mbx); - break; - case FM10K_MSG_ERROR: - err = fm10k_mbx_process_error(hw, mbx); - break; - default: - err = FM10K_MBX_ERR_TYPE; - break; - } - -msg_err: - /* notify partner of errors on our end */ - if (err < 0) - fm10k_mbx_create_error_msg(mbx, err); - - /* copy data from mailbox */ - fm10k_mbx_write(hw, mbx); - - return err; -} - -/** - * fm10k_mbx_disconnect - Shutdown mailbox connection - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * - * This function will shut down the mailbox. It places the mailbox first - * in the disconnect state, it then allows up to a predefined timeout for - * the mailbox to transition to close on its own. If this does not occur - * then the mailbox will be forced into the closed state. - * - * Any mailbox transactions not completed before calling this function - * are not guaranteed to complete and may be dropped. - **/ -STATIC void fm10k_mbx_disconnect(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx) -{ - int timeout = mbx->timeout ? FM10K_MBX_DISCONNECT_TIMEOUT : 0; - - DEBUGFUNC("fm10k_mbx_disconnect"); - - /* Place mbx in ready to disconnect state */ - mbx->state = FM10K_STATE_DISCONNECT; - - /* trigger interrupt to start shutdown process */ - FM10K_WRITE_MBX(hw, mbx->mbx_reg, FM10K_MBX_REQ | - FM10K_MBX_INTERRUPT_DISABLE); - do { - usec_delay(FM10K_MBX_POLL_DELAY); - mbx->ops.process(hw, mbx); - timeout -= FM10K_MBX_POLL_DELAY; - } while ((timeout > 0) && (mbx->state != FM10K_STATE_CLOSED)); - - /* in case we didn't close just force the mailbox into shutdown */ - fm10k_mbx_connect_reset(mbx); - fm10k_mbx_update_max_size(mbx, 0); - - FM10K_WRITE_MBX(hw, mbx->mbmem_reg, 0); -} - -/** - * fm10k_mbx_connect - Start mailbox connection - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * - * This function will initiate a mailbox connection. It will populate the - * mailbox with a broadcast connect message and then initialize the lock. - * This is safe since the connect message is a single DWORD so the mailbox - * transaction is guaranteed to be atomic. - * - * This function will return an error if the mailbox has not been initiated - * or is currently in use. - **/ -STATIC s32 fm10k_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx) -{ - DEBUGFUNC("fm10k_mbx_connect"); - - /* we cannot connect an uninitialized mailbox */ - if (!mbx->rx.buffer) - return FM10K_MBX_ERR_NO_SPACE; - - /* we cannot connect an already connected mailbox */ - if (mbx->state != FM10K_STATE_CLOSED) - return FM10K_MBX_ERR_BUSY; - - /* mailbox timeout can now become active */ - mbx->timeout = FM10K_MBX_INIT_TIMEOUT; - - /* Place mbx in ready to connect state */ - mbx->state = FM10K_STATE_CONNECT; - - /* initialize header of remote mailbox */ - fm10k_mbx_create_disconnect_hdr(mbx); - FM10K_WRITE_MBX(hw, mbx->mbmem_reg ^ mbx->mbmem_len, mbx->mbx_hdr); - - /* enable interrupt and notify other party of new message */ - mbx->mbx_lock = FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT | - FM10K_MBX_INTERRUPT_ENABLE; - - /* generate and load connect header into mailbox */ - fm10k_mbx_create_connect_hdr(mbx); - fm10k_mbx_write(hw, mbx); - - return FM10K_SUCCESS; -} - -/** - * fm10k_mbx_validate_handlers - Validate layout of message parsing data - * @msg_data: handlers for mailbox events - * - * This function validates the layout of the message parsing data. This - * should be mostly static, but it is important to catch any errors that - * are made when constructing the parsers. - **/ -STATIC s32 fm10k_mbx_validate_handlers(const struct fm10k_msg_data *msg_data) -{ - const struct fm10k_tlv_attr *attr; - unsigned int id; - - DEBUGFUNC("fm10k_mbx_validate_handlers"); - - /* Allow NULL mailboxes that transmit but don't receive */ - if (!msg_data) - return FM10K_SUCCESS; - - while (msg_data->id != FM10K_TLV_ERROR) { - /* all messages should have a function handler */ - if (!msg_data->func) - return FM10K_ERR_PARAM; - - /* parser is optional */ - attr = msg_data->attr; - if (attr) { - while (attr->id != FM10K_TLV_ERROR) { - id = attr->id; - attr++; - /* ID should always be increasing */ - if (id >= attr->id) - return FM10K_ERR_PARAM; - /* ID should fit in results array */ - if (id >= FM10K_TLV_RESULTS_MAX) - return FM10K_ERR_PARAM; - } - - /* verify terminator is in the list */ - if (attr->id != FM10K_TLV_ERROR) - return FM10K_ERR_PARAM; - } - - id = msg_data->id; - msg_data++; - /* ID should always be increasing */ - if (id >= msg_data->id) - return FM10K_ERR_PARAM; - } - - /* verify terminator is in the list */ - if ((msg_data->id != FM10K_TLV_ERROR) || !msg_data->func) - return FM10K_ERR_PARAM; - - return FM10K_SUCCESS; -} - -/** - * fm10k_mbx_register_handlers - Register a set of handler ops for mailbox - * @mbx: pointer to mailbox - * @msg_data: handlers for mailbox events - * - * This function associates a set of message handling ops with a mailbox. - **/ -STATIC s32 fm10k_mbx_register_handlers(struct fm10k_mbx_info *mbx, - const struct fm10k_msg_data *msg_data) -{ - DEBUGFUNC("fm10k_mbx_register_handlers"); - - /* validate layout of handlers before assigning them */ - if (fm10k_mbx_validate_handlers(msg_data)) - return FM10K_ERR_PARAM; - - /* initialize the message handlers */ - mbx->msg_data = msg_data; - - return FM10K_SUCCESS; -} - -/** - * fm10k_pfvf_mbx_init - Initialize mailbox memory for PF/VF mailbox - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * @msg_data: handlers for mailbox events - * @id: ID reference for PF as it supports up to 64 PF/VF mailboxes - * - * This function initializes the mailbox for use. It will split the - * buffer provided an use that th populate both the Tx and Rx FIFO by - * evenly splitting it. In order to allow for easy masking of head/tail - * the value reported in size must be a power of 2 and is reported in - * DWORDs, not bytes. Any invalid values will cause the mailbox to return - * error. - **/ -s32 fm10k_pfvf_mbx_init(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx, - const struct fm10k_msg_data *msg_data, u8 id) -{ - DEBUGFUNC("fm10k_pfvf_mbx_init"); - - /* initialize registers */ - switch (hw->mac.type) { - case fm10k_mac_vf: - mbx->mbx_reg = FM10K_VFMBX; - mbx->mbmem_reg = FM10K_VFMBMEM(FM10K_VFMBMEM_VF_XOR); - break; - case fm10k_mac_pf: - /* there are only 64 VF <-> PF mailboxes */ - if (id < 64) { - mbx->mbx_reg = FM10K_MBX(id); - mbx->mbmem_reg = FM10K_MBMEM_VF(id, 0); - break; - } - /* fallthough */ - default: - return FM10K_MBX_ERR_NO_MBX; - } - - /* start out in closed state */ - mbx->state = FM10K_STATE_CLOSED; - - /* validate layout of handlers before assigning them */ - if (fm10k_mbx_validate_handlers(msg_data)) - return FM10K_ERR_PARAM; - - /* initialize the message handlers */ - mbx->msg_data = msg_data; - - /* start mailbox as timed out and let the reset_hw call - * set the timeout value to begin communications - */ - mbx->timeout = 0; - mbx->usec_delay = FM10K_MBX_INIT_DELAY; - - /* initialize tail and head */ - mbx->tail = 1; - mbx->head = 1; - - /* initialize CRC seeds */ - mbx->local = FM10K_MBX_CRC_SEED; - mbx->remote = FM10K_MBX_CRC_SEED; - - /* Split buffer for use by Tx/Rx FIFOs */ - mbx->max_size = FM10K_MBX_MSG_MAX_SIZE; - mbx->mbmem_len = FM10K_VFMBMEM_VF_XOR; - - /* initialize the FIFOs, sizes are in 4 byte increments */ - fm10k_fifo_init(&mbx->tx, mbx->buffer, FM10K_MBX_TX_BUFFER_SIZE); - fm10k_fifo_init(&mbx->rx, &mbx->buffer[FM10K_MBX_TX_BUFFER_SIZE], - FM10K_MBX_RX_BUFFER_SIZE); - - /* initialize function pointers */ - mbx->ops.connect = fm10k_mbx_connect; - mbx->ops.disconnect = fm10k_mbx_disconnect; - mbx->ops.rx_ready = fm10k_mbx_rx_ready; - mbx->ops.tx_ready = fm10k_mbx_tx_ready; - mbx->ops.tx_complete = fm10k_mbx_tx_complete; - mbx->ops.enqueue_tx = fm10k_mbx_enqueue_tx; - mbx->ops.process = fm10k_mbx_process; - mbx->ops.register_handlers = fm10k_mbx_register_handlers; - - return FM10K_SUCCESS; -} - -/** - * fm10k_sm_mbx_create_data_hdr - Generate a mailbox header for local FIFO - * @mbx: pointer to mailbox - * - * This function returns a connection mailbox header - **/ -STATIC void fm10k_sm_mbx_create_data_hdr(struct fm10k_mbx_info *mbx) -{ - if (mbx->tail_len) - mbx->mbx_lock |= FM10K_MBX_REQ; - - mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(mbx->tail, SM_TAIL) | - FM10K_MSG_HDR_FIELD_SET(mbx->remote, SM_VER) | - FM10K_MSG_HDR_FIELD_SET(mbx->head, SM_HEAD); -} - -/** - * fm10k_sm_mbx_create_connect_hdr - Generate a mailbox header for local FIFO - * @mbx: pointer to mailbox - * @err: error flags to report if any - * - * This function returns a connection mailbox header - **/ -STATIC void fm10k_sm_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx, u8 err) -{ - if (mbx->local) - mbx->mbx_lock |= FM10K_MBX_REQ; - - mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(mbx->tail, SM_TAIL) | - FM10K_MSG_HDR_FIELD_SET(mbx->remote, SM_VER) | - FM10K_MSG_HDR_FIELD_SET(mbx->head, SM_HEAD) | - FM10K_MSG_HDR_FIELD_SET(err, SM_ERR); -} - -/** - * fm10k_sm_mbx_connect_reset - Reset following request for reset - * @mbx: pointer to mailbox - * - * This function resets the mailbox to a just connected state - **/ -STATIC void fm10k_sm_mbx_connect_reset(struct fm10k_mbx_info *mbx) -{ - /* flush any uncompleted work */ - fm10k_mbx_reset_work(mbx); - - /* set local version to max and remote version to 0 */ - mbx->local = FM10K_SM_MBX_VERSION; - mbx->remote = 0; - - /* initialize tail and head */ - mbx->tail = 1; - mbx->head = 1; - - /* reset state back to connect */ - mbx->state = FM10K_STATE_CONNECT; -} - -/** - * fm10k_sm_mbx_connect - Start switch manager mailbox connection - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * - * This function will initiate a mailbox connection with the switch - * manager. To do this it will first disconnect the mailbox, and then - * reconnect it in order to complete a reset of the mailbox. - * - * This function will return an error if the mailbox has not been initiated - * or is currently in use. - **/ -STATIC s32 fm10k_sm_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx) -{ - DEBUGFUNC("fm10k_mbx_connect"); - - /* we cannot connect an uninitialized mailbox */ - if (!mbx->rx.buffer) - return FM10K_MBX_ERR_NO_SPACE; - - /* we cannot connect an already connected mailbox */ - if (mbx->state != FM10K_STATE_CLOSED) - return FM10K_MBX_ERR_BUSY; - - /* mailbox timeout can now become active */ - mbx->timeout = FM10K_MBX_INIT_TIMEOUT; - - /* Place mbx in ready to connect state */ - mbx->state = FM10K_STATE_CONNECT; - mbx->max_size = FM10K_MBX_MSG_MAX_SIZE; - - /* reset interface back to connect */ - fm10k_sm_mbx_connect_reset(mbx); - - /* enable interrupt and notify other party of new message */ - mbx->mbx_lock = FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT | - FM10K_MBX_INTERRUPT_ENABLE; - - /* generate and load connect header into mailbox */ - fm10k_sm_mbx_create_connect_hdr(mbx, 0); - fm10k_mbx_write(hw, mbx); - - /* enable interrupt and notify other party of new message */ - - return FM10K_SUCCESS; -} - -/** - * fm10k_sm_mbx_disconnect - Shutdown mailbox connection - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * - * This function will shut down the mailbox. It places the mailbox first - * in the disconnect state, it then allows up to a predefined timeout for - * the mailbox to transition to close on its own. If this does not occur - * then the mailbox will be forced into the closed state. - * - * Any mailbox transactions not completed before calling this function - * are not guaranteed to complete and may be dropped. - **/ -STATIC void fm10k_sm_mbx_disconnect(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx) -{ - int timeout = mbx->timeout ? FM10K_MBX_DISCONNECT_TIMEOUT : 0; - - DEBUGFUNC("fm10k_sm_mbx_disconnect"); - - /* Place mbx in ready to disconnect state */ - mbx->state = FM10K_STATE_DISCONNECT; - - /* trigger interrupt to start shutdown process */ - FM10K_WRITE_REG(hw, mbx->mbx_reg, FM10K_MBX_REQ | - FM10K_MBX_INTERRUPT_DISABLE); - do { - usec_delay(FM10K_MBX_POLL_DELAY); - mbx->ops.process(hw, mbx); - timeout -= FM10K_MBX_POLL_DELAY; - } while ((timeout > 0) && (mbx->state != FM10K_STATE_CLOSED)); - - /* in case we didn't close just force the mailbox into shutdown */ - mbx->state = FM10K_STATE_CLOSED; - mbx->remote = 0; - fm10k_mbx_reset_work(mbx); - fm10k_mbx_update_max_size(mbx, 0); - - FM10K_WRITE_REG(hw, mbx->mbmem_reg, 0); -} - -/** - * fm10k_mbx_validate_fifo_hdr - Validate fields in the remote FIFO header - * @mbx: pointer to mailbox - * - * This function will parse up the fields in the mailbox header and return - * an error if the header contains any of a number of invalid configurations - * including unrecognized offsets or version numbers. - **/ -STATIC s32 fm10k_sm_mbx_validate_fifo_hdr(struct fm10k_mbx_info *mbx) -{ - const u32 *hdr = &mbx->mbx_hdr; - u16 tail, head, ver; - - DEBUGFUNC("fm10k_mbx_validate_msg_hdr"); - - tail = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_TAIL); - ver = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_VER); - head = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_HEAD); - - switch (ver) { - case 0: - break; - case FM10K_SM_MBX_VERSION: - if (!head || head > FM10K_SM_MBX_FIFO_LEN) - return FM10K_MBX_ERR_HEAD; - if (!tail || tail > FM10K_SM_MBX_FIFO_LEN) - return FM10K_MBX_ERR_TAIL; - if (mbx->tail < head) - head += mbx->mbmem_len - 1; - if (tail < mbx->head) - tail += mbx->mbmem_len - 1; - if (fm10k_mbx_index_len(mbx, head, mbx->tail) > mbx->tail_len) - return FM10K_MBX_ERR_HEAD; - if (fm10k_mbx_index_len(mbx, mbx->head, tail) < mbx->mbmem_len) - break; - return FM10K_MBX_ERR_TAIL; - default: - return FM10K_MBX_ERR_SRC; - } - - return FM10K_SUCCESS; -} - -/** - * fm10k_sm_mbx_process_error - Process header with error flag set - * @mbx: pointer to mailbox - * - * This function is meant to respond to a request where the error flag - * is set. As a result we will terminate a connection if one is present - * and fall back into the reset state with a connection header of version - * 0 (RESET). - **/ -STATIC void fm10k_sm_mbx_process_error(struct fm10k_mbx_info *mbx) -{ - const enum fm10k_mbx_state state = mbx->state; - - switch (state) { - case FM10K_STATE_DISCONNECT: - /* if there is an error just disconnect */ - mbx->remote = 0; - break; - case FM10K_STATE_OPEN: - /* flush any uncompleted work */ - fm10k_sm_mbx_connect_reset(mbx); - break; - case FM10K_STATE_CONNECT: - /* try connnecting at lower version */ - if (mbx->remote) { - while (mbx->local > 1) - mbx->local--; - mbx->remote = 0; - } - break; - default: - break; - } - - fm10k_sm_mbx_create_connect_hdr(mbx, 0); -} - -/** - * fm10k_sm_mbx_create_error_message - Process an error in FIFO hdr - * @mbx: pointer to mailbox - * @err: local error encountered - * - * This function will interpret the error provided by err, and based on - * that it may set the error bit in the local message header - **/ -STATIC void fm10k_sm_mbx_create_error_msg(struct fm10k_mbx_info *mbx, s32 err) -{ - /* only generate an error message for these types */ - switch (err) { - case FM10K_MBX_ERR_TAIL: - case FM10K_MBX_ERR_HEAD: - case FM10K_MBX_ERR_SRC: - case FM10K_MBX_ERR_SIZE: - case FM10K_MBX_ERR_RSVD0: - break; - default: - return; - } - - /* process it as though we received an error, and send error reply */ - fm10k_sm_mbx_process_error(mbx); - fm10k_sm_mbx_create_connect_hdr(mbx, 1); -} - -/** - * fm10k_sm_mbx_receive - Take message from Rx mailbox FIFO and put it in Rx - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * - * This function will dequeue one message from the Rx switch manager mailbox - * FIFO and place it in the Rx mailbox FIFO for processing by software. - **/ -STATIC s32 fm10k_sm_mbx_receive(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx, - u16 tail) -{ - /* reduce length by 1 to convert to a mask */ - u16 mbmem_len = mbx->mbmem_len - 1; - s32 err; - - DEBUGFUNC("fm10k_sm_mbx_receive"); - - /* push tail in front of head */ - if (tail < mbx->head) - tail += mbmem_len; - - /* copy data to the Rx FIFO */ - err = fm10k_mbx_push_tail(hw, mbx, tail); - if (err < 0) - return err; - - /* process messages if we have received any */ - fm10k_mbx_dequeue_rx(hw, mbx); - - /* guarantee head aligns with the end of the last message */ - mbx->head = fm10k_mbx_head_sub(mbx, mbx->pushed); - mbx->pushed = 0; - - /* clear any extra bits left over since index adds 1 extra bit */ - if (mbx->head > mbmem_len) - mbx->head -= mbmem_len; - - return err; -} - -/** - * fm10k_sm_mbx_transmit - Take message from Tx and put it in Tx mailbox FIFO - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * - * This function will dequeue one message from the Tx mailbox FIFO and place - * it in the Tx switch manager mailbox FIFO for processing by hardware. - **/ -STATIC void fm10k_sm_mbx_transmit(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx, u16 head) -{ - struct fm10k_mbx_fifo *fifo = &mbx->tx; - /* reduce length by 1 to convert to a mask */ - u16 mbmem_len = mbx->mbmem_len - 1; - u16 tail_len, len = 0; - u32 *msg; - - DEBUGFUNC("fm10k_sm_mbx_transmit"); - - /* push head behind tail */ - if (mbx->tail < head) - head += mbmem_len; - - fm10k_mbx_pull_head(hw, mbx, head); - - /* determine msg aligned offset for end of buffer */ - do { - msg = fifo->buffer + fm10k_fifo_head_offset(fifo, len); - tail_len = len; - len += FM10K_TLV_DWORD_LEN(*msg); - } while ((len <= mbx->tail_len) && (len < mbmem_len)); - - /* guarantee we stop on a message boundary */ - if (mbx->tail_len > tail_len) { - mbx->tail = fm10k_mbx_tail_sub(mbx, mbx->tail_len - tail_len); - mbx->tail_len = tail_len; - } - - /* clear any extra bits left over since index adds 1 extra bit */ - if (mbx->tail > mbmem_len) - mbx->tail -= mbmem_len; -} - -/** - * fm10k_sm_mbx_create_reply - Generate reply based on state and remote head - * @mbx: pointer to mailbox - * @head: acknowledgement number - * - * This function will generate an outgoing message based on the current - * mailbox state and the remote fifo head. It will return the length - * of the outgoing message excluding header on success, and a negative value - * on error. - **/ -STATIC void fm10k_sm_mbx_create_reply(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx, u16 head) -{ - switch (mbx->state) { - case FM10K_STATE_OPEN: - case FM10K_STATE_DISCONNECT: - /* flush out Tx data */ - fm10k_sm_mbx_transmit(hw, mbx, head); - - /* generate new header based on data */ - if (mbx->tail_len || (mbx->state == FM10K_STATE_OPEN)) { - fm10k_sm_mbx_create_data_hdr(mbx); - } else { - mbx->remote = 0; - fm10k_sm_mbx_create_connect_hdr(mbx, 0); - } - break; - case FM10K_STATE_CONNECT: - case FM10K_STATE_CLOSED: - fm10k_sm_mbx_create_connect_hdr(mbx, 0); - break; - default: - break; - } -} - -/** - * fm10k_sm_mbx_process_reset - Process header with version == 0 (RESET) - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * - * This function is meant to respond to a request where the version data - * is set to 0. As such we will either terminate the connection or go - * into the connect state in order to re-establish the connection. This - * function can also be used to respond to an error as the connection - * resetting would also be a means of dealing with errors. - **/ -STATIC void fm10k_sm_mbx_process_reset(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx) -{ - const enum fm10k_mbx_state state = mbx->state; - - switch (state) { - case FM10K_STATE_DISCONNECT: - /* drop remote connections and disconnect */ - mbx->state = FM10K_STATE_CLOSED; - mbx->remote = 0; - mbx->local = 0; - break; - case FM10K_STATE_OPEN: - /* flush any incomplete work */ - fm10k_sm_mbx_connect_reset(mbx); - break; - case FM10K_STATE_CONNECT: - /* Update remote value to match local value */ - mbx->remote = mbx->local; - default: - break; - } - - fm10k_sm_mbx_create_reply(hw, mbx, mbx->tail); -} - -/** - * fm10k_sm_mbx_process_version_1 - Process header with version == 1 - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * - * This function is meant to process messages received when the remote - * mailbox is active. - **/ -STATIC s32 fm10k_sm_mbx_process_version_1(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx) -{ - const u32 *hdr = &mbx->mbx_hdr; - u16 head, tail; - s32 len; - - /* pull all fields needed for verification */ - tail = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_TAIL); - head = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_HEAD); - - /* if we are in connect and wanting version 1 then start up and go */ - if (mbx->state == FM10K_STATE_CONNECT) { - if (!mbx->remote) - goto send_reply; - if (mbx->remote != 1) - return FM10K_MBX_ERR_SRC; - - mbx->state = FM10K_STATE_OPEN; - } - - do { - /* abort on message size errors */ - len = fm10k_sm_mbx_receive(hw, mbx, tail); - if (len < 0) - return len; - - /* continue until we have flushed the Rx FIFO */ - } while (len); - -send_reply: - fm10k_sm_mbx_create_reply(hw, mbx, head); - - return FM10K_SUCCESS; -} - -/** - * fm10k_sm_mbx_process - Process mailbox switch mailbox interrupt - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * - * This function will process incoming mailbox events and generate mailbox - * replies. It will return a value indicating the number of DWORDs - * transmitted excluding header on success or a negative value on error. - **/ -STATIC s32 fm10k_sm_mbx_process(struct fm10k_hw *hw, - struct fm10k_mbx_info *mbx) -{ - s32 err; - - DEBUGFUNC("fm10k_sm_mbx_process"); - - /* we do not read mailbox if closed */ - if (mbx->state == FM10K_STATE_CLOSED) - return FM10K_SUCCESS; - - /* retrieve data from switch manager */ - err = fm10k_mbx_read(hw, mbx); - if (err) - return err; - - err = fm10k_sm_mbx_validate_fifo_hdr(mbx); - if (err < 0) - goto fifo_err; - - if (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_ERR)) { - fm10k_sm_mbx_process_error(mbx); - goto fifo_err; - } - - switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_VER)) { - case 0: - fm10k_sm_mbx_process_reset(hw, mbx); - break; - case FM10K_SM_MBX_VERSION: - err = fm10k_sm_mbx_process_version_1(hw, mbx); - break; - } - -fifo_err: - if (err < 0) - fm10k_sm_mbx_create_error_msg(mbx, err); - - /* report data to switch manager */ - fm10k_mbx_write(hw, mbx); - - return err; -} - -/** - * fm10k_sm_mbx_init - Initialize mailbox memory for PF/SM mailbox - * @hw: pointer to hardware structure - * @mbx: pointer to mailbox - * @msg_data: handlers for mailbox events - * - * This function for now is used to stub out the PF/SM mailbox - **/ -s32 fm10k_sm_mbx_init(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx, - const struct fm10k_msg_data *msg_data) -{ - DEBUGFUNC("fm10k_sm_mbx_init"); - UNREFERENCED_1PARAMETER(hw); - - mbx->mbx_reg = FM10K_GMBX; - mbx->mbmem_reg = FM10K_MBMEM_PF(0); - - /* start out in closed state */ - mbx->state = FM10K_STATE_CLOSED; - - /* validate layout of handlers before assigning them */ - if (fm10k_mbx_validate_handlers(msg_data)) - return FM10K_ERR_PARAM; - - /* initialize the message handlers */ - mbx->msg_data = msg_data; - - /* start mailbox as timed out and let the reset_hw call - * set the timeout value to begin communications - */ - mbx->timeout = 0; - mbx->usec_delay = FM10K_MBX_INIT_DELAY; - - /* Split buffer for use by Tx/Rx FIFOs */ - mbx->max_size = FM10K_MBX_MSG_MAX_SIZE; - mbx->mbmem_len = FM10K_MBMEM_PF_XOR; - - /* initialize the FIFOs, sizes are in 4 byte increments */ - fm10k_fifo_init(&mbx->tx, mbx->buffer, FM10K_MBX_TX_BUFFER_SIZE); - fm10k_fifo_init(&mbx->rx, &mbx->buffer[FM10K_MBX_TX_BUFFER_SIZE], - FM10K_MBX_RX_BUFFER_SIZE); - - /* initialize function pointers */ - mbx->ops.connect = fm10k_sm_mbx_connect; - mbx->ops.disconnect = fm10k_sm_mbx_disconnect; - mbx->ops.rx_ready = fm10k_mbx_rx_ready; - mbx->ops.tx_ready = fm10k_mbx_tx_ready; - mbx->ops.tx_complete = fm10k_mbx_tx_complete; - mbx->ops.enqueue_tx = fm10k_mbx_enqueue_tx; - mbx->ops.process = fm10k_sm_mbx_process; - mbx->ops.register_handlers = fm10k_mbx_register_handlers; - - return FM10K_SUCCESS; -} diff --git a/lib/librte_pmd_fm10k/base/fm10k_mbx.h b/lib/librte_pmd_fm10k/base/fm10k_mbx.h deleted file mode 100644 index 6332584..0000000 --- a/lib/librte_pmd_fm10k/base/fm10k_mbx.h +++ /dev/null @@ -1,329 +0,0 @@ -/******************************************************************************* - -Copyright (c) 2013 - 2015, 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. - -***************************************************************************/ - -#ifndef _FM10K_MBX_H_ -#define _FM10K_MBX_H_ - -/* forward declaration */ -struct fm10k_mbx_info; - -#include "fm10k_type.h" -#include "fm10k_tlv.h" - -/* PF Mailbox Registers */ -#define FM10K_MBMEM(_n) ((_n) + 0x18000) -#define FM10K_MBMEM_VF(_n, _m) (((_n) * 0x10) + (_m) + 0x18000) -#define FM10K_MBMEM_SM(_n) ((_n) + 0x18400) -#define FM10K_MBMEM_PF(_n) ((_n) + 0x18600) -/* XOR provides means of switching from Tx to Rx FIFO */ -#define FM10K_MBMEM_PF_XOR (FM10K_MBMEM_SM(0) ^ FM10K_MBMEM_PF(0)) -#define FM10K_MBX(_n) ((_n) + 0x18800) -#define FM10K_MBX_OWNER 0x00000001 -#define FM10K_MBX_REQ 0x00000002 -#define FM10K_MBX_ACK 0x00000004 -#define FM10K_MBX_REQ_INTERRUPT 0x00000008 -#define FM10K_MBX_ACK_INTERRUPT 0x00000010 -#define FM10K_MBX_INTERRUPT_ENABLE 0x00000020 -#define FM10K_MBX_INTERRUPT_DISABLE 0x00000040 -#define FM10K_MBICR(_n) ((_n) + 0x18840) -#define FM10K_GMBX 0x18842 - -/* VF Mailbox Registers */ -#define FM10K_VFMBX 0x00010 -#define FM10K_VFMBMEM(_n) ((_n) + 0x00020) -#define FM10K_VFMBMEM_LEN 16 -#define FM10K_VFMBMEM_VF_XOR (FM10K_VFMBMEM_LEN / 2) - -/* Delays/timeouts */ -#define FM10K_MBX_DISCONNECT_TIMEOUT 500 -#define FM10K_MBX_POLL_DELAY 19 -#define FM10K_MBX_INT_DELAY 20 - -#define FM10K_WRITE_MBX(hw, reg, value) FM10K_WRITE_REG(hw, reg, value) - -/* PF/VF Mailbox state machine - * - * +----------+ connect() +----------+ - * | CLOSED | --------------> | CONNECT | - * +----------+ +----------+ - * ^ ^ | - * | rcv: rcv: | | rcv: - * | Connect Disconnect | | Connect - * | Disconnect Error | | Data - * | | | - * | | V - * +----------+ disconnect() +----------+ - * |DISCONNECT| <-------------- | OPEN | - * +----------+ +----------+ - * - * The diagram above describes the PF/VF mailbox state machine. There - * are four main states to this machine. - * Closed: This state represents a mailbox that is in a standby state - * with interrupts disabled. In this state the mailbox should not - * read the mailbox or write any data. The only means of exiting - * this state is for the system to make the connect() call for the - * mailbox, it will then transition to the connect state. - * Connect: In this state the mailbox is seeking a connection. It will - * post a connect message with no specified destination and will - * wait for a reply from the other side of the mailbox. This state - * is exited when either a connect with the local mailbox as the - * destination is received or when a data message is received with - * a valid sequence number. - * Open: In this state the mailbox is able to transfer data between the local - * entity and the remote. It will fall back to connect in the event of - * receiving either an error message, or a disconnect message. It will - * transition to disconnect on a call to disconnect(); - * Disconnect: In this state the mailbox is attempting to gracefully terminate - * the connection. It will do so at the first point where it knows - * that the remote endpoint is either done sending, or when the - * remote endpoint has fallen back into connect. - */ -enum fm10k_mbx_state { - FM10K_STATE_CLOSED, - FM10K_STATE_CONNECT, - FM10K_STATE_OPEN, - FM10K_STATE_DISCONNECT, -}; - -/* PF/VF Mailbox header format - * 3 2 1 0 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Size/Err_no/CRC | Rsvd0 | Head | Tail | Type | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * The layout above describes the format for the header used in the PF/VF - * mailbox. The header is broken out into the following fields: - * Type: There are 4 supported message types - * 0x8: Data header - used to transport message data - * 0xC: Connect header - used to establish connection - * 0xD: Disconnect header - used to tear down a connection - * 0xE: Error header - used to address message exceptions - * Tail: Tail index for local FIFO - * Tail index actually consists of two parts. The MSB of - * the head is a loop tracker, it is 0 on an even numbered - * loop through the FIFO, and 1 on the odd numbered loops. - * To get the actual mailbox offset based on the tail it - * is necessary to add bit 3 to bit 0 and clear bit 3. This - * gives us a valid range of 0x1 - 0xE. - * Head: Head index for remote FIFO - * Head index follows the same format as the tail index. - * Rsvd0: Reserved 0 portion of the mailbox header - * CRC: Running CRC for all data since connect plus current message header - * Size: Maximum message size - Applies only to connect headers - * The maximum message size is provided during connect to avoid - * jamming the mailbox with messages that do not fit. - * Err_no: Error number - Applies only to error headers - * The error number provides a indication of the type of error - * experienced. - */ - -/* macros for retriving and setting header values */ -#define FM10K_MSG_HDR_MASK(name) \ - ((0x1u << FM10K_MSG_##name##_SIZE) - 1) -#define FM10K_MSG_HDR_FIELD_SET(value, name) \ - (((u32)(value) & FM10K_MSG_HDR_MASK(name)) << FM10K_MSG_##name##_SHIFT) -#define FM10K_MSG_HDR_FIELD_GET(value, name) \ - ((u16)((value) >> FM10K_MSG_##name##_SHIFT) & FM10K_MSG_HDR_MASK(name)) - -/* offsets shared between all headers */ -#define FM10K_MSG_TYPE_SHIFT 0 -#define FM10K_MSG_TYPE_SIZE 4 -#define FM10K_MSG_TAIL_SHIFT 4 -#define FM10K_MSG_TAIL_SIZE 4 -#define FM10K_MSG_HEAD_SHIFT 8 -#define FM10K_MSG_HEAD_SIZE 4 -#define FM10K_MSG_RSVD0_SHIFT 12 -#define FM10K_MSG_RSVD0_SIZE 4 - -/* offsets for data/disconnect headers */ -#define FM10K_MSG_CRC_SHIFT 16 -#define FM10K_MSG_CRC_SIZE 16 - -/* offsets for connect headers */ -#define FM10K_MSG_CONNECT_SIZE_SHIFT 16 -#define FM10K_MSG_CONNECT_SIZE_SIZE 16 - -/* offsets for error headers */ -#define FM10K_MSG_ERR_NO_SHIFT 16 -#define FM10K_MSG_ERR_NO_SIZE 16 - -enum fm10k_msg_type { - FM10K_MSG_DATA = 0x8, - FM10K_MSG_CONNECT = 0xC, - FM10K_MSG_DISCONNECT = 0xD, - FM10K_MSG_ERROR = 0xE, -}; - -/* HNI/SM Mailbox FIFO format - * 3 2 1 0 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-------+-----------------------+-------+-----------------------+ - * | Error | Remote Head |Version| Local Tail | - * +-------+-----------------------+-------+-----------------------+ - * | | - * . Local FIFO Data . - * . . - * +-------+-----------------------+-------+-----------------------+ - * - * The layout above describes the format for the FIFOs used by the host - * network interface and the switch manager to communicate messages back - * and forth. Both the HNI and the switch maintain one such FIFO. The - * layout in memory has the switch manager FIFO followed immediately by - * the HNI FIFO. For this reason I am using just the pointer to the - * HNI FIFO in the mailbox ops as the offset between the two is fixed. - * - * The header for the FIFO is broken out into the following fields: - * Local Tail: Offset into FIFO region for next DWORD to write. - * Version: Version info for mailbox, only values of 0/1 are supported. - * Remote Head: Offset into remote FIFO to indicate how much we have read. - * Error: Error indication, values TBD. - */ - -/* version number for switch manager mailboxes */ -#define FM10K_SM_MBX_VERSION 1 -#define FM10K_SM_MBX_FIFO_LEN (FM10K_MBMEM_PF_XOR - 1) -#define FM10K_SM_MBX_FIFO_HDR_LEN 1 - -/* offsets shared between all SM FIFO headers */ -#define FM10K_MSG_SM_TAIL_SHIFT 0 -#define FM10K_MSG_SM_TAIL_SIZE 12 -#define FM10K_MSG_SM_VER_SHIFT 12 -#define FM10K_MSG_SM_VER_SIZE 4 -#define FM10K_MSG_SM_HEAD_SHIFT 16 -#define FM10K_MSG_SM_HEAD_SIZE 12 -#define FM10K_MSG_SM_ERR_SHIFT 28 -#define FM10K_MSG_SM_ERR_SIZE 4 - -/* All error messages returned by mailbox functions - * The value -511 is 0xFE01 in hex. The idea is to order the errors - * from 0xFE01 - 0xFEFF so error codes are easily visible in the mailbox - * messages. This also helps to avoid error number collisions as Linux - * doesn't appear to use error numbers 256 - 511. - */ -#define FM10K_MBX_ERR(_n) ((_n) - 512) -#define FM10K_MBX_ERR_NO_MBX FM10K_MBX_ERR(0x01) -#define FM10K_MBX_ERR_NO_MSG FM10K_MBX_ERR(0x02) -#define FM10K_MBX_ERR_NO_SPACE FM10K_MBX_ERR(0x03) -#define FM10K_MBX_ERR_LOCK FM10K_MBX_ERR(0x04) -#define FM10K_MBX_ERR_TAIL FM10K_MBX_ERR(0x05) -#define FM10K_MBX_ERR_HEAD FM10K_MBX_ERR(0x06) -#define FM10K_MBX_ERR_DST FM10K_MBX_ERR(0x07) -#define FM10K_MBX_ERR_SRC FM10K_MBX_ERR(0x08) -#define FM10K_MBX_ERR_TYPE FM10K_MBX_ERR(0x09) -#define FM10K_MBX_ERR_LEN FM10K_MBX_ERR(0x0A) -#define FM10K_MBX_ERR_SIZE FM10K_MBX_ERR(0x0B) -#define FM10K_MBX_ERR_BUSY FM10K_MBX_ERR(0x0C) -#define FM10K_MBX_ERR_VALUE FM10K_MBX_ERR(0x0D) -#define FM10K_MBX_ERR_RSVD0 FM10K_MBX_ERR(0x0E) -#define FM10K_MBX_ERR_CRC FM10K_MBX_ERR(0x0F) - -#define FM10K_MBX_CRC_SEED 0xFFFF - -struct fm10k_mbx_ops { - s32 (*connect)(struct fm10k_hw *, struct fm10k_mbx_info *); - void (*disconnect)(struct fm10k_hw *, struct fm10k_mbx_info *); - bool (*rx_ready)(struct fm10k_mbx_info *); - bool (*tx_ready)(struct fm10k_mbx_info *, u16); - bool (*tx_complete)(struct fm10k_mbx_info *); - s32 (*enqueue_tx)(struct fm10k_hw *, struct fm10k_mbx_info *, - const u32 *); - s32 (*process)(struct fm10k_hw *, struct fm10k_mbx_info *); - s32 (*register_handlers)(struct fm10k_mbx_info *, - const struct fm10k_msg_data *); -}; - -struct fm10k_mbx_fifo { - u32 *buffer; - u16 head; - u16 tail; - u16 size; -}; - -/* size of buffer to be stored in mailbox for FIFOs */ -#define FM10K_MBX_TX_BUFFER_SIZE 512 -#define FM10K_MBX_RX_BUFFER_SIZE 128 -#define FM10K_MBX_BUFFER_SIZE \ - (FM10K_MBX_TX_BUFFER_SIZE + FM10K_MBX_RX_BUFFER_SIZE) - -/* minimum and maximum message size in dwords */ -#define FM10K_MBX_MSG_MAX_SIZE \ - ((FM10K_MBX_TX_BUFFER_SIZE - 1) & (FM10K_MBX_RX_BUFFER_SIZE - 1)) -#define FM10K_VFMBX_MSG_MTU ((FM10K_VFMBMEM_LEN / 2) - 1) - -#define FM10K_MBX_INIT_TIMEOUT 2000 /* number of retries on mailbox */ -#define FM10K_MBX_INIT_DELAY 500 /* microseconds between retries */ - -struct fm10k_mbx_info { - /* function pointers for mailbox operations */ - struct fm10k_mbx_ops ops; - const struct fm10k_msg_data *msg_data; - - /* message FIFOs */ - struct fm10k_mbx_fifo rx; - struct fm10k_mbx_fifo tx; - - /* delay for handling timeouts */ - u32 timeout; - u32 usec_delay; - - /* mailbox state info */ - u32 mbx_reg, mbmem_reg, mbx_lock, mbx_hdr; - u16 max_size, mbmem_len; - u16 tail, tail_len, pulled; - u16 head, head_len, pushed; - u16 local, remote; - enum fm10k_mbx_state state; - - /* result of last mailbox test */ - s32 test_result; - - /* statistics */ - u64 tx_busy; - u64 tx_dropped; - u64 tx_messages; - u64 tx_dwords; - u64 rx_messages; - u64 rx_dwords; - u64 rx_parse_err; - - /* Buffer to store messages */ - u32 buffer[FM10K_MBX_BUFFER_SIZE]; -}; - -s32 fm10k_pfvf_mbx_init(struct fm10k_hw *, struct fm10k_mbx_info *, - const struct fm10k_msg_data *, u8); -s32 fm10k_sm_mbx_init(struct fm10k_hw *, struct fm10k_mbx_info *, - const struct fm10k_msg_data *); - -#endif /* _FM10K_MBX_H_ */ diff --git a/lib/librte_pmd_fm10k/base/fm10k_osdep.h b/lib/librte_pmd_fm10k/base/fm10k_osdep.h deleted file mode 100644 index 04f8fe9..0000000 --- a/lib/librte_pmd_fm10k/base/fm10k_osdep.h +++ /dev/null @@ -1,148 +0,0 @@ -/******************************************************************************* - -Copyright (c) 2013-2015, 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. - -***************************************************************************/ - -#ifndef _FM10K_OSDEP_H_ -#define _FM10K_OSDEP_H_ - -#include -#include -#include -#include -#include -#include "../fm10k_logs.h" - -/* TODO: this does not look like it should be used... */ -#define ERROR_REPORT2(v1, v2, v3) do { } while (0) - -#define STATIC static -#define DEBUGFUNC(F) DEBUGOUT(F); -#define DEBUGOUT(S, args...) PMD_DRV_LOG_RAW(DEBUG, S, ##args) -#define DEBUGOUT1(S, args...) DEBUGOUT(S, ##args) -#define DEBUGOUT2(S, args...) DEBUGOUT(S, ##args) -#define DEBUGOUT3(S, args...) DEBUGOUT(S, ##args) -#define DEBUGOUT6(S, args...) DEBUGOUT(S, ##args) -#define DEBUGOUT7(S, args...) DEBUGOUT(S, ##args) - -#define FALSE 0 -#define TRUE 1 -#ifndef false -#define false FALSE -#endif -#ifndef true -#define true TRUE -#endif - -typedef uint8_t u8; -typedef int8_t s8; -typedef uint16_t u16; -typedef int16_t s16; -typedef uint32_t u32; -typedef int32_t s32; -typedef int64_t s64; -typedef uint64_t u64; -typedef int bool; - -#ifndef __le16 -#define __le16 u16 -#define __le32 u32 -#define __le64 u64 -#endif -#ifndef __be16 -#define __be16 u16 -#define __be32 u32 -#define __be64 u64 -#endif - -/* offsets are WORD offsets, not BYTE offsets */ -#define FM10K_WRITE_REG(hw, reg, val) \ - ((((volatile uint32_t *)(hw)->hw_addr)[(reg)]) = ((uint32_t)(val))) -#define FM10K_READ_REG(hw, reg) \ - (((volatile uint32_t *)(hw)->hw_addr)[(reg)]) -#define FM10K_WRITE_FLUSH(a) FM10K_READ_REG(a, FM10K_CTRL) - -#define FM10K_PCI_REG(reg) (*((volatile uint32_t *)(reg))) - -#define FM10K_PCI_REG_WRITE(reg, value) do { \ - FM10K_PCI_REG((reg)) = (value); \ -} while (0) - -/* not implemented */ -#define FM10K_READ_PCI_WORD(hw, reg) 0 - -#define FM10K_WRITE_MBX(hw, reg, value) FM10K_WRITE_REG(hw, reg, value) -#define FM10K_READ_MBX(hw, reg) FM10K_READ_REG(hw, reg) - -#define FM10K_LE16_TO_CPU rte_le_to_cpu_16 -#define FM10K_LE32_TO_CPU rte_le_to_cpu_32 -#define FM10K_CPU_TO_LE32 rte_cpu_to_le_32 -#define FM10K_CPU_TO_LE16 rte_cpu_to_le_16 - -#define FM10K_RMB rte_rmb -#define FM10K_WMB rte_wmb - -#define usec_delay rte_delay_us - -#define FM10K_REMOVED(hw_addr) (!(hw_addr)) - -#ifndef FM10K_IS_ZERO_ETHER_ADDR -/* make certain address is not 0 */ -#define FM10K_IS_ZERO_ETHER_ADDR(addr) \ -(!((addr)[0] | (addr)[1] | (addr)[2] | (addr)[3] | (addr)[4] | (addr)[5])) -#endif - -#ifndef FM10K_IS_MULTICAST_ETHER_ADDR -#define FM10K_IS_MULTICAST_ETHER_ADDR(addr) ((addr)[0] & 0x1) -#endif - -#ifndef FM10K_IS_VALID_ETHER_ADDR -/* make certain address is not multicast or 0 */ -#define FM10K_IS_VALID_ETHER_ADDR(addr) \ -(!FM10K_IS_MULTICAST_ETHER_ADDR(addr) && !FM10K_IS_ZERO_ETHER_ADDR(addr)) -#endif - -#ifndef do_div -#define do_div(n, base) ({\ - (n) = (n) / (base);\ -}) -#endif /* do_div */ - -/* DPDK can't access IOMEM directly */ -#ifndef FM10K_WRITE_SW_REG -#define FM10K_WRITE_SW_REG(v1, v2, v3) do { } while (0) -#endif - -#ifndef fm10k_read_reg -#define fm10k_read_reg FM10K_READ_REG -#endif - -#endif /* _FM10K_OSDEP_H_ */ diff --git a/lib/librte_pmd_fm10k/base/fm10k_pf.c b/lib/librte_pmd_fm10k/base/fm10k_pf.c deleted file mode 100644 index 3545a24..0000000 --- a/lib/librte_pmd_fm10k/base/fm10k_pf.c +++ /dev/null @@ -1,1992 +0,0 @@ -/******************************************************************************* - -Copyright (c) 2013 - 2015, 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. - -***************************************************************************/ - -#include "fm10k_pf.h" -#include "fm10k_vf.h" - -/** - * fm10k_reset_hw_pf - PF hardware reset - * @hw: pointer to hardware structure - * - * This function should return the hardware to a state similar to the - * one it is in after being powered on. - **/ -STATIC s32 fm10k_reset_hw_pf(struct fm10k_hw *hw) -{ - s32 err; - u32 reg; - u16 i; - - DEBUGFUNC("fm10k_reset_hw_pf"); - - /* Disable interrupts */ - FM10K_WRITE_REG(hw, FM10K_EIMR, FM10K_EIMR_DISABLE(ALL)); - - /* Lock ITR2 reg 0 into itself and disable interrupt moderation */ - FM10K_WRITE_REG(hw, FM10K_ITR2(0), 0); - FM10K_WRITE_REG(hw, FM10K_INT_CTRL, 0); - - /* We assume here Tx and Rx queue 0 are owned by the PF */ - - /* Shut off VF access to their queues forcing them to queue 0 */ - for (i = 0; i < FM10K_TQMAP_TABLE_SIZE; i++) { - FM10K_WRITE_REG(hw, FM10K_TQMAP(i), 0); - FM10K_WRITE_REG(hw, FM10K_RQMAP(i), 0); - } - - /* shut down all rings */ - err = fm10k_disable_queues_generic(hw, FM10K_MAX_QUEUES); - if (err) - return err; - - /* Verify that DMA is no longer active */ - reg = FM10K_READ_REG(hw, FM10K_DMA_CTRL); - if (reg & (FM10K_DMA_CTRL_TX_ACTIVE | FM10K_DMA_CTRL_RX_ACTIVE)) - return FM10K_ERR_DMA_PENDING; - - /* verify the switch is ready for reset */ - reg = FM10K_READ_REG(hw, FM10K_DMA_CTRL2); - if (!(reg & FM10K_DMA_CTRL2_SWITCH_READY)) - goto out; - - /* Inititate data path reset */ - reg |= FM10K_DMA_CTRL_DATAPATH_RESET; - FM10K_WRITE_REG(hw, FM10K_DMA_CTRL, reg); - - /* Flush write and allow 100us for reset to complete */ - FM10K_WRITE_FLUSH(hw); - usec_delay(FM10K_RESET_TIMEOUT); - - /* Verify we made it out of reset */ - reg = FM10K_READ_REG(hw, FM10K_IP); - if (!(reg & FM10K_IP_NOTINRESET)) - err = FM10K_ERR_RESET_FAILED; - -out: - return err; -} - -/** - * fm10k_is_ari_hierarchy_pf - Indicate ARI hierarchy support - * @hw: pointer to hardware structure - * - * Looks at the ARI hierarchy bit to determine whether ARI is supported or not. - **/ -STATIC bool fm10k_is_ari_hierarchy_pf(struct fm10k_hw *hw) -{ - u16 sriov_ctrl = FM10K_READ_PCI_WORD(hw, FM10K_PCIE_SRIOV_CTRL); - - DEBUGFUNC("fm10k_is_ari_hierarchy_pf"); - - return !!(sriov_ctrl & FM10K_PCIE_SRIOV_CTRL_VFARI); -} - -/** - * fm10k_init_hw_pf - PF hardware initialization - * @hw: pointer to hardware structure - * - **/ -STATIC s32 fm10k_init_hw_pf(struct fm10k_hw *hw) -{ - u32 dma_ctrl, txqctl; - u16 i; - - DEBUGFUNC("fm10k_init_hw_pf"); - - /* Establish default VSI as valid */ - FM10K_WRITE_REG(hw, FM10K_DGLORTDEC(fm10k_dglort_default), 0); - FM10K_WRITE_REG(hw, FM10K_DGLORTMAP(fm10k_dglort_default), - FM10K_DGLORTMAP_ANY); - - /* Invalidate all other GLORT entries */ - for (i = 1; i < FM10K_DGLORT_COUNT; i++) - FM10K_WRITE_REG(hw, FM10K_DGLORTMAP(i), FM10K_DGLORTMAP_NONE); - - /* reset ITR2(0) to point to itself */ - FM10K_WRITE_REG(hw, FM10K_ITR2(0), 0); - - /* reset VF ITR2(0) to point to 0 avoid PF registers */ - FM10K_WRITE_REG(hw, FM10K_ITR2(FM10K_ITR_REG_COUNT_PF), 0); - - /* loop through all PF ITR2 registers pointing them to the previous */ - for (i = 1; i < FM10K_ITR_REG_COUNT_PF; i++) - FM10K_WRITE_REG(hw, FM10K_ITR2(i), i - 1); - - /* Enable interrupt moderator if not already enabled */ - FM10K_WRITE_REG(hw, FM10K_INT_CTRL, FM10K_INT_CTRL_ENABLEMODERATOR); - - /* compute the default txqctl configuration */ - txqctl = FM10K_TXQCTL_PF | FM10K_TXQCTL_UNLIMITED_BW | - (hw->mac.default_vid << FM10K_TXQCTL_VID_SHIFT); - - for (i = 0; i < FM10K_MAX_QUEUES; i++) { - /* configure rings for 256 Queue / 32 Descriptor cache mode */ - FM10K_WRITE_REG(hw, FM10K_TQDLOC(i), - (i * FM10K_TQDLOC_BASE_32_DESC) | - FM10K_TQDLOC_SIZE_32_DESC); - FM10K_WRITE_REG(hw, FM10K_TXQCTL(i), txqctl); - - /* configure rings to provide TPH processing hints */ - FM10K_WRITE_REG(hw, FM10K_TPH_TXCTRL(i), - FM10K_TPH_TXCTRL_DESC_TPHEN | - FM10K_TPH_TXCTRL_DESC_RROEN | - FM10K_TPH_TXCTRL_DESC_WROEN | - FM10K_TPH_TXCTRL_DATA_RROEN); - FM10K_WRITE_REG(hw, FM10K_TPH_RXCTRL(i), - FM10K_TPH_RXCTRL_DESC_TPHEN | - FM10K_TPH_RXCTRL_DESC_RROEN | - FM10K_TPH_RXCTRL_DATA_WROEN | - FM10K_TPH_RXCTRL_HDR_WROEN); - } - - /* set max hold interval to align with 1.024 usec in all modes */ - switch (hw->bus.speed) { - case fm10k_bus_speed_2500: - dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN1; - break; - case fm10k_bus_speed_5000: - dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN2; - break; - case fm10k_bus_speed_8000: - dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN3; - break; - default: - dma_ctrl = 0; - break; - } - - /* Configure TSO flags */ - FM10K_WRITE_REG(hw, FM10K_DTXTCPFLGL, FM10K_TSO_FLAGS_LOW); - FM10K_WRITE_REG(hw, FM10K_DTXTCPFLGH, FM10K_TSO_FLAGS_HI); - - /* Enable DMA engine - * Set Rx Descriptor size to 32 - * Set Minimum MSS to 64 - * Set Maximum number of Rx queues to 256 / 32 Descriptor - */ - dma_ctrl |= FM10K_DMA_CTRL_TX_ENABLE | FM10K_DMA_CTRL_RX_ENABLE | - FM10K_DMA_CTRL_RX_DESC_SIZE | FM10K_DMA_CTRL_MINMSS_64 | - FM10K_DMA_CTRL_32_DESC; - - FM10K_WRITE_REG(hw, FM10K_DMA_CTRL, dma_ctrl); - - /* record maximum queue count, we limit ourselves to 128 */ - hw->mac.max_queues = FM10K_MAX_QUEUES_PF; - - /* We support either 64 VFs or 7 VFs depending on if we have ARI */ - hw->iov.total_vfs = fm10k_is_ari_hierarchy_pf(hw) ? 64 : 7; - - return FM10K_SUCCESS; -} - -/** - * fm10k_is_slot_appropriate_pf - Indicate appropriate slot for this SKU - * @hw: pointer to hardware structure - * - * Looks at the PCIe bus info to confirm whether or not this slot can support - * the necessary bandwidth for this device. - **/ -STATIC bool fm10k_is_slot_appropriate_pf(struct fm10k_hw *hw) -{ - DEBUGFUNC("fm10k_is_slot_appropriate_pf"); - - return (hw->bus.speed == hw->bus_caps.speed) && - (hw->bus.width == hw->bus_caps.width); -} - -/** - * fm10k_update_vlan_pf - Update status of VLAN ID in VLAN filter table - * @hw: pointer to hardware structure - * @vid: VLAN ID to add to table - * @vsi: Index indicating VF ID or PF ID in table - * @set: Indicates if this is a set or clear operation - * - * This function adds or removes the corresponding VLAN ID from the VLAN - * filter table for the corresponding function. In addition to the - * standard set/clear that supports one bit a multi-bit write is - * supported to set 64 bits at a time. - **/ -STATIC s32 fm10k_update_vlan_pf(struct fm10k_hw *hw, u32 vid, u8 vsi, bool set) -{ - u32 vlan_table, reg, mask, bit, len; - - /* verify the VSI index is valid */ - if (vsi > FM10K_VLAN_TABLE_VSI_MAX) - return FM10K_ERR_PARAM; - - /* VLAN multi-bit write: - * The multi-bit write has several parts to it. - * 3 2 1 0 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | RSVD0 | Length |C|RSVD0| VLAN ID | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * VLAN ID: Vlan Starting value - * RSVD0: Reserved section, must be 0 - * C: Flag field, 0 is set, 1 is clear (Used in VF VLAN message) - * Length: Number of times to repeat the bit being set - */ - len = vid >> 16; - vid = (vid << 17) >> 17; - - /* verify the reserved 0 fields are 0 */ - if (len >= FM10K_VLAN_TABLE_VID_MAX || vid >= FM10K_VLAN_TABLE_VID_MAX) - return FM10K_ERR_PARAM; - - /* Loop through the table updating all required VLANs */ - for (reg = FM10K_VLAN_TABLE(vsi, vid / 32), bit = vid % 32; - len < FM10K_VLAN_TABLE_VID_MAX; - len -= 32 - bit, reg++, bit = 0) { - /* record the initial state of the register */ - vlan_table = FM10K_READ_REG(hw, reg); - - /* truncate mask if we are at the start or end of the run */ - mask = (~(u32)0 >> ((len < 31) ? 31 - len : 0)) << bit; - - /* make necessary modifications to the register */ - mask &= set ? ~vlan_table : vlan_table; - if (mask) - FM10K_WRITE_REG(hw, reg, vlan_table ^ mask); - } - - return FM10K_SUCCESS; -} - -/** - * fm10k_read_mac_addr_pf - Read device MAC address - * @hw: pointer to the HW structure - * - * Reads the device MAC address from the SM_AREA and stores the value. - **/ -STATIC s32 fm10k_read_mac_addr_pf(struct fm10k_hw *hw) -{ - u8 perm_addr[ETH_ALEN]; - u32 serial_num; - int i; - - DEBUGFUNC("fm10k_read_mac_addr_pf"); - - serial_num = FM10K_READ_REG(hw, FM10K_SM_AREA(1)); - - /* last byte should be all 1's */ - if ((~serial_num) << 24) - return FM10K_ERR_INVALID_MAC_ADDR; - - perm_addr[0] = (u8)(serial_num >> 24); - perm_addr[1] = (u8)(serial_num >> 16); - perm_addr[2] = (u8)(serial_num >> 8); - - serial_num = FM10K_READ_REG(hw, FM10K_SM_AREA(0)); - - /* first byte should be all 1's */ - if ((~serial_num) >> 24) - return FM10K_ERR_INVALID_MAC_ADDR; - - perm_addr[3] = (u8)(serial_num >> 16); - perm_addr[4] = (u8)(serial_num >> 8); - perm_addr[5] = (u8)(serial_num); - - for (i = 0; i < ETH_ALEN; i++) { - hw->mac.perm_addr[i] = perm_addr[i]; - hw->mac.addr[i] = perm_addr[i]; - } - - return FM10K_SUCCESS; -} - -/** - * fm10k_glort_valid_pf - Validate that the provided glort is valid - * @hw: pointer to the HW structure - * @glort: base glort to be validated - * - * This function will return an error if the provided glort is invalid - **/ -bool fm10k_glort_valid_pf(struct fm10k_hw *hw, u16 glort) -{ - glort &= hw->mac.dglort_map >> FM10K_DGLORTMAP_MASK_SHIFT; - - return glort == (hw->mac.dglort_map & FM10K_DGLORTMAP_NONE); -} - -/** - * fm10k_update_xc_addr_pf - Update device addresses - * @hw: pointer to the HW structure - * @glort: base resource tag for this request - * @mac: MAC address to add/remove from table - * @vid: VLAN ID to add/remove from table - * @add: Indicates if this is an add or remove operation - * @flags: flags field to indicate add and secure - * - * This function generates a message to the Switch API requesting - * that the given logical port add/remove the given L2 MAC/VLAN address. - **/ -STATIC s32 fm10k_update_xc_addr_pf(struct fm10k_hw *hw, u16 glort, - const u8 *mac, u16 vid, bool add, u8 flags) -{ - struct fm10k_mbx_info *mbx = &hw->mbx; - struct fm10k_mac_update mac_update; - u32 msg[5]; - - DEBUGFUNC("fm10k_update_xc_addr_pf"); - - /* if glort or VLAN are not valid return error */ - if (!fm10k_glort_valid_pf(hw, glort) || vid >= FM10K_VLAN_TABLE_VID_MAX) - return FM10K_ERR_PARAM; - - /* record fields */ - mac_update.mac_lower = FM10K_CPU_TO_LE32(((u32)mac[2] << 24) | - ((u32)mac[3] << 16) | - ((u32)mac[4] << 8) | - ((u32)mac[5])); - mac_update.mac_upper = FM10K_CPU_TO_LE16(((u32)mac[0] << 8) | - ((u32)mac[1])); - mac_update.vlan = FM10K_CPU_TO_LE16(vid); - mac_update.glort = FM10K_CPU_TO_LE16(glort); - mac_update.action = add ? 0 : 1; - mac_update.flags = flags; - - /* populate mac_update fields */ - fm10k_tlv_msg_init(msg, FM10K_PF_MSG_ID_UPDATE_MAC_FWD_RULE); - fm10k_tlv_attr_put_le_struct(msg, FM10K_PF_ATTR_ID_MAC_UPDATE, - &mac_update, sizeof(mac_update)); - - /* load onto outgoing mailbox */ - return mbx->ops.enqueue_tx(hw, mbx, msg); -} - -/** - * fm10k_update_uc_addr_pf - Update device unicast addresses - * @hw: pointer to the HW structure - * @glort: base resource tag for this request - * @mac: MAC address to add/remove from table - * @vid: VLAN ID to add/remove from table - * @add: Indicates if this is an add or remove operation - * @flags: flags field to indicate add and secure - * - * This function is used to add or remove unicast addresses for - * the PF. - **/ -STATIC s32 fm10k_update_uc_addr_pf(struct fm10k_hw *hw, u16 glort, - const u8 *mac, u16 vid, bool add, u8 flags) -{ - DEBUGFUNC("fm10k_update_uc_addr_pf"); - - /* verify MAC address is valid */ - if (!FM10K_IS_VALID_ETHER_ADDR(mac)) - return FM10K_ERR_PARAM; - - return fm10k_update_xc_addr_pf(hw, glort, mac, vid, add, flags); -} - -/** - * fm10k_update_mc_addr_pf - Update device multicast addresses - * @hw: pointer to the HW structure - * @glort: base resource tag for this request - * @mac: MAC address to add/remove from table - * @vid: VLAN ID to add/remove from table - * @add: Indicates if this is an add or remove operation - * - * This function is used to add or remove multicast MAC addresses for - * the PF. - **/ -STATIC s32 fm10k_update_mc_addr_pf(struct fm10k_hw *hw, u16 glort, - const u8 *mac, u16 vid, bool add) -{ - DEBUGFUNC("fm10k_update_mc_addr_pf"); - - /* verify multicast address is valid */ - if (!FM10K_IS_MULTICAST_ETHER_ADDR(mac)) - return FM10K_ERR_PARAM; - - return fm10k_update_xc_addr_pf(hw, glort, mac, vid, add, 0); -} - -/** - * fm10k_update_xcast_mode_pf - Request update of multicast mode - * @hw: pointer to hardware structure - * @glort: base resource tag for this request - * @mode: integer value indicating mode being requested - * - * This function will attempt to request a higher mode for the port - * so that it can enable either multicast, multicast promiscuous, or - * promiscuous mode of operation. - **/ -STATIC s32 fm10k_update_xcast_mode_pf(struct fm10k_hw *hw, u16 glort, u8 mode) -{ - struct fm10k_mbx_info *mbx = &hw->mbx; - u32 msg[3], xcast_mode; - - DEBUGFUNC("fm10k_update_xcast_mode_pf"); - - if (mode > FM10K_XCAST_MODE_NONE) - return FM10K_ERR_PARAM; - - /* if glort is not valid return error */ - if (!fm10k_glort_valid_pf(hw, glort)) - return FM10K_ERR_PARAM; - - /* write xcast mode as a single u32 value, - * lower 16 bits: glort - * upper 16 bits: mode - */ - xcast_mode = ((u32)mode << 16) | glort; - - /* generate message requesting to change xcast mode */ - fm10k_tlv_msg_init(msg, FM10K_PF_MSG_ID_XCAST_MODES); - fm10k_tlv_attr_put_u32(msg, FM10K_PF_ATTR_ID_XCAST_MODE, xcast_mode); - - /* load onto outgoing mailbox */ - return mbx->ops.enqueue_tx(hw, mbx, msg); -} - -/** - * fm10k_update_int_moderator_pf - Update interrupt moderator linked list - * @hw: pointer to hardware structure - * - * This function walks through the MSI-X vector table to determine the - * number of active interrupts and based on that information updates the - * interrupt moderator linked list. - **/ -STATIC void fm10k_update_int_moderator_pf(struct fm10k_hw *hw) -{ - u32 i; - - /* Disable interrupt moderator */ - FM10K_WRITE_REG(hw, FM10K_INT_CTRL, 0); - - /* loop through PF from last to first looking enabled vectors */ - for (i = FM10K_ITR_REG_COUNT_PF - 1; i; i--) { - if (!FM10K_READ_REG(hw, FM10K_MSIX_VECTOR_MASK(i))) - break; - } - - /* always reset VFITR2[0] to point to last enabled PF vector */ - FM10K_WRITE_REG(hw, FM10K_ITR2(FM10K_ITR_REG_COUNT_PF), i); - - /* reset ITR2[0] to point to last enabled PF vector */ - if (!hw->iov.num_vfs) - FM10K_WRITE_REG(hw, FM10K_ITR2(0), i); - - /* Enable interrupt moderator */ - FM10K_WRITE_REG(hw, FM10K_INT_CTRL, FM10K_INT_CTRL_ENABLEMODERATOR); -} - -/** - * fm10k_update_lport_state_pf - Notify the switch of a change in port state - * @hw: pointer to the HW structure - * @glort: base resource tag for this request - * @count: number of logical ports being updated - * @enable: boolean value indicating enable or disable - * - * This function is used to add/remove a logical port from the switch. - **/ -STATIC s32 fm10k_update_lport_state_pf(struct fm10k_hw *hw, u16 glort, - u16 count, bool enable) -{ - struct fm10k_mbx_info *mbx = &hw->mbx; - u32 msg[3], lport_msg; - - DEBUGFUNC("fm10k_lport_state_pf"); - - /* do nothing if we are being asked to create or destroy 0 ports */ - if (!count) - return FM10K_SUCCESS; - - /* if glort is not valid return error */ - if (!fm10k_glort_valid_pf(hw, glort)) - return FM10K_ERR_PARAM; - - /* construct the lport message from the 2 pieces of data we have */ - lport_msg = ((u32)count << 16) | glort; - - /* generate lport create/delete message */ - fm10k_tlv_msg_init(msg, enable ? FM10K_PF_MSG_ID_LPORT_CREATE : - FM10K_PF_MSG_ID_LPORT_DELETE); - fm10k_tlv_attr_put_u32(msg, FM10K_PF_ATTR_ID_PORT, lport_msg); - - /* load onto outgoing mailbox */ - return mbx->ops.enqueue_tx(hw, mbx, msg); -} - -/** - * fm10k_configure_dglort_map_pf - Configures GLORT entry and queues - * @hw: pointer to hardware structure - * @dglort: pointer to dglort configuration structure - * - * Reads the configuration structure contained in dglort_cfg and uses - * that information to then populate a DGLORTMAP/DEC entry and the queues - * to which it has been assigned. - **/ -STATIC s32 fm10k_configure_dglort_map_pf(struct fm10k_hw *hw, - struct fm10k_dglort_cfg *dglort) -{ - u16 glort, queue_count, vsi_count, pc_count; - u16 vsi, queue, pc, q_idx; - u32 txqctl, dglortdec, dglortmap; - - /* verify the dglort pointer */ - if (!dglort) - return FM10K_ERR_PARAM; - - /* verify the dglort values */ - if ((dglort->idx > 7) || (dglort->rss_l > 7) || (dglort->pc_l > 3) || - (dglort->vsi_l > 6) || (dglort->vsi_b > 64) || - (dglort->queue_l > 8) || (dglort->queue_b >= 256)) - return FM10K_ERR_PARAM; - - /* determine count of VSIs and queues */ - queue_count = 1 << (dglort->rss_l + dglort->pc_l); - vsi_count = 1 << (dglort->vsi_l + dglort->queue_l); - glort = dglort->glort; - q_idx = dglort->queue_b; - - /* configure SGLORT for queues */ - for (vsi = 0; vsi < vsi_count; vsi++, glort++) { - for (queue = 0; queue < queue_count; queue++, q_idx++) { - if (q_idx >= FM10K_MAX_QUEUES) - break; - - FM10K_WRITE_REG(hw, FM10K_TX_SGLORT(q_idx), glort); - FM10K_WRITE_REG(hw, FM10K_RX_SGLORT(q_idx), glort); - } - } - - /* determine count of PCs and queues */ - queue_count = 1 << (dglort->queue_l + dglort->rss_l + dglort->vsi_l); - pc_count = 1 << dglort->pc_l; - - /* configure PC for Tx queues */ - for (pc = 0; pc < pc_count; pc++) { - q_idx = pc + dglort->queue_b; - for (queue = 0; queue < queue_count; queue++) { - if (q_idx >= FM10K_MAX_QUEUES) - break; - - txqctl = FM10K_READ_REG(hw, FM10K_TXQCTL(q_idx)); - txqctl &= ~FM10K_TXQCTL_PC_MASK; - txqctl |= pc << FM10K_TXQCTL_PC_SHIFT; - FM10K_WRITE_REG(hw, FM10K_TXQCTL(q_idx), txqctl); - - q_idx += pc_count; - } - } - - /* configure DGLORTDEC */ - dglortdec = ((u32)(dglort->rss_l) << FM10K_DGLORTDEC_RSSLENGTH_SHIFT) | - ((u32)(dglort->queue_b) << FM10K_DGLORTDEC_QBASE_SHIFT) | - ((u32)(dglort->pc_l) << FM10K_DGLORTDEC_PCLENGTH_SHIFT) | - ((u32)(dglort->vsi_b) << FM10K_DGLORTDEC_VSIBASE_SHIFT) | - ((u32)(dglort->vsi_l) << FM10K_DGLORTDEC_VSILENGTH_SHIFT) | - ((u32)(dglort->queue_l)); - if (dglort->inner_rss) - dglortdec |= FM10K_DGLORTDEC_INNERRSS_ENABLE; - - /* configure DGLORTMAP */ - dglortmap = (dglort->idx == fm10k_dglort_default) ? - FM10K_DGLORTMAP_ANY : FM10K_DGLORTMAP_ZERO; - dglortmap <<= dglort->vsi_l + dglort->queue_l + dglort->shared_l; - dglortmap |= dglort->glort; - - /* write values to hardware */ - FM10K_WRITE_REG(hw, FM10K_DGLORTDEC(dglort->idx), dglortdec); - FM10K_WRITE_REG(hw, FM10K_DGLORTMAP(dglort->idx), dglortmap); - - return FM10K_SUCCESS; -} - -u16 fm10k_queues_per_pool(struct fm10k_hw *hw) -{ - u16 num_pools = hw->iov.num_pools; - - return (num_pools > 32) ? 2 : (num_pools > 16) ? 4 : (num_pools > 8) ? - 8 : FM10K_MAX_QUEUES_POOL; -} - -u16 fm10k_vf_queue_index(struct fm10k_hw *hw, u16 vf_idx) -{ - u16 num_vfs = hw->iov.num_vfs; - u16 vf_q_idx = FM10K_MAX_QUEUES; - - vf_q_idx -= fm10k_queues_per_pool(hw) * (num_vfs - vf_idx); - - return vf_q_idx; -} - -STATIC u16 fm10k_vectors_per_pool(struct fm10k_hw *hw) -{ - u16 num_pools = hw->iov.num_pools; - - return (num_pools > 32) ? 8 : (num_pools > 16) ? 16 : - FM10K_MAX_VECTORS_POOL; -} - -STATIC u16 fm10k_vf_vector_index(struct fm10k_hw *hw, u16 vf_idx) -{ - u16 vf_v_idx = FM10K_MAX_VECTORS_PF; - - vf_v_idx += fm10k_vectors_per_pool(hw) * vf_idx; - - return vf_v_idx; -} - -/** - * fm10k_iov_assign_resources_pf - Assign pool resources for virtualization - * @hw: pointer to the HW structure - * @num_vfs: number of VFs to be allocated - * @num_pools: number of virtualization pools to be allocated - * - * Allocates queues and traffic classes to virtualization entities to prepare - * the PF for SR-IOV and VMDq - **/ -STATIC s32 fm10k_iov_assign_resources_pf(struct fm10k_hw *hw, u16 num_vfs, - u16 num_pools) -{ - u16 qmap_stride, qpp, vpp, vf_q_idx, vf_q_idx0, qmap_idx; - u32 vid = hw->mac.default_vid << FM10K_TXQCTL_VID_SHIFT; - int i, j; - - /* hardware only supports up to 64 pools */ - if (num_pools > 64) - return FM10K_ERR_PARAM; - - /* the number of VFs cannot exceed the number of pools */ - if ((num_vfs > num_pools) || (num_vfs > hw->iov.total_vfs)) - return FM10K_ERR_PARAM; - - /* record number of virtualization entities */ - hw->iov.num_vfs = num_vfs; - hw->iov.num_pools = num_pools; - - /* determine qmap offsets and counts */ - qmap_stride = (num_vfs > 8) ? 32 : 256; - qpp = fm10k_queues_per_pool(hw); - vpp = fm10k_vectors_per_pool(hw); - - /* calculate starting index for queues */ - vf_q_idx = fm10k_vf_queue_index(hw, 0); - qmap_idx = 0; - - /* establish TCs with -1 credits and no quanta to prevent transmit */ - for (i = 0; i < num_vfs; i++) { - FM10K_WRITE_REG(hw, FM10K_TC_MAXCREDIT(i), 0); - FM10K_WRITE_REG(hw, FM10K_TC_RATE(i), 0); - FM10K_WRITE_REG(hw, FM10K_TC_CREDIT(i), - FM10K_TC_CREDIT_CREDIT_MASK); - } - - /* zero out all mbmem registers */ - for (i = FM10K_VFMBMEM_LEN * num_vfs; i--;) - FM10K_WRITE_REG(hw, FM10K_MBMEM(i), 0); - - /* clear event notification of VF FLR */ - FM10K_WRITE_REG(hw, FM10K_PFVFLREC(0), ~0); - FM10K_WRITE_REG(hw, FM10K_PFVFLREC(1), ~0); - - /* loop through unallocated rings assigning them back to PF */ - for (i = FM10K_MAX_QUEUES_PF; i < vf_q_idx; i++) { - FM10K_WRITE_REG(hw, FM10K_TXDCTL(i), 0); - FM10K_WRITE_REG(hw, FM10K_TXQCTL(i), FM10K_TXQCTL_PF | vid); - FM10K_WRITE_REG(hw, FM10K_RXQCTL(i), FM10K_RXQCTL_PF); - } - - /* PF should have already updated VFITR2[0] */ - - /* update all ITR registers to flow to VFITR2[0] */ - for (i = FM10K_ITR_REG_COUNT_PF + 1; i < FM10K_ITR_REG_COUNT; i++) { - if (!(i & (vpp - 1))) - FM10K_WRITE_REG(hw, FM10K_ITR2(i), i - vpp); - else - FM10K_WRITE_REG(hw, FM10K_ITR2(i), i - 1); - } - - /* update PF ITR2[0] to reference the last vector */ - FM10K_WRITE_REG(hw, FM10K_ITR2(0), - fm10k_vf_vector_index(hw, num_vfs - 1)); - - /* loop through rings populating rings and TCs */ - for (i = 0; i < num_vfs; i++) { - /* record index for VF queue 0 for use in end of loop */ - vf_q_idx0 = vf_q_idx; - - for (j = 0; j < qpp; j++, qmap_idx++, vf_q_idx++) { - /* assign VF and locked TC to queues */ - FM10K_WRITE_REG(hw, FM10K_TXDCTL(vf_q_idx), 0); - FM10K_WRITE_REG(hw, FM10K_TXQCTL(vf_q_idx), - (i << FM10K_TXQCTL_TC_SHIFT) | i | - FM10K_TXQCTL_VF | vid); - FM10K_WRITE_REG(hw, FM10K_RXDCTL(vf_q_idx), - FM10K_RXDCTL_WRITE_BACK_MIN_DELAY | - FM10K_RXDCTL_DROP_ON_EMPTY); - FM10K_WRITE_REG(hw, FM10K_RXQCTL(vf_q_idx), - FM10K_RXQCTL_VF | - (i << FM10K_RXQCTL_VF_SHIFT)); - - /* map queue pair to VF */ - FM10K_WRITE_REG(hw, FM10K_TQMAP(qmap_idx), vf_q_idx); - FM10K_WRITE_REG(hw, FM10K_RQMAP(qmap_idx), vf_q_idx); - } - - /* repeat the first ring for all of the remaining VF rings */ - for (; j < qmap_stride; j++, qmap_idx++) { - FM10K_WRITE_REG(hw, FM10K_TQMAP(qmap_idx), vf_q_idx0); - FM10K_WRITE_REG(hw, FM10K_RQMAP(qmap_idx), vf_q_idx0); - } - } - - /* loop through remaining indexes assigning all to queue 0 */ - while (qmap_idx < FM10K_TQMAP_TABLE_SIZE) { - FM10K_WRITE_REG(hw, FM10K_TQMAP(qmap_idx), 0); - FM10K_WRITE_REG(hw, FM10K_RQMAP(qmap_idx), 0); - qmap_idx++; - } - - return FM10K_SUCCESS; -} - -/** - * fm10k_iov_configure_tc_pf - Configure the shaping group for VF - * @hw: pointer to the HW structure - * @vf_idx: index of VF receiving GLORT - * @rate: Rate indicated in Mb/s - * - * Configured the TC for a given VF to allow only up to a given number - * of Mb/s of outgoing Tx throughput. - **/ -STATIC s32 fm10k_iov_configure_tc_pf(struct fm10k_hw *hw, u16 vf_idx, int rate) -{ - /* configure defaults */ - u32 interval = FM10K_TC_RATE_INTERVAL_4US_GEN3; - u32 tc_rate = FM10K_TC_RATE_QUANTA_MASK; - - /* verify vf is in range */ - if (vf_idx >= hw->iov.num_vfs) - return FM10K_ERR_PARAM; - - /* set interval to align with 4.096 usec in all modes */ - switch (hw->bus.speed) { - case fm10k_bus_speed_2500: - interval = FM10K_TC_RATE_INTERVAL_4US_GEN1; - break; - case fm10k_bus_speed_5000: - interval = FM10K_TC_RATE_INTERVAL_4US_GEN2; - break; - default: - break; - } - - if (rate) { - if (rate > FM10K_VF_TC_MAX || rate < FM10K_VF_TC_MIN) - return FM10K_ERR_PARAM; - - /* The quanta is measured in Bytes per 4.096 or 8.192 usec - * The rate is provided in Mbits per second - * To tralslate from rate to quanta we need to multiply the - * rate by 8.192 usec and divide by 8 bits/byte. To avoid - * dealing with floating point we can round the values up - * to the nearest whole number ratio which gives us 128 / 125. - */ - tc_rate = (rate * 128) / 125; - - /* try to keep the rate limiting accurate by increasing - * the number of credits and interval for rates less than 4Gb/s - */ - if (rate < 4000) - interval <<= 1; - else - tc_rate >>= 1; - } - - /* update rate limiter with new values */ - FM10K_WRITE_REG(hw, FM10K_TC_RATE(vf_idx), tc_rate | interval); - FM10K_WRITE_REG(hw, FM10K_TC_MAXCREDIT(vf_idx), FM10K_TC_MAXCREDIT_64K); - FM10K_WRITE_REG(hw, FM10K_TC_CREDIT(vf_idx), FM10K_TC_MAXCREDIT_64K); - - return FM10K_SUCCESS; -} - -/** - * fm10k_iov_assign_int_moderator_pf - Add VF interrupts to moderator list - * @hw: pointer to the HW structure - * @vf_idx: index of VF receiving GLORT - * - * Update the interrupt moderator linked list to include any MSI-X - * interrupts which the VF has enabled in the MSI-X vector table. - **/ -STATIC s32 fm10k_iov_assign_int_moderator_pf(struct fm10k_hw *hw, u16 vf_idx) -{ - u16 vf_v_idx, vf_v_limit, i; - - /* verify vf is in range */ - if (vf_idx >= hw->iov.num_vfs) - return FM10K_ERR_PARAM; - - /* determine vector offset and count */ - vf_v_idx = fm10k_vf_vector_index(hw, vf_idx); - vf_v_limit = vf_v_idx + fm10k_vectors_per_pool(hw); - - /* search for first vector that is not masked */ - for (i = vf_v_limit - 1; i > vf_v_idx; i--) { - if (!FM10K_READ_REG(hw, FM10K_MSIX_VECTOR_MASK(i))) - break; - } - - /* reset linked list so it now includes our active vectors */ - if (vf_idx == (hw->iov.num_vfs - 1)) - FM10K_WRITE_REG(hw, FM10K_ITR2(0), i); - else - FM10K_WRITE_REG(hw, FM10K_ITR2(vf_v_limit), i); - - return FM10K_SUCCESS; -} - -/** - * fm10k_iov_assign_default_mac_vlan_pf - Assign a MAC and VLAN to VF - * @hw: pointer to the HW structure - * @vf_info: pointer to VF information structure - * - * Assign a MAC address and default VLAN to a VF and notify it of the update - **/ -STATIC s32 fm10k_iov_assign_default_mac_vlan_pf(struct fm10k_hw *hw, - struct fm10k_vf_info *vf_info) -{ - u16 qmap_stride, queues_per_pool, vf_q_idx, timeout, qmap_idx, i; - u32 msg[4], txdctl, txqctl, tdbal = 0, tdbah = 0; - s32 err = FM10K_SUCCESS; - u16 vf_idx, vf_vid; - - /* verify vf is in range */ - if (!vf_info || vf_info->vf_idx >= hw->iov.num_vfs) - return FM10K_ERR_PARAM; - - /* determine qmap offsets and counts */ - qmap_stride = (hw->iov.num_vfs > 8) ? 32 : 256; - queues_per_pool = fm10k_queues_per_pool(hw); - - /* calculate starting index for queues */ - vf_idx = vf_info->vf_idx; - vf_q_idx = fm10k_vf_queue_index(hw, vf_idx); - qmap_idx = qmap_stride * vf_idx; - - /* MAP Tx queue back to 0 temporarily, and disable it */ - FM10K_WRITE_REG(hw, FM10K_TQMAP(qmap_idx), 0); - FM10K_WRITE_REG(hw, FM10K_TXDCTL(vf_q_idx), 0); - - /* determine correct default VLAN ID */ - if (vf_info->pf_vid) - vf_vid = vf_info->pf_vid | FM10K_VLAN_CLEAR; - else - vf_vid = vf_info->sw_vid; - - /* generate MAC_ADDR request */ - fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN); - fm10k_tlv_attr_put_mac_vlan(msg, FM10K_MAC_VLAN_MSG_DEFAULT_MAC, - vf_info->mac, vf_vid); - - /* load onto outgoing mailbox, ignore any errors on enqueue */ - if (vf_info->mbx.ops.enqueue_tx) - vf_info->mbx.ops.enqueue_tx(hw, &vf_info->mbx, msg); - - /* verify ring has disabled before modifying base address registers */ - txdctl = FM10K_READ_REG(hw, FM10K_TXDCTL(vf_q_idx)); - for (timeout = 0; txdctl & FM10K_TXDCTL_ENABLE; timeout++) { - /* limit ourselves to a 1ms timeout */ - if (timeout == 10) { - err = FM10K_ERR_DMA_PENDING; - goto err_out; - } - - usec_delay(100); - txdctl = FM10K_READ_REG(hw, FM10K_TXDCTL(vf_q_idx)); - } - - /* Update base address registers to contain MAC address */ - if (FM10K_IS_VALID_ETHER_ADDR(vf_info->mac)) { - tdbal = (((u32)vf_info->mac[3]) << 24) | - (((u32)vf_info->mac[4]) << 16) | - (((u32)vf_info->mac[5]) << 8); - - tdbah = (((u32)0xFF) << 24) | - (((u32)vf_info->mac[0]) << 16) | - (((u32)vf_info->mac[1]) << 8) | - ((u32)vf_info->mac[2]); - } - - /* Record the base address into queue 0 */ - FM10K_WRITE_REG(hw, FM10K_TDBAL(vf_q_idx), tdbal); - FM10K_WRITE_REG(hw, FM10K_TDBAH(vf_q_idx), tdbah); - -err_out: - /* configure Queue control register */ - txqctl = ((u32)vf_vid << FM10K_TXQCTL_VID_SHIFT) & - FM10K_TXQCTL_VID_MASK; - txqctl |= (vf_idx << FM10K_TXQCTL_TC_SHIFT) | - FM10K_TXQCTL_VF | vf_idx; - - /* assign VID */ - for (i = 0; i < queues_per_pool; i++) - FM10K_WRITE_REG(hw, FM10K_TXQCTL(vf_q_idx + i), txqctl); - - /* restore the queue back to VF ownership */ - FM10K_WRITE_REG(hw, FM10K_TQMAP(qmap_idx), vf_q_idx); - return err; -} - -/** - * fm10k_iov_reset_resources_pf - Reassign queues and interrupts to a VF - * @hw: pointer to the HW structure - * @vf_info: pointer to VF information structure - * - * Reassign the interrupts and queues to a VF following an FLR - **/ -STATIC s32 fm10k_iov_reset_resources_pf(struct fm10k_hw *hw, - struct fm10k_vf_info *vf_info) -{ - u16 qmap_stride, queues_per_pool, vf_q_idx, qmap_idx; - u32 tdbal = 0, tdbah = 0, txqctl, rxqctl; - u16 vf_v_idx, vf_v_limit, vf_vid; - u8 vf_idx = vf_info->vf_idx; - int i; - - /* verify vf is in range */ - if (vf_idx >= hw->iov.num_vfs) - return FM10K_ERR_PARAM; - - /* clear event notification of VF FLR */ - FM10K_WRITE_REG(hw, FM10K_PFVFLREC(vf_idx / 32), 1 << (vf_idx % 32)); - - /* force timeout and then disconnect the mailbox */ - vf_info->mbx.timeout = 0; - if (vf_info->mbx.ops.disconnect) - vf_info->mbx.ops.disconnect(hw, &vf_info->mbx); - - /* determine vector offset and count */ - vf_v_idx = fm10k_vf_vector_index(hw, vf_idx); - vf_v_limit = vf_v_idx + fm10k_vectors_per_pool(hw); - - /* determine qmap offsets and counts */ - qmap_stride = (hw->iov.num_vfs > 8) ? 32 : 256; - queues_per_pool = fm10k_queues_per_pool(hw); - qmap_idx = qmap_stride * vf_idx; - - /* make all the queues inaccessible to the VF */ - for (i = qmap_idx; i < (qmap_idx + qmap_stride); i++) { - FM10K_WRITE_REG(hw, FM10K_TQMAP(i), 0); - FM10K_WRITE_REG(hw, FM10K_RQMAP(i), 0); - } - - /* calculate starting index for queues */ - vf_q_idx = fm10k_vf_queue_index(hw, vf_idx); - - /* determine correct default VLAN ID */ - if (vf_info->pf_vid) - vf_vid = vf_info->pf_vid; - else - vf_vid = vf_info->sw_vid; - - /* configure Queue control register */ - txqctl = ((u32)vf_vid << FM10K_TXQCTL_VID_SHIFT) | - (vf_idx << FM10K_TXQCTL_TC_SHIFT) | - FM10K_TXQCTL_VF | vf_idx; - rxqctl = FM10K_RXQCTL_VF | (vf_idx << FM10K_RXQCTL_VF_SHIFT); - - /* stop further DMA and reset queue ownership back to VF */ - for (i = vf_q_idx; i < (queues_per_pool + vf_q_idx); i++) { - FM10K_WRITE_REG(hw, FM10K_TXDCTL(i), 0); - FM10K_WRITE_REG(hw, FM10K_TXQCTL(i), txqctl); - FM10K_WRITE_REG(hw, FM10K_RXDCTL(i), - FM10K_RXDCTL_WRITE_BACK_MIN_DELAY | - FM10K_RXDCTL_DROP_ON_EMPTY); - FM10K_WRITE_REG(hw, FM10K_RXQCTL(i), rxqctl); - } - - /* reset TC with -1 credits and no quanta to prevent transmit */ - FM10K_WRITE_REG(hw, FM10K_TC_MAXCREDIT(vf_idx), 0); - FM10K_WRITE_REG(hw, FM10K_TC_RATE(vf_idx), 0); - FM10K_WRITE_REG(hw, FM10K_TC_CREDIT(vf_idx), - FM10K_TC_CREDIT_CREDIT_MASK); - - /* update our first entry in the table based on previous VF */ - if (!vf_idx) - hw->mac.ops.update_int_moderator(hw); - else - hw->iov.ops.assign_int_moderator(hw, vf_idx - 1); - - /* reset linked list so it now includes our active vectors */ - if (vf_idx == (hw->iov.num_vfs - 1)) - FM10K_WRITE_REG(hw, FM10K_ITR2(0), vf_v_idx); - else - FM10K_WRITE_REG(hw, FM10K_ITR2(vf_v_limit), vf_v_idx); - - /* link remaining vectors so that next points to previous */ - for (vf_v_idx++; vf_v_idx < vf_v_limit; vf_v_idx++) - FM10K_WRITE_REG(hw, FM10K_ITR2(vf_v_idx), vf_v_idx - 1); - - /* zero out MBMEM, VLAN_TABLE, RETA, RSSRK, and MRQC registers */ - for (i = FM10K_VFMBMEM_LEN; i--;) - FM10K_WRITE_REG(hw, FM10K_MBMEM_VF(vf_idx, i), 0); - for (i = FM10K_VLAN_TABLE_SIZE; i--;) - FM10K_WRITE_REG(hw, FM10K_VLAN_TABLE(vf_info->vsi, i), 0); - for (i = FM10K_RETA_SIZE; i--;) - FM10K_WRITE_REG(hw, FM10K_RETA(vf_info->vsi, i), 0); - for (i = FM10K_RSSRK_SIZE; i--;) - FM10K_WRITE_REG(hw, FM10K_RSSRK(vf_info->vsi, i), 0); - FM10K_WRITE_REG(hw, FM10K_MRQC(vf_info->vsi), 0); - - /* Update base address registers to contain MAC address */ - if (FM10K_IS_VALID_ETHER_ADDR(vf_info->mac)) { - tdbal = (((u32)vf_info->mac[3]) << 24) | - (((u32)vf_info->mac[4]) << 16) | - (((u32)vf_info->mac[5]) << 8); - tdbah = (((u32)0xFF) << 24) | - (((u32)vf_info->mac[0]) << 16) | - (((u32)vf_info->mac[1]) << 8) | - ((u32)vf_info->mac[2]); - } - - /* map queue pairs back to VF from last to first */ - for (i = queues_per_pool; i--;) { - FM10K_WRITE_REG(hw, FM10K_TDBAL(vf_q_idx + i), tdbal); - FM10K_WRITE_REG(hw, FM10K_TDBAH(vf_q_idx + i), tdbah); - FM10K_WRITE_REG(hw, FM10K_TQMAP(qmap_idx + i), vf_q_idx + i); - FM10K_WRITE_REG(hw, FM10K_RQMAP(qmap_idx + i), vf_q_idx + i); - } - - return FM10K_SUCCESS; -} - -/** - * fm10k_iov_set_lport_pf - Assign and enable a logical port for a given VF - * @hw: pointer to hardware structure - * @vf_info: pointer to VF information structure - * @lport_idx: Logical port offset from the hardware glort - * @flags: Set of capability flags to extend port beyond basic functionality - * - * This function allows enabling a VF port by assigning it a GLORT and - * setting the flags so that it can enable an Rx mode. - **/ -STATIC s32 fm10k_iov_set_lport_pf(struct fm10k_hw *hw, - struct fm10k_vf_info *vf_info, - u16 lport_idx, u8 flags) -{ - u16 glort = (hw->mac.dglort_map + lport_idx) & FM10K_DGLORTMAP_NONE; - - DEBUGFUNC("fm10k_iov_set_lport_state_pf"); - - /* if glort is not valid return error */ - if (!fm10k_glort_valid_pf(hw, glort)) - return FM10K_ERR_PARAM; - - vf_info->vf_flags = flags | FM10K_VF_FLAG_NONE_CAPABLE; - vf_info->glort = glort; - - return FM10K_SUCCESS; -} - -/** - * fm10k_iov_reset_lport_pf - Disable a logical port for a given VF - * @hw: pointer to hardware structure - * @vf_info: pointer to VF information structure - * - * This function disables a VF port by stripping it of a GLORT and - * setting the flags so that it cannot enable any Rx mode. - **/ -STATIC void fm10k_iov_reset_lport_pf(struct fm10k_hw *hw, - struct fm10k_vf_info *vf_info) -{ - u32 msg[1]; - - DEBUGFUNC("fm10k_iov_reset_lport_state_pf"); - - /* need to disable the port if it is already enabled */ - if (FM10K_VF_FLAG_ENABLED(vf_info)) { - /* notify switch that this port has been disabled */ - fm10k_update_lport_state_pf(hw, vf_info->glort, 1, false); - - /* generate port state response to notify VF it is not ready */ - fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE); - vf_info->mbx.ops.enqueue_tx(hw, &vf_info->mbx, msg); - } - - /* clear flags and glort if it exists */ - vf_info->vf_flags = 0; - vf_info->glort = 0; -} - -/** - * fm10k_iov_update_stats_pf - Updates hardware related statistics for VFs - * @hw: pointer to hardware structure - * @q: stats for all queues of a VF - * @vf_idx: index of VF - * - * This function collects queue stats for VFs. - **/ -STATIC void fm10k_iov_update_stats_pf(struct fm10k_hw *hw, - struct fm10k_hw_stats_q *q, - u16 vf_idx) -{ - u32 idx, qpp; - - /* get stats for all of the queues */ - qpp = fm10k_queues_per_pool(hw); - idx = fm10k_vf_queue_index(hw, vf_idx); - fm10k_update_hw_stats_q(hw, q, idx, qpp); -} - -STATIC s32 fm10k_iov_report_timestamp_pf(struct fm10k_hw *hw, - struct fm10k_vf_info *vf_info, - u64 timestamp) -{ - u32 msg[4]; - - /* generate port state response to notify VF it is not ready */ - fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_1588); - fm10k_tlv_attr_put_u64(msg, FM10K_1588_MSG_TIMESTAMP, timestamp); - - return vf_info->mbx.ops.enqueue_tx(hw, &vf_info->mbx, msg); -} - -/** - * fm10k_iov_msg_msix_pf - Message handler for MSI-X request from VF - * @hw: Pointer to hardware structure - * @results: Pointer array to message, results[0] is pointer to message - * @mbx: Pointer to mailbox information structure - * - * This function is a default handler for MSI-X requests from the VF. The - * assumption is that in this case it is acceptable to just directly - * hand off the message from the VF to the underlying shared code. - **/ -s32 fm10k_iov_msg_msix_pf(struct fm10k_hw *hw, u32 **results, - struct fm10k_mbx_info *mbx) -{ - struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx; - u8 vf_idx = vf_info->vf_idx; - - UNREFERENCED_1PARAMETER(results); - DEBUGFUNC("fm10k_iov_msg_msix_pf"); - - return hw->iov.ops.assign_int_moderator(hw, vf_idx); -} - -/** - * fm10k_iov_msg_mac_vlan_pf - Message handler for MAC/VLAN request from VF - * @hw: Pointer to hardware structure - * @results: Pointer array to message, results[0] is pointer to message - * @mbx: Pointer to mailbox information structure - * - * This function is a default handler for MAC/VLAN requests from the VF. - * The assumption is that in this case it is acceptable to just directly - * hand off the message from the VF to the underlying shared code. - **/ -s32 fm10k_iov_msg_mac_vlan_pf(struct fm10k_hw *hw, u32 **results, - struct fm10k_mbx_info *mbx) -{ - struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx; - int err = FM10K_SUCCESS; - u8 mac[ETH_ALEN]; - u32 *result; - u16 vlan; - u32 vid; - - DEBUGFUNC("fm10k_iov_msg_mac_vlan_pf"); - - /* we shouldn't be updating rules on a disabled interface */ - if (!FM10K_VF_FLAG_ENABLED(vf_info)) - err = FM10K_ERR_PARAM; - - if (!err && !!results[FM10K_MAC_VLAN_MSG_VLAN]) { - result = results[FM10K_MAC_VLAN_MSG_VLAN]; - - /* record VLAN id requested */ - err = fm10k_tlv_attr_get_u32(result, &vid); - if (err) - return err; - - /* if VLAN ID is 0, set the default VLAN ID instead of 0 */ - if (!vid || (vid == FM10K_VLAN_CLEAR)) { - if (vf_info->pf_vid) - vid |= vf_info->pf_vid; - else - vid |= vf_info->sw_vid; - } else if (vid != vf_info->pf_vid) { - return FM10K_ERR_PARAM; - } - - /* update VSI info for VF in regards to VLAN table */ - err = hw->mac.ops.update_vlan(hw, vid, vf_info->vsi, - !(vid & FM10K_VLAN_CLEAR)); - } - - if (!err && !!results[FM10K_MAC_VLAN_MSG_MAC]) { - result = results[FM10K_MAC_VLAN_MSG_MAC]; - - /* record unicast MAC address requested */ - err = fm10k_tlv_attr_get_mac_vlan(result, mac, &vlan); - if (err) - return err; - - /* block attempts to set MAC for a locked device */ - if (FM10K_IS_VALID_ETHER_ADDR(vf_info->mac) && - memcmp(mac, vf_info->mac, ETH_ALEN)) - return FM10K_ERR_PARAM; - - /* if VLAN ID is 0, set the default VLAN ID instead of 0 */ - if (!vlan || (vlan == FM10K_VLAN_CLEAR)) { - if (vf_info->pf_vid) - vlan |= vf_info->pf_vid; - else - vlan |= vf_info->sw_vid; - } else if (vf_info->pf_vid) { - return FM10K_ERR_PARAM; - } - - /* notify switch of request for new unicast address */ - err = hw->mac.ops.update_uc_addr(hw, vf_info->glort, mac, vlan, - !(vlan & FM10K_VLAN_CLEAR), 0); - } - - if (!err && !!results[FM10K_MAC_VLAN_MSG_MULTICAST]) { - result = results[FM10K_MAC_VLAN_MSG_MULTICAST]; - - /* record multicast MAC address requested */ - err = fm10k_tlv_attr_get_mac_vlan(result, mac, &vlan); - if (err) - return err; - - /* verify that the VF is allowed to request multicast */ - if (!(vf_info->vf_flags & FM10K_VF_FLAG_MULTI_ENABLED)) - return FM10K_ERR_PARAM; - - /* if VLAN ID is 0, set the default VLAN ID instead of 0 */ - if (!vlan || (vlan == FM10K_VLAN_CLEAR)) { - if (vf_info->pf_vid) - vlan |= vf_info->pf_vid; - else - vlan |= vf_info->sw_vid; - } else if (vf_info->pf_vid) { - return FM10K_ERR_PARAM; - } - - /* notify switch of request for new multicast address */ - err = hw->mac.ops.update_mc_addr(hw, vf_info->glort, mac, - !(vlan & FM10K_VLAN_CLEAR), 0); - } - - return err; -} - -/** - * fm10k_iov_supported_xcast_mode_pf - Determine best match for xcast mode - * @vf_info: VF info structure containing capability flags - * @mode: Requested xcast mode - * - * This function outputs the mode that most closely matches the requested - * mode. If not modes match it will request we disable the port - **/ -STATIC u8 fm10k_iov_supported_xcast_mode_pf(struct fm10k_vf_info *vf_info, - u8 mode) -{ - u8 vf_flags = vf_info->vf_flags; - - /* match up mode to capabilities as best as possible */ - switch (mode) { - case FM10K_XCAST_MODE_PROMISC: - if (vf_flags & FM10K_VF_FLAG_PROMISC_CAPABLE) - return FM10K_XCAST_MODE_PROMISC; - /* fallthough */ - case FM10K_XCAST_MODE_ALLMULTI: - if (vf_flags & FM10K_VF_FLAG_ALLMULTI_CAPABLE) - return FM10K_XCAST_MODE_ALLMULTI; - /* fallthough */ - case FM10K_XCAST_MODE_MULTI: - if (vf_flags & FM10K_VF_FLAG_MULTI_CAPABLE) - return FM10K_XCAST_MODE_MULTI; - /* fallthough */ - case FM10K_XCAST_MODE_NONE: - if (vf_flags & FM10K_VF_FLAG_NONE_CAPABLE) - return FM10K_XCAST_MODE_NONE; - /* fallthough */ - default: - break; - } - - /* disable interface as it should not be able to request any */ - return FM10K_XCAST_MODE_DISABLE; -} - -/** - * fm10k_iov_msg_lport_state_pf - Message handler for port state requests - * @hw: Pointer to hardware structure - * @results: Pointer array to message, results[0] is pointer to message - * @mbx: Pointer to mailbox information structure - * - * This function is a default handler for port state requests. The port - * state requests for now are basic and consist of enabling or disabling - * the port. - **/ -s32 fm10k_iov_msg_lport_state_pf(struct fm10k_hw *hw, u32 **results, - struct fm10k_mbx_info *mbx) -{ - struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx; - u32 *result; - s32 err = FM10K_SUCCESS; - u32 msg[2]; - u8 mode = 0; - - DEBUGFUNC("fm10k_iov_msg_lport_state_pf"); - - /* verify VF is allowed to enable even minimal mode */ - if (!(vf_info->vf_flags & FM10K_VF_FLAG_NONE_CAPABLE)) - return FM10K_ERR_PARAM; - - if (!!results[FM10K_LPORT_STATE_MSG_XCAST_MODE]) { - result = results[FM10K_LPORT_STATE_MSG_XCAST_MODE]; - - /* XCAST mode update requested */ - err = fm10k_tlv_attr_get_u8(result, &mode); - if (err) - return FM10K_ERR_PARAM; - - /* prep for possible demotion depending on capabilities */ - mode = fm10k_iov_supported_xcast_mode_pf(vf_info, mode); - - /* if mode is not currently enabled, enable it */ - if (!(FM10K_VF_FLAG_ENABLED(vf_info) & (1 << mode))) - fm10k_update_xcast_mode_pf(hw, vf_info->glort, mode); - - /* swap mode back to a bit flag */ - mode = FM10K_VF_FLAG_SET_MODE(mode); - } else if (!results[FM10K_LPORT_STATE_MSG_DISABLE]) { - /* need to disable the port if it is already enabled */ - if (FM10K_VF_FLAG_ENABLED(vf_info)) - err = fm10k_update_lport_state_pf(hw, vf_info->glort, - 1, false); - - /* when enabling the port we should reset the rate limiters */ - hw->iov.ops.configure_tc(hw, vf_info->vf_idx, vf_info->rate); - - /* set mode for minimal functionality */ - mode = FM10K_VF_FLAG_SET_MODE_NONE; - - /* generate port state response to notify VF it is ready */ - fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE); - fm10k_tlv_attr_put_bool(msg, FM10K_LPORT_STATE_MSG_READY); - mbx->ops.enqueue_tx(hw, mbx, msg); - } - - /* if enable state toggled note the update */ - if (!err && (!FM10K_VF_FLAG_ENABLED(vf_info) != !mode)) - err = fm10k_update_lport_state_pf(hw, vf_info->glort, 1, - !!mode); - - /* if state change succeeded, then update our stored state */ - mode |= FM10K_VF_FLAG_CAPABLE(vf_info); - if (!err) - vf_info->vf_flags = mode; - - return err; -} - -const struct fm10k_msg_data fm10k_iov_msg_data_pf[] = { - FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test), - FM10K_VF_MSG_MSIX_HANDLER(fm10k_iov_msg_msix_pf), - FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_iov_msg_mac_vlan_pf), - FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_iov_msg_lport_state_pf), - FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error), -}; - -/** - * fm10k_update_stats_hw_pf - Updates hardware related statistics of PF - * @hw: pointer to hardware structure - * @stats: pointer to the stats structure to update - * - * This function collects and aggregates global and per queue hardware - * statistics. - **/ -STATIC void fm10k_update_hw_stats_pf(struct fm10k_hw *hw, - struct fm10k_hw_stats *stats) -{ - u32 timeout, ur, ca, um, xec, vlan_drop, loopback_drop, nodesc_drop; - u32 id, id_prev; - - DEBUGFUNC("fm10k_update_hw_stats_pf"); - - /* Use Tx queue 0 as a canary to detect a reset */ - id = FM10K_READ_REG(hw, FM10K_TXQCTL(0)); - - /* Read Global Statistics */ - do { - timeout = fm10k_read_hw_stats_32b(hw, FM10K_STATS_TIMEOUT, - &stats->timeout); - ur = fm10k_read_hw_stats_32b(hw, FM10K_STATS_UR, &stats->ur); - ca = fm10k_read_hw_stats_32b(hw, FM10K_STATS_CA, &stats->ca); - um = fm10k_read_hw_stats_32b(hw, FM10K_STATS_UM, &stats->um); - xec = fm10k_read_hw_stats_32b(hw, FM10K_STATS_XEC, &stats->xec); - vlan_drop = fm10k_read_hw_stats_32b(hw, FM10K_STATS_VLAN_DROP, - &stats->vlan_drop); - loopback_drop = fm10k_read_hw_stats_32b(hw, - FM10K_STATS_LOOPBACK_DROP, - &stats->loopback_drop); - nodesc_drop = fm10k_read_hw_stats_32b(hw, - FM10K_STATS_NODESC_DROP, - &stats->nodesc_drop); - - /* if value has not changed then we have consistent data */ - id_prev = id; - id = FM10K_READ_REG(hw, FM10K_TXQCTL(0)); - } while ((id ^ id_prev) & FM10K_TXQCTL_ID_MASK); - - /* drop non-ID bits and set VALID ID bit */ - id &= FM10K_TXQCTL_ID_MASK; - id |= FM10K_STAT_VALID; - - /* Update Global Statistics */ - if (stats->stats_idx == id) { - stats->timeout.count += timeout; - stats->ur.count += ur; - stats->ca.count += ca; - stats->um.count += um; - stats->xec.count += xec; - stats->vlan_drop.count += vlan_drop; - stats->loopback_drop.count += loopback_drop; - stats->nodesc_drop.count += nodesc_drop; - } - - /* Update bases and record current PF id */ - fm10k_update_hw_base_32b(&stats->timeout, timeout); - fm10k_update_hw_base_32b(&stats->ur, ur); - fm10k_update_hw_base_32b(&stats->ca, ca); - fm10k_update_hw_base_32b(&stats->um, um); - fm10k_update_hw_base_32b(&stats->xec, xec); - fm10k_update_hw_base_32b(&stats->vlan_drop, vlan_drop); - fm10k_update_hw_base_32b(&stats->loopback_drop, loopback_drop); - fm10k_update_hw_base_32b(&stats->nodesc_drop, nodesc_drop); - stats->stats_idx = id; - - /* Update Queue Statistics */ - fm10k_update_hw_stats_q(hw, stats->q, 0, hw->mac.max_queues); -} - -/** - * fm10k_rebind_hw_stats_pf - Resets base for hardware statistics of PF - * @hw: pointer to hardware structure - * @stats: pointer to the stats structure to update - * - * This function resets the base for global and per queue hardware - * statistics. - **/ -STATIC void fm10k_rebind_hw_stats_pf(struct fm10k_hw *hw, - struct fm10k_hw_stats *stats) -{ - DEBUGFUNC("fm10k_rebind_hw_stats_pf"); - - /* Unbind Global Statistics */ - fm10k_unbind_hw_stats_32b(&stats->timeout); - fm10k_unbind_hw_stats_32b(&stats->ur); - fm10k_unbind_hw_stats_32b(&stats->ca); - fm10k_unbind_hw_stats_32b(&stats->um); - fm10k_unbind_hw_stats_32b(&stats->xec); - fm10k_unbind_hw_stats_32b(&stats->vlan_drop); - fm10k_unbind_hw_stats_32b(&stats->loopback_drop); - fm10k_unbind_hw_stats_32b(&stats->nodesc_drop); - - /* Unbind Queue Statistics */ - fm10k_unbind_hw_stats_q(stats->q, 0, hw->mac.max_queues); - - /* Reinitialize bases for all stats */ - fm10k_update_hw_stats_pf(hw, stats); -} - -/** - * fm10k_set_dma_mask_pf - Configures PhyAddrSpace to limit DMA to system - * @hw: pointer to hardware structure - * @dma_mask: 64 bit DMA mask required for platform - * - * This function sets the PHYADDR.PhyAddrSpace bits for the endpoint in order - * to limit the access to memory beyond what is physically in the system. - **/ -STATIC void fm10k_set_dma_mask_pf(struct fm10k_hw *hw, u64 dma_mask) -{ - /* we need to write the upper 32 bits of DMA mask to PhyAddrSpace */ - u32 phyaddr = (u32)(dma_mask >> 32); - - DEBUGFUNC("fm10k_set_dma_mask_pf"); - - FM10K_WRITE_REG(hw, FM10K_PHYADDR, phyaddr); -} - -/** - * fm10k_get_fault_pf - Record a fault in one of the interface units - * @hw: pointer to hardware structure - * @type: pointer to fault type register offset - * @fault: pointer to memory location to record the fault - * - * Record the fault register contents to the fault data structure and - * clear the entry from the register. - * - * Returns ERR_PARAM if invalid register is specified or no error is present. - **/ -STATIC s32 fm10k_get_fault_pf(struct fm10k_hw *hw, int type, - struct fm10k_fault *fault) -{ - u32 func; - - DEBUGFUNC("fm10k_get_fault_pf"); - - /* verify the fault register is in range and is aligned */ - switch (type) { - case FM10K_PCA_FAULT: - case FM10K_THI_FAULT: - case FM10K_FUM_FAULT: - break; - default: - return FM10K_ERR_PARAM; - } - - /* only service faults that are valid */ - func = FM10K_READ_REG(hw, type + FM10K_FAULT_FUNC); - if (!(func & FM10K_FAULT_FUNC_VALID)) - return FM10K_ERR_PARAM; - - /* read remaining fields */ - fault->address = FM10K_READ_REG(hw, type + FM10K_FAULT_ADDR_HI); - fault->address <<= 32; - fault->address = FM10K_READ_REG(hw, type + FM10K_FAULT_ADDR_LO); - fault->specinfo = FM10K_READ_REG(hw, type + FM10K_FAULT_SPECINFO); - - /* clear valid bit to allow for next error */ - FM10K_WRITE_REG(hw, type + FM10K_FAULT_FUNC, FM10K_FAULT_FUNC_VALID); - - /* Record which function triggered the error */ - if (func & FM10K_FAULT_FUNC_PF) - fault->func = 0; - else - fault->func = 1 + ((func & FM10K_FAULT_FUNC_VF_MASK) >> - FM10K_FAULT_FUNC_VF_SHIFT); - - /* record fault type */ - fault->type = func & FM10K_FAULT_FUNC_TYPE_MASK; - - return FM10K_SUCCESS; -} - -/** - * fm10k_request_lport_map_pf - Request LPORT map from the switch API - * @hw: pointer to hardware structure - * - **/ -STATIC s32 fm10k_request_lport_map_pf(struct fm10k_hw *hw) -{ - struct fm10k_mbx_info *mbx = &hw->mbx; - u32 msg[1]; - - DEBUGFUNC("fm10k_request_lport_pf"); - - /* issue request asking for LPORT map */ - fm10k_tlv_msg_init(msg, FM10K_PF_MSG_ID_LPORT_MAP); - - /* load onto outgoing mailbox */ - return mbx->ops.enqueue_tx(hw, mbx, msg); -} - -/** - * fm10k_get_host_state_pf - Returns the state of the switch and mailbox - * @hw: pointer to hardware structure - * @switch_ready: pointer to boolean value that will record switch state - * - * This funciton will check the DMA_CTRL2 register and mailbox in order - * to determine if the switch is ready for the PF to begin requesting - * addresses and mapping traffic to the local interface. - **/ -STATIC s32 fm10k_get_host_state_pf(struct fm10k_hw *hw, bool *switch_ready) -{ - s32 ret_val = FM10K_SUCCESS; - u32 dma_ctrl2; - - DEBUGFUNC("fm10k_get_host_state_pf"); - - /* verify the switch is ready for interaction */ - dma_ctrl2 = FM10K_READ_REG(hw, FM10K_DMA_CTRL2); - if (!(dma_ctrl2 & FM10K_DMA_CTRL2_SWITCH_READY)) - goto out; - - /* retrieve generic host state info */ - ret_val = fm10k_get_host_state_generic(hw, switch_ready); - if (ret_val) - goto out; - - /* interface cannot receive traffic without logical ports */ - if (hw->mac.dglort_map == FM10K_DGLORTMAP_NONE) - ret_val = fm10k_request_lport_map_pf(hw); - -out: - return ret_val; -} - -/* This structure defines the attibutes to be parsed below */ -const struct fm10k_tlv_attr fm10k_lport_map_msg_attr[] = { - FM10K_TLV_ATTR_U32(FM10K_PF_ATTR_ID_LPORT_MAP), - FM10K_TLV_ATTR_LAST -}; - -/** - * fm10k_msg_lport_map_pf - Message handler for lport_map message from SM - * @hw: Pointer to hardware structure - * @results: pointer array containing parsed data - * @mbx: Pointer to mailbox information structure - * - * This handler configures the lport mapping based on the reply from the - * switch API. - **/ -s32 fm10k_msg_lport_map_pf(struct fm10k_hw *hw, u32 **results, - struct fm10k_mbx_info *mbx) -{ - u16 glort, mask; - u32 dglort_map; - s32 err; - - UNREFERENCED_1PARAMETER(mbx); - DEBUGFUNC("fm10k_msg_lport_map_pf"); - - err = fm10k_tlv_attr_get_u32(results[FM10K_PF_ATTR_ID_LPORT_MAP], - &dglort_map); - if (err) - return err; - - /* extract values out of the header */ - glort = FM10K_MSG_HDR_FIELD_GET(dglort_map, LPORT_MAP_GLORT); - mask = FM10K_MSG_HDR_FIELD_GET(dglort_map, LPORT_MAP_MASK); - - /* verify mask is set and none of the masked bits in glort are set */ - if (!mask || (glort & ~mask)) - return FM10K_ERR_PARAM; - - /* verify the mask is contiguous, and that it is 1's followed by 0's */ - if (((~(mask - 1) & mask) + mask) & FM10K_DGLORTMAP_NONE) - return FM10K_ERR_PARAM; - - /* record the glort, mask, and port count */ - hw->mac.dglort_map = dglort_map; - - return FM10K_SUCCESS; -} - -const struct fm10k_tlv_attr fm10k_update_pvid_msg_attr[] = { - FM10K_TLV_ATTR_U32(FM10K_PF_ATTR_ID_UPDATE_PVID), - FM10K_TLV_ATTR_LAST -}; - -/** - * fm10k_msg_update_pvid_pf - Message handler for port VLAN message from SM - * @hw: Pointer to hardware structure - * @results: pointer array containing parsed data - * @mbx: Pointer to mailbox information structure - * - * This handler configures the default VLAN for the PF - **/ -s32 fm10k_msg_update_pvid_pf(struct fm10k_hw *hw, u32 **results, - struct fm10k_mbx_info *mbx) -{ - u16 glort, pvid; - u32 pvid_update; - s32 err; - - UNREFERENCED_1PARAMETER(mbx); - DEBUGFUNC("fm10k_msg_update_pvid_pf"); - - err = fm10k_tlv_attr_get_u32(results[FM10K_PF_ATTR_ID_UPDATE_PVID], - &pvid_update); - if (err) - return err; - - /* extract values from the pvid update */ - glort = FM10K_MSG_HDR_FIELD_GET(pvid_update, UPDATE_PVID_GLORT); - pvid = FM10K_MSG_HDR_FIELD_GET(pvid_update, UPDATE_PVID_PVID); - - /* if glort is not valid return error */ - if (!fm10k_glort_valid_pf(hw, glort)) - return FM10K_ERR_PARAM; - - /* verify VID is valid */ - if (pvid >= FM10K_VLAN_TABLE_VID_MAX) - return FM10K_ERR_PARAM; - - /* record the port VLAN ID value */ - hw->mac.default_vid = pvid; - - return FM10K_SUCCESS; -} - -/** - * fm10k_record_global_table_data - Move global table data to swapi table info - * @from: pointer to source table data structure - * @to: pointer to destination table info structure - * - * This function is will copy table_data to the table_info contained in - * the hw struct. - **/ -static void fm10k_record_global_table_data(struct fm10k_global_table_data *from, - struct fm10k_swapi_table_info *to) -{ - /* convert from le32 struct to CPU byte ordered values */ - to->used = FM10K_LE32_TO_CPU(from->used); - to->avail = FM10K_LE32_TO_CPU(from->avail); -} - -const struct fm10k_tlv_attr fm10k_err_msg_attr[] = { - FM10K_TLV_ATTR_LE_STRUCT(FM10K_PF_ATTR_ID_ERR, - sizeof(struct fm10k_swapi_error)), - FM10K_TLV_ATTR_LAST -}; - -/** - * fm10k_msg_err_pf - Message handler for error reply - * @hw: Pointer to hardware structure - * @results: pointer array containing parsed data - * @mbx: Pointer to mailbox information structure - * - * This handler will capture the data for any error replies to previous - * messages that the PF has sent. - **/ -s32 fm10k_msg_err_pf(struct fm10k_hw *hw, u32 **results, - struct fm10k_mbx_info *mbx) -{ - struct fm10k_swapi_error err_msg; - s32 err; - - UNREFERENCED_1PARAMETER(mbx); - DEBUGFUNC("fm10k_msg_err_pf"); - - /* extract structure from message */ - err = fm10k_tlv_attr_get_le_struct(results[FM10K_PF_ATTR_ID_ERR], - &err_msg, sizeof(err_msg)); - if (err) - return err; - - /* record table status */ - fm10k_record_global_table_data(&err_msg.mac, &hw->swapi.mac); - fm10k_record_global_table_data(&err_msg.nexthop, &hw->swapi.nexthop); - fm10k_record_global_table_data(&err_msg.ffu, &hw->swapi.ffu); - - /* record SW API status value */ - hw->swapi.status = FM10K_LE32_TO_CPU(err_msg.status); - - return FM10K_SUCCESS; -} - -const struct fm10k_tlv_attr fm10k_1588_timestamp_msg_attr[] = { - FM10K_TLV_ATTR_LE_STRUCT(FM10K_PF_ATTR_ID_1588_TIMESTAMP, - sizeof(struct fm10k_swapi_1588_timestamp)), - FM10K_TLV_ATTR_LAST -}; - -/* currently there is no shared 1588 timestamp handler */ - -/** - * fm10k_request_tx_timestamp_mode_pf - Request a specific Tx timestamping mode - * @hw: pointer to hardware structure - * @glort: base resource tag for this request - * @mode: integer value indicating the requested mode - * - * This function will attempt to request a specific timestamp mode for the - * port so that it can receive Tx timestamp messages. - **/ -STATIC s32 fm10k_request_tx_timestamp_mode_pf(struct fm10k_hw *hw, - u16 glort, - u8 mode) -{ - struct fm10k_mbx_info *mbx = &hw->mbx; - u32 msg[3], timestamp_mode; - - DEBUGFUNC("fm10k_request_timestamp_mode_pf"); - - if (mode > FM10K_TIMESTAMP_MODE_PEP_TO_ANY) - return FM10K_ERR_PARAM; - - /* if glort is not valid return error */ - if (!fm10k_glort_valid_pf(hw, glort)) - return FM10K_ERR_PARAM; - - /* write timestamp mode as a single u32 value, - * lower 16 bits: glort - * upper 16 bits: mode - */ - timestamp_mode = ((u32)mode << 16) | glort; - - /* generate message requesting change to xcast mode */ - fm10k_tlv_msg_init(msg, FM10K_PF_MSG_ID_TX_TIMESTAMP_MODE); - fm10k_tlv_attr_put_u32(msg, FM10K_PF_ATTR_ID_TIMESTAMP_MODE_REQ, timestamp_mode); - - /* load onto outgoing mailbox */ - return mbx->ops.enqueue_tx(hw, mbx, msg); -} - -/** - * fm10k_adjust_systime_pf - Adjust systime frequency - * @hw: pointer to hardware structure - * @ppb: adjustment rate in parts per billion - * - * This function will adjust the SYSTIME_CFG register contained in BAR 4 - * if this function is supported for BAR 4 access. The adjustment amount - * is based on the parts per billion value provided and adjusted to a - * value based on parts per 2^48 clock cycles. - * - * If adjustment is not supported or the requested value is too large - * we will return an error. - **/ -STATIC s32 fm10k_adjust_systime_pf(struct fm10k_hw *hw, s32 ppb) -{ - u64 systime_adjust; - - DEBUGFUNC("fm10k_adjust_systime_vf"); - - /* if sw_addr is not set we don't have switch register access */ - if (!hw->sw_addr) - return ppb ? FM10K_ERR_PARAM : FM10K_SUCCESS; - - /* we must convert the value from parts per billion to parts per - * 2^48 cycles. In addition I have opted to only use the 30 most - * significant bits of the adjustment value as the 8 least - * significant bits are located in another register and represent - * a value significantly less than a part per billion, the result - * of dropping the 8 least significant bits is that the adjustment - * value is effectively multiplied by 2^8 when we write it. - * - * As a result of all this the math for this breaks down as follows: - * ppb / 10^9 == adjust * 2^8 / 2^48 - * If we solve this for adjust, and simplify it comes out as: - * ppb * 2^31 / 5^9 == adjust - */ - systime_adjust = (ppb < 0) ? -ppb : ppb; - systime_adjust <<= 31; - do_div(systime_adjust, 1953125); - - /* verify the requested adjustment value is in range */ - if (systime_adjust > FM10K_SW_SYSTIME_ADJUST_MASK) - return FM10K_ERR_PARAM; - - if (ppb < 0) - systime_adjust |= FM10K_SW_SYSTIME_ADJUST_DIR_NEGATIVE; - - FM10K_WRITE_SW_REG(hw, FM10K_SW_SYSTIME_ADJUST, (u32)systime_adjust); - - return FM10K_SUCCESS; -} - -/** - * fm10k_read_systime_pf - Reads value of systime registers - * @hw: pointer to the hardware structure - * - * Function reads the content of 2 registers, combined to represent a 64 bit - * value measured in nanosecods. In order to guarantee the value is accurate - * we check the 32 most significant bits both before and after reading the - * 32 least significant bits to verify they didn't change as we were reading - * the registers. - **/ -static u64 fm10k_read_systime_pf(struct fm10k_hw *hw) -{ - u32 systime_l, systime_h, systime_tmp; - - systime_h = fm10k_read_reg(hw, FM10K_SYSTIME + 1); - - do { - systime_tmp = systime_h; - systime_l = fm10k_read_reg(hw, FM10K_SYSTIME); - systime_h = fm10k_read_reg(hw, FM10K_SYSTIME + 1); - } while (systime_tmp != systime_h); - - return ((u64)systime_h << 32) | systime_l; -} - -static const struct fm10k_msg_data fm10k_msg_data_pf[] = { - FM10K_PF_MSG_ERR_HANDLER(XCAST_MODES, fm10k_msg_err_pf), - FM10K_PF_MSG_ERR_HANDLER(UPDATE_MAC_FWD_RULE, fm10k_msg_err_pf), - FM10K_PF_MSG_LPORT_MAP_HANDLER(fm10k_msg_lport_map_pf), - FM10K_PF_MSG_ERR_HANDLER(LPORT_CREATE, fm10k_msg_err_pf), - FM10K_PF_MSG_ERR_HANDLER(LPORT_DELETE, fm10k_msg_err_pf), - FM10K_PF_MSG_UPDATE_PVID_HANDLER(fm10k_msg_update_pvid_pf), - FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error), -}; - -/** - * fm10k_init_ops_pf - Inits func ptrs and MAC type - * @hw: pointer to hardware structure - * - * Initialize the function pointers and assign the MAC type for PF. - * Does not touch the hardware. - **/ -s32 fm10k_init_ops_pf(struct fm10k_hw *hw) -{ - struct fm10k_mac_info *mac = &hw->mac; - struct fm10k_iov_info *iov = &hw->iov; - - DEBUGFUNC("fm10k_init_ops_pf"); - - fm10k_init_ops_generic(hw); - - mac->ops.reset_hw = &fm10k_reset_hw_pf; - mac->ops.init_hw = &fm10k_init_hw_pf; - mac->ops.start_hw = &fm10k_start_hw_generic; - mac->ops.stop_hw = &fm10k_stop_hw_generic; - mac->ops.is_slot_appropriate = &fm10k_is_slot_appropriate_pf; - mac->ops.update_vlan = &fm10k_update_vlan_pf; - mac->ops.read_mac_addr = &fm10k_read_mac_addr_pf; - mac->ops.update_uc_addr = &fm10k_update_uc_addr_pf; - mac->ops.update_mc_addr = &fm10k_update_mc_addr_pf; - mac->ops.update_xcast_mode = &fm10k_update_xcast_mode_pf; - mac->ops.update_int_moderator = &fm10k_update_int_moderator_pf; - mac->ops.update_lport_state = &fm10k_update_lport_state_pf; - mac->ops.update_hw_stats = &fm10k_update_hw_stats_pf; - mac->ops.rebind_hw_stats = &fm10k_rebind_hw_stats_pf; - mac->ops.configure_dglort_map = &fm10k_configure_dglort_map_pf; - mac->ops.set_dma_mask = &fm10k_set_dma_mask_pf; - mac->ops.get_fault = &fm10k_get_fault_pf; - mac->ops.get_host_state = &fm10k_get_host_state_pf; - mac->ops.adjust_systime = &fm10k_adjust_systime_pf; - mac->ops.read_systime = &fm10k_read_systime_pf; - mac->ops.request_tx_timestamp_mode = &fm10k_request_tx_timestamp_mode_pf; - - mac->max_msix_vectors = fm10k_get_pcie_msix_count_generic(hw); - - iov->ops.assign_resources = &fm10k_iov_assign_resources_pf; - iov->ops.configure_tc = &fm10k_iov_configure_tc_pf; - iov->ops.assign_int_moderator = &fm10k_iov_assign_int_moderator_pf; - iov->ops.assign_default_mac_vlan = fm10k_iov_assign_default_mac_vlan_pf; - iov->ops.reset_resources = &fm10k_iov_reset_resources_pf; - iov->ops.set_lport = &fm10k_iov_set_lport_pf; - iov->ops.reset_lport = &fm10k_iov_reset_lport_pf; - iov->ops.update_stats = &fm10k_iov_update_stats_pf; - iov->ops.report_timestamp = &fm10k_iov_report_timestamp_pf; - - return fm10k_sm_mbx_init(hw, &hw->mbx, fm10k_msg_data_pf); -} diff --git a/lib/librte_pmd_fm10k/base/fm10k_pf.h b/lib/librte_pmd_fm10k/base/fm10k_pf.h deleted file mode 100644 index f6c290a..0000000 --- a/lib/librte_pmd_fm10k/base/fm10k_pf.h +++ /dev/null @@ -1,155 +0,0 @@ -/******************************************************************************* - -Copyright (c) 2013 - 2015, 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. - -***************************************************************************/ - -#ifndef _FM10K_PF_H_ -#define _FM10K_PF_H_ - -#include "fm10k_type.h" -#include "fm10k_common.h" - -bool fm10k_glort_valid_pf(struct fm10k_hw *hw, u16 glort); -u16 fm10k_queues_per_pool(struct fm10k_hw *hw); -u16 fm10k_vf_queue_index(struct fm10k_hw *hw, u16 vf_idx); - -enum fm10k_pf_tlv_msg_id_v1 { - FM10K_PF_MSG_ID_TEST = 0x000, /* msg ID reserved */ - FM10K_PF_MSG_ID_XCAST_MODES = 0x001, - FM10K_PF_MSG_ID_UPDATE_MAC_FWD_RULE = 0x002, - FM10K_PF_MSG_ID_LPORT_MAP = 0x100, - FM10K_PF_MSG_ID_LPORT_CREATE = 0x200, - FM10K_PF_MSG_ID_LPORT_DELETE = 0x201, - FM10K_PF_MSG_ID_CONFIG = 0x300, - FM10K_PF_MSG_ID_UPDATE_PVID = 0x400, - FM10K_PF_MSG_ID_CREATE_FLOW_TABLE = 0x501, - FM10K_PF_MSG_ID_DELETE_FLOW_TABLE = 0x502, - FM10K_PF_MSG_ID_UPDATE_FLOW = 0x503, - FM10K_PF_MSG_ID_DELETE_FLOW = 0x504, - FM10K_PF_MSG_ID_SET_FLOW_STATE = 0x505, - FM10K_PF_MSG_ID_GET_1588_INFO = 0x506, - FM10K_PF_MSG_ID_1588_TIMESTAMP = 0x701, - FM10K_PF_MSG_ID_TX_TIMESTAMP_MODE = 0x702, -}; - -enum fm10k_pf_tlv_attr_id_v1 { - FM10K_PF_ATTR_ID_ERR = 0x00, - FM10K_PF_ATTR_ID_LPORT_MAP = 0x01, - FM10K_PF_ATTR_ID_XCAST_MODE = 0x02, - FM10K_PF_ATTR_ID_MAC_UPDATE = 0x03, - FM10K_PF_ATTR_ID_VLAN_UPDATE = 0x04, - FM10K_PF_ATTR_ID_CONFIG = 0x05, - FM10K_PF_ATTR_ID_CREATE_FLOW_TABLE = 0x06, - FM10K_PF_ATTR_ID_DELETE_FLOW_TABLE = 0x07, - FM10K_PF_ATTR_ID_UPDATE_FLOW = 0x08, - FM10K_PF_ATTR_ID_FLOW_STATE = 0x09, - FM10K_PF_ATTR_ID_FLOW_HANDLE = 0x0A, - FM10K_PF_ATTR_ID_DELETE_FLOW = 0x0B, - FM10K_PF_ATTR_ID_PORT = 0x0C, - FM10K_PF_ATTR_ID_UPDATE_PVID = 0x0D, - FM10K_PF_ATTR_ID_1588_TIMESTAMP = 0x10, - FM10K_PF_ATTR_ID_TIMESTAMP_MODE_REQ = 0x11, - FM10K_PF_ATTR_ID_TIMESTAMP_MODE_RESP = 0x12, -}; - -#define FM10K_MSG_LPORT_MAP_GLORT_SHIFT 0 -#define FM10K_MSG_LPORT_MAP_GLORT_SIZE 16 -#define FM10K_MSG_LPORT_MAP_MASK_SHIFT 16 -#define FM10K_MSG_LPORT_MAP_MASK_SIZE 16 - -#define FM10K_MSG_UPDATE_PVID_GLORT_SHIFT 0 -#define FM10K_MSG_UPDATE_PVID_GLORT_SIZE 16 -#define FM10K_MSG_UPDATE_PVID_PVID_SHIFT 16 -#define FM10K_MSG_UPDATE_PVID_PVID_SIZE 16 - -struct fm10k_mac_update { - __le32 mac_lower; - __le16 mac_upper; - __le16 vlan; - __le16 glort; - u8 flags; - u8 action; -}; - -struct fm10k_global_table_data { - __le32 used; - __le32 avail; -}; - -struct fm10k_swapi_error { - __le32 status; - struct fm10k_global_table_data mac; - struct fm10k_global_table_data nexthop; - struct fm10k_global_table_data ffu; -}; - -struct fm10k_swapi_1588_timestamp { - __le64 egress; - __le64 ingress; - __le16 dglort; - __le16 sglort; -}; - -#define FM10K_PF_MSG_LPORT_CREATE_HANDLER(func) \ - FM10K_MSG_HANDLER(FM10K_PF_MSG_ID_LPORT_CREATE, NULL, func) -#define FM10K_PF_MSG_LPORT_DELETE_HANDLER(func) \ - FM10K_MSG_HANDLER(FM10K_PF_MSG_ID_LPORT_DELETE, NULL, func) -s32 fm10k_msg_lport_map_pf(struct fm10k_hw *, u32 **, struct fm10k_mbx_info *); -extern const struct fm10k_tlv_attr fm10k_lport_map_msg_attr[]; -#define FM10K_PF_MSG_LPORT_MAP_HANDLER(func) \ - FM10K_MSG_HANDLER(FM10K_PF_MSG_ID_LPORT_MAP, \ - fm10k_lport_map_msg_attr, func) -s32 fm10k_msg_update_pvid_pf(struct fm10k_hw *, u32 **, - struct fm10k_mbx_info *); -extern const struct fm10k_tlv_attr fm10k_update_pvid_msg_attr[]; -#define FM10K_PF_MSG_UPDATE_PVID_HANDLER(func) \ - FM10K_MSG_HANDLER(FM10K_PF_MSG_ID_UPDATE_PVID, \ - fm10k_update_pvid_msg_attr, func) - -s32 fm10k_msg_err_pf(struct fm10k_hw *, u32 **, struct fm10k_mbx_info *); -extern const struct fm10k_tlv_attr fm10k_err_msg_attr[]; -#define FM10K_PF_MSG_ERR_HANDLER(msg, func) \ - FM10K_MSG_HANDLER(FM10K_PF_MSG_ID_##msg, fm10k_err_msg_attr, func) - -extern const struct fm10k_tlv_attr fm10k_1588_timestamp_msg_attr[]; -#define FM10K_PF_MSG_1588_TIMESTAMP_HANDLER(func) \ - FM10K_MSG_HANDLER(FM10K_PF_MSG_ID_1588_TIMESTAMP, \ - fm10k_1588_timestamp_msg_attr, func) - -s32 fm10k_iov_msg_msix_pf(struct fm10k_hw *, u32 **, struct fm10k_mbx_info *); -s32 fm10k_iov_msg_mac_vlan_pf(struct fm10k_hw *, u32 **, - struct fm10k_mbx_info *); -s32 fm10k_iov_msg_lport_state_pf(struct fm10k_hw *, u32 **, - struct fm10k_mbx_info *); -extern const struct fm10k_msg_data fm10k_iov_msg_data_pf[]; - -s32 fm10k_init_ops_pf(struct fm10k_hw *hw); -#endif /* _FM10K_PF_H */ diff --git a/lib/librte_pmd_fm10k/base/fm10k_tlv.c b/lib/librte_pmd_fm10k/base/fm10k_tlv.c deleted file mode 100644 index 1d9d7d8..0000000 --- a/lib/librte_pmd_fm10k/base/fm10k_tlv.c +++ /dev/null @@ -1,914 +0,0 @@ -/******************************************************************************* - -Copyright (c) 2013 - 2015, 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. - -***************************************************************************/ - -#include "fm10k_tlv.h" - -/** - * fm10k_tlv_msg_init - Initialize message block for TLV data storage - * @msg: Pointer to message block - * @msg_id: Message ID indicating message type - * - * This function return success if provided with a valid message pointer - **/ -s32 fm10k_tlv_msg_init(u32 *msg, u16 msg_id) -{ - DEBUGFUNC("fm10k_tlv_msg_init"); - - /* verify pointer is not NULL */ - if (!msg) - return FM10K_ERR_PARAM; - - *msg = (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT) | msg_id; - - return FM10K_SUCCESS; -} - -/** - * fm10k_tlv_attr_put_null_string - Place null terminated string on message - * @msg: Pointer to message block - * @attr_id: Attribute ID - * @string: Pointer to string to be stored in attribute - * - * This function will reorder a string to be CPU endian and store it in - * the attribute buffer. It will return success if provided with a valid - * pointers. - **/ -s32 fm10k_tlv_attr_put_null_string(u32 *msg, u16 attr_id, - const unsigned char *string) -{ - u32 attr_data = 0, len = 0; - u32 *attr; - - DEBUGFUNC("fm10k_tlv_attr_put_null_string"); - - /* verify pointers are not NULL */ - if (!string || !msg) - return FM10K_ERR_PARAM; - - attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; - - /* copy string into local variable and then write to msg */ - do { - /* write data to message */ - if (len && !(len % 4)) { - attr[len / 4] = attr_data; - attr_data = 0; - } - - /* record character to offset location */ - attr_data |= (u32)(*string) << (8 * (len % 4)); - len++; - - /* test for NULL and then increment */ - } while (*(string++)); - - /* write last piece of data to message */ - attr[(len + 3) / 4] = attr_data; - - /* record attribute header, update message length */ - len <<= FM10K_TLV_LEN_SHIFT; - attr[0] = len | attr_id; - - /* add header length to length */ - len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; - *msg += FM10K_TLV_LEN_ALIGN(len); - - return FM10K_SUCCESS; -} - -/** - * fm10k_tlv_attr_get_null_string - Get null terminated string from attribute - * @attr: Pointer to attribute - * @string: Pointer to location of destination string - * - * This function pulls the string back out of the attribute and will place - * it in the array pointed by by string. It will return success if provided - * with a valid pointers. - **/ -s32 fm10k_tlv_attr_get_null_string(u32 *attr, unsigned char *string) -{ - u32 len; - - DEBUGFUNC("fm10k_tlv_attr_get_null_string"); - - /* verify pointers are not NULL */ - if (!string || !attr) - return FM10K_ERR_PARAM; - - len = *attr >> FM10K_TLV_LEN_SHIFT; - attr++; - - while (len--) - string[len] = (u8)(attr[len / 4] >> (8 * (len % 4))); - - return FM10K_SUCCESS; -} - -/** - * fm10k_tlv_attr_put_mac_vlan - Store MAC/VLAN attribute in message - * @msg: Pointer to message block - * @attr_id: Attribute ID - * @mac_addr: MAC address to be stored - * - * This function will reorder a MAC address to be CPU endian and store it - * in the attribute buffer. It will return success if provided with a - * valid pointers. - **/ -s32 fm10k_tlv_attr_put_mac_vlan(u32 *msg, u16 attr_id, - const u8 *mac_addr, u16 vlan) -{ - u32 len = ETH_ALEN << FM10K_TLV_LEN_SHIFT; - u32 *attr; - - DEBUGFUNC("fm10k_tlv_attr_put_mac_vlan"); - - /* verify pointers are not NULL */ - if (!msg || !mac_addr) - return FM10K_ERR_PARAM; - - attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; - - /* record attribute header, update message length */ - attr[0] = len | attr_id; - - /* copy value into local variable and then write to msg */ - attr[1] = FM10K_LE32_TO_CPU(*(const __le32 *)&mac_addr[0]); - attr[2] = FM10K_LE16_TO_CPU(*(const __le16 *)&mac_addr[4]); - attr[2] |= (u32)vlan << 16; - - /* add header length to length */ - len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; - *msg += FM10K_TLV_LEN_ALIGN(len); - - return FM10K_SUCCESS; -} - -/** - * fm10k_tlv_attr_get_mac_vlan - Get MAC/VLAN stored in attribute - * @attr: Pointer to attribute - * @attr_id: Attribute ID - * @mac_addr: location of buffer to store MAC address - * - * This function pulls the MAC address back out of the attribute and will - * place it in the array pointed by by mac_addr. It will return success - * if provided with a valid pointers. - **/ -s32 fm10k_tlv_attr_get_mac_vlan(u32 *attr, u8 *mac_addr, u16 *vlan) -{ - DEBUGFUNC("fm10k_tlv_attr_get_mac_vlan"); - - /* verify pointers are not NULL */ - if (!mac_addr || !attr) - return FM10K_ERR_PARAM; - - *(__le32 *)&mac_addr[0] = FM10K_CPU_TO_LE32(attr[1]); - *(__le16 *)&mac_addr[4] = FM10K_CPU_TO_LE16((u16)(attr[2])); - *vlan = (u16)(attr[2] >> 16); - - return FM10K_SUCCESS; -} - -/** - * fm10k_tlv_attr_put_bool - Add header indicating value "true" - * @msg: Pointer to message block - * @attr_id: Attribute ID - * - * This function will simply add an attribute header, the fact - * that the header is here means the attribute value is true, else - * it is false. The function will return success if provided with a - * valid pointers. - **/ -s32 fm10k_tlv_attr_put_bool(u32 *msg, u16 attr_id) -{ - DEBUGFUNC("fm10k_tlv_attr_put_bool"); - - /* verify pointers are not NULL */ - if (!msg) - return FM10K_ERR_PARAM; - - /* record attribute header */ - msg[FM10K_TLV_DWORD_LEN(*msg)] = attr_id; - - /* add header length to length */ - *msg += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; - - return FM10K_SUCCESS; -} - -/** - * fm10k_tlv_attr_put_value - Store integer value attribute in message - * @msg: Pointer to message block - * @attr_id: Attribute ID - * @value: Value to be written - * @len: Size of value - * - * This function will place an integer value of up to 8 bytes in size - * in a message attribute. The function will return success provided - * that msg is a valid pointer, and len is 1, 2, 4, or 8. - **/ -s32 fm10k_tlv_attr_put_value(u32 *msg, u16 attr_id, s64 value, u32 len) -{ - u32 *attr; - - DEBUGFUNC("fm10k_tlv_attr_put_value"); - - /* verify non-null msg and len is 1, 2, 4, or 8 */ - if (!msg || !len || len > 8 || (len & (len - 1))) - return FM10K_ERR_PARAM; - - attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; - - if (len < 4) { - attr[1] = (u32)value & ((0x1ul << (8 * len)) - 1); - } else { - attr[1] = (u32)value; - if (len > 4) - attr[2] = (u32)(value >> 32); - } - - /* record attribute header, update message length */ - len <<= FM10K_TLV_LEN_SHIFT; - attr[0] = len | attr_id; - - /* add header length to length */ - len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; - *msg += FM10K_TLV_LEN_ALIGN(len); - - return FM10K_SUCCESS; -} - -/** - * fm10k_tlv_attr_get_value - Get integer value stored in attribute - * @attr: Pointer to attribute - * @value: Pointer to destination buffer - * @len: Size of value - * - * This function will place an integer value of up to 8 bytes in size - * in the offset pointed to by value. The function will return success - * provided that pointers are valid and the len value matches the - * attribute length. - **/ -s32 fm10k_tlv_attr_get_value(u32 *attr, void *value, u32 len) -{ - DEBUGFUNC("fm10k_tlv_attr_get_value"); - - /* verify pointers are not NULL */ - if (!attr || !value) - return FM10K_ERR_PARAM; - - if ((*attr >> FM10K_TLV_LEN_SHIFT) != len) - return FM10K_ERR_PARAM; - - if (len == 8) - *(u64 *)value = ((u64)attr[2] << 32) | attr[1]; - else if (len == 4) - *(u32 *)value = attr[1]; - else if (len == 2) - *(u16 *)value = (u16)attr[1]; - else - *(u8 *)value = (u8)attr[1]; - - return FM10K_SUCCESS; -} - -/** - * fm10k_tlv_attr_put_le_struct - Store little endian structure in message - * @msg: Pointer to message block - * @attr_id: Attribute ID - * @le_struct: Pointer to structure to be written - * @len: Size of le_struct - * - * This function will place a little endian structure value in a message - * attribute. The function will return success provided that all pointers - * are valid and length is a non-zero multiple of 4. - **/ -s32 fm10k_tlv_attr_put_le_struct(u32 *msg, u16 attr_id, - const void *le_struct, u32 len) -{ - const __le32 *le32_ptr = (const __le32 *)le_struct; - u32 *attr; - u32 i; - - DEBUGFUNC("fm10k_tlv_attr_put_le_struct"); - - /* verify non-null msg and len is in 32 bit words */ - if (!msg || !len || (len % 4)) - return FM10K_ERR_PARAM; - - attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; - - /* copy le32 structure into host byte order at 32b boundaries */ - for (i = 0; i < (len / 4); i++) - attr[i + 1] = FM10K_LE32_TO_CPU(le32_ptr[i]); - - /* record attribute header, update message length */ - len <<= FM10K_TLV_LEN_SHIFT; - attr[0] = len | attr_id; - - /* add header length to length */ - len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; - *msg += FM10K_TLV_LEN_ALIGN(len); - - return FM10K_SUCCESS; -} - -/** - * fm10k_tlv_attr_get_le_struct - Get little endian struct form attribute - * @attr: Pointer to attribute - * @le_struct: Pointer to structure to be written - * @len: Size of structure - * - * This function will place a little endian structure in the buffer - * pointed to by le_struct. The function will return success - * provided that pointers are valid and the len value matches the - * attribute length. - **/ -s32 fm10k_tlv_attr_get_le_struct(u32 *attr, void *le_struct, u32 len) -{ - __le32 *le32_ptr = (__le32 *)le_struct; - u32 i; - - DEBUGFUNC("fm10k_tlv_attr_get_le_struct"); - - /* verify pointers are not NULL */ - if (!le_struct || !attr) - return FM10K_ERR_PARAM; - - if ((*attr >> FM10K_TLV_LEN_SHIFT) != len) - return FM10K_ERR_PARAM; - - attr++; - - for (i = 0; len; i++, len -= 4) - le32_ptr[i] = FM10K_CPU_TO_LE32(attr[i]); - - return FM10K_SUCCESS; -} - -/** - * fm10k_tlv_attr_nest_start - Start a set of nested attributes - * @msg: Pointer to message block - * @attr_id: Attribute ID - * - * This function will mark off a new nested region for encapsulating - * a given set of attributes. The idea is if you wish to place a secondary - * structure within the message this mechanism allows for that. The - * function will return NULL on failure, and a pointer to the start - * of the nested attributes on success. - **/ -u32 *fm10k_tlv_attr_nest_start(u32 *msg, u16 attr_id) -{ - u32 *attr; - - DEBUGFUNC("fm10k_tlv_attr_nest_start"); - - /* verify pointer is not NULL */ - if (!msg) - return NULL; - - attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; - - attr[0] = attr_id; - - /* return pointer to nest header */ - return attr; -} - -/** - * fm10k_tlv_attr_nest_start - Start a set of nested attributes - * @msg: Pointer to message block - * - * This function closes off an existing set of nested attributes. The - * message pointer should be pointing to the parent of the nest. So in - * the case of a nest within the nest this would be the outer nest pointer. - * This function will return success provided all pointers are valid. - **/ -s32 fm10k_tlv_attr_nest_stop(u32 *msg) -{ - u32 *attr; - u32 len; - - DEBUGFUNC("fm10k_tlv_attr_nest_stop"); - - /* verify pointer is not NULL */ - if (!msg) - return FM10K_ERR_PARAM; - - /* locate the nested header and retrieve its length */ - attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; - len = (attr[0] >> FM10K_TLV_LEN_SHIFT) << FM10K_TLV_LEN_SHIFT; - - /* only include nest if data was added to it */ - if (len) { - len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; - *msg += len; - } - - return FM10K_SUCCESS; -} - -/** - * fm10k_tlv_attr_validate - Validate attribute metadata - * @attr: Pointer to attribute - * @tlv_attr: Type and length info for attribute - * - * This function does some basic validation of the input TLV. It - * verifies the length, and in the case of null terminated strings - * it verifies that the last byte is null. The function will - * return FM10K_ERR_PARAM if any attribute is malformed, otherwise - * it returns 0. - **/ -STATIC s32 fm10k_tlv_attr_validate(u32 *attr, - const struct fm10k_tlv_attr *tlv_attr) -{ - u32 attr_id = *attr & FM10K_TLV_ID_MASK; - u16 len = *attr >> FM10K_TLV_LEN_SHIFT; - - DEBUGFUNC("fm10k_tlv_attr_validate"); - - /* verify this is an attribute and not a message */ - if (*attr & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT)) - return FM10K_ERR_PARAM; - - /* search through the list of attributes to find a matching ID */ - while (tlv_attr->id < attr_id) - tlv_attr++; - - /* if didn't find a match then we should exit */ - if (tlv_attr->id != attr_id) - return FM10K_NOT_IMPLEMENTED; - - /* move to start of attribute data */ - attr++; - - switch (tlv_attr->type) { - case FM10K_TLV_NULL_STRING: - if (!len || - (attr[(len - 1) / 4] & (0xFF << (8 * ((len - 1) % 4))))) - return FM10K_ERR_PARAM; - if (len > tlv_attr->len) - return FM10K_ERR_PARAM; - break; - case FM10K_TLV_MAC_ADDR: - if (len != ETH_ALEN) - return FM10K_ERR_PARAM; - break; - case FM10K_TLV_BOOL: - if (len) - return FM10K_ERR_PARAM; - break; - case FM10K_TLV_UNSIGNED: - case FM10K_TLV_SIGNED: - if (len != tlv_attr->len) - return FM10K_ERR_PARAM; - break; - case FM10K_TLV_LE_STRUCT: - /* struct must be 4 byte aligned */ - if ((len % 4) || len != tlv_attr->len) - return FM10K_ERR_PARAM; - break; - case FM10K_TLV_NESTED: - /* nested attributes must be 4 byte aligned */ - if (len % 4) - return FM10K_ERR_PARAM; - break; - default: - /* attribute id is mapped to bad value */ - return FM10K_ERR_PARAM; - } - - return FM10K_SUCCESS; -} - -/** - * fm10k_tlv_attr_parse - Parses stream of attribute data - * @attr: Pointer to attribute list - * @results: Pointer array to store pointers to attributes - * @tlv_attr: Type and length info for attributes - * - * This function validates a stream of attributes and parses them - * up into an array of pointers stored in results. The function will - * return FM10K_ERR_PARAM on any input or message error, - * FM10K_NOT_IMPLEMENTED for any attribute that is outside of the array - * and 0 on success. - **/ -s32 fm10k_tlv_attr_parse(u32 *attr, u32 **results, - const struct fm10k_tlv_attr *tlv_attr) -{ - u32 i, attr_id, offset = 0; - s32 err = 0; - u16 len; - - DEBUGFUNC("fm10k_tlv_attr_parse"); - - /* verify pointers are not NULL */ - if (!attr || !results) - return FM10K_ERR_PARAM; - - /* initialize results to NULL */ - for (i = 0; i < FM10K_TLV_RESULTS_MAX; i++) - results[i] = NULL; - - /* pull length from the message header */ - len = *attr >> FM10K_TLV_LEN_SHIFT; - - /* no attributes to parse if there is no length */ - if (!len) - return FM10K_SUCCESS; - - /* no attributes to parse, just raw data, message becomes attribute */ - if (!tlv_attr) { - results[0] = attr; - return FM10K_SUCCESS; - } - - /* move to start of attribute data */ - attr++; - - /* run through list parsing all attributes */ - while (offset < len) { - attr_id = *attr & FM10K_TLV_ID_MASK; - - if (attr_id < FM10K_TLV_RESULTS_MAX) - err = fm10k_tlv_attr_validate(attr, tlv_attr); - else - err = FM10K_NOT_IMPLEMENTED; - - if (err < 0) - return err; - if (!err) - results[attr_id] = attr; - - /* update offset */ - offset += FM10K_TLV_DWORD_LEN(*attr) * 4; - - /* move to next attribute */ - attr = &attr[FM10K_TLV_DWORD_LEN(*attr)]; - } - - /* we should find ourselves at the end of the list */ - if (offset != len) - return FM10K_ERR_PARAM; - - return FM10K_SUCCESS; -} - -/** - * fm10k_tlv_msg_parse - Parses message header and calls function handler - * @hw: Pointer to hardware structure - * @msg: Pointer to message - * @mbx: Pointer to mailbox information structure - * @func: Function array containing list of message handling functions - * - * This function should be the first function called upon receiving a - * message. The handler will identify the message type and call the correct - * handler for the given message. It will return the value from the function - * call on a recognized message type, otherwise it will return - * FM10K_NOT_IMPLEMENTED on an unrecognized type. - **/ -s32 fm10k_tlv_msg_parse(struct fm10k_hw *hw, u32 *msg, - struct fm10k_mbx_info *mbx, - const struct fm10k_msg_data *data) -{ - u32 *results[FM10K_TLV_RESULTS_MAX]; - u32 msg_id; - s32 err; - - DEBUGFUNC("fm10k_tlv_msg_parse"); - - /* verify pointer is not NULL */ - if (!msg || !data) - return FM10K_ERR_PARAM; - - /* verify this is a message and not an attribute */ - if (!(*msg & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT))) - return FM10K_ERR_PARAM; - - /* grab message ID */ - msg_id = *msg & FM10K_TLV_ID_MASK; - - while (data->id < msg_id) - data++; - - /* if we didn't find it then pass it up as an error */ - if (data->id != msg_id) { - while (data->id != FM10K_TLV_ERROR) - data++; - } - - /* parse the attributes into the results list */ - err = fm10k_tlv_attr_parse(msg, results, data->attr); - if (err < 0) - return err; - - return data->func(hw, results, mbx); -} - -/** - * fm10k_tlv_msg_error - Default handler for unrecognized TLV message IDs - * @hw: Pointer to hardware structure - * @results: Pointer array to message, results[0] is pointer to message - * @mbx: Unused mailbox pointer - * - * This function is a default handler for unrecognized messages. At a - * a minimum it just indicates that the message requested was - * unimplemented. - **/ -s32 fm10k_tlv_msg_error(struct fm10k_hw *hw, u32 **results, - struct fm10k_mbx_info *mbx) -{ - UNREFERENCED_3PARAMETER(hw, results, mbx); - DEBUGOUT1("Unknown message ID %u\n", **results & FM10K_TLV_ID_MASK); - return FM10K_NOT_IMPLEMENTED; -} - -STATIC const unsigned char test_str[] = "fm10k"; -STATIC const unsigned char test_mac[ETH_ALEN] = { 0x12, 0x34, 0x56, - 0x78, 0x9a, 0xbc }; -STATIC const u16 test_vlan = 0x0FED; -STATIC const u64 test_u64 = 0xfedcba9876543210ull; -STATIC const u32 test_u32 = 0x87654321; -STATIC const u16 test_u16 = 0x8765; -STATIC const u8 test_u8 = 0x87; -STATIC const s64 test_s64 = -0x123456789abcdef0ll; -STATIC const s32 test_s32 = -0x1235678; -STATIC const s16 test_s16 = -0x1234; -STATIC const s8 test_s8 = -0x12; -STATIC const __le32 test_le[2] = { FM10K_CPU_TO_LE32(0x12345678), - FM10K_CPU_TO_LE32(0x9abcdef0)}; - -/* The message below is meant to be used as a test message to demonstrate - * how to use the TLV interface and to test the types. Normally this code - * be compiled out by stripping the code wrapped in FM10K_TLV_TEST_MSG - */ -const struct fm10k_tlv_attr fm10k_tlv_msg_test_attr[] = { - FM10K_TLV_ATTR_NULL_STRING(FM10K_TEST_MSG_STRING, 80), - FM10K_TLV_ATTR_MAC_ADDR(FM10K_TEST_MSG_MAC_ADDR), - FM10K_TLV_ATTR_U8(FM10K_TEST_MSG_U8), - FM10K_TLV_ATTR_U16(FM10K_TEST_MSG_U16), - FM10K_TLV_ATTR_U32(FM10K_TEST_MSG_U32), - FM10K_TLV_ATTR_U64(FM10K_TEST_MSG_U64), - FM10K_TLV_ATTR_S8(FM10K_TEST_MSG_S8), - FM10K_TLV_ATTR_S16(FM10K_TEST_MSG_S16), - FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_S32), - FM10K_TLV_ATTR_S64(FM10K_TEST_MSG_S64), - FM10K_TLV_ATTR_LE_STRUCT(FM10K_TEST_MSG_LE_STRUCT, 8), - FM10K_TLV_ATTR_NESTED(FM10K_TEST_MSG_NESTED), - FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_RESULT), - FM10K_TLV_ATTR_LAST -}; - -/** - * fm10k_tlv_msg_test_generate_data - Stuff message with data - * @msg: Pointer to message - * @attr_flags: List of flags indicating what attributes to add - * - * This function is meant to load a message buffer with attribute data - **/ -STATIC void fm10k_tlv_msg_test_generate_data(u32 *msg, u32 attr_flags) -{ - DEBUGFUNC("fm10k_tlv_msg_test_generate_data"); - - if (attr_flags & (1 << FM10K_TEST_MSG_STRING)) - fm10k_tlv_attr_put_null_string(msg, FM10K_TEST_MSG_STRING, - test_str); - if (attr_flags & (1 << FM10K_TEST_MSG_MAC_ADDR)) - fm10k_tlv_attr_put_mac_vlan(msg, FM10K_TEST_MSG_MAC_ADDR, - test_mac, test_vlan); - if (attr_flags & (1 << FM10K_TEST_MSG_U8)) - fm10k_tlv_attr_put_u8(msg, FM10K_TEST_MSG_U8, test_u8); - if (attr_flags & (1 << FM10K_TEST_MSG_U16)) - fm10k_tlv_attr_put_u16(msg, FM10K_TEST_MSG_U16, test_u16); - if (attr_flags & (1 << FM10K_TEST_MSG_U32)) - fm10k_tlv_attr_put_u32(msg, FM10K_TEST_MSG_U32, test_u32); - if (attr_flags & (1 << FM10K_TEST_MSG_U64)) - fm10k_tlv_attr_put_u64(msg, FM10K_TEST_MSG_U64, test_u64); - if (attr_flags & (1 << FM10K_TEST_MSG_S8)) - fm10k_tlv_attr_put_s8(msg, FM10K_TEST_MSG_S8, test_s8); - if (attr_flags & (1 << FM10K_TEST_MSG_S16)) - fm10k_tlv_attr_put_s16(msg, FM10K_TEST_MSG_S16, test_s16); - if (attr_flags & (1 << FM10K_TEST_MSG_S32)) - fm10k_tlv_attr_put_s32(msg, FM10K_TEST_MSG_S32, test_s32); - if (attr_flags & (1 << FM10K_TEST_MSG_S64)) - fm10k_tlv_attr_put_s64(msg, FM10K_TEST_MSG_S64, test_s64); - if (attr_flags & (1 << FM10K_TEST_MSG_LE_STRUCT)) - fm10k_tlv_attr_put_le_struct(msg, FM10K_TEST_MSG_LE_STRUCT, - test_le, 8); -} - -/** - * fm10k_tlv_msg_test_create - Create a test message testing all attributes - * @msg: Pointer to message - * @attr_flags: List of flags indicating what attributes to add - * - * This function is meant to load a message buffer with all attribute types - * including a nested attribute. - **/ -void fm10k_tlv_msg_test_create(u32 *msg, u32 attr_flags) -{ - u32 *nest = NULL; - - DEBUGFUNC("fm10k_tlv_msg_test_create"); - - fm10k_tlv_msg_init(msg, FM10K_TLV_MSG_ID_TEST); - - fm10k_tlv_msg_test_generate_data(msg, attr_flags); - - /* check for nested attributes */ - attr_flags >>= FM10K_TEST_MSG_NESTED; - - if (attr_flags) { - nest = fm10k_tlv_attr_nest_start(msg, FM10K_TEST_MSG_NESTED); - - fm10k_tlv_msg_test_generate_data(nest, attr_flags); - - fm10k_tlv_attr_nest_stop(msg); - } -} - -/** - * fm10k_tlv_msg_test - Validate all results on test message receive - * @hw: Pointer to hardware structure - * @results: Pointer array to attributes in the message - * @mbx: Pointer to mailbox information structure - * - * This function does a check to verify all attributes match what the test - * message placed in the message buffer. It is the default handler - * for TLV test messages. - **/ -s32 fm10k_tlv_msg_test(struct fm10k_hw *hw, u32 **results, - struct fm10k_mbx_info *mbx) -{ - u32 *nest_results[FM10K_TLV_RESULTS_MAX]; - unsigned char result_str[80]; - unsigned char result_mac[ETH_ALEN]; - s32 err = FM10K_SUCCESS; - __le32 result_le[2]; - u16 result_vlan; - u64 result_u64; - u32 result_u32; - u16 result_u16; - u8 result_u8; - s64 result_s64; - s32 result_s32; - s16 result_s16; - s8 result_s8; - u32 reply[3]; - - DEBUGFUNC("fm10k_tlv_msg_test"); - - /* retrieve results of a previous test */ - if (!!results[FM10K_TEST_MSG_RESULT]) - return fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_RESULT], - &mbx->test_result); - -parse_nested: - if (!!results[FM10K_TEST_MSG_STRING]) { - err = fm10k_tlv_attr_get_null_string( - results[FM10K_TEST_MSG_STRING], - result_str); - if (!err && memcmp(test_str, result_str, sizeof(test_str))) - err = FM10K_ERR_INVALID_VALUE; - if (err) - goto report_result; - } - if (!!results[FM10K_TEST_MSG_MAC_ADDR]) { - err = fm10k_tlv_attr_get_mac_vlan( - results[FM10K_TEST_MSG_MAC_ADDR], - result_mac, &result_vlan); - if (!err && memcmp(test_mac, result_mac, ETH_ALEN)) - err = FM10K_ERR_INVALID_VALUE; - if (!err && test_vlan != result_vlan) - err = FM10K_ERR_INVALID_VALUE; - if (err) - goto report_result; - } - if (!!results[FM10K_TEST_MSG_U8]) { - err = fm10k_tlv_attr_get_u8(results[FM10K_TEST_MSG_U8], - &result_u8); - if (!err && test_u8 != result_u8) - err = FM10K_ERR_INVALID_VALUE; - if (err) - goto report_result; - } - if (!!results[FM10K_TEST_MSG_U16]) { - err = fm10k_tlv_attr_get_u16(results[FM10K_TEST_MSG_U16], - &result_u16); - if (!err && test_u16 != result_u16) - err = FM10K_ERR_INVALID_VALUE; - if (err) - goto report_result; - } - if (!!results[FM10K_TEST_MSG_U32]) { - err = fm10k_tlv_attr_get_u32(results[FM10K_TEST_MSG_U32], - &result_u32); - if (!err && test_u32 != result_u32) - err = FM10K_ERR_INVALID_VALUE; - if (err) - goto report_result; - } - if (!!results[FM10K_TEST_MSG_U64]) { - err = fm10k_tlv_attr_get_u64(results[FM10K_TEST_MSG_U64], - &result_u64); - if (!err && test_u64 != result_u64) - err = FM10K_ERR_INVALID_VALUE; - if (err) - goto report_result; - } - if (!!results[FM10K_TEST_MSG_S8]) { - err = fm10k_tlv_attr_get_s8(results[FM10K_TEST_MSG_S8], - &result_s8); - if (!err && test_s8 != result_s8) - err = FM10K_ERR_INVALID_VALUE; - if (err) - goto report_result; - } - if (!!results[FM10K_TEST_MSG_S16]) { - err = fm10k_tlv_attr_get_s16(results[FM10K_TEST_MSG_S16], - &result_s16); - if (!err && test_s16 != result_s16) - err = FM10K_ERR_INVALID_VALUE; - if (err) - goto report_result; - } - if (!!results[FM10K_TEST_MSG_S32]) { - err = fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_S32], - &result_s32); - if (!err && test_s32 != result_s32) - err = FM10K_ERR_INVALID_VALUE; - if (err) - goto report_result; - } - if (!!results[FM10K_TEST_MSG_S64]) { - err = fm10k_tlv_attr_get_s64(results[FM10K_TEST_MSG_S64], - &result_s64); - if (!err && test_s64 != result_s64) - err = FM10K_ERR_INVALID_VALUE; - if (err) - goto report_result; - } - if (!!results[FM10K_TEST_MSG_LE_STRUCT]) { - err = fm10k_tlv_attr_get_le_struct( - results[FM10K_TEST_MSG_LE_STRUCT], - result_le, - sizeof(result_le)); - if (!err && memcmp(test_le, result_le, sizeof(test_le))) - err = FM10K_ERR_INVALID_VALUE; - if (err) - goto report_result; - } - - if (!!results[FM10K_TEST_MSG_NESTED]) { - /* clear any pointers */ - memset(nest_results, 0, sizeof(nest_results)); - - /* parse the nested attributes into the nest results list */ - err = fm10k_tlv_attr_parse(results[FM10K_TEST_MSG_NESTED], - nest_results, - fm10k_tlv_msg_test_attr); - if (err) - goto report_result; - - /* loop back through to the start */ - results = nest_results; - goto parse_nested; - } - -report_result: - /* generate reply with test result */ - fm10k_tlv_msg_init(reply, FM10K_TLV_MSG_ID_TEST); - fm10k_tlv_attr_put_s32(reply, FM10K_TEST_MSG_RESULT, err); - - /* load onto outgoing mailbox */ - return mbx->ops.enqueue_tx(hw, mbx, reply); -} diff --git a/lib/librte_pmd_fm10k/base/fm10k_tlv.h b/lib/librte_pmd_fm10k/base/fm10k_tlv.h deleted file mode 100644 index ad97236..0000000 --- a/lib/librte_pmd_fm10k/base/fm10k_tlv.h +++ /dev/null @@ -1,199 +0,0 @@ -/******************************************************************************* - -Copyright (c) 2013 - 2015, 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. - -***************************************************************************/ - -#ifndef _FM10K_TLV_H_ -#define _FM10K_TLV_H_ - -/* forward declaration */ -struct fm10k_msg_data; - -#include "fm10k_type.h" - -/* Message / Argument header format - * 3 2 1 0 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Length | Flags | Type / ID | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * The message header format described here is used for messages that are - * passed between the PF and the VF. To allow for messages larger then - * mailbox size we will provide a message with the above header and it - * will be segmented and transported to the mailbox to the other side where - * it is reassembled. It contains the following fields: - * Len: Length of the message in bytes excluding the message header - * Flags: TBD - * Rule: These will be the message/argument types we pass - */ -/* message data header */ -#define FM10K_TLV_ID_SHIFT 0 -#define FM10K_TLV_ID_SIZE 16 -#define FM10K_TLV_ID_MASK ((1u << FM10K_TLV_ID_SIZE) - 1) -#define FM10K_TLV_FLAGS_SHIFT 16 -#define FM10K_TLV_FLAGS_MSG 0x1 -#define FM10K_TLV_FLAGS_SIZE 4 -#define FM10K_TLV_LEN_SHIFT 20 -#define FM10K_TLV_LEN_SIZE 12 - -#define FM10K_TLV_HDR_LEN 4ul -#define FM10K_TLV_LEN_ALIGN_MASK \ - ((FM10K_TLV_HDR_LEN - 1) << FM10K_TLV_LEN_SHIFT) -#define FM10K_TLV_LEN_ALIGN(tlv) \ - (((tlv) + FM10K_TLV_LEN_ALIGN_MASK) & ~FM10K_TLV_LEN_ALIGN_MASK) -#define FM10K_TLV_DWORD_LEN(tlv) \ - ((u16)((FM10K_TLV_LEN_ALIGN(tlv)) >> (FM10K_TLV_LEN_SHIFT + 2)) + 1) - -#define FM10K_TLV_RESULTS_MAX 32 - -enum fm10k_tlv_type { - FM10K_TLV_NULL_STRING, - FM10K_TLV_MAC_ADDR, - FM10K_TLV_BOOL, - FM10K_TLV_UNSIGNED, - FM10K_TLV_SIGNED, - FM10K_TLV_LE_STRUCT, - FM10K_TLV_NESTED, - FM10K_TLV_MAX_TYPE -}; - -#define FM10K_TLV_ERROR (~0u) - -struct fm10k_tlv_attr { - unsigned int id; - enum fm10k_tlv_type type; - u16 len; -}; - -#define FM10K_TLV_ATTR_NULL_STRING(id, len) { id, FM10K_TLV_NULL_STRING, len } -#define FM10K_TLV_ATTR_MAC_ADDR(id) { id, FM10K_TLV_MAC_ADDR, 6 } -#define FM10K_TLV_ATTR_BOOL(id) { id, FM10K_TLV_BOOL, 0 } -#define FM10K_TLV_ATTR_U8(id) { id, FM10K_TLV_UNSIGNED, 1 } -#define FM10K_TLV_ATTR_U16(id) { id, FM10K_TLV_UNSIGNED, 2 } -#define FM10K_TLV_ATTR_U32(id) { id, FM10K_TLV_UNSIGNED, 4 } -#define FM10K_TLV_ATTR_U64(id) { id, FM10K_TLV_UNSIGNED, 8 } -#define FM10K_TLV_ATTR_S8(id) { id, FM10K_TLV_SIGNED, 1 } -#define FM10K_TLV_ATTR_S16(id) { id, FM10K_TLV_SIGNED, 2 } -#define FM10K_TLV_ATTR_S32(id) { id, FM10K_TLV_SIGNED, 4 } -#define FM10K_TLV_ATTR_S64(id) { id, FM10K_TLV_SIGNED, 8 } -#define FM10K_TLV_ATTR_LE_STRUCT(id, len) { id, FM10K_TLV_LE_STRUCT, len } -#define FM10K_TLV_ATTR_NESTED(id) { id, FM10K_TLV_NESTED } -#define FM10K_TLV_ATTR_LAST { FM10K_TLV_ERROR } - -struct fm10k_msg_data { - unsigned int id; - const struct fm10k_tlv_attr *attr; - s32 (*func)(struct fm10k_hw *, u32 **, - struct fm10k_mbx_info *); -}; - -#define FM10K_MSG_HANDLER(id, attr, func) { id, attr, func } - -s32 fm10k_tlv_msg_init(u32 *, u16); -s32 fm10k_tlv_attr_put_null_string(u32 *, u16, const unsigned char *); -s32 fm10k_tlv_attr_get_null_string(u32 *, unsigned char *); -s32 fm10k_tlv_attr_put_mac_vlan(u32 *, u16, const u8 *, u16); -s32 fm10k_tlv_attr_get_mac_vlan(u32 *, u8 *, u16 *); -s32 fm10k_tlv_attr_put_bool(u32 *, u16); -s32 fm10k_tlv_attr_put_value(u32 *, u16, s64, u32); -#define fm10k_tlv_attr_put_u8(msg, attr_id, val) \ - fm10k_tlv_attr_put_value(msg, attr_id, val, 1) -#define fm10k_tlv_attr_put_u16(msg, attr_id, val) \ - fm10k_tlv_attr_put_value(msg, attr_id, val, 2) -#define fm10k_tlv_attr_put_u32(msg, attr_id, val) \ - fm10k_tlv_attr_put_value(msg, attr_id, val, 4) -#define fm10k_tlv_attr_put_u64(msg, attr_id, val) \ - fm10k_tlv_attr_put_value(msg, attr_id, val, 8) -#define fm10k_tlv_attr_put_s8(msg, attr_id, val) \ - fm10k_tlv_attr_put_value(msg, attr_id, val, 1) -#define fm10k_tlv_attr_put_s16(msg, attr_id, val) \ - fm10k_tlv_attr_put_value(msg, attr_id, val, 2) -#define fm10k_tlv_attr_put_s32(msg, attr_id, val) \ - fm10k_tlv_attr_put_value(msg, attr_id, val, 4) -#define fm10k_tlv_attr_put_s64(msg, attr_id, val) \ - fm10k_tlv_attr_put_value(msg, attr_id, val, 8) -s32 fm10k_tlv_attr_get_value(u32 *, void *, u32); -#define fm10k_tlv_attr_get_u8(attr, ptr) \ - fm10k_tlv_attr_get_value(attr, ptr, sizeof(u8)) -#define fm10k_tlv_attr_get_u16(attr, ptr) \ - fm10k_tlv_attr_get_value(attr, ptr, sizeof(u16)) -#define fm10k_tlv_attr_get_u32(attr, ptr) \ - fm10k_tlv_attr_get_value(attr, ptr, sizeof(u32)) -#define fm10k_tlv_attr_get_u64(attr, ptr) \ - fm10k_tlv_attr_get_value(attr, ptr, sizeof(u64)) -#define fm10k_tlv_attr_get_s8(attr, ptr) \ - fm10k_tlv_attr_get_value(attr, ptr, sizeof(s8)) -#define fm10k_tlv_attr_get_s16(attr, ptr) \ - fm10k_tlv_attr_get_value(attr, ptr, sizeof(s16)) -#define fm10k_tlv_attr_get_s32(attr, ptr) \ - fm10k_tlv_attr_get_value(attr, ptr, sizeof(s32)) -#define fm10k_tlv_attr_get_s64(attr, ptr) \ - fm10k_tlv_attr_get_value(attr, ptr, sizeof(s64)) -s32 fm10k_tlv_attr_put_le_struct(u32 *, u16, const void *, u32); -s32 fm10k_tlv_attr_get_le_struct(u32 *, void *, u32); -u32 *fm10k_tlv_attr_nest_start(u32 *, u16); -s32 fm10k_tlv_attr_nest_stop(u32 *); -s32 fm10k_tlv_attr_parse(u32 *, u32 **, const struct fm10k_tlv_attr *); -s32 fm10k_tlv_msg_parse(struct fm10k_hw *, u32 *, struct fm10k_mbx_info *, - const struct fm10k_msg_data *); -s32 fm10k_tlv_msg_error(struct fm10k_hw *hw, u32 **results, - struct fm10k_mbx_info *); - -#define FM10K_TLV_MSG_ID_TEST 0 - -enum fm10k_tlv_test_attr_id { - FM10K_TEST_MSG_UNSET, - FM10K_TEST_MSG_STRING, - FM10K_TEST_MSG_MAC_ADDR, - FM10K_TEST_MSG_U8, - FM10K_TEST_MSG_U16, - FM10K_TEST_MSG_U32, - FM10K_TEST_MSG_U64, - FM10K_TEST_MSG_S8, - FM10K_TEST_MSG_S16, - FM10K_TEST_MSG_S32, - FM10K_TEST_MSG_S64, - FM10K_TEST_MSG_LE_STRUCT, - FM10K_TEST_MSG_NESTED, - FM10K_TEST_MSG_RESULT, - FM10K_TEST_MSG_MAX -}; - -extern const struct fm10k_tlv_attr fm10k_tlv_msg_test_attr[]; -void fm10k_tlv_msg_test_create(u32 *, u32); -s32 fm10k_tlv_msg_test(struct fm10k_hw *, u32 **, struct fm10k_mbx_info *); - -#define FM10K_TLV_MSG_TEST_HANDLER(func) \ - FM10K_MSG_HANDLER(FM10K_TLV_MSG_ID_TEST, fm10k_tlv_msg_test_attr, func) -#define FM10K_TLV_MSG_ERROR_HANDLER(func) \ - FM10K_MSG_HANDLER(FM10K_TLV_ERROR, NULL, func) -#endif /* _FM10K_MSG_H_ */ diff --git a/lib/librte_pmd_fm10k/base/fm10k_type.h b/lib/librte_pmd_fm10k/base/fm10k_type.h deleted file mode 100644 index 534fab4..0000000 --- a/lib/librte_pmd_fm10k/base/fm10k_type.h +++ /dev/null @@ -1,937 +0,0 @@ -/******************************************************************************* - -Copyright (c) 2013 - 2015, 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. - -***************************************************************************/ - -#ifndef _FM10K_TYPE_H_ -#define _FM10K_TYPE_H_ - -/* forward declaration */ -struct fm10k_hw; - -#include "fm10k_osdep.h" -#include "fm10k_mbx.h" - -#define FM10K_INTEL_VENDOR_ID 0x8086 -#define FM10K_DEV_ID_PF 0x15A4 -#define FM10K_DEV_ID_VF 0x15A5 - -#define FM10K_MAX_QUEUES 256 -#define FM10K_MAX_QUEUES_PF 128 -#define FM10K_MAX_QUEUES_POOL 16 - -#define FM10K_48_BIT_MASK 0x0000FFFFFFFFFFFFull -#define FM10K_STAT_VALID 0x80000000 - -/* PCI Bus Info */ -#define FM10K_PCIE_LINK_CAP 0x7C -#define FM10K_PCIE_LINK_STATUS 0x82 -#define FM10K_PCIE_LINK_WIDTH 0x3F0 -#define FM10K_PCIE_LINK_WIDTH_1 0x10 -#define FM10K_PCIE_LINK_WIDTH_2 0x20 -#define FM10K_PCIE_LINK_WIDTH_4 0x40 -#define FM10K_PCIE_LINK_WIDTH_8 0x80 -#define FM10K_PCIE_LINK_SPEED 0xF -#define FM10K_PCIE_LINK_SPEED_2500 0x1 -#define FM10K_PCIE_LINK_SPEED_5000 0x2 -#define FM10K_PCIE_LINK_SPEED_8000 0x3 - -/* PCIe payload size */ -#define FM10K_PCIE_DEV_CAP 0x74 -#define FM10K_PCIE_DEV_CAP_PAYLOAD 0x07 -#define FM10K_PCIE_DEV_CAP_PAYLOAD_128 0x00 -#define FM10K_PCIE_DEV_CAP_PAYLOAD_256 0x01 -#define FM10K_PCIE_DEV_CAP_PAYLOAD_512 0x02 -#define FM10K_PCIE_DEV_CTRL 0x78 -#define FM10K_PCIE_DEV_CTRL_PAYLOAD 0xE0 -#define FM10K_PCIE_DEV_CTRL_PAYLOAD_128 0x00 -#define FM10K_PCIE_DEV_CTRL_PAYLOAD_256 0x20 -#define FM10K_PCIE_DEV_CTRL_PAYLOAD_512 0x40 - -/* PCIe MSI-X Capability info */ -#define FM10K_PCI_MSIX_MSG_CTRL 0xB2 -#define FM10K_PCI_MSIX_MSG_CTRL_TBL_SZ_MASK 0x7FF -#define FM10K_MAX_MSIX_VECTORS 256 -#define FM10K_MAX_VECTORS_PF 256 -#define FM10K_MAX_VECTORS_POOL 32 - -/* PCIe SR-IOV Info */ -#define FM10K_PCIE_SRIOV_CTRL 0x190 -#define FM10K_PCIE_SRIOV_CTRL_VFARI 0x10 - -#define FM10K_SUCCESS 0 -#define FM10K_ERR_DEVICE_NOT_SUPPORTED -1 -#define FM10K_ERR_PARAM -2 -#define FM10K_ERR_NO_RESOURCES -3 -#define FM10K_ERR_REQUESTS_PENDING -4 -#define FM10K_ERR_RESET_REQUESTED -5 -#define FM10K_ERR_DMA_PENDING -6 -#define FM10K_ERR_RESET_FAILED -7 -#define FM10K_ERR_INVALID_MAC_ADDR -8 -#define FM10K_ERR_INVALID_VALUE -9 -#define FM10K_NOT_IMPLEMENTED 0x7FFFFFFF - -#define UNREFERENCED_XPARAMETER -#define UNREFERENCED_1PARAMETER(_p) (_p) -#define UNREFERENCED_2PARAMETER(_p, _q) do { (_p); (_q); } while (0) -#define UNREFERENCED_3PARAMETER(_p, _q, _r) do { (_p); (_q); (_r); } while (0) - -/* Start of PF registers */ -#define FM10K_CTRL 0x0000 -#define FM10K_CTRL_BAR4_ALLOWED 0x00000004 - -#define FM10K_CTRL_EXT 0x0001 -#define FM10K_CTRL_EXT_NS_DIS 0x00000001 -#define FM10K_CTRL_EXT_RO_DIS 0x00000002 -#define FM10K_CTRL_EXT_SWITCH_LOOPBACK 0x00000004 -#define FM10K_EXVET 0x0002 -#define FM10K_EXVET_ETHERTYPE_MASK 0x000000FF -#define FM10K_EXVET_TAG_SIZE_SHIFT 16 -#define FM10K_EXVET_AFTER_VLAN 0x00040000 -#define FM10K_GCR 0x0003 -#define FM10K_FACTPS 0x0004 -#define FM10K_GCR_EXT 0x0005 - -/* Interrupt control registers */ -#define FM10K_EICR 0x0006 -#define FM10K_EICR_PCA_FAULT 0x00000001 -#define FM10K_EICR_THI_FAULT 0x00000004 -#define FM10K_EICR_FUM_FAULT 0x00000020 -#define FM10K_EICR_FAULT_MASK 0x0000003F -#define FM10K_EICR_MAILBOX 0x00000040 -#define FM10K_EICR_SWITCHREADY 0x00000080 -#define FM10K_EICR_SWITCHNOTREADY 0x00000100 -#define FM10K_EICR_SWITCHINTERRUPT 0x00000200 -#define FM10K_EICR_SRAMERROR 0x00000400 -#define FM10K_EICR_VFLR 0x00000800 -#define FM10K_EICR_MAXHOLDTIME 0x00001000 -#define FM10K_EIMR 0x0007 -#define FM10K_EIMR_PCA_FAULT 0x00000001 -#define FM10K_EIMR_THI_FAULT 0x00000010 -#define FM10K_EIMR_FUM_FAULT 0x00000400 -#define FM10K_EIMR_MAILBOX 0x00001000 -#define FM10K_EIMR_SWITCHREADY 0x00004000 -#define FM10K_EIMR_SWITCHNOTREADY 0x00010000 -#define FM10K_EIMR_SWITCHINTERRUPT 0x00040000 -#define FM10K_EIMR_SRAMERROR 0x00100000 -#define FM10K_EIMR_VFLR 0x00400000 -#define FM10K_EIMR_MAXHOLDTIME 0x01000000 -#define FM10K_EIMR_ALL 0x55555555 -#define FM10K_EIMR_DISABLE(NAME) ((FM10K_EIMR_ ## NAME) << 0) -#define FM10K_EIMR_ENABLE(NAME) ((FM10K_EIMR_ ## NAME) << 1) -#define FM10K_FAULT_ADDR_LO 0x0 -#define FM10K_FAULT_ADDR_HI 0x1 -#define FM10K_FAULT_SPECINFO 0x2 -#define FM10K_FAULT_FUNC 0x3 -#define FM10K_FAULT_SIZE 0x4 -#define FM10K_FAULT_FUNC_VALID 0x00008000 -#define FM10K_FAULT_FUNC_PF 0x00004000 -#define FM10K_FAULT_FUNC_VF_MASK 0x00003F00 -#define FM10K_FAULT_FUNC_VF_SHIFT 8 -#define FM10K_FAULT_FUNC_TYPE_MASK 0x000000FF - -#define FM10K_PCA_FAULT 0x0008 -#define FM10K_THI_FAULT 0x0010 -#define FM10K_FUM_FAULT 0x001C - -/* Rx queue timeout indicator */ -#define FM10K_MAXHOLDQ(_n) ((_n) + 0x0020) - -/* Switch Manager info */ -#define FM10K_SM_AREA(_n) ((_n) + 0x0028) - -/* GLORT mapping registers */ -#define FM10K_DGLORTMAP(_n) ((_n) + 0x0030) -#define FM10K_DGLORT_COUNT 8 -#define FM10K_DGLORTMAP_MASK_SHIFT 16 -#define FM10K_DGLORTMAP_ANY 0x00000000 -#define FM10K_DGLORTMAP_NONE 0x0000FFFF -#define FM10K_DGLORTMAP_ZERO 0xFFFF0000 -#define FM10K_DGLORTDEC(_n) ((_n) + 0x0038) -#define FM10K_DGLORTDEC_VSILENGTH_SHIFT 4 -#define FM10K_DGLORTDEC_VSIBASE_SHIFT 7 -#define FM10K_DGLORTDEC_PCLENGTH_SHIFT 14 -#define FM10K_DGLORTDEC_QBASE_SHIFT 16 -#define FM10K_DGLORTDEC_RSSLENGTH_SHIFT 24 -#define FM10K_DGLORTDEC_INNERRSS_ENABLE 0x08000000 -#define FM10K_TUNNEL_CFG 0x0040 -#define FM10K_TUNNEL_CFG_NVGRE_SHIFT 16 -#define FM10K_TUNNEL_CFG_GENEVE 0x0041 -#define FM10K_SWPRI_MAP(_n) ((_n) + 0x0050) -#define FM10K_SWPRI_MAX 16 -#define FM10K_RSSRK(_n, _m) (((_n) * 0x10) + (_m) + 0x0800) -#define FM10K_RSSRK_SIZE 10 -#define FM10K_RSSRK_ENTRIES_PER_REG 4 -#define FM10K_RETA(_n, _m) (((_n) * 0x20) + (_m) + 0x1000) -#define FM10K_RETA_SIZE 32 -#define FM10K_RETA_ENTRIES_PER_REG 4 -#define FM10K_MAX_RSS_INDICES 128 - -/* Rate limiting registers */ -#define FM10K_TC_CREDIT(_n) ((_n) + 0x2000) -#define FM10K_TC_CREDIT_CREDIT_MASK 0x001FFFFF -#define FM10K_TC_MAXCREDIT(_n) ((_n) + 0x2040) -#define FM10K_TC_MAXCREDIT_64K 0x00010000 -#define FM10K_TC_RATE(_n) ((_n) + 0x2080) -#define FM10K_TC_RATE_QUANTA_MASK 0x0000FFFF -#define FM10K_TC_RATE_INTERVAL_4US_GEN1 0x00020000 -#define FM10K_TC_RATE_INTERVAL_4US_GEN2 0x00040000 -#define FM10K_TC_RATE_INTERVAL_4US_GEN3 0x00080000 -#define FM10K_TC_RATE_STATUS 0x20C0 -#define FM10K_PAUSE 0x20C2 - -/* DMA control registers */ -#define FM10K_DMA_CTRL 0x20C3 -#define FM10K_DMA_CTRL_TX_ENABLE 0x00000001 -#define FM10K_DMA_CTRL_TX_HOST_PENDING 0x00000002 -#define FM10K_DMA_CTRL_TX_DATA 0x00000004 -#define FM10K_DMA_CTRL_TX_ACTIVE 0x00000008 -#define FM10K_DMA_CTRL_RX_ENABLE 0x00000010 -#define FM10K_DMA_CTRL_RX_HOST_PENDING 0x00000020 -#define FM10K_DMA_CTRL_RX_DATA 0x00000040 -#define FM10K_DMA_CTRL_RX_ACTIVE 0x00000080 -#define FM10K_DMA_CTRL_RX_DESC_SIZE 0x00000100 -#define FM10K_DMA_CTRL_MINMSS_SHIFT 9 -#define FM10K_DMA_CTRL_MINMSS_64 0x00008000 -#define FM10K_DMA_CTRL_MAX_HOLD_TIME_SHIFT 23 -#define FM10K_DMA_CTRL_MAX_HOLD_1US_GEN3 0x04800000 -#define FM10K_DMA_CTRL_MAX_HOLD_1US_GEN2 0x04000000 -#define FM10K_DMA_CTRL_MAX_HOLD_1US_GEN1 0x03800000 -#define FM10K_DMA_CTRL_DATAPATH_RESET 0x20000000 -#define FM10K_DMA_CTRL_MAXNUMOFQ_MASK 0xC0000000 -#define FM10K_DMA_CTRL_32_DESC 0x00000000 -#define FM10K_DMA_CTRL_64_DESC 0x40000000 -#define FM10K_DMA_CTRL_128_DESC 0x80000000 - -#define FM10K_DMA_CTRL2 0x20C4 -#define FM10K_DMA_CTRL2_TX_FRAME_SPACING_SHIFT 5 -#define FM10K_DMA_CTRL2_SWITCH_READY 0x00002000 -#define FM10K_DMA_CTRL2_RX_DESC_READ_PRIO_SHIFT 14 -#define FM10K_DMA_CTRL2_TX_DESC_READ_PRIO_SHIFT 17 -#define FM10K_DMA_CTRL2_TX_DATA_READ_PRIO_SHIFT 20 - -/* TSO flags configuration - * First packet contains all flags except for fin and psh - * Middle packet contains only urg and ack - * Last packet contains urg, ack, fin, and psh - */ -#define FM10K_TSO_FLAGS_LOW 0x00300FF6 -#define FM10K_TSO_FLAGS_HI 0x00000039 -#define FM10K_DTXTCPFLGL 0x20C5 -#define FM10K_DTXTCPFLGH 0x20C6 - -#define FM10K_TPH_CTRL 0x20C7 -#define FM10K_TPH_CTRL_DISABLE_READ_HINT 0x00000080 -#define FM10K_MRQC(_n) ((_n) + 0x2100) -#define FM10K_MRQC_TCP_IPV4 0x00000001 -#define FM10K_MRQC_IPV4 0x00000002 -#define FM10K_MRQC_IPV6 0x00000010 -#define FM10K_MRQC_TCP_IPV6 0x00000020 -#define FM10K_MRQC_UDP_IPV4 0x00000040 -#define FM10K_MRQC_UDP_IPV6 0x00000080 - -#define FM10K_TQMAP(_n) ((_n) + 0x2800) -#define FM10K_TQMAP_TABLE_SIZE 2048 -#define FM10K_RQMAP(_n) ((_n) + 0x3000) -#define FM10K_RQMAP_TABLE_SIZE 2048 - -/* Hardware Statistics */ -#define FM10K_STATS_TIMEOUT 0x3800 -#define FM10K_STATS_UR 0x3801 -#define FM10K_STATS_CA 0x3802 -#define FM10K_STATS_UM 0x3803 -#define FM10K_STATS_XEC 0x3804 -#define FM10K_STATS_VLAN_DROP 0x3805 -#define FM10K_STATS_LOOPBACK_DROP 0x3806 -#define FM10K_STATS_NODESC_DROP 0x3807 - -/* Timesync registers */ -#define FM10K_RRTIME_CFG 0x3808 -#define FM10K_RRTIME_LIMIT(_n) ((_n) + 0x380C) -#define FM10K_RRTIME_COUNT(_n) ((_n) + 0x3810) -#define FM10K_SYSTIME 0x3814 -#define FM10K_SYSTIME0 0x3816 -#define FM10K_SYSTIME_CFG 0x3818 -#define FM10K_SYSTIME_CFG_STEP_MASK 0x0000000F - -/* PCIe state registers */ -#define FM10K_PFVFBME(_n) ((_n) + 0x381A) -#define FM10K_PHYADDR 0x381C - -/* Rx ring registers */ -#define FM10K_RDBAL(_n) ((0x40 * (_n)) + 0x4000) -#define FM10K_RDBAH(_n) ((0x40 * (_n)) + 0x4001) -#define FM10K_RDLEN(_n) ((0x40 * (_n)) + 0x4002) -#define FM10K_TPH_RXCTRL(_n) ((0x40 * (_n)) + 0x4003) -#define FM10K_TPH_RXCTRL_DESC_TPHEN 0x00000020 -#define FM10K_TPH_RXCTRL_HDR_TPHEN 0x00000040 -#define FM10K_TPH_RXCTRL_DATA_TPHEN 0x00000080 -#define FM10K_TPH_RXCTRL_DESC_RROEN 0x00000200 -#define FM10K_TPH_RXCTRL_DATA_WROEN 0x00002000 -#define FM10K_TPH_RXCTRL_HDR_WROEN 0x00008000 -#define FM10K_RDH(_n) ((0x40 * (_n)) + 0x4004) -#define FM10K_RDT(_n) ((0x40 * (_n)) + 0x4005) -#define FM10K_RXQCTL(_n) ((0x40 * (_n)) + 0x4006) -#define FM10K_RXQCTL_ENABLE 0x00000001 -#define FM10K_RXQCTL_PF 0x000000FC -#define FM10K_RXQCTL_VF_SHIFT 2 -#define FM10K_RXQCTL_VF 0x00000100 -#define FM10K_RXQCTL_ID_MASK (FM10K_RXQCTL_PF | FM10K_RXQCTL_VF) -#define FM10K_RXDCTL(_n) ((0x40 * (_n)) + 0x4007) -#define FM10K_RXDCTL_WRITE_BACK_MIN_DELAY 0x00000001 -#define FM10K_RXDCTL_WRITE_BACK_IMM 0x00000100 -#define FM10K_RXDCTL_DROP_ON_EMPTY 0x00000200 -#define FM10K_RXINT(_n) ((0x40 * (_n)) + 0x4008) -#define FM10K_RXINT_TIMER_SHIFT 8 -#define FM10K_SRRCTL(_n) ((0x40 * (_n)) + 0x4009) -#define FM10K_SRRCTL_BSIZEPKT_SHIFT 8 /* shift _right_ */ -#define FM10K_SRRCTL_BSIZEHDR_SHIFT 2 /* shift _left_ */ -#define FM10K_SRRCTL_BSIZEHDR_MASK 0x00003F00 -#define FM10K_SRRCTL_DESCTYPE_HDR_SPLIT 0x00004000 -#define FM10K_SRRCTL_DESCTYPE_SIZE_SPLIT 0x00008000 -#define FM10K_SRRCTL_PSRTYPE_INNER_TCPHDR 0x00010000 -#define FM10K_SRRCTL_PSRTYPE_INNER_UDPHDR 0x00020000 -#define FM10K_SRRCTL_PSRTYPE_INNER_IPV4HDR 0x00040000 -#define FM10K_SRRCTL_PSRTYPE_INNER_IPV6HDR 0x00080000 -#define FM10K_SRRCTL_PSRTYPE_INNER_L2HDR 0x00100000 -#define FM10K_SRRCTL_PSRTYPE_ENCAPHDR 0x00200000 -#define FM10K_SRRCTL_PSRTYPE_TCPHDR 0x00400000 -#define FM10K_SRRCTL_PSRTYPE_UDPHDR 0x00800000 -#define FM10K_SRRCTL_PSRTYPE_IPV4HDR 0x01000000 -#define FM10K_SRRCTL_PSRTYPE_IPV6HDR 0x02000000 -#define FM10K_SRRCTL_PSRTYPE_L2HDR 0x04000000 -#define FM10K_SRRCTL_LOOPBACK_SUPPRESS 0x40000000 -#define FM10K_SRRCTL_BUFFER_CHAINING_EN 0x80000000 - -/* Rx Statistics */ -#define FM10K_QPRC(_n) ((0x40 * (_n)) + 0x400A) -#define FM10K_QPRDC(_n) ((0x40 * (_n)) + 0x400B) -#define FM10K_QBRC_L(_n) ((0x40 * (_n)) + 0x400C) -#define FM10K_QBRC_H(_n) ((0x40 * (_n)) + 0x400D) - -/* Rx GLORT register */ -#define FM10K_RX_SGLORT(_n) ((0x40 * (_n)) + 0x400E) - -/* Tx ring registers */ -#define FM10K_TDBAL(_n) ((0x40 * (_n)) + 0x8000) -#define FM10K_TDBAH(_n) ((0x40 * (_n)) + 0x8001) -#define FM10K_TDLEN(_n) ((0x40 * (_n)) + 0x8002) -#define FM10K_TPH_TXCTRL(_n) ((0x40 * (_n)) + 0x8003) -#define FM10K_TPH_TXCTRL_DESC_TPHEN 0x00000020 -#define FM10K_TPH_TXCTRL_DESC_RROEN 0x00000200 -#define FM10K_TPH_TXCTRL_DESC_WROEN 0x00000800 -#define FM10K_TPH_TXCTRL_DATA_RROEN 0x00002000 -#define FM10K_TDH(_n) ((0x40 * (_n)) + 0x8004) -#define FM10K_TDT(_n) ((0x40 * (_n)) + 0x8005) -#define FM10K_TXDCTL(_n) ((0x40 * (_n)) + 0x8006) -#define FM10K_TXDCTL_ENABLE 0x00004000 -#define FM10K_TXDCTL_MAX_TIME_SHIFT 16 -#define FM10K_TXDCTL_PUSH_DESC 0x10000000 -#define FM10K_TXQCTL(_n) ((0x40 * (_n)) + 0x8007) -#define FM10K_TXQCTL_PF 0x0000003F -#define FM10K_TXQCTL_VF 0x00000040 -#define FM10K_TXQCTL_ID_MASK (FM10K_TXQCTL_PF | FM10K_TXQCTL_VF) -#define FM10K_TXQCTL_PC_SHIFT 7 -#define FM10K_TXQCTL_PC_MASK 0x00000380 -#define FM10K_TXQCTL_TC_SHIFT 10 -#define FM10K_TXQCTL_TC_MASK 0x0000FC00 -#define FM10K_TXQCTL_VID_SHIFT 16 -#define FM10K_TXQCTL_VID_MASK 0x0FFF0000 -#define FM10K_TXQCTL_UNLIMITED_BW 0x10000000 -#define FM10K_TXQCTL_PUSHMODEDIS 0x20000000 -#define FM10K_TXINT(_n) ((0x40 * (_n)) + 0x8008) -#define FM10K_TXINT_TIMER_SHIFT 8 - -/* Tx Statistics */ -#define FM10K_QPTC(_n) ((0x40 * (_n)) + 0x8009) -#define FM10K_QBTC_L(_n) ((0x40 * (_n)) + 0x800A) -#define FM10K_QBTC_H(_n) ((0x40 * (_n)) + 0x800B) - -/* Tx Push registers */ -#define FM10K_TQDLOC(_n) ((0x40 * (_n)) + 0x800C) -#define FM10K_TQDLOC_BASE_32_DESC 0x08 -#define FM10K_TQDLOC_BASE_64_DESC 0x10 -#define FM10K_TQDLOC_BASE_128_DESC 0x20 -#define FM10K_TQDLOC_SIZE_32_DESC 0x00050000 -#define FM10K_TQDLOC_SIZE_64_DESC 0x00060000 -#define FM10K_TQDLOC_SIZE_128_DESC 0x00070000 -#define FM10K_TQDLOC_SIZE_SHIFT 16 -#define FM10K_TX_DCACHE(_n, _m) ((0x400 * (_n)) + (0x4 * (_m)) + 0x40000) - -/* Tx GLORT registers */ -#define FM10K_TX_SGLORT(_n) ((0x40 * (_n)) + 0x800D) -#define FM10K_PFVTCTL(_n) ((0x40 * (_n)) + 0x800E) -#define FM10K_PFVTCTL_FTAG_DESC_ENABLE 0x00000001 - -/* Interrupt moderation and control registers */ -#define FM10K_PBACL(_n) ((_n) + 0x10000) -#define FM10K_INT_MAP(_n) ((_n) + 0x10080) -#define FM10K_INT_MAP_TIMER0 0x00000000 -#define FM10K_INT_MAP_TIMER1 0x00000100 -#define FM10K_INT_MAP_IMMEDIATE 0x00000200 -#define FM10K_INT_MAP_DISABLE 0x00000300 -#define FM10K_MSIX_VECTOR_ADDR_LO(_n) ((0x4 * (_n)) + 0x11000) -#define FM10K_MSIX_VECTOR_ADDR_HI(_n) ((0x4 * (_n)) + 0x11001) -#define FM10K_MSIX_VECTOR_DATA(_n) ((0x4 * (_n)) + 0x11002) -#define FM10K_MSIX_VECTOR_MASK(_n) ((0x4 * (_n)) + 0x11003) -#define FM10K_INT_CTRL 0x12000 -#define FM10K_INT_CTRL_ENABLEMODERATOR 0x00000400 -#define FM10K_ITR(_n) ((_n) + 0x12400) -#define FM10K_ITR_INTERVAL1_SHIFT 12 -#define FM10K_ITR_TIMER0_EXPIRED 0x01000000 -#define FM10K_ITR_TIMER1_EXPIRED 0x02000000 -#define FM10K_ITR_PENDING0 0x04000000 -#define FM10K_ITR_PENDING1 0x08000000 -#define FM10K_ITR_PENDING2 0x10000000 -#define FM10K_ITR_AUTOMASK 0x20000000 -#define FM10K_ITR_MASK_SET 0x40000000 -#define FM10K_ITR_MASK_CLEAR 0x80000000 -#define FM10K_ITR2(_n) ((0x2 * (_n)) + 0x12800) -#define FM10K_ITR2_LP(_n) ((0x2 * (_n)) + 0x12801) -#define FM10K_ITR_REG_COUNT 768 -#define FM10K_ITR_REG_COUNT_PF 256 - -/* Switch manager interrupt registers */ -#define FM10K_IP 0x13000 -#define FM10K_IP_HOT_RESET 0x00000001 -#define FM10K_IP_DEVICE_STATE_CHANGE 0x00000002 -#define FM10K_IP_MAILBOX 0x00000004 -#define FM10K_IP_VPD_REQUEST 0x00000008 -#define FM10K_IP_SRAMERROR 0x00000010 -#define FM10K_IP_PFLR 0x00000020 -#define FM10K_IP_DATAPATHRESET 0x00000040 -#define FM10K_IP_OUTOFRESET 0x00000080 -#define FM10K_IP_NOTINRESET 0x00000100 -#define FM10K_IP_TIMEOUT 0x00000200 -#define FM10K_IP_VFLR 0x00000400 -#define FM10K_IM 0x13001 -#define FM10K_IB 0x13002 -#define FM10K_SRAM_IP 0x13003 -#define FM10K_SRAM_IM 0x13004 - -/* VLAN registers */ -#define FM10K_VLAN_TABLE(_n, _m) ((0x80 * (_n)) + (_m) + 0x14000) -#define FM10K_VLAN_TABLE_SIZE 128 - -/* VLAN specific message offsets */ -#define FM10K_VLAN_TABLE_VID_MAX 4096 -#define FM10K_VLAN_TABLE_VSI_MAX 64 -#define FM10K_VLAN_LENGTH_SHIFT 16 -#define FM10K_VLAN_CLEAR (1 << 15) -#define FM10K_VLAN_ALL \ - ((FM10K_VLAN_TABLE_VID_MAX - 1) << FM10K_VLAN_LENGTH_SHIFT) - -/* VF FLR event notification registers */ -#define FM10K_PFVFLRE(_n) ((0x1 * (_n)) + 0x18844) -#define FM10K_PFVFLREC(_n) ((0x1 * (_n)) + 0x18846) - -/* Defines for size of uncacheable and write-combining memories */ -#define FM10K_UC_ADDR_START 0x000000 /* start of standard regs */ -#define FM10K_WC_ADDR_START 0x100000 /* start of Tx Desc Cache */ -#define FM10K_DBI_ADDR_START 0x200000 /* start of debug registers */ -#define FM10K_UC_ADDR_SIZE (FM10K_WC_ADDR_START - FM10K_UC_ADDR_START) -#define FM10K_WC_ADDR_SIZE (FM10K_DBI_ADDR_START - FM10K_WC_ADDR_START) - -/* Define timeouts for resets and disables */ -#define FM10K_QUEUE_DISABLE_TIMEOUT 100 -#define FM10K_RESET_TIMEOUT 150 - -/* Maximum supported combined inner and outer header length for encapsulation */ -#define FM10K_TUNNEL_HEADER_LENGTH 184 - -/* VF registers */ -#define FM10K_VFCTRL 0x00000 -#define FM10K_VFCTRL_RST 0x00000008 -#define FM10K_VFINT_MAP 0x00030 -#define FM10K_VFSYSTIME 0x00040 -#define FM10K_VFITR(_n) ((_n) + 0x00060) -#define FM10K_VFPBACL(_n) ((_n) + 0x00008) - -/* Registers contained in BAR 4 for Switch management */ -#define FM10K_SW_SYSTIME_CFG 0x0224C -#define FM10K_SW_SYSTIME_CFG_STEP_SHIFT 4 -#define FM10K_SW_SYSTIME_CFG_ADJUST_MASK 0xFF000000 -#define FM10K_SW_SYSTIME_ADJUST 0x0224D -#define FM10K_SW_SYSTIME_ADJUST_MASK 0x3FFFFFFF -#define FM10K_SW_SYSTIME_ADJUST_DIR_NEGATIVE 0x80000000 -#define FM10K_SW_SYSTIME_PULSE(_n) ((_n) + 0x02252) - -#ifndef ETH_ALEN -#define ETH_ALEN 6 -#endif /* ETH_ALEN */ - - - - -enum fm10k_int_source { - fm10k_int_Mailbox = 0, - fm10k_int_PCIeFault = 1, - fm10k_int_SwitchUpDown = 2, - fm10k_int_SwitchEvent = 3, - fm10k_int_SRAM = 4, - fm10k_int_VFLR = 5, - fm10k_int_MaxHoldTime = 6, - fm10k_int_sources_max_pf -}; - -/* PCIe bus speeds */ -enum fm10k_bus_speed { - fm10k_bus_speed_unknown = 0, - fm10k_bus_speed_2500 = 2500, - fm10k_bus_speed_5000 = 5000, - fm10k_bus_speed_8000 = 8000, - fm10k_bus_speed_reserved -}; - -/* PCIe bus widths */ -enum fm10k_bus_width { - fm10k_bus_width_unknown = 0, - fm10k_bus_width_pcie_x1 = 1, - fm10k_bus_width_pcie_x2 = 2, - fm10k_bus_width_pcie_x4 = 4, - fm10k_bus_width_pcie_x8 = 8, - fm10k_bus_width_reserved -}; - -/* PCIe payload sizes */ -enum fm10k_bus_payload { - fm10k_bus_payload_unknown = 0, - fm10k_bus_payload_128 = 1, - fm10k_bus_payload_256 = 2, - fm10k_bus_payload_512 = 3, - fm10k_bus_payload_reserved -}; - -/* Bus parameters */ -struct fm10k_bus_info { - enum fm10k_bus_speed speed; - enum fm10k_bus_width width; - enum fm10k_bus_payload payload; -}; - -/* Statistics related declarations */ -struct fm10k_hw_stat { - u64 count; - u32 base_l; - u32 base_h; -}; - -struct fm10k_hw_stats_q { - struct fm10k_hw_stat tx_bytes; - struct fm10k_hw_stat tx_packets; -#define tx_stats_idx tx_packets.base_h - struct fm10k_hw_stat rx_bytes; - struct fm10k_hw_stat rx_packets; -#define rx_stats_idx rx_packets.base_h - struct fm10k_hw_stat rx_drops; -}; - -struct fm10k_hw_stats { - struct fm10k_hw_stat timeout; -#define stats_idx timeout.base_h - struct fm10k_hw_stat ur; - struct fm10k_hw_stat ca; - struct fm10k_hw_stat um; - struct fm10k_hw_stat xec; - struct fm10k_hw_stat vlan_drop; - struct fm10k_hw_stat loopback_drop; - struct fm10k_hw_stat nodesc_drop; - struct fm10k_hw_stats_q q[FM10K_MAX_QUEUES_PF]; -}; - -/* Establish DGLORT feature priority */ -enum fm10k_dglortdec_idx { - fm10k_dglort_default = 0, - fm10k_dglort_vf_rsvd0 = 1, - fm10k_dglort_vf_rss = 2, - fm10k_dglort_pf_rsvd0 = 3, - fm10k_dglort_pf_queue = 4, - fm10k_dglort_pf_vsi = 5, - fm10k_dglort_pf_rsvd1 = 6, - fm10k_dglort_pf_rss = 7 -}; - -struct fm10k_dglort_cfg { - u16 glort; /* GLORT base */ - u16 queue_b; /* Base value for queue */ - u8 vsi_b; /* Base value for VSI */ - u8 idx; /* index of DGLORTDEC entry */ - u8 rss_l; /* RSS indices */ - u8 pc_l; /* Priority Class indices */ - u8 vsi_l; /* Number of bits from GLORT used to determine VSI */ - u8 queue_l; /* Number of bits from GLORT used to determine queue */ - u8 shared_l; /* Ignored bits from GLORT resulting in shared VSI */ - u8 inner_rss; /* Boolean value if inner header is used for RSS */ -}; - -enum fm10k_pca_fault { - PCA_NO_FAULT, - PCA_UNMAPPED_ADDR, - PCA_BAD_QACCESS_PF, - PCA_BAD_QACCESS_VF, - PCA_MALICIOUS_REQ, - PCA_POISONED_TLP, - PCA_TLP_ABORT, - __PCA_MAX -}; - -enum fm10k_thi_fault { - THI_NO_FAULT, - THI_MAL_DIS_Q_FAULT, - __THI_MAX -}; - -enum fm10k_fum_fault { - FUM_NO_FAULT, - FUM_UNMAPPED_ADDR, - FUM_POISONED_TLP, - FUM_BAD_VF_QACCESS, - FUM_ADD_DECODE_ERR, - FUM_RO_ERROR, - FUM_QPRC_CRC_ERROR, - FUM_CSR_TIMEOUT, - FUM_INVALID_TYPE, - FUM_INVALID_LENGTH, - FUM_INVALID_BE, - FUM_INVALID_ALIGN, - __FUM_MAX -}; - -struct fm10k_fault { - u64 address; /* Address at the time fault was detected */ - u32 specinfo; /* Extra info on this fault (fault dependent) */ - u8 type; /* Fault value dependent on subunit */ - u8 func; /* Function number of the fault */ -}; - -struct fm10k_mac_ops { - /* basic bring-up and tear-down */ - s32 (*reset_hw)(struct fm10k_hw *); - s32 (*init_hw)(struct fm10k_hw *); - s32 (*start_hw)(struct fm10k_hw *); - s32 (*stop_hw)(struct fm10k_hw *); - s32 (*get_bus_info)(struct fm10k_hw *); - s32 (*get_host_state)(struct fm10k_hw *, bool *); - bool (*is_slot_appropriate)(struct fm10k_hw *); - s32 (*update_vlan)(struct fm10k_hw *, u32, u8, bool); - s32 (*read_mac_addr)(struct fm10k_hw *); - s32 (*update_uc_addr)(struct fm10k_hw *, u16, const u8 *, - u16, bool, u8); - s32 (*update_mc_addr)(struct fm10k_hw *, u16, const u8 *, u16, bool); - s32 (*update_xcast_mode)(struct fm10k_hw *, u16, u8); - void (*update_int_moderator)(struct fm10k_hw *); - s32 (*update_lport_state)(struct fm10k_hw *, u16, u16, bool); - void (*update_hw_stats)(struct fm10k_hw *, struct fm10k_hw_stats *); - void (*rebind_hw_stats)(struct fm10k_hw *, struct fm10k_hw_stats *); - s32 (*configure_dglort_map)(struct fm10k_hw *, - struct fm10k_dglort_cfg *); - void (*set_dma_mask)(struct fm10k_hw *, u64); - s32 (*get_fault)(struct fm10k_hw *, int, struct fm10k_fault *); - void (*request_lport_map)(struct fm10k_hw *); - s32 (*adjust_systime)(struct fm10k_hw *, s32 ppb); - u64 (*read_systime)(struct fm10k_hw *); - s32 (*request_tx_timestamp_mode)(struct fm10k_hw *, u16, u8); -}; - -enum fm10k_mac_type { - fm10k_mac_unknown = 0, - fm10k_mac_pf, - fm10k_mac_vf, - fm10k_num_macs -}; - -struct fm10k_mac_info { - struct fm10k_mac_ops ops; - enum fm10k_mac_type type; - u8 addr[ETH_ALEN]; - u8 perm_addr[ETH_ALEN]; - u16 default_vid; - u16 max_msix_vectors; - u16 max_queues; - bool vlan_override; - bool get_host_state; - bool tx_ready; - u32 dglort_map; -}; - -struct fm10k_swapi_table_info { - u32 used; - u32 avail; -}; - -struct fm10k_swapi_info { - u32 status; - struct fm10k_swapi_table_info mac; - struct fm10k_swapi_table_info nexthop; - struct fm10k_swapi_table_info ffu; -}; - -enum fm10k_xcast_modes { - FM10K_XCAST_MODE_ALLMULTI = 0, - FM10K_XCAST_MODE_MULTI = 1, - FM10K_XCAST_MODE_PROMISC = 2, - FM10K_XCAST_MODE_NONE = 3, - FM10K_XCAST_MODE_DISABLE = 4 -}; - -enum fm10k_timestamp_modes { - FM10K_TIMESTAMP_MODE_NONE = 0, - FM10K_TIMESTAMP_MODE_PEP_TO_PEP = 1, - FM10K_TIMESTAMP_MODE_PEP_TO_ANY = 2, -}; - -#define FM10K_VF_TC_MAX 100000 /* 100,000 Mb/s aka 100Gb/s */ -#define FM10K_VF_TC_MIN 1 /* 1 Mb/s is the slowest rate */ - -struct fm10k_vf_info { - /* mbx must be first field in struct unless all default IOV message - * handlers are redone as the assumption is that vf_info starts - * at the same offset as the mailbox - */ - struct fm10k_mbx_info mbx; /* PF side of VF mailbox */ - int rate; /* Tx BW cap as defined by OS */ - u16 glort; /* resource tag for this VF */ - u16 sw_vid; /* Switch API assigned VLAN */ - u16 pf_vid; /* PF assigned Default VLAN */ - u8 mac[ETH_ALEN]; /* PF Default MAC address */ - u8 vsi; /* VSI identifier */ - u8 vf_idx; /* which VF this is */ - u8 vf_flags; /* flags indicating what modes - * are supported for the port - */ -}; - -#define FM10K_VF_FLAG_ALLMULTI_CAPABLE ((u8)1 << FM10K_XCAST_MODE_ALLMULTI) -#define FM10K_VF_FLAG_MULTI_CAPABLE ((u8)1 << FM10K_XCAST_MODE_MULTI) -#define FM10K_VF_FLAG_PROMISC_CAPABLE ((u8)1 << FM10K_XCAST_MODE_PROMISC) -#define FM10K_VF_FLAG_NONE_CAPABLE ((u8)1 << FM10K_XCAST_MODE_NONE) -#define FM10K_VF_FLAG_CAPABLE(vf_info) ((vf_info)->vf_flags & (u8)0xF) -#define FM10K_VF_FLAG_ENABLED(vf_info) ((vf_info)->vf_flags >> 4) -#define FM10K_VF_FLAG_SET_MODE(mode) ((u8)0x10 << (mode)) -#define FM10K_VF_FLAG_ENABLED_MODE_SHIFT 4 -#define FM10K_VF_FLAG_SET_MODE_MASK ((u8)0xF0) -#define FM10K_VF_FLAG_SET_MODE_NONE \ - FM10K_VF_FLAG_SET_MODE(FM10K_XCAST_MODE_NONE) -#define FM10K_VF_FLAG_MULTI_ENABLED \ - (FM10K_VF_FLAG_SET_MODE(FM10K_XCAST_MODE_ALLMULTI) | \ - FM10K_VF_FLAG_SET_MODE(FM10K_XCAST_MODE_MULTI) | \ - FM10K_VF_FLAG_SET_MODE(FM10K_XCAST_MODE_PROMISC)) - -struct fm10k_iov_ops { - /* IOV related bring-up and tear-down */ - s32 (*assign_resources)(struct fm10k_hw *, u16, u16); - s32 (*configure_tc)(struct fm10k_hw *, u16, int); - s32 (*assign_int_moderator)(struct fm10k_hw *, u16); - s32 (*assign_default_mac_vlan)(struct fm10k_hw *, - struct fm10k_vf_info *); - s32 (*reset_resources)(struct fm10k_hw *, - struct fm10k_vf_info *); - s32 (*set_lport)(struct fm10k_hw *, struct fm10k_vf_info *, u16, u8); - void (*reset_lport)(struct fm10k_hw *, struct fm10k_vf_info *); - void (*update_stats)(struct fm10k_hw *, struct fm10k_hw_stats_q *, u16); - s32 (*report_timestamp)(struct fm10k_hw *, struct fm10k_vf_info *, u64); -}; - -struct fm10k_iov_info { - struct fm10k_iov_ops ops; - u16 total_vfs; - u16 num_vfs; - u16 num_pools; -}; - -struct fm10k_hw { - u32 *hw_addr; - u32 *sw_addr; - void *back; - struct fm10k_mac_info mac; - struct fm10k_bus_info bus; - struct fm10k_bus_info bus_caps; - struct fm10k_iov_info iov; - struct fm10k_mbx_info mbx; - struct fm10k_swapi_info swapi; - u16 device_id; - u16 vendor_id; - u16 subsystem_device_id; - u16 subsystem_vendor_id; - u8 revision_id; -}; - -/* Number of Transmit and Receive Descriptors must be a multiple of 8 */ -#define FM10K_REQ_TX_DESCRIPTOR_MULTIPLE 8 -#define FM10K_REQ_RX_DESCRIPTOR_MULTIPLE 8 - -/* Transmit Descriptor */ -struct fm10k_tx_desc { - __le64 buffer_addr; /* Address of the descriptor's data buffer */ - __le16 buflen; /* Length of data to be DMAed */ - __le16 vlan; /* VLAN_ID and VPRI to be inserted in FTAG */ - __le16 mss; /* MSS for segmentation offload */ - u8 hdrlen; /* Header size for segmentation offload */ - u8 flags; /* Status and offload request flags */ -}; - -/* Transmit Descriptor Cache Structure */ -struct fm10k_tx_desc_cache { - struct fm10k_tx_desc tx_desc[256]; -}; - -#define FM10K_TXD_FLAG_INT 0x01 -#define FM10K_TXD_FLAG_TIME 0x02 -#define FM10K_TXD_FLAG_CSUM 0x04 -#define FM10K_TXD_FLAG_CSUM2 0x08 -#define FM10K_TXD_FLAG_FTAG 0x10 -#define FM10K_TXD_FLAG_RS 0x20 -#define FM10K_TXD_FLAG_LAST 0x40 -#define FM10K_TXD_FLAG_DONE 0x80 - -#define FM10K_TXD_VLAN_PRI_SHIFT 12 - -/* These macros are meant to enable optimal placement of the RS and INT - * bits. It will point us to the last descriptor in the cache for either the - * start of the packet, or the end of the packet. If the index is actually - * at the start of the FIFO it will point to the offset for the last index - * in the FIFO to prevent an unnecessary write. - */ -#define FM10K_TXD_WB_FIFO_SIZE 4 -#define FM10K_TXD_WB_IDX(idx) \ - (((idx) - 1) | (FM10K_TXD_WB_FIFO_SIZE - 1)) - -/* Receive Descriptor - 32B */ -union fm10k_rx_desc { - struct { - __le64 pkt_addr; /* Packet buffer address */ - __le64 hdr_addr; /* Header buffer address */ - __le64 reserved; /* Empty space, RSS hash */ - __le64 timestamp; - } q; /* Read, Writeback, 64b quad-words */ - struct { - __le32 data; /* RSS and header data */ - __le32 rss; /* RSS Hash */ - __le32 staterr; - __le32 vlan_len; - __le32 glort; /* sglort/dglort */ - } d; /* Writeback, 32b double-words */ - struct { - __le16 pkt_info; /* RSS, Pkt type */ - __le16 hdr_info; /* Splithdr, hdrlen, xC */ - __le16 rss_lower; - __le16 rss_upper; - __le16 status; /* status/error */ - __le16 csum_err; /* checksum or extended error value */ - __le16 length; /* Packet length */ - __le16 vlan; /* VLAN tag */ - __le16 dglort; - __le16 sglort; - } w; /* Writeback, 16b words */ -}; - -#define FM10K_RXD_RSSTYPE_MASK 0x000F -enum fm10k_rdesc_rss_type { - FM10K_RSSTYPE_NONE = 0x0, - FM10K_RSSTYPE_IPV4_TCP = 0x1, - FM10K_RSSTYPE_IPV4 = 0x2, - FM10K_RSSTYPE_IPV6_TCP = 0x3, - /* Reserved 0x4 */ - FM10K_RSSTYPE_IPV6 = 0x5, - /* Reserved 0x6 */ - FM10K_RSSTYPE_IPV4_UDP = 0x7, - FM10K_RSSTYPE_IPV6_UDP = 0x8 - /* Reserved 0x9 - 0xF */ -}; - -#define FM10K_RXD_PKTTYPE_MASK 0x03F0 -#define FM10K_RXD_PKTTYPE_MASK_L3 0x0070 -#define FM10K_RXD_PKTTYPE_MASK_L4 0x0380 -#define FM10K_RXD_PKTTYPE_SHIFT 4 -#define FM10K_RXD_PKTTYPE_INNER_MASK_L3 0x1C00 -#define FM10K_RXD_PKTTYPE_INNER_MASK_L4 0xE000 -#define FM10K_RXD_PKTTYPE_INNER_SHIFT 10 -enum fm10k_rdesc_pkt_type { - /* L3 type */ - FM10K_PKTTYPE_OTHER = 0x00, - FM10K_PKTTYPE_IPV4 = 0x01, - FM10K_PKTTYPE_IPV4_EX = 0x02, - FM10K_PKTTYPE_IPV6 = 0x03, - FM10K_PKTTYPE_IPV6_EX = 0x04, - - /* L4 type */ - FM10K_PKTTYPE_TCP = 0x08, - FM10K_PKTTYPE_UDP = 0x10, - FM10K_PKTTYPE_GRE = 0x18, - FM10K_PKTTYPE_VXLAN = 0x20, - FM10K_PKTTYPE_NVGRE = 0x28, - FM10K_PKTTYPE_GENEVE = 0x30 -}; - -#define FM10K_RXD_HDR_INFO_XC_MASK 0x0006 -enum fm10k_rxdesc_xc { - FM10K_XC_UNICAST = 0x0, - FM10K_XC_MULTICAST = 0x4, - FM10K_XC_BROADCAST = 0x6 -}; - -#define FM10K_RXD_HDR_INFO_LEN_SHIFT 5 -#define FM10K_RXD_HDR_INFO_SPH 0x8000 - -#define FM10K_RXD_STATUS_DD 0x0001 /* Descriptor done */ -#define FM10K_RXD_STATUS_EOP 0x0002 /* End of packet */ -#define FM10K_RXD_STATUS_VEXT 0x0004 /* A VLAN tag is present */ -#define FM10K_RXD_STATUS_IPCS 0x0008 /* Indicates IPv4 csum */ -#define FM10K_RXD_STATUS_L4CS 0x0010 /* Indicates an L4 csum */ -#define FM10K_RXD_STATUS_IPCS2 0x0020 /* Inner header IPv4 csum */ -#define FM10K_RXD_STATUS_L4CS2 0x0040 /* Inner header L4 csum */ -#define FM10K_RXD_STATUS_IPFRAG_MASK 0x0180 /* Fragment mask */ -#define FM10K_RXD_STATUS_IPFRAG_CSUM 0x0100 /* Fragment w/ CSUM field */ -#define FM10K_RXD_STATUS_VEXT2 0x0200 /* A custom tag is present */ -#define FM10K_RXD_STATUS_HBO 0x0400 /* header buffer overrun */ -#define FM10K_RXD_STATUS_L4E2 0x0800 /* Inner header L4 csum err */ -#define FM10K_RXD_STATUS_IPE2 0x1000 /* Inner header IPv4 csum err */ -#define FM10K_RXD_STATUS_RXE 0x2000 /* Generic Rx error */ -#define FM10K_RXD_STATUS_L4E 0x4000 /* L4 csum error */ -#define FM10K_RXD_STATUS_IPE 0x8000 /* IPv4 csum error */ - -#define FM10K_RXD_ERR_SWITCH_ERROR 0x0001 /* Switch found bad packet */ -#define FM10K_RXD_ERR_NO_DESCRIPTOR 0x0002 /* No descriptor available */ -#define FM10K_RXD_ERR_PP_ERROR 0x0004 /* RAM error during processing */ -#define FM10K_RXD_ERR_SWITCH_READY 0x0008 /* Link transition mid-packet */ -#define FM10K_RXD_ERR_TOO_BIG 0x0010 /* Pkt too big for single buf */ - -#define FM10K_RXD_VLAN_ID_MASK 0x0FFF -#define FM10K_RXD_VLAN_PRI_SHIFT FM10K_TXD_VLAN_PRI_SHIFT - -struct fm10k_ftag { - __be16 swpri_type_user; - __be16 vlan; - __be16 sglort; - __be16 dglort; -}; - -#endif /* _FM10K_TYPE_H */ diff --git a/lib/librte_pmd_fm10k/base/fm10k_vf.c b/lib/librte_pmd_fm10k/base/fm10k_vf.c deleted file mode 100644 index 2246688..0000000 --- a/lib/librte_pmd_fm10k/base/fm10k_vf.c +++ /dev/null @@ -1,641 +0,0 @@ -/******************************************************************************* - -Copyright (c) 2013 - 2015, 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. - -***************************************************************************/ - -#include "fm10k_vf.h" - -/** - * fm10k_stop_hw_vf - Stop Tx/Rx units - * @hw: pointer to hardware structure - * - **/ -STATIC s32 fm10k_stop_hw_vf(struct fm10k_hw *hw) -{ - u8 *perm_addr = hw->mac.perm_addr; - u32 bal = 0, bah = 0; - s32 err; - u16 i; - - DEBUGFUNC("fm10k_stop_hw_vf"); - - /* we need to disable the queues before taking further steps */ - err = fm10k_stop_hw_generic(hw); - if (err) - return err; - - /* If permanent address is set then we need to restore it */ - if (FM10K_IS_VALID_ETHER_ADDR(perm_addr)) { - bal = (((u32)perm_addr[3]) << 24) | - (((u32)perm_addr[4]) << 16) | - (((u32)perm_addr[5]) << 8); - bah = (((u32)0xFF) << 24) | - (((u32)perm_addr[0]) << 16) | - (((u32)perm_addr[1]) << 8) | - ((u32)perm_addr[2]); - } - - /* The queues have already been disabled so we just need to - * update their base address registers - */ - for (i = 0; i < hw->mac.max_queues; i++) { - FM10K_WRITE_REG(hw, FM10K_TDBAL(i), bal); - FM10K_WRITE_REG(hw, FM10K_TDBAH(i), bah); - FM10K_WRITE_REG(hw, FM10K_RDBAL(i), bal); - FM10K_WRITE_REG(hw, FM10K_RDBAH(i), bah); - } - - return FM10K_SUCCESS; -} - -/** - * fm10k_reset_hw_vf - VF hardware reset - * @hw: pointer to hardware structure - * - * This function should return the hardware to a state similar to the - * one it is in after just being initialized. - **/ -STATIC s32 fm10k_reset_hw_vf(struct fm10k_hw *hw) -{ - s32 err; - - DEBUGFUNC("fm10k_reset_hw_vf"); - - /* shut down queues we own and reset DMA configuration */ - err = fm10k_stop_hw_vf(hw); - if (err) - return err; - - /* Inititate VF reset */ - FM10K_WRITE_REG(hw, FM10K_VFCTRL, FM10K_VFCTRL_RST); - - /* Flush write and allow 100us for reset to complete */ - FM10K_WRITE_FLUSH(hw); - usec_delay(FM10K_RESET_TIMEOUT); - - /* Clear reset bit and verify it was cleared */ - FM10K_WRITE_REG(hw, FM10K_VFCTRL, 0); - if (FM10K_READ_REG(hw, FM10K_VFCTRL) & FM10K_VFCTRL_RST) - err = FM10K_ERR_RESET_FAILED; - - return err; -} - -/** - * fm10k_init_hw_vf - VF hardware initialization - * @hw: pointer to hardware structure - * - **/ -STATIC s32 fm10k_init_hw_vf(struct fm10k_hw *hw) -{ - u32 tqdloc, tqdloc0 = ~FM10K_READ_REG(hw, FM10K_TQDLOC(0)); - s32 err; - u16 i; - - DEBUGFUNC("fm10k_init_hw_vf"); - - /* assume we always have at least 1 queue */ - for (i = 1; tqdloc0 && (i < FM10K_MAX_QUEUES_POOL); i++) { - /* verify the Descriptor cache offsets are increasing */ - tqdloc = ~FM10K_READ_REG(hw, FM10K_TQDLOC(i)); - if (!tqdloc || (tqdloc == tqdloc0)) - break; - - /* check to verify the PF doesn't own any of our queues */ - if (!~FM10K_READ_REG(hw, FM10K_TXQCTL(i)) || - !~FM10K_READ_REG(hw, FM10K_RXQCTL(i))) - break; - } - - /* shut down queues we own and reset DMA configuration */ - err = fm10k_disable_queues_generic(hw, i); - if (err) - return err; - - /* record maximum queue count */ - hw->mac.max_queues = i; - - /* fetch default VLAN */ - hw->mac.default_vid = (FM10K_READ_REG(hw, FM10K_TXQCTL(0)) & - FM10K_TXQCTL_VID_MASK) >> FM10K_TXQCTL_VID_SHIFT; - - return FM10K_SUCCESS; -} - -/** - * fm10k_is_slot_appropriate_vf - Indicate appropriate slot for this SKU - * @hw: pointer to hardware structure - * - * Looks at the PCIe bus info to confirm whether or not this slot can support - * the necessary bandwidth for this device. Since the VF has no control over - * the "slot" it is in, always indicate that the slot is appropriate. - **/ -STATIC bool fm10k_is_slot_appropriate_vf(struct fm10k_hw *hw) -{ - UNREFERENCED_1PARAMETER(hw); - DEBUGFUNC("fm10k_is_slot_appropriate_vf"); - - return TRUE; -} - -/* This structure defines the attibutes to be parsed below */ -const struct fm10k_tlv_attr fm10k_mac_vlan_msg_attr[] = { - FM10K_TLV_ATTR_U32(FM10K_MAC_VLAN_MSG_VLAN), - FM10K_TLV_ATTR_BOOL(FM10K_MAC_VLAN_MSG_SET), - FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_MAC), - FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_DEFAULT_MAC), - FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_MULTICAST), - FM10K_TLV_ATTR_LAST -}; - -/** - * fm10k_update_vlan_vf - Update status of VLAN ID in VLAN filter table - * @hw: pointer to hardware structure - * @vid: VLAN ID to add to table - * @vsi: Reserved, should always be 0 - * @set: Indicates if this is a set or clear operation - * - * This function adds or removes the corresponding VLAN ID from the VLAN - * filter table for this VF. - **/ -STATIC s32 fm10k_update_vlan_vf(struct fm10k_hw *hw, u32 vid, u8 vsi, bool set) -{ - struct fm10k_mbx_info *mbx = &hw->mbx; - u32 msg[4]; - - /* verify the index is not set */ - if (vsi) - return FM10K_ERR_PARAM; - - /* verify upper 4 bits of vid and length are 0 */ - if ((vid << 16 | vid) >> 28) - return FM10K_ERR_PARAM; - - /* encode set bit into the VLAN ID */ - if (!set) - vid |= FM10K_VLAN_CLEAR; - - /* generate VLAN request */ - fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN); - fm10k_tlv_attr_put_u32(msg, FM10K_MAC_VLAN_MSG_VLAN, vid); - - /* load onto outgoing mailbox */ - return mbx->ops.enqueue_tx(hw, mbx, msg); -} - -/** - * fm10k_msg_mac_vlan_vf - Read device MAC address from mailbox message - * @hw: pointer to the HW structure - * @results: Attributes for message - * @mbx: unused mailbox data - * - * This function should determine the MAC address for the VF - **/ -s32 fm10k_msg_mac_vlan_vf(struct fm10k_hw *hw, u32 **results, - struct fm10k_mbx_info *mbx) -{ - u8 perm_addr[ETH_ALEN]; - u16 vid; - s32 err; - - UNREFERENCED_1PARAMETER(mbx); - DEBUGFUNC("fm10k_msg_mac_vlan_vf"); - - /* record MAC address requested */ - err = fm10k_tlv_attr_get_mac_vlan( - results[FM10K_MAC_VLAN_MSG_DEFAULT_MAC], - perm_addr, &vid); - if (err) - return err; - - memcpy(hw->mac.perm_addr, perm_addr, ETH_ALEN); - hw->mac.default_vid = vid & (FM10K_VLAN_TABLE_VID_MAX - 1); - hw->mac.vlan_override = !!(vid & FM10K_VLAN_CLEAR); - - return FM10K_SUCCESS; -} - -/** - * fm10k_read_mac_addr_vf - Read device MAC address - * @hw: pointer to the HW structure - * - * This function should determine the MAC address for the VF - **/ -STATIC s32 fm10k_read_mac_addr_vf(struct fm10k_hw *hw) -{ - u8 perm_addr[ETH_ALEN]; - u32 base_addr; - - DEBUGFUNC("fm10k_read_mac_addr_vf"); - - base_addr = FM10K_READ_REG(hw, FM10K_TDBAL(0)); - - /* last byte should be 0 */ - if (base_addr << 24) - return FM10K_ERR_INVALID_MAC_ADDR; - - perm_addr[3] = (u8)(base_addr >> 24); - perm_addr[4] = (u8)(base_addr >> 16); - perm_addr[5] = (u8)(base_addr >> 8); - - base_addr = FM10K_READ_REG(hw, FM10K_TDBAH(0)); - - /* first byte should be all 1's */ - if ((~base_addr) >> 24) - return FM10K_ERR_INVALID_MAC_ADDR; - - perm_addr[0] = (u8)(base_addr >> 16); - perm_addr[1] = (u8)(base_addr >> 8); - perm_addr[2] = (u8)(base_addr); - - memcpy(hw->mac.perm_addr, perm_addr, ETH_ALEN); - memcpy(hw->mac.addr, perm_addr, ETH_ALEN); - - return FM10K_SUCCESS; -} - -/** - * fm10k_update_uc_addr_vf - Update device unicast addresses - * @hw: pointer to the HW structure - * @glort: unused - * @mac: MAC address to add/remove from table - * @vid: VLAN ID to add/remove from table - * @add: Indicates if this is an add or remove operation - * @flags: flags field to indicate add and secure - unused - * - * This function is used to add or remove unicast MAC addresses for - * the VF. - **/ -STATIC s32 fm10k_update_uc_addr_vf(struct fm10k_hw *hw, u16 glort, - const u8 *mac, u16 vid, bool add, u8 flags) -{ - struct fm10k_mbx_info *mbx = &hw->mbx; - u32 msg[7]; - - DEBUGFUNC("fm10k_update_uc_addr_vf"); - - UNREFERENCED_2PARAMETER(glort, flags); - - /* verify VLAN ID is valid */ - if (vid >= FM10K_VLAN_TABLE_VID_MAX) - return FM10K_ERR_PARAM; - - /* verify MAC address is valid */ - if (!FM10K_IS_VALID_ETHER_ADDR(mac)) - return FM10K_ERR_PARAM; - - /* verify we are not locked down on the MAC address */ - if (FM10K_IS_VALID_ETHER_ADDR(hw->mac.perm_addr) && - memcmp(hw->mac.perm_addr, mac, ETH_ALEN)) - return FM10K_ERR_PARAM; - - /* add bit to notify us if this is a set or clear operation */ - if (!add) - vid |= FM10K_VLAN_CLEAR; - - /* generate VLAN request */ - fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN); - fm10k_tlv_attr_put_mac_vlan(msg, FM10K_MAC_VLAN_MSG_MAC, mac, vid); - - /* load onto outgoing mailbox */ - return mbx->ops.enqueue_tx(hw, mbx, msg); -} - -/** - * fm10k_update_mc_addr_vf - Update device multicast addresses - * @hw: pointer to the HW structure - * @glort: unused - * @mac: MAC address to add/remove from table - * @vid: VLAN ID to add/remove from table - * @add: Indicates if this is an add or remove operation - * - * This function is used to add or remove multicast MAC addresses for - * the VF. - **/ -STATIC s32 fm10k_update_mc_addr_vf(struct fm10k_hw *hw, u16 glort, - const u8 *mac, u16 vid, bool add) -{ - struct fm10k_mbx_info *mbx = &hw->mbx; - u32 msg[7]; - - DEBUGFUNC("fm10k_update_uc_addr_vf"); - - UNREFERENCED_1PARAMETER(glort); - - /* verify VLAN ID is valid */ - if (vid >= FM10K_VLAN_TABLE_VID_MAX) - return FM10K_ERR_PARAM; - - /* verify multicast address is valid */ - if (!FM10K_IS_MULTICAST_ETHER_ADDR(mac)) - return FM10K_ERR_PARAM; - - /* add bit to notify us if this is a set or clear operation */ - if (!add) - vid |= FM10K_VLAN_CLEAR; - - /* generate VLAN request */ - fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN); - fm10k_tlv_attr_put_mac_vlan(msg, FM10K_MAC_VLAN_MSG_MULTICAST, - mac, vid); - - /* load onto outgoing mailbox */ - return mbx->ops.enqueue_tx(hw, mbx, msg); -} - -/** - * fm10k_update_int_moderator_vf - Request update of interrupt moderator list - * @hw: pointer to hardware structure - * - * This function will issue a request to the PF to rescan our MSI-X table - * and to update the interrupt moderator linked list. - **/ -STATIC void fm10k_update_int_moderator_vf(struct fm10k_hw *hw) -{ - struct fm10k_mbx_info *mbx = &hw->mbx; - u32 msg[1]; - - /* generate MSI-X request */ - fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MSIX); - - /* load onto outgoing mailbox */ - mbx->ops.enqueue_tx(hw, mbx, msg); -} - -/* This structure defines the attibutes to be parsed below */ -const struct fm10k_tlv_attr fm10k_lport_state_msg_attr[] = { - FM10K_TLV_ATTR_BOOL(FM10K_LPORT_STATE_MSG_DISABLE), - FM10K_TLV_ATTR_U8(FM10K_LPORT_STATE_MSG_XCAST_MODE), - FM10K_TLV_ATTR_BOOL(FM10K_LPORT_STATE_MSG_READY), - FM10K_TLV_ATTR_LAST -}; - -/** - * fm10k_msg_lport_state_vf - Message handler for lport_state message from PF - * @hw: Pointer to hardware structure - * @results: pointer array containing parsed data - * @mbx: Pointer to mailbox information structure - * - * This handler is meant to capture the indication from the PF that we - * are ready to bring up the interface. - **/ -s32 fm10k_msg_lport_state_vf(struct fm10k_hw *hw, u32 **results, - struct fm10k_mbx_info *mbx) -{ - UNREFERENCED_1PARAMETER(mbx); - DEBUGFUNC("fm10k_msg_lport_state_vf"); - - hw->mac.dglort_map = !results[FM10K_LPORT_STATE_MSG_READY] ? - FM10K_DGLORTMAP_NONE : FM10K_DGLORTMAP_ZERO; - - return FM10K_SUCCESS; -} - -/** - * fm10k_update_lport_state_vf - Update device state in lower device - * @hw: pointer to the HW structure - * @glort: unused - * @count: number of logical ports to enable - unused (always 1) - * @enable: boolean value indicating if this is an enable or disable request - * - * Notify the lower device of a state change. If the lower device is - * enabled we can add filters, if it is disabled all filters for this - * logical port are flushed. - **/ -STATIC s32 fm10k_update_lport_state_vf(struct fm10k_hw *hw, u16 glort, - u16 count, bool enable) -{ - struct fm10k_mbx_info *mbx = &hw->mbx; - u32 msg[2]; - - UNREFERENCED_2PARAMETER(glort, count); - DEBUGFUNC("fm10k_update_lport_state_vf"); - - /* reset glort mask 0 as we have to wait to be enabled */ - hw->mac.dglort_map = FM10K_DGLORTMAP_NONE; - - /* generate port state request */ - fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE); - if (!enable) - fm10k_tlv_attr_put_bool(msg, FM10K_LPORT_STATE_MSG_DISABLE); - - /* load onto outgoing mailbox */ - return mbx->ops.enqueue_tx(hw, mbx, msg); -} - -/** - * fm10k_update_xcast_mode_vf - Request update of multicast mode - * @hw: pointer to hardware structure - * @glort: unused - * @mode: integer value indicating mode being requested - * - * This function will attempt to request a higher mode for the port - * so that it can enable either multicast, multicast promiscuous, or - * promiscuous mode of operation. - **/ -STATIC s32 fm10k_update_xcast_mode_vf(struct fm10k_hw *hw, u16 glort, u8 mode) -{ - struct fm10k_mbx_info *mbx = &hw->mbx; - u32 msg[3]; - - UNREFERENCED_1PARAMETER(glort); - DEBUGFUNC("fm10k_update_xcast_mode_vf"); - - if (mode > FM10K_XCAST_MODE_NONE) - return FM10K_ERR_PARAM; - - /* generate message requesting to change xcast mode */ - fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE); - fm10k_tlv_attr_put_u8(msg, FM10K_LPORT_STATE_MSG_XCAST_MODE, mode); - - /* load onto outgoing mailbox */ - return mbx->ops.enqueue_tx(hw, mbx, msg); -} - -const struct fm10k_tlv_attr fm10k_1588_msg_attr[] = { - FM10K_TLV_ATTR_U64(FM10K_1588_MSG_TIMESTAMP), - FM10K_TLV_ATTR_LAST -}; - -/* currently there is no shared 1588 timestamp handler */ - -/** - * fm10k_update_hw_stats_vf - Updates hardware related statistics of VF - * @hw: pointer to hardware structure - * @stats: pointer to statistics structure - * - * This function collects and aggregates per queue hardware statistics. - **/ -STATIC void fm10k_update_hw_stats_vf(struct fm10k_hw *hw, - struct fm10k_hw_stats *stats) -{ - DEBUGFUNC("fm10k_update_hw_stats_vf"); - - fm10k_update_hw_stats_q(hw, stats->q, 0, hw->mac.max_queues); -} - -/** - * fm10k_rebind_hw_stats_vf - Resets base for hardware statistics of VF - * @hw: pointer to hardware structure - * @stats: pointer to the stats structure to update - * - * This function resets the base for queue hardware statistics. - **/ -STATIC void fm10k_rebind_hw_stats_vf(struct fm10k_hw *hw, - struct fm10k_hw_stats *stats) -{ - DEBUGFUNC("fm10k_rebind_hw_stats_vf"); - - /* Unbind Queue Statistics */ - fm10k_unbind_hw_stats_q(stats->q, 0, hw->mac.max_queues); - - /* Reinitialize bases for all stats */ - fm10k_update_hw_stats_vf(hw, stats); -} - -/** - * fm10k_configure_dglort_map_vf - Configures GLORT entry and queues - * @hw: pointer to hardware structure - * @dglort: pointer to dglort configuration structure - * - * Reads the configuration structure contained in dglort_cfg and uses - * that information to then populate a DGLORTMAP/DEC entry and the queues - * to which it has been assigned. - **/ -STATIC s32 fm10k_configure_dglort_map_vf(struct fm10k_hw *hw, - struct fm10k_dglort_cfg *dglort) -{ - UNREFERENCED_1PARAMETER(hw); - DEBUGFUNC("fm10k_configure_dglort_map_vf"); - - /* verify the dglort pointer */ - if (!dglort) - return FM10K_ERR_PARAM; - - /* stub for now until we determine correct message for this */ - - return FM10K_SUCCESS; -} - -/** - * fm10k_adjust_systime_vf - Adjust systime frequency - * @hw: pointer to hardware structure - * @ppb: adjustment rate in parts per billion - * - * This function takes an adjustment rate in parts per billion and will - * verify that this value is 0 as the VF cannot support adjusting the - * systime clock. - * - * If the ppb value is non-zero the return is ERR_PARAM else success - **/ -STATIC s32 fm10k_adjust_systime_vf(struct fm10k_hw *hw, s32 ppb) -{ - UNREFERENCED_1PARAMETER(hw); - DEBUGFUNC("fm10k_adjust_systime_vf"); - - /* The VF cannot adjust the clock frequency, however it should - * already have a syntonic clock with whichever host interface is - * running as the master for the host interface clock domain so - * there should be not frequency adjustment necessary. - */ - return ppb ? FM10K_ERR_PARAM : FM10K_SUCCESS; -} - -/** - * fm10k_read_systime_vf - Reads value of systime registers - * @hw: pointer to the hardware structure - * - * Function reads the content of 2 registers, combined to represent a 64 bit - * value measured in nanoseconds. In order to guarantee the value is accurate - * we check the 32 most significant bits both before and after reading the - * 32 least significant bits to verify they didn't change as we were reading - * the registers. - **/ -static u64 fm10k_read_systime_vf(struct fm10k_hw *hw) -{ - u32 systime_l, systime_h, systime_tmp; - - systime_h = fm10k_read_reg(hw, FM10K_VFSYSTIME + 1); - - do { - systime_tmp = systime_h; - systime_l = fm10k_read_reg(hw, FM10K_VFSYSTIME); - systime_h = fm10k_read_reg(hw, FM10K_VFSYSTIME + 1); - } while (systime_tmp != systime_h); - - return ((u64)systime_h << 32) | systime_l; -} - -static const struct fm10k_msg_data fm10k_msg_data_vf[] = { - FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test), - FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_msg_mac_vlan_vf), - FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_msg_lport_state_vf), - FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error), -}; - -/** - * fm10k_init_ops_vf - Inits func ptrs and MAC type - * @hw: pointer to hardware structure - * - * Initialize the function pointers and assign the MAC type for VF. - * Does not touch the hardware. - **/ -s32 fm10k_init_ops_vf(struct fm10k_hw *hw) -{ - struct fm10k_mac_info *mac = &hw->mac; - - DEBUGFUNC("fm10k_init_ops_vf"); - - fm10k_init_ops_generic(hw); - - mac->ops.reset_hw = &fm10k_reset_hw_vf; - mac->ops.init_hw = &fm10k_init_hw_vf; - mac->ops.start_hw = &fm10k_start_hw_generic; - mac->ops.stop_hw = &fm10k_stop_hw_vf; - mac->ops.is_slot_appropriate = &fm10k_is_slot_appropriate_vf; - mac->ops.update_vlan = &fm10k_update_vlan_vf; - mac->ops.read_mac_addr = &fm10k_read_mac_addr_vf; - mac->ops.update_uc_addr = &fm10k_update_uc_addr_vf; - mac->ops.update_mc_addr = &fm10k_update_mc_addr_vf; - mac->ops.update_xcast_mode = &fm10k_update_xcast_mode_vf; - mac->ops.update_int_moderator = &fm10k_update_int_moderator_vf; - mac->ops.update_lport_state = &fm10k_update_lport_state_vf; - mac->ops.update_hw_stats = &fm10k_update_hw_stats_vf; - mac->ops.rebind_hw_stats = &fm10k_rebind_hw_stats_vf; - mac->ops.configure_dglort_map = &fm10k_configure_dglort_map_vf; - mac->ops.get_host_state = &fm10k_get_host_state_generic; - mac->ops.adjust_systime = &fm10k_adjust_systime_vf; - mac->ops.read_systime = &fm10k_read_systime_vf, - - mac->max_msix_vectors = fm10k_get_pcie_msix_count_generic(hw); - - return fm10k_pfvf_mbx_init(hw, &hw->mbx, fm10k_msg_data_vf, 0); -} diff --git a/lib/librte_pmd_fm10k/base/fm10k_vf.h b/lib/librte_pmd_fm10k/base/fm10k_vf.h deleted file mode 100644 index 0438542..0000000 --- a/lib/librte_pmd_fm10k/base/fm10k_vf.h +++ /dev/null @@ -1,91 +0,0 @@ -/******************************************************************************* - -Copyright (c) 2013 - 2015, 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. - -***************************************************************************/ - -#ifndef _FM10K_VF_H_ -#define _FM10K_VF_H_ - -#include "fm10k_type.h" -#include "fm10k_common.h" - -enum fm10k_vf_tlv_msg_id { - FM10K_VF_MSG_ID_TEST = 0, /* msg ID reserved for testing */ - FM10K_VF_MSG_ID_MSIX, - FM10K_VF_MSG_ID_MAC_VLAN, - FM10K_VF_MSG_ID_LPORT_STATE, - FM10K_VF_MSG_ID_1588, - FM10K_VF_MSG_ID_MAX, -}; - -enum fm10k_tlv_mac_vlan_attr_id { - FM10K_MAC_VLAN_MSG_VLAN, - FM10K_MAC_VLAN_MSG_SET, - FM10K_MAC_VLAN_MSG_MAC, - FM10K_MAC_VLAN_MSG_DEFAULT_MAC, - FM10K_MAC_VLAN_MSG_MULTICAST, - FM10K_MAC_VLAN_MSG_ID_MAX -}; - -enum fm10k_tlv_lport_state_attr_id { - FM10K_LPORT_STATE_MSG_DISABLE, - FM10K_LPORT_STATE_MSG_XCAST_MODE, - FM10K_LPORT_STATE_MSG_READY, - FM10K_LPORT_STATE_MSG_MAX -}; - -enum fm10k_tlv_1588_attr_id { - FM10K_1588_MSG_TIMESTAMP, - FM10K_1588_MSG_MAX -}; - -#define FM10K_VF_MSG_MSIX_HANDLER(func) \ - FM10K_MSG_HANDLER(FM10K_VF_MSG_ID_MSIX, NULL, func) - -s32 fm10k_msg_mac_vlan_vf(struct fm10k_hw *, u32 **, struct fm10k_mbx_info *); -extern const struct fm10k_tlv_attr fm10k_mac_vlan_msg_attr[]; -#define FM10K_VF_MSG_MAC_VLAN_HANDLER(func) \ - FM10K_MSG_HANDLER(FM10K_VF_MSG_ID_MAC_VLAN, \ - fm10k_mac_vlan_msg_attr, func) - -s32 fm10k_msg_lport_state_vf(struct fm10k_hw *, u32 **, - struct fm10k_mbx_info *); -extern const struct fm10k_tlv_attr fm10k_lport_state_msg_attr[]; -#define FM10K_VF_MSG_LPORT_STATE_HANDLER(func) \ - FM10K_MSG_HANDLER(FM10K_VF_MSG_ID_LPORT_STATE, \ - fm10k_lport_state_msg_attr, func) - -extern const struct fm10k_tlv_attr fm10k_1588_msg_attr[]; -#define FM10K_VF_MSG_1588_HANDLER(func) \ - FM10K_MSG_HANDLER(FM10K_VF_MSG_ID_1588, fm10k_1588_msg_attr, func) - -s32 fm10k_init_ops_vf(struct fm10k_hw *hw); -#endif /* _FM10K_VF_H */ diff --git a/lib/librte_pmd_fm10k/fm10k.h b/lib/librte_pmd_fm10k/fm10k.h deleted file mode 100644 index 0e31796..0000000 --- a/lib/librte_pmd_fm10k/fm10k.h +++ /dev/null @@ -1,292 +0,0 @@ -/*- - * BSD LICENSE - * - * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of 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. - */ - -#ifndef _FM10K_H_ -#define _FM10K_H_ - -#include -#include -#include -#include -#include -#include "fm10k_logs.h" -#include "base/fm10k_type.h" - -/* descriptor ring base addresses must be aligned to the following */ -#define FM10K_ALIGN_RX_DESC 128 -#define FM10K_ALIGN_TX_DESC 128 - -/* The maximum packet size that FM10K supports */ -#define FM10K_MAX_PKT_SIZE (15 * 1024) - -/* Minimum size of RX buffer FM10K supported */ -#define FM10K_MIN_RX_BUF_SIZE 256 - -/* The maximum of SRIOV VFs per port supported */ -#define FM10K_MAX_VF_NUM 64 - -/* number of descriptors must be a multiple of the following */ -#define FM10K_MULT_RX_DESC FM10K_REQ_RX_DESCRIPTOR_MULTIPLE -#define FM10K_MULT_TX_DESC FM10K_REQ_TX_DESCRIPTOR_MULTIPLE - -/* maximum size of descriptor rings */ -#define FM10K_MAX_RX_RING_SZ (512 * 1024) -#define FM10K_MAX_TX_RING_SZ (512 * 1024) - -/* minimum and maximum number of descriptors in a ring */ -#define FM10K_MIN_RX_DESC 32 -#define FM10K_MIN_TX_DESC 32 -#define FM10K_MAX_RX_DESC (FM10K_MAX_RX_RING_SZ / sizeof(union fm10k_rx_desc)) -#define FM10K_MAX_TX_DESC (FM10K_MAX_TX_RING_SZ / sizeof(struct fm10k_tx_desc)) - -/* - * byte aligment for HW RX data buffer - * Datasheet requires RX buffer addresses shall either be 512-byte aligned or - * be 8-byte aligned but without crossing host memory pages (4KB alignment - * boundaries). Satisfy first option. - */ -#define FM10K_RX_DATABUF_ALIGN 512 - -/* - * threshold default, min, max, and divisor constraints - * the configured values must satisfy the following: - * MIN <= value <= MAX - * DIV % value == 0 - */ -#define FM10K_RX_FREE_THRESH_DEFAULT(rxq) 32 -#define FM10K_RX_FREE_THRESH_MIN(rxq) 1 -#define FM10K_RX_FREE_THRESH_MAX(rxq) ((rxq)->nb_desc - 1) -#define FM10K_RX_FREE_THRESH_DIV(rxq) ((rxq)->nb_desc) - -#define FM10K_TX_FREE_THRESH_DEFAULT(txq) 32 -#define FM10K_TX_FREE_THRESH_MIN(txq) 1 -#define FM10K_TX_FREE_THRESH_MAX(txq) ((txq)->nb_desc - 3) -#define FM10K_TX_FREE_THRESH_DIV(txq) 0 - -#define FM10K_DEFAULT_RX_PTHRESH 8 -#define FM10K_DEFAULT_RX_HTHRESH 8 -#define FM10K_DEFAULT_RX_WTHRESH 0 - -#define FM10K_DEFAULT_TX_PTHRESH 32 -#define FM10K_DEFAULT_TX_HTHRESH 0 -#define FM10K_DEFAULT_TX_WTHRESH 0 - -#define FM10K_TX_RS_THRESH_DEFAULT(txq) 32 -#define FM10K_TX_RS_THRESH_MIN(txq) 1 -#define FM10K_TX_RS_THRESH_MAX(txq) \ - RTE_MIN(((txq)->nb_desc - 2), (txq)->free_thresh) -#define FM10K_TX_RS_THRESH_DIV(txq) ((txq)->nb_desc) - -#define FM10K_VLAN_TAG_SIZE 4 - -struct fm10k_dev_info { - volatile uint32_t enable; - volatile uint32_t glort; - /* Protect the mailbox to avoid race condition */ - rte_spinlock_t mbx_lock; -}; - -/* - * Structure to store private data for each driver instance. - */ -struct fm10k_adapter { - struct fm10k_hw hw; - struct fm10k_hw_stats stats; - struct fm10k_dev_info info; -}; - -#define FM10K_DEV_PRIVATE_TO_HW(adapter) \ - (&((struct fm10k_adapter *)adapter)->hw) - -#define FM10K_DEV_PRIVATE_TO_STATS(adapter) \ - (&((struct fm10k_adapter *)adapter)->stats) - -#define FM10K_DEV_PRIVATE_TO_INFO(adapter) \ - (&((struct fm10k_adapter *)adapter)->info) - -#define FM10K_DEV_PRIVATE_TO_MBXLOCK(adapter) \ - (&(((struct fm10k_adapter *)adapter)->info.mbx_lock)) - -struct fm10k_rx_queue { - struct rte_mempool *mp; - struct rte_mbuf **sw_ring; - volatile union fm10k_rx_desc *hw_ring; - struct rte_mbuf *pkt_first_seg; /**< First segment of current packet. */ - struct rte_mbuf *pkt_last_seg; /**< Last segment of current packet. */ - uint64_t hw_ring_phys_addr; - uint16_t next_dd; - uint16_t next_alloc; - uint16_t next_trigger; - uint16_t alloc_thresh; - volatile uint32_t *tail_ptr; - uint16_t nb_desc; - uint16_t queue_id; - uint8_t port_id; - uint8_t drop_en; - uint8_t rx_deferred_start; /**< don't start this queue in dev start. */ -}; - -/* - * a FIFO is used to track which descriptors have their RS bit set for Tx - * queues which are configured to allow multiple descriptors per packet - */ -struct fifo { - uint16_t *list; - uint16_t *head; - uint16_t *tail; - uint16_t *endp; -}; - -struct fm10k_tx_queue { - struct rte_mbuf **sw_ring; - struct fm10k_tx_desc *hw_ring; - uint64_t hw_ring_phys_addr; - struct fifo rs_tracker; - uint16_t last_free; - uint16_t next_free; - uint16_t nb_free; - uint16_t nb_used; - uint16_t free_trigger; - uint16_t free_thresh; - uint16_t rs_thresh; - volatile uint32_t *tail_ptr; - uint16_t nb_desc; - uint8_t port_id; - uint8_t tx_deferred_start; /** < don't start this queue in dev start. */ - uint16_t queue_id; -}; - -#define MBUF_DMA_ADDR(mb) \ - ((uint64_t) ((mb)->buf_physaddr + (mb)->data_off)) - -/* enforce 512B alignment on default Rx DMA addresses */ -#define MBUF_DMA_ADDR_DEFAULT(mb) \ - ((uint64_t) RTE_ALIGN(((mb)->buf_physaddr + RTE_PKTMBUF_HEADROOM), 512)) - -static inline void fifo_reset(struct fifo *fifo, uint32_t len) -{ - fifo->head = fifo->tail = fifo->list; - fifo->endp = fifo->list + len; -} - -static inline void fifo_insert(struct fifo *fifo, uint16_t val) -{ - *fifo->head = val; - if (++fifo->head == fifo->endp) - fifo->head = fifo->list; -} - -/* do not worry about list being empty since we only check it once we know - * we have used enough descriptors to set the RS bit at least once */ -static inline uint16_t fifo_peek(struct fifo *fifo) -{ - return *fifo->tail; -} - -static inline uint16_t fifo_remove(struct fifo *fifo) -{ - uint16_t val; - val = *fifo->tail; - if (++fifo->tail == fifo->endp) - fifo->tail = fifo->list; - return val; -} - -static inline void -fm10k_pktmbuf_reset(struct rte_mbuf *mb, uint8_t in_port) -{ - rte_mbuf_refcnt_set(mb, 1); - mb->next = NULL; - mb->nb_segs = 1; - - /* enforce 512B alignment on default Rx virtual addresses */ - mb->data_off = (uint16_t)(RTE_PTR_ALIGN((char *)mb->buf_addr + - RTE_PKTMBUF_HEADROOM, FM10K_RX_DATABUF_ALIGN) - - (char *)mb->buf_addr); - mb->port = in_port; -} - -/* - * Verify Rx packet buffer alignment is valid. - * - * Hardware requires specific alignment for Rx packet buffers. At - * least one of the following two conditions must be satisfied. - * 1. Address is 512B aligned - * 2. Address is 8B aligned and buffer does not cross 4K boundary. - * - * Return 1 if buffer alignment satisfies at least one condition, - * otherwise return 0. - * - * Note: Alignment is checked by the driver when the Rx queue is reset. It - * is assumed that if an entire descriptor ring can be filled with - * buffers containing valid alignment, then all buffers in that mempool - * have valid address alignment. It is the responsibility of the user - * to ensure all buffers have valid alignment, as it is the user who - * creates the mempool. - * Note: It is assumed the buffer needs only to store a maximum size Ethernet - * frame. - */ -static inline int -fm10k_addr_alignment_valid(struct rte_mbuf *mb) -{ - uint64_t addr = MBUF_DMA_ADDR_DEFAULT(mb); - uint64_t boundary1, boundary2; - - /* 512B aligned? */ - if (RTE_ALIGN(addr, 512) == addr) - return 1; - - /* 8B aligned, and max Ethernet frame would not cross a 4KB boundary? */ - if (RTE_ALIGN(addr, 8) == addr) { - boundary1 = RTE_ALIGN_FLOOR(addr, 4096); - boundary2 = RTE_ALIGN_FLOOR(addr + ETHER_MAX_VLAN_FRAME_LEN, - 4096); - if (boundary1 == boundary2) - return 1; - } - - PMD_INIT_LOG(ERR, "Error: Invalid buffer alignment!"); - - return 0; -} - -/* Rx and Tx prototypes */ -uint16_t fm10k_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, - uint16_t nb_pkts); - -uint16_t fm10k_recv_scattered_pkts(void *rx_queue, - struct rte_mbuf **rx_pkts, uint16_t nb_pkts); - -uint16_t fm10k_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, - uint16_t nb_pkts); -#endif diff --git a/lib/librte_pmd_fm10k/fm10k_ethdev.c b/lib/librte_pmd_fm10k/fm10k_ethdev.c deleted file mode 100644 index 275c19c..0000000 --- a/lib/librte_pmd_fm10k/fm10k_ethdev.c +++ /dev/null @@ -1,1872 +0,0 @@ -/*- - * BSD LICENSE - * - * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of 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. - */ - -#include -#include -#include -#include -#include -#include - -#include "fm10k.h" -#include "base/fm10k_api.h" - -#define FM10K_RX_BUFF_ALIGN 512 -/* Default delay to acquire mailbox lock */ -#define FM10K_MBXLOCK_DELAY_US 20 -#define UINT64_LOWER_32BITS_MASK 0x00000000ffffffffULL - -/* Number of chars per uint32 type */ -#define CHARS_PER_UINT32 (sizeof(uint32_t)) -#define BIT_MASK_PER_UINT32 ((1 << CHARS_PER_UINT32) - 1) - -static void fm10k_close_mbx_service(struct fm10k_hw *hw); - -static void -fm10k_mbx_initlock(struct fm10k_hw *hw) -{ - rte_spinlock_init(FM10K_DEV_PRIVATE_TO_MBXLOCK(hw->back)); -} - -static void -fm10k_mbx_lock(struct fm10k_hw *hw) -{ - while (!rte_spinlock_trylock(FM10K_DEV_PRIVATE_TO_MBXLOCK(hw->back))) - rte_delay_us(FM10K_MBXLOCK_DELAY_US); -} - -static void -fm10k_mbx_unlock(struct fm10k_hw *hw) -{ - rte_spinlock_unlock(FM10K_DEV_PRIVATE_TO_MBXLOCK(hw->back)); -} - -/* - * reset queue to initial state, allocate software buffers used when starting - * device. - * return 0 on success - * return -ENOMEM if buffers cannot be allocated - * return -EINVAL if buffers do not satisfy alignment condition - */ -static inline int -rx_queue_reset(struct fm10k_rx_queue *q) -{ - uint64_t dma_addr; - int i, diag; - PMD_INIT_FUNC_TRACE(); - - diag = rte_mempool_get_bulk(q->mp, (void **)q->sw_ring, q->nb_desc); - if (diag != 0) - return -ENOMEM; - - for (i = 0; i < q->nb_desc; ++i) { - fm10k_pktmbuf_reset(q->sw_ring[i], q->port_id); - if (!fm10k_addr_alignment_valid(q->sw_ring[i])) { - rte_mempool_put_bulk(q->mp, (void **)q->sw_ring, - q->nb_desc); - return -EINVAL; - } - dma_addr = MBUF_DMA_ADDR_DEFAULT(q->sw_ring[i]); - q->hw_ring[i].q.pkt_addr = dma_addr; - q->hw_ring[i].q.hdr_addr = dma_addr; - } - - q->next_dd = 0; - q->next_alloc = 0; - q->next_trigger = q->alloc_thresh - 1; - FM10K_PCI_REG_WRITE(q->tail_ptr, q->nb_desc - 1); - return 0; -} - -/* - * clean queue, descriptor rings, free software buffers used when stopping - * device. - */ -static inline void -rx_queue_clean(struct fm10k_rx_queue *q) -{ - union fm10k_rx_desc zero = {.q = {0, 0, 0, 0} }; - uint32_t i; - PMD_INIT_FUNC_TRACE(); - - /* zero descriptor rings */ - for (i = 0; i < q->nb_desc; ++i) - q->hw_ring[i] = zero; - - /* free software buffers */ - for (i = 0; i < q->nb_desc; ++i) { - if (q->sw_ring[i]) { - rte_pktmbuf_free_seg(q->sw_ring[i]); - q->sw_ring[i] = NULL; - } - } -} - -/* - * free all queue memory used when releasing the queue (i.e. configure) - */ -static inline void -rx_queue_free(struct fm10k_rx_queue *q) -{ - PMD_INIT_FUNC_TRACE(); - if (q) { - PMD_INIT_LOG(DEBUG, "Freeing rx queue %p", q); - rx_queue_clean(q); - if (q->sw_ring) { - rte_free(q->sw_ring); - q->sw_ring = NULL; - } - rte_free(q); - q = NULL; - } -} - -/* - * disable RX queue, wait unitl HW finished necessary flush operation - */ -static inline int -rx_queue_disable(struct fm10k_hw *hw, uint16_t qnum) -{ - uint32_t reg, i; - - reg = FM10K_READ_REG(hw, FM10K_RXQCTL(qnum)); - FM10K_WRITE_REG(hw, FM10K_RXQCTL(qnum), - reg & ~FM10K_RXQCTL_ENABLE); - - /* Wait 100us at most */ - for (i = 0; i < FM10K_QUEUE_DISABLE_TIMEOUT; i++) { - rte_delay_us(1); - reg = FM10K_READ_REG(hw, FM10K_RXQCTL(i)); - if (!(reg & FM10K_RXQCTL_ENABLE)) - break; - } - - if (i == FM10K_QUEUE_DISABLE_TIMEOUT) - return -1; - - return 0; -} - -/* - * reset queue to initial state, allocate software buffers used when starting - * device - */ -static inline void -tx_queue_reset(struct fm10k_tx_queue *q) -{ - PMD_INIT_FUNC_TRACE(); - q->last_free = 0; - q->next_free = 0; - q->nb_used = 0; - q->nb_free = q->nb_desc - 1; - q->free_trigger = q->nb_free - q->free_thresh; - fifo_reset(&q->rs_tracker, (q->nb_desc + 1) / q->rs_thresh); - FM10K_PCI_REG_WRITE(q->tail_ptr, 0); -} - -/* - * clean queue, descriptor rings, free software buffers used when stopping - * device - */ -static inline void -tx_queue_clean(struct fm10k_tx_queue *q) -{ - struct fm10k_tx_desc zero = {0, 0, 0, 0, 0, 0}; - uint32_t i; - PMD_INIT_FUNC_TRACE(); - - /* zero descriptor rings */ - for (i = 0; i < q->nb_desc; ++i) - q->hw_ring[i] = zero; - - /* free software buffers */ - for (i = 0; i < q->nb_desc; ++i) { - if (q->sw_ring[i]) { - rte_pktmbuf_free_seg(q->sw_ring[i]); - q->sw_ring[i] = NULL; - } - } -} - -/* - * free all queue memory used when releasing the queue (i.e. configure) - */ -static inline void -tx_queue_free(struct fm10k_tx_queue *q) -{ - PMD_INIT_FUNC_TRACE(); - if (q) { - PMD_INIT_LOG(DEBUG, "Freeing tx queue %p", q); - tx_queue_clean(q); - if (q->rs_tracker.list) { - rte_free(q->rs_tracker.list); - q->rs_tracker.list = NULL; - } - if (q->sw_ring) { - rte_free(q->sw_ring); - q->sw_ring = NULL; - } - rte_free(q); - q = NULL; - } -} - -/* - * disable TX queue, wait unitl HW finished necessary flush operation - */ -static inline int -tx_queue_disable(struct fm10k_hw *hw, uint16_t qnum) -{ - uint32_t reg, i; - - reg = FM10K_READ_REG(hw, FM10K_TXDCTL(qnum)); - FM10K_WRITE_REG(hw, FM10K_TXDCTL(qnum), - reg & ~FM10K_TXDCTL_ENABLE); - - /* Wait 100us at most */ - for (i = 0; i < FM10K_QUEUE_DISABLE_TIMEOUT; i++) { - rte_delay_us(1); - reg = FM10K_READ_REG(hw, FM10K_TXDCTL(i)); - if (!(reg & FM10K_TXDCTL_ENABLE)) - break; - } - - if (i == FM10K_QUEUE_DISABLE_TIMEOUT) - return -1; - - return 0; -} - -static int -fm10k_dev_configure(struct rte_eth_dev *dev) -{ - PMD_INIT_FUNC_TRACE(); - - if (dev->data->dev_conf.rxmode.hw_strip_crc == 0) - PMD_INIT_LOG(WARNING, "fm10k always strip CRC"); - - return 0; -} - -static void -fm10k_dev_mq_rx_configure(struct rte_eth_dev *dev) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct rte_eth_conf *dev_conf = &dev->data->dev_conf; - uint32_t mrqc, *key, i, reta, j; - uint64_t hf; - -#define RSS_KEY_SIZE 40 - static uint8_t rss_intel_key[RSS_KEY_SIZE] = { - 0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2, - 0x41, 0x67, 0x25, 0x3D, 0x43, 0xA3, 0x8F, 0xB0, - 0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4, - 0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C, - 0x6A, 0x42, 0xB7, 0x3B, 0xBE, 0xAC, 0x01, 0xFA, - }; - - if (dev->data->nb_rx_queues == 1 || - dev_conf->rxmode.mq_mode != ETH_MQ_RX_RSS || - dev_conf->rx_adv_conf.rss_conf.rss_hf == 0) - return; - - /* random key is rss_intel_key (default) or user provided (rss_key) */ - if (dev_conf->rx_adv_conf.rss_conf.rss_key == NULL) - key = (uint32_t *)rss_intel_key; - else - key = (uint32_t *)dev_conf->rx_adv_conf.rss_conf.rss_key; - - /* Now fill our hash function seeds, 4 bytes at a time */ - for (i = 0; i < RSS_KEY_SIZE / sizeof(*key); ++i) - FM10K_WRITE_REG(hw, FM10K_RSSRK(0, i), key[i]); - - /* - * Fill in redirection table - * The byte-swap is needed because NIC registers are in - * little-endian order. - */ - reta = 0; - for (i = 0, j = 0; i < FM10K_RETA_SIZE; i++, j++) { - if (j == dev->data->nb_rx_queues) - j = 0; - reta = (reta << CHAR_BIT) | j; - if ((i & 3) == 3) - FM10K_WRITE_REG(hw, FM10K_RETA(0, i >> 2), - rte_bswap32(reta)); - } - - /* - * Generate RSS hash based on packet types, TCP/UDP - * port numbers and/or IPv4/v6 src and dst addresses - */ - hf = dev_conf->rx_adv_conf.rss_conf.rss_hf; - mrqc = 0; - mrqc |= (hf & ETH_RSS_IPV4) ? FM10K_MRQC_IPV4 : 0; - mrqc |= (hf & ETH_RSS_IPV6) ? FM10K_MRQC_IPV6 : 0; - mrqc |= (hf & ETH_RSS_IPV6_EX) ? FM10K_MRQC_IPV6 : 0; - mrqc |= (hf & ETH_RSS_NONFRAG_IPV4_TCP) ? FM10K_MRQC_TCP_IPV4 : 0; - mrqc |= (hf & ETH_RSS_NONFRAG_IPV6_TCP) ? FM10K_MRQC_TCP_IPV6 : 0; - mrqc |= (hf & ETH_RSS_IPV6_TCP_EX) ? FM10K_MRQC_TCP_IPV6 : 0; - mrqc |= (hf & ETH_RSS_NONFRAG_IPV4_UDP) ? FM10K_MRQC_UDP_IPV4 : 0; - mrqc |= (hf & ETH_RSS_NONFRAG_IPV6_UDP) ? FM10K_MRQC_UDP_IPV6 : 0; - mrqc |= (hf & ETH_RSS_IPV6_UDP_EX) ? FM10K_MRQC_UDP_IPV6 : 0; - - if (mrqc == 0) { - PMD_INIT_LOG(ERR, "Specified RSS mode 0x%"PRIx64"is not" - "supported", hf); - return; - } - - FM10K_WRITE_REG(hw, FM10K_MRQC(0), mrqc); -} - -static int -fm10k_dev_tx_init(struct rte_eth_dev *dev) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - int i, ret; - struct fm10k_tx_queue *txq; - uint64_t base_addr; - uint32_t size; - - /* Disable TXINT to avoid possible interrupt */ - for (i = 0; i < hw->mac.max_queues; i++) - FM10K_WRITE_REG(hw, FM10K_TXINT(i), - 3 << FM10K_TXINT_TIMER_SHIFT); - - /* Setup TX queue */ - for (i = 0; i < dev->data->nb_tx_queues; ++i) { - txq = dev->data->tx_queues[i]; - base_addr = txq->hw_ring_phys_addr; - size = txq->nb_desc * sizeof(struct fm10k_tx_desc); - - /* disable queue to avoid issues while updating state */ - ret = tx_queue_disable(hw, i); - if (ret) { - PMD_INIT_LOG(ERR, "failed to disable queue %d", i); - return -1; - } - - /* set location and size for descriptor ring */ - FM10K_WRITE_REG(hw, FM10K_TDBAL(i), - base_addr & UINT64_LOWER_32BITS_MASK); - FM10K_WRITE_REG(hw, FM10K_TDBAH(i), - base_addr >> (CHAR_BIT * sizeof(uint32_t))); - FM10K_WRITE_REG(hw, FM10K_TDLEN(i), size); - } - return 0; -} - -static int -fm10k_dev_rx_init(struct rte_eth_dev *dev) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - int i, ret; - struct fm10k_rx_queue *rxq; - uint64_t base_addr; - uint32_t size; - uint32_t rxdctl = FM10K_RXDCTL_WRITE_BACK_MIN_DELAY; - uint16_t buf_size; - - /* Disable RXINT to avoid possible interrupt */ - for (i = 0; i < hw->mac.max_queues; i++) - FM10K_WRITE_REG(hw, FM10K_RXINT(i), - 3 << FM10K_RXINT_TIMER_SHIFT); - - /* Setup RX queues */ - for (i = 0; i < dev->data->nb_rx_queues; ++i) { - rxq = dev->data->rx_queues[i]; - base_addr = rxq->hw_ring_phys_addr; - size = rxq->nb_desc * sizeof(union fm10k_rx_desc); - - /* disable queue to avoid issues while updating state */ - ret = rx_queue_disable(hw, i); - if (ret) { - PMD_INIT_LOG(ERR, "failed to disable queue %d", i); - return -1; - } - - /* Setup the Base and Length of the Rx Descriptor Ring */ - FM10K_WRITE_REG(hw, FM10K_RDBAL(i), - base_addr & UINT64_LOWER_32BITS_MASK); - FM10K_WRITE_REG(hw, FM10K_RDBAH(i), - base_addr >> (CHAR_BIT * sizeof(uint32_t))); - FM10K_WRITE_REG(hw, FM10K_RDLEN(i), size); - - /* Configure the Rx buffer size for one buff without split */ - buf_size = (uint16_t)(rte_pktmbuf_data_room_size(rxq->mp) - - RTE_PKTMBUF_HEADROOM); - FM10K_WRITE_REG(hw, FM10K_SRRCTL(i), - buf_size >> FM10K_SRRCTL_BSIZEPKT_SHIFT); - - /* It adds dual VLAN length for supporting dual VLAN */ - if ((dev->data->dev_conf.rxmode.max_rx_pkt_len + - 2 * FM10K_VLAN_TAG_SIZE) > buf_size){ - dev->data->scattered_rx = 1; - dev->rx_pkt_burst = fm10k_recv_scattered_pkts; - } - - /* Enable drop on empty, it's RO for VF */ - if (hw->mac.type == fm10k_mac_pf && rxq->drop_en) - rxdctl |= FM10K_RXDCTL_DROP_ON_EMPTY; - - FM10K_WRITE_REG(hw, FM10K_RXDCTL(i), rxdctl); - FM10K_WRITE_FLUSH(hw); - } - - if (dev->data->dev_conf.rxmode.enable_scatter) { - dev->rx_pkt_burst = fm10k_recv_scattered_pkts; - dev->data->scattered_rx = 1; - } - - /* Configure RSS if applicable */ - fm10k_dev_mq_rx_configure(dev); - return 0; -} - -static int -fm10k_dev_rx_queue_start(struct rte_eth_dev *dev, uint16_t rx_queue_id) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - int err = -1; - uint32_t reg; - struct fm10k_rx_queue *rxq; - - PMD_INIT_FUNC_TRACE(); - - if (rx_queue_id < dev->data->nb_rx_queues) { - rxq = dev->data->rx_queues[rx_queue_id]; - err = rx_queue_reset(rxq); - if (err == -ENOMEM) { - PMD_INIT_LOG(ERR, "Failed to alloc memory : %d", err); - return err; - } else if (err == -EINVAL) { - PMD_INIT_LOG(ERR, "Invalid buffer address alignment :" - " %d", err); - return err; - } - - /* Setup the HW Rx Head and Tail Descriptor Pointers - * Note: this must be done AFTER the queue is enabled on real - * hardware, but BEFORE the queue is enabled when using the - * emulation platform. Do it in both places for now and remove - * this comment and the following two register writes when the - * emulation platform is no longer being used. - */ - FM10K_WRITE_REG(hw, FM10K_RDH(rx_queue_id), 0); - FM10K_WRITE_REG(hw, FM10K_RDT(rx_queue_id), rxq->nb_desc - 1); - - /* Set PF ownership flag for PF devices */ - reg = FM10K_READ_REG(hw, FM10K_RXQCTL(rx_queue_id)); - if (hw->mac.type == fm10k_mac_pf) - reg |= FM10K_RXQCTL_PF; - reg |= FM10K_RXQCTL_ENABLE; - /* enable RX queue */ - FM10K_WRITE_REG(hw, FM10K_RXQCTL(rx_queue_id), reg); - FM10K_WRITE_FLUSH(hw); - - /* Setup the HW Rx Head and Tail Descriptor Pointers - * Note: this must be done AFTER the queue is enabled - */ - FM10K_WRITE_REG(hw, FM10K_RDH(rx_queue_id), 0); - FM10K_WRITE_REG(hw, FM10K_RDT(rx_queue_id), rxq->nb_desc - 1); - } - - return err; -} - -static int -fm10k_dev_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rx_queue_id) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - - PMD_INIT_FUNC_TRACE(); - - if (rx_queue_id < dev->data->nb_rx_queues) { - /* Disable RX queue */ - rx_queue_disable(hw, rx_queue_id); - - /* Free mbuf and clean HW ring */ - rx_queue_clean(dev->data->rx_queues[rx_queue_id]); - } - - return 0; -} - -static int -fm10k_dev_tx_queue_start(struct rte_eth_dev *dev, uint16_t tx_queue_id) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - /** @todo - this should be defined in the shared code */ -#define FM10K_TXDCTL_WRITE_BACK_MIN_DELAY 0x00010000 - uint32_t txdctl = FM10K_TXDCTL_WRITE_BACK_MIN_DELAY; - int err = 0; - - PMD_INIT_FUNC_TRACE(); - - if (tx_queue_id < dev->data->nb_tx_queues) { - tx_queue_reset(dev->data->tx_queues[tx_queue_id]); - - /* reset head and tail pointers */ - FM10K_WRITE_REG(hw, FM10K_TDH(tx_queue_id), 0); - FM10K_WRITE_REG(hw, FM10K_TDT(tx_queue_id), 0); - - /* enable TX queue */ - FM10K_WRITE_REG(hw, FM10K_TXDCTL(tx_queue_id), - FM10K_TXDCTL_ENABLE | txdctl); - FM10K_WRITE_FLUSH(hw); - } else - err = -1; - - return err; -} - -static int -fm10k_dev_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - - PMD_INIT_FUNC_TRACE(); - - if (tx_queue_id < dev->data->nb_tx_queues) { - tx_queue_disable(hw, tx_queue_id); - tx_queue_clean(dev->data->tx_queues[tx_queue_id]); - } - - return 0; -} - -/* fls = find last set bit = 32 minus the number of leading zeros */ -#ifndef fls -#define fls(x) (((x) == 0) ? 0 : (32 - __builtin_clz((x)))) -#endif -#define BSIZEPKT_ROUNDUP ((1 << FM10K_SRRCTL_BSIZEPKT_SHIFT) - 1) -static int -fm10k_dev_start(struct rte_eth_dev *dev) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - int i, diag; - - PMD_INIT_FUNC_TRACE(); - - /* stop, init, then start the hw */ - diag = fm10k_stop_hw(hw); - if (diag != FM10K_SUCCESS) { - PMD_INIT_LOG(ERR, "Hardware stop failed: %d", diag); - return -EIO; - } - - diag = fm10k_init_hw(hw); - if (diag != FM10K_SUCCESS) { - PMD_INIT_LOG(ERR, "Hardware init failed: %d", diag); - return -EIO; - } - - diag = fm10k_start_hw(hw); - if (diag != FM10K_SUCCESS) { - PMD_INIT_LOG(ERR, "Hardware start failed: %d", diag); - return -EIO; - } - - diag = fm10k_dev_tx_init(dev); - if (diag) { - PMD_INIT_LOG(ERR, "TX init failed: %d", diag); - return diag; - } - - diag = fm10k_dev_rx_init(dev); - if (diag) { - PMD_INIT_LOG(ERR, "RX init failed: %d", diag); - return diag; - } - - if (hw->mac.type == fm10k_mac_pf) { - /* Establish only VSI 0 as valid */ - FM10K_WRITE_REG(hw, FM10K_DGLORTMAP(0), FM10K_DGLORTMAP_ANY); - - /* Configure RSS bits used in RETA table */ - FM10K_WRITE_REG(hw, FM10K_DGLORTDEC(0), - fls(dev->data->nb_rx_queues - 1) << - FM10K_DGLORTDEC_RSSLENGTH_SHIFT); - - /* Invalidate all other GLORT entries */ - for (i = 1; i < FM10K_DGLORT_COUNT; i++) - FM10K_WRITE_REG(hw, FM10K_DGLORTMAP(i), - FM10K_DGLORTMAP_NONE); - } - - for (i = 0; i < dev->data->nb_rx_queues; i++) { - struct fm10k_rx_queue *rxq; - rxq = dev->data->rx_queues[i]; - - if (rxq->rx_deferred_start) - continue; - diag = fm10k_dev_rx_queue_start(dev, i); - if (diag != 0) { - int j; - for (j = 0; j < i; ++j) - rx_queue_clean(dev->data->rx_queues[j]); - return diag; - } - } - - for (i = 0; i < dev->data->nb_tx_queues; i++) { - struct fm10k_tx_queue *txq; - txq = dev->data->tx_queues[i]; - - if (txq->tx_deferred_start) - continue; - diag = fm10k_dev_tx_queue_start(dev, i); - if (diag != 0) { - int j; - for (j = 0; j < dev->data->nb_rx_queues; ++j) - rx_queue_clean(dev->data->rx_queues[j]); - return diag; - } - } - - return 0; -} - -static void -fm10k_dev_stop(struct rte_eth_dev *dev) -{ - int i; - - PMD_INIT_FUNC_TRACE(); - - for (i = 0; i < dev->data->nb_tx_queues; i++) - fm10k_dev_tx_queue_stop(dev, i); - - for (i = 0; i < dev->data->nb_rx_queues; i++) - fm10k_dev_rx_queue_stop(dev, i); -} - -static void -fm10k_dev_close(struct rte_eth_dev *dev) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - - PMD_INIT_FUNC_TRACE(); - - /* Stop mailbox service first */ - fm10k_close_mbx_service(hw); - fm10k_dev_stop(dev); - fm10k_stop_hw(hw); -} - -static int -fm10k_link_update(struct rte_eth_dev *dev, - __rte_unused int wait_to_complete) -{ - PMD_INIT_FUNC_TRACE(); - - /* The host-interface link is always up. The speed is ~50Gbps per Gen3 - * x8 PCIe interface. For now, we leave the speed undefined since there - * is no 50Gbps Ethernet. */ - dev->data->dev_link.link_speed = 0; - dev->data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX; - dev->data->dev_link.link_status = 1; - - return 0; -} - -static void -fm10k_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) -{ - uint64_t ipackets, opackets, ibytes, obytes; - struct fm10k_hw *hw = - FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct fm10k_hw_stats *hw_stats = - FM10K_DEV_PRIVATE_TO_STATS(dev->data->dev_private); - int i; - - PMD_INIT_FUNC_TRACE(); - - fm10k_update_hw_stats(hw, hw_stats); - - ipackets = opackets = ibytes = obytes = 0; - for (i = 0; (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) && - (i < FM10K_MAX_QUEUES_PF); ++i) { - stats->q_ipackets[i] = hw_stats->q[i].rx_packets.count; - stats->q_opackets[i] = hw_stats->q[i].tx_packets.count; - stats->q_ibytes[i] = hw_stats->q[i].rx_bytes.count; - stats->q_obytes[i] = hw_stats->q[i].tx_bytes.count; - ipackets += stats->q_ipackets[i]; - opackets += stats->q_opackets[i]; - ibytes += stats->q_ibytes[i]; - obytes += stats->q_obytes[i]; - } - stats->ipackets = ipackets; - stats->opackets = opackets; - stats->ibytes = ibytes; - stats->obytes = obytes; -} - -static void -fm10k_stats_reset(struct rte_eth_dev *dev) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct fm10k_hw_stats *hw_stats = - FM10K_DEV_PRIVATE_TO_STATS(dev->data->dev_private); - - PMD_INIT_FUNC_TRACE(); - - memset(hw_stats, 0, sizeof(*hw_stats)); - fm10k_rebind_hw_stats(hw, hw_stats); -} - -static void -fm10k_dev_infos_get(struct rte_eth_dev *dev, - struct rte_eth_dev_info *dev_info) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - - PMD_INIT_FUNC_TRACE(); - - dev_info->min_rx_bufsize = FM10K_MIN_RX_BUF_SIZE; - dev_info->max_rx_pktlen = FM10K_MAX_PKT_SIZE; - dev_info->max_rx_queues = hw->mac.max_queues; - dev_info->max_tx_queues = hw->mac.max_queues; - dev_info->max_mac_addrs = 1; - dev_info->max_hash_mac_addrs = 0; - dev_info->max_vfs = FM10K_MAX_VF_NUM; - dev_info->max_vmdq_pools = ETH_64_POOLS; - dev_info->rx_offload_capa = - DEV_RX_OFFLOAD_IPV4_CKSUM | - DEV_RX_OFFLOAD_UDP_CKSUM | - DEV_RX_OFFLOAD_TCP_CKSUM; - dev_info->tx_offload_capa = 0; - dev_info->reta_size = FM10K_MAX_RSS_INDICES; - - dev_info->default_rxconf = (struct rte_eth_rxconf) { - .rx_thresh = { - .pthresh = FM10K_DEFAULT_RX_PTHRESH, - .hthresh = FM10K_DEFAULT_RX_HTHRESH, - .wthresh = FM10K_DEFAULT_RX_WTHRESH, - }, - .rx_free_thresh = FM10K_RX_FREE_THRESH_DEFAULT(0), - .rx_drop_en = 0, - }; - - dev_info->default_txconf = (struct rte_eth_txconf) { - .tx_thresh = { - .pthresh = FM10K_DEFAULT_TX_PTHRESH, - .hthresh = FM10K_DEFAULT_TX_HTHRESH, - .wthresh = FM10K_DEFAULT_TX_WTHRESH, - }, - .tx_free_thresh = FM10K_TX_FREE_THRESH_DEFAULT(0), - .tx_rs_thresh = FM10K_TX_RS_THRESH_DEFAULT(0), - .txq_flags = ETH_TXQ_FLAGS_NOMULTSEGS | - ETH_TXQ_FLAGS_NOOFFLOADS, - }; - -} - -static int -fm10k_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - - PMD_INIT_FUNC_TRACE(); - - /* @todo - add support for the VF */ - if (hw->mac.type != fm10k_mac_pf) - return -ENOTSUP; - - return fm10k_update_vlan(hw, vlan_id, 0, on); -} - -static inline int -check_nb_desc(uint16_t min, uint16_t max, uint16_t mult, uint16_t request) -{ - if ((request < min) || (request > max) || ((request % mult) != 0)) - return -1; - else - return 0; -} - -/* - * Create a memzone for hardware descriptor rings. Malloc cannot be used since - * the physical address is required. If the memzone is already created, then - * this function returns a pointer to the existing memzone. - */ -static inline const struct rte_memzone * -allocate_hw_ring(const char *driver_name, const char *ring_name, - uint8_t port_id, uint16_t queue_id, int socket_id, - uint32_t size, uint32_t align) -{ - char name[RTE_MEMZONE_NAMESIZE]; - const struct rte_memzone *mz; - - snprintf(name, sizeof(name), "%s_%s_%d_%d_%d", - driver_name, ring_name, port_id, queue_id, socket_id); - - /* return the memzone if it already exists */ - mz = rte_memzone_lookup(name); - if (mz) - return mz; - -#ifdef RTE_LIBRTE_XEN_DOM0 - return rte_memzone_reserve_bounded(name, size, socket_id, 0, align, - RTE_PGSIZE_2M); -#else - return rte_memzone_reserve_aligned(name, size, socket_id, 0, align); -#endif -} - -static inline int -check_thresh(uint16_t min, uint16_t max, uint16_t div, uint16_t request) -{ - if ((request < min) || (request > max) || ((div % request) != 0)) - return -1; - else - return 0; -} - -static inline int -handle_rxconf(struct fm10k_rx_queue *q, const struct rte_eth_rxconf *conf) -{ - uint16_t rx_free_thresh; - - if (conf->rx_free_thresh == 0) - rx_free_thresh = FM10K_RX_FREE_THRESH_DEFAULT(q); - else - rx_free_thresh = conf->rx_free_thresh; - - /* make sure the requested threshold satisfies the constraints */ - if (check_thresh(FM10K_RX_FREE_THRESH_MIN(q), - FM10K_RX_FREE_THRESH_MAX(q), - FM10K_RX_FREE_THRESH_DIV(q), - rx_free_thresh)) { - PMD_INIT_LOG(ERR, "rx_free_thresh (%u) must be " - "less than or equal to %u, " - "greater than or equal to %u, " - "and a divisor of %u", - rx_free_thresh, FM10K_RX_FREE_THRESH_MAX(q), - FM10K_RX_FREE_THRESH_MIN(q), - FM10K_RX_FREE_THRESH_DIV(q)); - return (-EINVAL); - } - - q->alloc_thresh = rx_free_thresh; - q->drop_en = conf->rx_drop_en; - q->rx_deferred_start = conf->rx_deferred_start; - - return 0; -} - -/* - * Hardware requires specific alignment for Rx packet buffers. At - * least one of the following two conditions must be satisfied. - * 1. Address is 512B aligned - * 2. Address is 8B aligned and buffer does not cross 4K boundary. - * - * As such, the driver may need to adjust the DMA address within the - * buffer by up to 512B. The mempool element size is checked here - * to make sure a maximally sized Ethernet frame can still be wholly - * contained within the buffer after 512B alignment. - * - * return 1 if the element size is valid, otherwise return 0. - */ -static int -mempool_element_size_valid(struct rte_mempool *mp) -{ - uint32_t min_size; - - /* elt_size includes mbuf header and headroom */ - min_size = mp->elt_size - sizeof(struct rte_mbuf) - - RTE_PKTMBUF_HEADROOM; - - /* account for up to 512B of alignment */ - min_size -= FM10K_RX_BUFF_ALIGN; - - /* sanity check for overflow */ - if (min_size > mp->elt_size) - return 0; - - if (min_size < ETHER_MAX_VLAN_FRAME_LEN) - return 0; - - /* size is valid */ - return 1; -} - -static int -fm10k_rx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_id, - uint16_t nb_desc, unsigned int socket_id, - const struct rte_eth_rxconf *conf, struct rte_mempool *mp) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct fm10k_rx_queue *q; - const struct rte_memzone *mz; - - PMD_INIT_FUNC_TRACE(); - - /* make sure the mempool element size can account for alignment. */ - if (!mempool_element_size_valid(mp)) { - PMD_INIT_LOG(ERR, "Error : Mempool element size is too small"); - return (-EINVAL); - } - - /* make sure a valid number of descriptors have been requested */ - if (check_nb_desc(FM10K_MIN_RX_DESC, FM10K_MAX_RX_DESC, - FM10K_MULT_RX_DESC, nb_desc)) { - PMD_INIT_LOG(ERR, "Number of Rx descriptors (%u) must be " - "less than or equal to %"PRIu32", " - "greater than or equal to %u, " - "and a multiple of %u", - nb_desc, (uint32_t)FM10K_MAX_RX_DESC, FM10K_MIN_RX_DESC, - FM10K_MULT_RX_DESC); - return (-EINVAL); - } - - /* - * if this queue existed already, free the associated memory. The - * queue cannot be reused in case we need to allocate memory on - * different socket than was previously used. - */ - if (dev->data->rx_queues[queue_id] != NULL) { - rx_queue_free(dev->data->rx_queues[queue_id]); - dev->data->rx_queues[queue_id] = NULL; - } - - /* allocate memory for the queue structure */ - q = rte_zmalloc_socket("fm10k", sizeof(*q), RTE_CACHE_LINE_SIZE, - socket_id); - if (q == NULL) { - PMD_INIT_LOG(ERR, "Cannot allocate queue structure"); - return (-ENOMEM); - } - - /* setup queue */ - q->mp = mp; - q->nb_desc = nb_desc; - q->port_id = dev->data->port_id; - q->queue_id = queue_id; - q->tail_ptr = (volatile uint32_t *) - &((uint32_t *)hw->hw_addr)[FM10K_RDT(queue_id)]; - if (handle_rxconf(q, conf)) - return (-EINVAL); - - /* allocate memory for the software ring */ - q->sw_ring = rte_zmalloc_socket("fm10k sw ring", - nb_desc * sizeof(struct rte_mbuf *), - RTE_CACHE_LINE_SIZE, socket_id); - if (q->sw_ring == NULL) { - PMD_INIT_LOG(ERR, "Cannot allocate software ring"); - rte_free(q); - return (-ENOMEM); - } - - /* - * allocate memory for the hardware descriptor ring. A memzone large - * enough to hold the maximum ring size is requested to allow for - * resizing in later calls to the queue setup function. - */ - mz = allocate_hw_ring(dev->driver->pci_drv.name, "rx_ring", - dev->data->port_id, queue_id, socket_id, - FM10K_MAX_RX_RING_SZ, FM10K_ALIGN_RX_DESC); - if (mz == NULL) { - PMD_INIT_LOG(ERR, "Cannot allocate hardware ring"); - rte_free(q->sw_ring); - rte_free(q); - return (-ENOMEM); - } - q->hw_ring = mz->addr; - q->hw_ring_phys_addr = mz->phys_addr; - - dev->data->rx_queues[queue_id] = q; - return 0; -} - -static void -fm10k_rx_queue_release(void *queue) -{ - PMD_INIT_FUNC_TRACE(); - - rx_queue_free(queue); -} - -static inline int -handle_txconf(struct fm10k_tx_queue *q, const struct rte_eth_txconf *conf) -{ - uint16_t tx_free_thresh; - uint16_t tx_rs_thresh; - - /* constraint MACROs require that tx_free_thresh is configured - * before tx_rs_thresh */ - if (conf->tx_free_thresh == 0) - tx_free_thresh = FM10K_TX_FREE_THRESH_DEFAULT(q); - else - tx_free_thresh = conf->tx_free_thresh; - - /* make sure the requested threshold satisfies the constraints */ - if (check_thresh(FM10K_TX_FREE_THRESH_MIN(q), - FM10K_TX_FREE_THRESH_MAX(q), - FM10K_TX_FREE_THRESH_DIV(q), - tx_free_thresh)) { - PMD_INIT_LOG(ERR, "tx_free_thresh (%u) must be " - "less than or equal to %u, " - "greater than or equal to %u, " - "and a divisor of %u", - tx_free_thresh, FM10K_TX_FREE_THRESH_MAX(q), - FM10K_TX_FREE_THRESH_MIN(q), - FM10K_TX_FREE_THRESH_DIV(q)); - return (-EINVAL); - } - - q->free_thresh = tx_free_thresh; - - if (conf->tx_rs_thresh == 0) - tx_rs_thresh = FM10K_TX_RS_THRESH_DEFAULT(q); - else - tx_rs_thresh = conf->tx_rs_thresh; - - q->tx_deferred_start = conf->tx_deferred_start; - - /* make sure the requested threshold satisfies the constraints */ - if (check_thresh(FM10K_TX_RS_THRESH_MIN(q), - FM10K_TX_RS_THRESH_MAX(q), - FM10K_TX_RS_THRESH_DIV(q), - tx_rs_thresh)) { - PMD_INIT_LOG(ERR, "tx_rs_thresh (%u) must be " - "less than or equal to %u, " - "greater than or equal to %u, " - "and a divisor of %u", - tx_rs_thresh, FM10K_TX_RS_THRESH_MAX(q), - FM10K_TX_RS_THRESH_MIN(q), - FM10K_TX_RS_THRESH_DIV(q)); - return (-EINVAL); - } - - q->rs_thresh = tx_rs_thresh; - - return 0; -} - -static int -fm10k_tx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_id, - uint16_t nb_desc, unsigned int socket_id, - const struct rte_eth_txconf *conf) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct fm10k_tx_queue *q; - const struct rte_memzone *mz; - - PMD_INIT_FUNC_TRACE(); - - /* make sure a valid number of descriptors have been requested */ - if (check_nb_desc(FM10K_MIN_TX_DESC, FM10K_MAX_TX_DESC, - FM10K_MULT_TX_DESC, nb_desc)) { - PMD_INIT_LOG(ERR, "Number of Tx descriptors (%u) must be " - "less than or equal to %"PRIu32", " - "greater than or equal to %u, " - "and a multiple of %u", - nb_desc, (uint32_t)FM10K_MAX_TX_DESC, FM10K_MIN_TX_DESC, - FM10K_MULT_TX_DESC); - return (-EINVAL); - } - - /* - * if this queue existed already, free the associated memory. The - * queue cannot be reused in case we need to allocate memory on - * different socket than was previously used. - */ - if (dev->data->tx_queues[queue_id] != NULL) { - tx_queue_free(dev->data->tx_queues[queue_id]); - dev->data->tx_queues[queue_id] = NULL; - } - - /* allocate memory for the queue structure */ - q = rte_zmalloc_socket("fm10k", sizeof(*q), RTE_CACHE_LINE_SIZE, - socket_id); - if (q == NULL) { - PMD_INIT_LOG(ERR, "Cannot allocate queue structure"); - return (-ENOMEM); - } - - /* setup queue */ - q->nb_desc = nb_desc; - q->port_id = dev->data->port_id; - q->queue_id = queue_id; - q->tail_ptr = (volatile uint32_t *) - &((uint32_t *)hw->hw_addr)[FM10K_TDT(queue_id)]; - if (handle_txconf(q, conf)) - return (-EINVAL); - - /* allocate memory for the software ring */ - q->sw_ring = rte_zmalloc_socket("fm10k sw ring", - nb_desc * sizeof(struct rte_mbuf *), - RTE_CACHE_LINE_SIZE, socket_id); - if (q->sw_ring == NULL) { - PMD_INIT_LOG(ERR, "Cannot allocate software ring"); - rte_free(q); - return (-ENOMEM); - } - - /* - * allocate memory for the hardware descriptor ring. A memzone large - * enough to hold the maximum ring size is requested to allow for - * resizing in later calls to the queue setup function. - */ - mz = allocate_hw_ring(dev->driver->pci_drv.name, "tx_ring", - dev->data->port_id, queue_id, socket_id, - FM10K_MAX_TX_RING_SZ, FM10K_ALIGN_TX_DESC); - if (mz == NULL) { - PMD_INIT_LOG(ERR, "Cannot allocate hardware ring"); - rte_free(q->sw_ring); - rte_free(q); - return (-ENOMEM); - } - q->hw_ring = mz->addr; - q->hw_ring_phys_addr = mz->phys_addr; - - /* - * allocate memory for the RS bit tracker. Enough slots to hold the - * descriptor index for each RS bit needing to be set are required. - */ - q->rs_tracker.list = rte_zmalloc_socket("fm10k rs tracker", - ((nb_desc + 1) / q->rs_thresh) * - sizeof(uint16_t), - RTE_CACHE_LINE_SIZE, socket_id); - if (q->rs_tracker.list == NULL) { - PMD_INIT_LOG(ERR, "Cannot allocate RS bit tracker"); - rte_free(q->sw_ring); - rte_free(q); - return (-ENOMEM); - } - - dev->data->tx_queues[queue_id] = q; - return 0; -} - -static void -fm10k_tx_queue_release(void *queue) -{ - PMD_INIT_FUNC_TRACE(); - - tx_queue_free(queue); -} - -static int -fm10k_reta_update(struct rte_eth_dev *dev, - struct rte_eth_rss_reta_entry64 *reta_conf, - uint16_t reta_size) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint16_t i, j, idx, shift; - uint8_t mask; - uint32_t reta; - - PMD_INIT_FUNC_TRACE(); - - if (reta_size > FM10K_MAX_RSS_INDICES) { - PMD_INIT_LOG(ERR, "The size of hash lookup table configured " - "(%d) doesn't match the number hardware can supported " - "(%d)", reta_size, FM10K_MAX_RSS_INDICES); - return -EINVAL; - } - - /* - * Update Redirection Table RETA[n], n=0..31. The redirection table has - * 128-entries in 32 registers - */ - for (i = 0; i < FM10K_MAX_RSS_INDICES; i += CHARS_PER_UINT32) { - idx = i / RTE_RETA_GROUP_SIZE; - shift = i % RTE_RETA_GROUP_SIZE; - mask = (uint8_t)((reta_conf[idx].mask >> shift) & - BIT_MASK_PER_UINT32); - if (mask == 0) - continue; - - reta = 0; - if (mask != BIT_MASK_PER_UINT32) - reta = FM10K_READ_REG(hw, FM10K_RETA(0, i >> 2)); - - for (j = 0; j < CHARS_PER_UINT32; j++) { - if (mask & (0x1 << j)) { - if (mask != 0xF) - reta &= ~(UINT8_MAX << CHAR_BIT * j); - reta |= reta_conf[idx].reta[shift + j] << - (CHAR_BIT * j); - } - } - FM10K_WRITE_REG(hw, FM10K_RETA(0, i >> 2), reta); - } - - return 0; -} - -static int -fm10k_reta_query(struct rte_eth_dev *dev, - struct rte_eth_rss_reta_entry64 *reta_conf, - uint16_t reta_size) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint16_t i, j, idx, shift; - uint8_t mask; - uint32_t reta; - - PMD_INIT_FUNC_TRACE(); - - if (reta_size < FM10K_MAX_RSS_INDICES) { - PMD_INIT_LOG(ERR, "The size of hash lookup table configured " - "(%d) doesn't match the number hardware can supported " - "(%d)", reta_size, FM10K_MAX_RSS_INDICES); - return -EINVAL; - } - - /* - * Read Redirection Table RETA[n], n=0..31. The redirection table has - * 128-entries in 32 registers - */ - for (i = 0; i < FM10K_MAX_RSS_INDICES; i += CHARS_PER_UINT32) { - idx = i / RTE_RETA_GROUP_SIZE; - shift = i % RTE_RETA_GROUP_SIZE; - mask = (uint8_t)((reta_conf[idx].mask >> shift) & - BIT_MASK_PER_UINT32); - if (mask == 0) - continue; - - reta = FM10K_READ_REG(hw, FM10K_RETA(0, i >> 2)); - for (j = 0; j < CHARS_PER_UINT32; j++) { - if (mask & (0x1 << j)) - reta_conf[idx].reta[shift + j] = ((reta >> - CHAR_BIT * j) & UINT8_MAX); - } - } - - return 0; -} - -static int -fm10k_rss_hash_update(struct rte_eth_dev *dev, - struct rte_eth_rss_conf *rss_conf) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint32_t *key = (uint32_t *)rss_conf->rss_key; - uint32_t mrqc; - uint64_t hf = rss_conf->rss_hf; - int i; - - PMD_INIT_FUNC_TRACE(); - - if (rss_conf->rss_key_len < FM10K_RSSRK_SIZE * - FM10K_RSSRK_ENTRIES_PER_REG) - return -EINVAL; - - if (hf == 0) - return -EINVAL; - - mrqc = 0; - mrqc |= (hf & ETH_RSS_IPV4) ? FM10K_MRQC_IPV4 : 0; - mrqc |= (hf & ETH_RSS_IPV6) ? FM10K_MRQC_IPV6 : 0; - mrqc |= (hf & ETH_RSS_IPV6_EX) ? FM10K_MRQC_IPV6 : 0; - mrqc |= (hf & ETH_RSS_NONFRAG_IPV4_TCP) ? FM10K_MRQC_TCP_IPV4 : 0; - mrqc |= (hf & ETH_RSS_NONFRAG_IPV6_TCP) ? FM10K_MRQC_TCP_IPV6 : 0; - mrqc |= (hf & ETH_RSS_IPV6_TCP_EX) ? FM10K_MRQC_TCP_IPV6 : 0; - mrqc |= (hf & ETH_RSS_NONFRAG_IPV4_UDP) ? FM10K_MRQC_UDP_IPV4 : 0; - mrqc |= (hf & ETH_RSS_NONFRAG_IPV6_UDP) ? FM10K_MRQC_UDP_IPV6 : 0; - mrqc |= (hf & ETH_RSS_IPV6_UDP_EX) ? FM10K_MRQC_UDP_IPV6 : 0; - - /* If the mapping doesn't fit any supported, return */ - if (mrqc == 0) - return -EINVAL; - - if (key != NULL) - for (i = 0; i < FM10K_RSSRK_SIZE; ++i) - FM10K_WRITE_REG(hw, FM10K_RSSRK(0, i), key[i]); - - FM10K_WRITE_REG(hw, FM10K_MRQC(0), mrqc); - - return 0; -} - -static int -fm10k_rss_hash_conf_get(struct rte_eth_dev *dev, - struct rte_eth_rss_conf *rss_conf) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint32_t *key = (uint32_t *)rss_conf->rss_key; - uint32_t mrqc; - uint64_t hf; - int i; - - PMD_INIT_FUNC_TRACE(); - - if (rss_conf->rss_key_len < FM10K_RSSRK_SIZE * - FM10K_RSSRK_ENTRIES_PER_REG) - return -EINVAL; - - if (key != NULL) - for (i = 0; i < FM10K_RSSRK_SIZE; ++i) - key[i] = FM10K_READ_REG(hw, FM10K_RSSRK(0, i)); - - mrqc = FM10K_READ_REG(hw, FM10K_MRQC(0)); - hf = 0; - hf |= (mrqc & FM10K_MRQC_IPV4) ? ETH_RSS_IPV4 : 0; - hf |= (mrqc & FM10K_MRQC_IPV6) ? ETH_RSS_IPV6 : 0; - hf |= (mrqc & FM10K_MRQC_IPV6) ? ETH_RSS_IPV6_EX : 0; - hf |= (mrqc & FM10K_MRQC_TCP_IPV4) ? ETH_RSS_NONFRAG_IPV4_TCP : 0; - hf |= (mrqc & FM10K_MRQC_TCP_IPV6) ? ETH_RSS_NONFRAG_IPV6_TCP : 0; - hf |= (mrqc & FM10K_MRQC_TCP_IPV6) ? ETH_RSS_IPV6_TCP_EX : 0; - hf |= (mrqc & FM10K_MRQC_UDP_IPV4) ? ETH_RSS_NONFRAG_IPV4_UDP : 0; - hf |= (mrqc & FM10K_MRQC_UDP_IPV6) ? ETH_RSS_NONFRAG_IPV6_UDP : 0; - hf |= (mrqc & FM10K_MRQC_UDP_IPV6) ? ETH_RSS_IPV6_UDP_EX : 0; - - rss_conf->rss_hf = hf; - - return 0; -} - -static void -fm10k_dev_enable_intr_pf(struct rte_eth_dev *dev) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint32_t int_map = FM10K_INT_MAP_IMMEDIATE; - - /* Bind all local non-queue interrupt to vector 0 */ - int_map |= 0; - - FM10K_WRITE_REG(hw, FM10K_INT_MAP(fm10k_int_Mailbox), int_map); - FM10K_WRITE_REG(hw, FM10K_INT_MAP(fm10k_int_PCIeFault), int_map); - FM10K_WRITE_REG(hw, FM10K_INT_MAP(fm10k_int_SwitchUpDown), int_map); - FM10K_WRITE_REG(hw, FM10K_INT_MAP(fm10k_int_SwitchEvent), int_map); - FM10K_WRITE_REG(hw, FM10K_INT_MAP(fm10k_int_SRAM), int_map); - FM10K_WRITE_REG(hw, FM10K_INT_MAP(fm10k_int_VFLR), int_map); - - /* Enable misc causes */ - FM10K_WRITE_REG(hw, FM10K_EIMR, FM10K_EIMR_ENABLE(PCA_FAULT) | - FM10K_EIMR_ENABLE(THI_FAULT) | - FM10K_EIMR_ENABLE(FUM_FAULT) | - FM10K_EIMR_ENABLE(MAILBOX) | - FM10K_EIMR_ENABLE(SWITCHREADY) | - FM10K_EIMR_ENABLE(SWITCHNOTREADY) | - FM10K_EIMR_ENABLE(SRAMERROR) | - FM10K_EIMR_ENABLE(VFLR)); - - /* Enable ITR 0 */ - FM10K_WRITE_REG(hw, FM10K_ITR(0), FM10K_ITR_AUTOMASK | - FM10K_ITR_MASK_CLEAR); - FM10K_WRITE_FLUSH(hw); -} - -static void -fm10k_dev_enable_intr_vf(struct rte_eth_dev *dev) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint32_t int_map = FM10K_INT_MAP_IMMEDIATE; - - /* Bind all local non-queue interrupt to vector 0 */ - int_map |= 0; - - /* Only INT 0 available, other 15 are reserved. */ - FM10K_WRITE_REG(hw, FM10K_VFINT_MAP, int_map); - - /* Enable ITR 0 */ - FM10K_WRITE_REG(hw, FM10K_VFITR(0), FM10K_ITR_AUTOMASK | - FM10K_ITR_MASK_CLEAR); - FM10K_WRITE_FLUSH(hw); -} - -static int -fm10k_dev_handle_fault(struct fm10k_hw *hw, uint32_t eicr) -{ - struct fm10k_fault fault; - int err; - const char *estr = "Unknown error"; - - /* Process PCA fault */ - if (eicr & FM10K_EIMR_PCA_FAULT) { - err = fm10k_get_fault(hw, FM10K_PCA_FAULT, &fault); - if (err) - goto error; - switch (fault.type) { - case PCA_NO_FAULT: - estr = "PCA_NO_FAULT"; break; - case PCA_UNMAPPED_ADDR: - estr = "PCA_UNMAPPED_ADDR"; break; - case PCA_BAD_QACCESS_PF: - estr = "PCA_BAD_QACCESS_PF"; break; - case PCA_BAD_QACCESS_VF: - estr = "PCA_BAD_QACCESS_VF"; break; - case PCA_MALICIOUS_REQ: - estr = "PCA_MALICIOUS_REQ"; break; - case PCA_POISONED_TLP: - estr = "PCA_POISONED_TLP"; break; - case PCA_TLP_ABORT: - estr = "PCA_TLP_ABORT"; break; - default: - goto error; - } - PMD_INIT_LOG(ERR, "%s: %s(%d) Addr:0x%"PRIx64" Spec: 0x%x", - estr, fault.func ? "VF" : "PF", fault.func, - fault.address, fault.specinfo); - } - - /* Process THI fault */ - if (eicr & FM10K_EIMR_THI_FAULT) { - err = fm10k_get_fault(hw, FM10K_THI_FAULT, &fault); - if (err) - goto error; - switch (fault.type) { - case THI_NO_FAULT: - estr = "THI_NO_FAULT"; break; - case THI_MAL_DIS_Q_FAULT: - estr = "THI_MAL_DIS_Q_FAULT"; break; - default: - goto error; - } - PMD_INIT_LOG(ERR, "%s: %s(%d) Addr:0x%"PRIx64" Spec: 0x%x", - estr, fault.func ? "VF" : "PF", fault.func, - fault.address, fault.specinfo); - } - - /* Process FUM fault */ - if (eicr & FM10K_EIMR_FUM_FAULT) { - err = fm10k_get_fault(hw, FM10K_FUM_FAULT, &fault); - if (err) - goto error; - switch (fault.type) { - case FUM_NO_FAULT: - estr = "FUM_NO_FAULT"; break; - case FUM_UNMAPPED_ADDR: - estr = "FUM_UNMAPPED_ADDR"; break; - case FUM_POISONED_TLP: - estr = "FUM_POISONED_TLP"; break; - case FUM_BAD_VF_QACCESS: - estr = "FUM_BAD_VF_QACCESS"; break; - case FUM_ADD_DECODE_ERR: - estr = "FUM_ADD_DECODE_ERR"; break; - case FUM_RO_ERROR: - estr = "FUM_RO_ERROR"; break; - case FUM_QPRC_CRC_ERROR: - estr = "FUM_QPRC_CRC_ERROR"; break; - case FUM_CSR_TIMEOUT: - estr = "FUM_CSR_TIMEOUT"; break; - case FUM_INVALID_TYPE: - estr = "FUM_INVALID_TYPE"; break; - case FUM_INVALID_LENGTH: - estr = "FUM_INVALID_LENGTH"; break; - case FUM_INVALID_BE: - estr = "FUM_INVALID_BE"; break; - case FUM_INVALID_ALIGN: - estr = "FUM_INVALID_ALIGN"; break; - default: - goto error; - } - PMD_INIT_LOG(ERR, "%s: %s(%d) Addr:0x%"PRIx64" Spec: 0x%x", - estr, fault.func ? "VF" : "PF", fault.func, - fault.address, fault.specinfo); - } - - if (estr) - return 0; - return 0; -error: - PMD_INIT_LOG(ERR, "Failed to handle fault event."); - return err; -} - -/** - * PF interrupt handler triggered by NIC for handling specific interrupt. - * - * @param handle - * Pointer to interrupt handle. - * @param param - * The address of parameter (struct rte_eth_dev *) regsitered before. - * - * @return - * void - */ -static void -fm10k_dev_interrupt_handler_pf( - __rte_unused struct rte_intr_handle *handle, - void *param) -{ - struct rte_eth_dev *dev = (struct rte_eth_dev *)param; - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint32_t cause, status; - - if (hw->mac.type != fm10k_mac_pf) - return; - - cause = FM10K_READ_REG(hw, FM10K_EICR); - - /* Handle PCI fault cases */ - if (cause & FM10K_EICR_FAULT_MASK) { - PMD_INIT_LOG(ERR, "INT: find fault!"); - fm10k_dev_handle_fault(hw, cause); - } - - /* Handle switch up/down */ - if (cause & FM10K_EICR_SWITCHNOTREADY) - PMD_INIT_LOG(ERR, "INT: Switch is not ready"); - - if (cause & FM10K_EICR_SWITCHREADY) - PMD_INIT_LOG(INFO, "INT: Switch is ready"); - - /* Handle mailbox message */ - fm10k_mbx_lock(hw); - hw->mbx.ops.process(hw, &hw->mbx); - fm10k_mbx_unlock(hw); - - /* Handle SRAM error */ - if (cause & FM10K_EICR_SRAMERROR) { - PMD_INIT_LOG(ERR, "INT: SRAM error on PEP"); - - status = FM10K_READ_REG(hw, FM10K_SRAM_IP); - /* Write to clear pending bits */ - FM10K_WRITE_REG(hw, FM10K_SRAM_IP, status); - - /* Todo: print out error message after shared code updates */ - } - - /* Clear these 3 events if having any */ - cause &= FM10K_EICR_SWITCHNOTREADY | FM10K_EICR_MAILBOX | - FM10K_EICR_SWITCHREADY; - if (cause) - FM10K_WRITE_REG(hw, FM10K_EICR, cause); - - /* Re-enable interrupt from device side */ - FM10K_WRITE_REG(hw, FM10K_ITR(0), FM10K_ITR_AUTOMASK | - FM10K_ITR_MASK_CLEAR); - /* Re-enable interrupt from host side */ - rte_intr_enable(&(dev->pci_dev->intr_handle)); -} - -/** - * VF interrupt handler triggered by NIC for handling specific interrupt. - * - * @param handle - * Pointer to interrupt handle. - * @param param - * The address of parameter (struct rte_eth_dev *) regsitered before. - * - * @return - * void - */ -static void -fm10k_dev_interrupt_handler_vf( - __rte_unused struct rte_intr_handle *handle, - void *param) -{ - struct rte_eth_dev *dev = (struct rte_eth_dev *)param; - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - - if (hw->mac.type != fm10k_mac_vf) - return; - - /* Handle mailbox message if lock is acquired */ - fm10k_mbx_lock(hw); - hw->mbx.ops.process(hw, &hw->mbx); - fm10k_mbx_unlock(hw); - - /* Re-enable interrupt from device side */ - FM10K_WRITE_REG(hw, FM10K_VFITR(0), FM10K_ITR_AUTOMASK | - FM10K_ITR_MASK_CLEAR); - /* Re-enable interrupt from host side */ - rte_intr_enable(&(dev->pci_dev->intr_handle)); -} - -/* Mailbox message handler in VF */ -static const struct fm10k_msg_data fm10k_msgdata_vf[] = { - FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test), - FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_msg_mac_vlan_vf), - FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_msg_lport_state_vf), - FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error), -}; - -/* Mailbox message handler in PF */ -static const struct fm10k_msg_data fm10k_msgdata_pf[] = { - FM10K_PF_MSG_ERR_HANDLER(XCAST_MODES, fm10k_msg_err_pf), - FM10K_PF_MSG_ERR_HANDLER(UPDATE_MAC_FWD_RULE, fm10k_msg_err_pf), - FM10K_PF_MSG_LPORT_MAP_HANDLER(fm10k_msg_lport_map_pf), - FM10K_PF_MSG_ERR_HANDLER(LPORT_CREATE, fm10k_msg_err_pf), - FM10K_PF_MSG_ERR_HANDLER(LPORT_DELETE, fm10k_msg_err_pf), - FM10K_PF_MSG_UPDATE_PVID_HANDLER(fm10k_msg_update_pvid_pf), - FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error), -}; - -static int -fm10k_setup_mbx_service(struct fm10k_hw *hw) -{ - int err; - - /* Initialize mailbox lock */ - fm10k_mbx_initlock(hw); - - /* Replace default message handler with new ones */ - if (hw->mac.type == fm10k_mac_pf) - err = hw->mbx.ops.register_handlers(&hw->mbx, fm10k_msgdata_pf); - else - err = hw->mbx.ops.register_handlers(&hw->mbx, fm10k_msgdata_vf); - - if (err) { - PMD_INIT_LOG(ERR, "Failed to register mailbox handler.err:%d", - err); - return err; - } - /* Connect to SM for PF device or PF for VF device */ - return hw->mbx.ops.connect(hw, &hw->mbx); -} - -static void -fm10k_close_mbx_service(struct fm10k_hw *hw) -{ - /* Disconnect from SM for PF device or PF for VF device */ - hw->mbx.ops.disconnect(hw, &hw->mbx); -} - -static const struct eth_dev_ops fm10k_eth_dev_ops = { - .dev_configure = fm10k_dev_configure, - .dev_start = fm10k_dev_start, - .dev_stop = fm10k_dev_stop, - .dev_close = fm10k_dev_close, - .stats_get = fm10k_stats_get, - .stats_reset = fm10k_stats_reset, - .link_update = fm10k_link_update, - .dev_infos_get = fm10k_dev_infos_get, - .vlan_filter_set = fm10k_vlan_filter_set, - .rx_queue_start = fm10k_dev_rx_queue_start, - .rx_queue_stop = fm10k_dev_rx_queue_stop, - .tx_queue_start = fm10k_dev_tx_queue_start, - .tx_queue_stop = fm10k_dev_tx_queue_stop, - .rx_queue_setup = fm10k_rx_queue_setup, - .rx_queue_release = fm10k_rx_queue_release, - .tx_queue_setup = fm10k_tx_queue_setup, - .tx_queue_release = fm10k_tx_queue_release, - .reta_update = fm10k_reta_update, - .reta_query = fm10k_reta_query, - .rss_hash_update = fm10k_rss_hash_update, - .rss_hash_conf_get = fm10k_rss_hash_conf_get, -}; - -static int -eth_fm10k_dev_init(struct rte_eth_dev *dev) -{ - struct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private); - int diag; - - PMD_INIT_FUNC_TRACE(); - - dev->dev_ops = &fm10k_eth_dev_ops; - dev->rx_pkt_burst = &fm10k_recv_pkts; - dev->tx_pkt_burst = &fm10k_xmit_pkts; - - if (dev->data->scattered_rx) - dev->rx_pkt_burst = &fm10k_recv_scattered_pkts; - - /* only initialize in the primary process */ - if (rte_eal_process_type() != RTE_PROC_PRIMARY) - return 0; - - /* Vendor and Device ID need to be set before init of shared code */ - memset(hw, 0, sizeof(*hw)); - hw->device_id = dev->pci_dev->id.device_id; - hw->vendor_id = dev->pci_dev->id.vendor_id; - hw->subsystem_device_id = dev->pci_dev->id.subsystem_device_id; - hw->subsystem_vendor_id = dev->pci_dev->id.subsystem_vendor_id; - hw->revision_id = 0; - hw->hw_addr = (void *)dev->pci_dev->mem_resource[0].addr; - if (hw->hw_addr == NULL) { - PMD_INIT_LOG(ERR, "Bad mem resource." - " Try to blacklist unused devices."); - return -EIO; - } - - /* Store fm10k_adapter pointer */ - hw->back = dev->data->dev_private; - - /* Initialize the shared code */ - diag = fm10k_init_shared_code(hw); - if (diag != FM10K_SUCCESS) { - PMD_INIT_LOG(ERR, "Shared code init failed: %d", diag); - return -EIO; - } - - /* - * Inialize bus info. Normally we would call fm10k_get_bus_info(), but - * there is no way to get link status without reading BAR4. Until this - * works, assume we have maximum bandwidth. - * @todo - fix bus info - */ - hw->bus_caps.speed = fm10k_bus_speed_8000; - hw->bus_caps.width = fm10k_bus_width_pcie_x8; - hw->bus_caps.payload = fm10k_bus_payload_512; - hw->bus.speed = fm10k_bus_speed_8000; - hw->bus.width = fm10k_bus_width_pcie_x8; - hw->bus.payload = fm10k_bus_payload_256; - - /* Initialize the hw */ - diag = fm10k_init_hw(hw); - if (diag != FM10K_SUCCESS) { - PMD_INIT_LOG(ERR, "Hardware init failed: %d", diag); - return -EIO; - } - - /* Initialize MAC address(es) */ - dev->data->mac_addrs = rte_zmalloc("fm10k", ETHER_ADDR_LEN, 0); - if (dev->data->mac_addrs == NULL) { - PMD_INIT_LOG(ERR, "Cannot allocate memory for MAC addresses"); - return -ENOMEM; - } - - diag = fm10k_read_mac_addr(hw); - if (diag != FM10K_SUCCESS) { - /* - * TODO: remove special handling on VF. Need shared code to - * fix first. - */ - if (hw->mac.type == fm10k_mac_pf) { - PMD_INIT_LOG(ERR, "Read MAC addr failed: %d", diag); - return -EIO; - } else { - /* Generate a random addr */ - eth_random_addr(hw->mac.addr); - memcpy(hw->mac.perm_addr, hw->mac.addr, ETH_ALEN); - } - } - - ether_addr_copy((const struct ether_addr *)hw->mac.addr, - &dev->data->mac_addrs[0]); - - /* Reset the hw statistics */ - fm10k_stats_reset(dev); - - /* Reset the hw */ - diag = fm10k_reset_hw(hw); - if (diag != FM10K_SUCCESS) { - PMD_INIT_LOG(ERR, "Hardware reset failed: %d", diag); - return -EIO; - } - - /* Setup mailbox service */ - diag = fm10k_setup_mbx_service(hw); - if (diag != FM10K_SUCCESS) { - PMD_INIT_LOG(ERR, "Failed to setup mailbox: %d", diag); - return -EIO; - } - - /*PF/VF has different interrupt handling mechanism */ - if (hw->mac.type == fm10k_mac_pf) { - /* register callback func to eal lib */ - rte_intr_callback_register(&(dev->pci_dev->intr_handle), - fm10k_dev_interrupt_handler_pf, (void *)dev); - - /* enable MISC interrupt */ - fm10k_dev_enable_intr_pf(dev); - } else { /* VF */ - rte_intr_callback_register(&(dev->pci_dev->intr_handle), - fm10k_dev_interrupt_handler_vf, (void *)dev); - - fm10k_dev_enable_intr_vf(dev); - } - - /* - * Below function will trigger operations on mailbox, acquire lock to - * avoid race condition from interrupt handler. Operations on mailbox - * FIFO will trigger interrupt to PF/SM, in which interrupt handler - * will handle and generate an interrupt to our side. Then, FIFO in - * mailbox will be touched. - */ - fm10k_mbx_lock(hw); - /* Enable port first */ - hw->mac.ops.update_lport_state(hw, 0, 0, 1); - - /* Update default vlan */ - hw->mac.ops.update_vlan(hw, hw->mac.default_vid, 0, true); - - /* - * Add default mac/vlan filter. glort is assigned by SM for PF, while is - * unused for VF. PF will assign correct glort for VF. - */ - hw->mac.ops.update_uc_addr(hw, hw->mac.dglort_map, hw->mac.addr, - hw->mac.default_vid, 1, 0); - - /* Set unicast mode by default. App can change to other mode in other - * API func. - */ - hw->mac.ops.update_xcast_mode(hw, hw->mac.dglort_map, - FM10K_XCAST_MODE_MULTI); - - fm10k_mbx_unlock(hw); - - /* enable uio intr after callback registered */ - rte_intr_enable(&(dev->pci_dev->intr_handle)); - - return 0; -} - -/* - * The set of PCI devices this driver supports. This driver will enable both PF - * and SRIOV-VF devices. - */ -static const struct rte_pci_id pci_id_fm10k_map[] = { -#define RTE_PCI_DEV_ID_DECL_FM10K(vend, dev) { RTE_PCI_DEVICE(vend, dev) }, -#define RTE_PCI_DEV_ID_DECL_FM10KVF(vend, dev) { RTE_PCI_DEVICE(vend, dev) }, -#include "rte_pci_dev_ids.h" - { .vendor_id = 0, /* sentinel */ }, -}; - -static struct eth_driver rte_pmd_fm10k = { - { - .name = "rte_pmd_fm10k", - .id_table = pci_id_fm10k_map, - .drv_flags = RTE_PCI_DRV_NEED_MAPPING, - }, - .eth_dev_init = eth_fm10k_dev_init, - .dev_private_size = sizeof(struct fm10k_adapter), -}; - -/* - * Driver initialization routine. - * Invoked once at EAL init time. - * Register itself as the [Poll Mode] Driver of PCI FM10K devices. - */ -static int -rte_pmd_fm10k_init(__rte_unused const char *name, - __rte_unused const char *params) -{ - PMD_INIT_FUNC_TRACE(); - rte_eth_driver_register(&rte_pmd_fm10k); - return 0; -} - -static struct rte_driver rte_fm10k_driver = { - .type = PMD_PDEV, - .init = rte_pmd_fm10k_init, -}; - -PMD_REGISTER_DRIVER(rte_fm10k_driver); diff --git a/lib/librte_pmd_fm10k/fm10k_logs.h b/lib/librte_pmd_fm10k/fm10k_logs.h deleted file mode 100644 index 41a45ce..0000000 --- a/lib/librte_pmd_fm10k/fm10k_logs.h +++ /dev/null @@ -1,80 +0,0 @@ -/*- - * BSD LICENSE - * - * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of 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. - */ - -#ifndef _FM10K_LOGS_H_ -#define _FM10K_LOGS_H_ - -#include - -#define PMD_INIT_LOG(level, fmt, args...) \ - rte_log(RTE_LOG_ ## level, RTE_LOGTYPE_PMD, \ - "PMD: %s(): " fmt "\n", __func__, ##args) - -#ifdef RTE_LIBRTE_FM10K_DEBUG_INIT -#define PMD_INIT_FUNC_TRACE() PMD_INIT_LOG(DEBUG, " >>") -#else -#define PMD_INIT_FUNC_TRACE() do { } while (0) -#endif - -#ifdef RTE_LIBRTE_FM10K_DEBUG_RX -#define PMD_RX_LOG(level, fmt, args...) \ - RTE_LOG(level, PMD, "%s(): " fmt "\n", __func__, ## args) -#else -#define PMD_RX_LOG(level, fmt, args...) do { } while (0) -#endif - -#ifdef RTE_LIBRTE_FM10K_DEBUG_TX -#define PMD_TX_LOG(level, fmt, args...) \ - RTE_LOG(level, PMD, "%s(): " fmt "\n", __func__, ## args) -#else -#define PMD_TX_LOG(level, fmt, args...) do { } while (0) -#endif - -#ifdef RTE_LIBRTE_FM10K_DEBUG_TX_FREE -#define PMD_TX_FREE_LOG(level, fmt, args...) \ - RTE_LOG(level, PMD, "%s(): " fmt "\n", __func__, ## args) -#else -#define PMD_TX_FREE_LOG(level, fmt, args...) do { } while (0) -#endif - -#ifdef RTE_LIBRTE_FM10K_DEBUG_DRIVER -#define PMD_DRV_LOG_RAW(level, fmt, args...) \ - RTE_LOG(level, PMD, "%s(): " fmt, __func__, ## args) -#else -#define PMD_DRV_LOG_RAW(level, fmt, args...) do { } while (0) -#endif - -#define PMD_DRV_LOG(level, fmt, args...) \ - PMD_DRV_LOG_RAW(level, fmt "\n", ## args) - -#endif /* _FM10K_LOGS_H_ */ diff --git a/lib/librte_pmd_fm10k/fm10k_rxtx.c b/lib/librte_pmd_fm10k/fm10k_rxtx.c deleted file mode 100644 index 83bddfc..0000000 --- a/lib/librte_pmd_fm10k/fm10k_rxtx.c +++ /dev/null @@ -1,461 +0,0 @@ -/*- - * BSD LICENSE - * - * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of 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. - */ -#include -#include -#include "fm10k.h" -#include "base/fm10k_type.h" - -#ifdef RTE_PMD_PACKET_PREFETCH -#define rte_packet_prefetch(p) rte_prefetch1(p) -#else -#define rte_packet_prefetch(p) do {} while (0) -#endif - -#ifdef RTE_LIBRTE_FM10K_DEBUG_RX -static inline void dump_rxd(union fm10k_rx_desc *rxd) -{ - PMD_RX_LOG(DEBUG, "+----------------|----------------+"); - PMD_RX_LOG(DEBUG, "| GLORT | PKT HDR & TYPE |"); - PMD_RX_LOG(DEBUG, "| 0x%08x | 0x%08x |", rxd->d.glort, - rxd->d.data); - PMD_RX_LOG(DEBUG, "+----------------|----------------+"); - PMD_RX_LOG(DEBUG, "| VLAN & LEN | STATUS |"); - PMD_RX_LOG(DEBUG, "| 0x%08x | 0x%08x |", rxd->d.vlan_len, - rxd->d.staterr); - PMD_RX_LOG(DEBUG, "+----------------|----------------+"); - PMD_RX_LOG(DEBUG, "| RESERVED | RSS_HASH |"); - PMD_RX_LOG(DEBUG, "| 0x%08x | 0x%08x |", 0, rxd->d.rss); - PMD_RX_LOG(DEBUG, "+----------------|----------------+"); - PMD_RX_LOG(DEBUG, "| TIME TAG |"); - PMD_RX_LOG(DEBUG, "| 0x%016lx |", rxd->q.timestamp); - PMD_RX_LOG(DEBUG, "+----------------|----------------+"); -} -#endif - -static inline void -rx_desc_to_ol_flags(struct rte_mbuf *m, const union fm10k_rx_desc *d) -{ - uint16_t ptype; - static const uint16_t pt_lut[] = { 0, - PKT_RX_IPV4_HDR, PKT_RX_IPV4_HDR_EXT, - PKT_RX_IPV6_HDR, PKT_RX_IPV6_HDR_EXT, - 0, 0, 0 - }; - - if (d->w.pkt_info & FM10K_RXD_RSSTYPE_MASK) - m->ol_flags |= PKT_RX_RSS_HASH; - - if (unlikely((d->d.staterr & - (FM10K_RXD_STATUS_IPCS | FM10K_RXD_STATUS_IPE)) == - (FM10K_RXD_STATUS_IPCS | FM10K_RXD_STATUS_IPE))) - m->ol_flags |= PKT_RX_IP_CKSUM_BAD; - - if (unlikely((d->d.staterr & - (FM10K_RXD_STATUS_L4CS | FM10K_RXD_STATUS_L4E)) == - (FM10K_RXD_STATUS_L4CS | FM10K_RXD_STATUS_L4E))) - m->ol_flags |= PKT_RX_L4_CKSUM_BAD; - - if (d->d.staterr & FM10K_RXD_STATUS_VEXT) - m->ol_flags |= PKT_RX_VLAN_PKT; - - if (unlikely(d->d.staterr & FM10K_RXD_STATUS_HBO)) - m->ol_flags |= PKT_RX_HBUF_OVERFLOW; - - if (unlikely(d->d.staterr & FM10K_RXD_STATUS_RXE)) - m->ol_flags |= PKT_RX_RECIP_ERR; - - ptype = (d->d.data & FM10K_RXD_PKTTYPE_MASK_L3) >> - FM10K_RXD_PKTTYPE_SHIFT; - m->ol_flags |= pt_lut[(uint8_t)ptype]; -} - -uint16_t -fm10k_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, - uint16_t nb_pkts) -{ - struct rte_mbuf *mbuf; - union fm10k_rx_desc desc; - struct fm10k_rx_queue *q = rx_queue; - uint16_t count = 0; - int alloc = 0; - uint16_t next_dd; - int ret; - - next_dd = q->next_dd; - - nb_pkts = RTE_MIN(nb_pkts, q->alloc_thresh); - for (count = 0; count < nb_pkts; ++count) { - mbuf = q->sw_ring[next_dd]; - desc = q->hw_ring[next_dd]; - if (!(desc.d.staterr & FM10K_RXD_STATUS_DD)) - break; -#ifdef RTE_LIBRTE_FM10K_DEBUG_RX - dump_rxd(&desc); -#endif - rte_pktmbuf_pkt_len(mbuf) = desc.w.length; - rte_pktmbuf_data_len(mbuf) = desc.w.length; - - mbuf->ol_flags = 0; -#ifdef RTE_LIBRTE_FM10K_RX_OLFLAGS_ENABLE - rx_desc_to_ol_flags(mbuf, &desc); -#endif - - mbuf->hash.rss = desc.d.rss; - - rx_pkts[count] = mbuf; - if (++next_dd == q->nb_desc) { - next_dd = 0; - alloc = 1; - } - - /* Prefetch next mbuf while processing current one. */ - rte_prefetch0(q->sw_ring[next_dd]); - - /* - * When next RX descriptor is on a cache-line boundary, - * prefetch the next 4 RX descriptors and the next 8 pointers - * to mbufs. - */ - if ((next_dd & 0x3) == 0) { - rte_prefetch0(&q->hw_ring[next_dd]); - rte_prefetch0(&q->sw_ring[next_dd]); - } - } - - q->next_dd = next_dd; - - if ((q->next_dd > q->next_trigger) || (alloc == 1)) { - ret = rte_mempool_get_bulk(q->mp, - (void **)&q->sw_ring[q->next_alloc], - q->alloc_thresh); - - if (unlikely(ret != 0)) { - uint8_t port = q->port_id; - PMD_RX_LOG(ERR, "Failed to alloc mbuf"); - /* - * Need to restore next_dd if we cannot allocate new - * buffers to replenish the old ones. - */ - q->next_dd = (q->next_dd + q->nb_desc - count) % - q->nb_desc; - rte_eth_devices[port].data->rx_mbuf_alloc_failed++; - return 0; - } - - for (; q->next_alloc <= q->next_trigger; ++q->next_alloc) { - mbuf = q->sw_ring[q->next_alloc]; - - /* setup static mbuf fields */ - fm10k_pktmbuf_reset(mbuf, q->port_id); - - /* write descriptor */ - desc.q.pkt_addr = MBUF_DMA_ADDR_DEFAULT(mbuf); - desc.q.hdr_addr = MBUF_DMA_ADDR_DEFAULT(mbuf); - q->hw_ring[q->next_alloc] = desc; - } - FM10K_PCI_REG_WRITE(q->tail_ptr, q->next_trigger); - q->next_trigger += q->alloc_thresh; - if (q->next_trigger >= q->nb_desc) { - q->next_trigger = q->alloc_thresh - 1; - q->next_alloc = 0; - } - } - - return count; -} - -uint16_t -fm10k_recv_scattered_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, - uint16_t nb_pkts) -{ - struct rte_mbuf *mbuf; - union fm10k_rx_desc desc; - struct fm10k_rx_queue *q = rx_queue; - uint16_t count = 0; - uint16_t nb_rcv, nb_seg; - int alloc = 0; - uint16_t next_dd; - struct rte_mbuf *first_seg = q->pkt_first_seg; - struct rte_mbuf *last_seg = q->pkt_last_seg; - int ret; - - next_dd = q->next_dd; - nb_rcv = 0; - - nb_seg = RTE_MIN(nb_pkts, q->alloc_thresh); - for (count = 0; count < nb_seg; count++) { - mbuf = q->sw_ring[next_dd]; - desc = q->hw_ring[next_dd]; - if (!(desc.d.staterr & FM10K_RXD_STATUS_DD)) - break; -#ifdef RTE_LIBRTE_FM10K_DEBUG_RX - dump_rxd(&desc); -#endif - - if (++next_dd == q->nb_desc) { - next_dd = 0; - alloc = 1; - } - - /* Prefetch next mbuf while processing current one. */ - rte_prefetch0(q->sw_ring[next_dd]); - - /* - * When next RX descriptor is on a cache-line boundary, - * prefetch the next 4 RX descriptors and the next 8 pointers - * to mbufs. - */ - if ((next_dd & 0x3) == 0) { - rte_prefetch0(&q->hw_ring[next_dd]); - rte_prefetch0(&q->sw_ring[next_dd]); - } - - /* Fill data length */ - rte_pktmbuf_data_len(mbuf) = desc.w.length; - - /* - * If this is the first buffer of the received packet, - * set the pointer to the first mbuf of the packet and - * initialize its context. - * Otherwise, update the total length and the number of segments - * of the current scattered packet, and update the pointer to - * the last mbuf of the current packet. - */ - if (!first_seg) { - first_seg = mbuf; - first_seg->pkt_len = desc.w.length; - } else { - first_seg->pkt_len = - (uint16_t)(first_seg->pkt_len + - rte_pktmbuf_data_len(mbuf)); - first_seg->nb_segs++; - last_seg->next = mbuf; - } - - /* - * If this is not the last buffer of the received packet, - * update the pointer to the last mbuf of the current scattered - * packet and continue to parse the RX ring. - */ - if (!(desc.d.staterr & FM10K_RXD_STATUS_EOP)) { - last_seg = mbuf; - continue; - } - - first_seg->ol_flags = 0; -#ifdef RTE_LIBRTE_FM10K_RX_OLFLAGS_ENABLE - rx_desc_to_ol_flags(first_seg, &desc); -#endif - first_seg->hash.rss = desc.d.rss; - - /* Prefetch data of first segment, if configured to do so. */ - rte_packet_prefetch((char *)first_seg->buf_addr + - first_seg->data_off); - - /* - * Store the mbuf address into the next entry of the array - * of returned packets. - */ - rx_pkts[nb_rcv++] = first_seg; - - /* - * Setup receipt context for a new packet. - */ - first_seg = NULL; - } - - q->next_dd = next_dd; - - if ((q->next_dd > q->next_trigger) || (alloc == 1)) { - ret = rte_mempool_get_bulk(q->mp, - (void **)&q->sw_ring[q->next_alloc], - q->alloc_thresh); - - if (unlikely(ret != 0)) { - uint8_t port = q->port_id; - PMD_RX_LOG(ERR, "Failed to alloc mbuf"); - /* - * Need to restore next_dd if we cannot allocate new - * buffers to replenish the old ones. - */ - q->next_dd = (q->next_dd + q->nb_desc - count) % - q->nb_desc; - rte_eth_devices[port].data->rx_mbuf_alloc_failed++; - return 0; - } - - for (; q->next_alloc <= q->next_trigger; ++q->next_alloc) { - mbuf = q->sw_ring[q->next_alloc]; - - /* setup static mbuf fields */ - fm10k_pktmbuf_reset(mbuf, q->port_id); - - /* write descriptor */ - desc.q.pkt_addr = MBUF_DMA_ADDR_DEFAULT(mbuf); - desc.q.hdr_addr = MBUF_DMA_ADDR_DEFAULT(mbuf); - q->hw_ring[q->next_alloc] = desc; - } - FM10K_PCI_REG_WRITE(q->tail_ptr, q->next_trigger); - q->next_trigger += q->alloc_thresh; - if (q->next_trigger >= q->nb_desc) { - q->next_trigger = q->alloc_thresh - 1; - q->next_alloc = 0; - } - } - - q->pkt_first_seg = first_seg; - q->pkt_last_seg = last_seg; - - return nb_rcv; -} - -static inline void tx_free_descriptors(struct fm10k_tx_queue *q) -{ - uint16_t next_rs, count = 0; - - next_rs = fifo_peek(&q->rs_tracker); - if (!(q->hw_ring[next_rs].flags & FM10K_TXD_FLAG_DONE)) - return; - - /* the DONE flag is set on this descriptor so remove the ID - * from the RS bit tracker and free the buffers */ - fifo_remove(&q->rs_tracker); - - /* wrap around? if so, free buffers from last_free up to but NOT - * including nb_desc */ - if (q->last_free > next_rs) { - count = q->nb_desc - q->last_free; - while (q->last_free < q->nb_desc) { - rte_pktmbuf_free_seg(q->sw_ring[q->last_free]); - q->sw_ring[q->last_free] = NULL; - ++q->last_free; - } - q->last_free = 0; - } - - /* adjust free descriptor count before the next loop */ - q->nb_free += count + (next_rs + 1 - q->last_free); - - /* free buffers from last_free, up to and including next_rs */ - while (q->last_free <= next_rs) { - rte_pktmbuf_free_seg(q->sw_ring[q->last_free]); - q->sw_ring[q->last_free] = NULL; - ++q->last_free; - } - - if (q->last_free == q->nb_desc) - q->last_free = 0; -} - -static inline void tx_xmit_pkt(struct fm10k_tx_queue *q, struct rte_mbuf *mb) -{ - uint16_t last_id; - uint8_t flags; - - /* always set the LAST flag on the last descriptor used to - * transmit the packet */ - flags = FM10K_TXD_FLAG_LAST; - last_id = q->next_free + mb->nb_segs - 1; - if (last_id >= q->nb_desc) - last_id = last_id - q->nb_desc; - - /* but only set the RS flag on the last descriptor if rs_thresh - * descriptors will be used since the RS flag was last set */ - if ((q->nb_used + mb->nb_segs) >= q->rs_thresh) { - flags |= FM10K_TXD_FLAG_RS; - fifo_insert(&q->rs_tracker, last_id); - q->nb_used = 0; - } else { - q->nb_used = q->nb_used + mb->nb_segs; - } - - q->hw_ring[last_id].flags = flags; - q->nb_free -= mb->nb_segs; - - /* set checksum flags on first descriptor of packet. SCTP checksum - * offload is not supported, but we do not explicitly check for this - * case in favor of greatly simplified processing. */ - if (mb->ol_flags & (PKT_TX_IP_CKSUM | PKT_TX_L4_MASK)) - q->hw_ring[q->next_free].flags |= FM10K_TXD_FLAG_CSUM; - - /* set vlan if requested */ - if (mb->ol_flags & PKT_TX_VLAN_PKT) - q->hw_ring[q->next_free].vlan = mb->vlan_tci; - - /* fill up the rings */ - for (; mb != NULL; mb = mb->next) { - q->sw_ring[q->next_free] = mb; - q->hw_ring[q->next_free].buffer_addr = - rte_cpu_to_le_64(MBUF_DMA_ADDR(mb)); - q->hw_ring[q->next_free].buflen = - rte_cpu_to_le_16(rte_pktmbuf_data_len(mb)); - if (++q->next_free == q->nb_desc) - q->next_free = 0; - } -} - -uint16_t -fm10k_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, - uint16_t nb_pkts) -{ - struct fm10k_tx_queue *q = tx_queue; - struct rte_mbuf *mb; - uint16_t count; - - for (count = 0; count < nb_pkts; ++count) { - mb = tx_pkts[count]; - - /* running low on descriptors? try to free some... */ - if (q->nb_free < q->free_trigger) - tx_free_descriptors(q); - - /* make sure there are enough free descriptors to transmit the - * entire packet before doing anything */ - if (q->nb_free < mb->nb_segs) - break; - - /* sanity check to make sure the mbuf is valid */ - if ((mb->nb_segs == 0) || - ((mb->nb_segs > 1) && (mb->next == NULL))) - break; - - /* process the packet */ - tx_xmit_pkt(q, mb); - } - - /* update the tail pointer if any packets were processed */ - if (likely(count > 0)) - FM10K_PCI_REG_WRITE(q->tail_ptr, q->next_free); - - return count; -} diff --git a/lib/librte_pmd_fm10k/rte_pmd_fm10k_version.map b/lib/librte_pmd_fm10k/rte_pmd_fm10k_version.map deleted file mode 100644 index ef35398..0000000 --- a/lib/librte_pmd_fm10k/rte_pmd_fm10k_version.map +++ /dev/null @@ -1,4 +0,0 @@ -DPDK_2.0 { - - local: *; -}; -- 2.1.0