Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,17 @@
# SPDX-License-Identifier: GPL-2.0
# Copyright(c) 2013 - 2018 Intel Corporation.
#
# Makefile for the Intel(R) Ethernet Adaptive Virtual Function (iavf)
# driver
#
#
ccflags-y += -I$(src)
subdir-ccflags-y += -I$(src)
obj-$(CONFIG_IAVF) += iavf.o
iavf-y := iavf_main.o iavf_ethtool.o iavf_virtchnl.o iavf_fdir.o \
iavf_adv_rss.o iavf_txrx.o iavf_common.o iavf_adminq.o
iavf-$(CONFIG_PTP_1588_CLOCK) += iavf_ptp.o
@@ -0,0 +1,628 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#ifndef _IAVF_H_
#define _IAVF_H_
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/sctp.h>
#include <linux/ipv6.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/gfp.h>
#include <linux/skbuff.h>
#include <linux/dma-mapping.h>
#include <linux/etherdevice.h>
#include <linux/socket.h>
#include <linux/jiffies.h>
#include <net/ip6_checksum.h>
#include <net/pkt_cls.h>
#include <net/pkt_sched.h>
#include <net/udp.h>
#include <net/tc_act/tc_gact.h>
#include <net/tc_act/tc_mirred.h>
#include <net/tc_act/tc_skbedit.h>
#include <net/net_shaper.h>
#include "iavf_type.h"
#include <linux/avf/virtchnl.h>
#include "iavf_txrx.h"
#include "iavf_fdir.h"
#include "iavf_adv_rss.h"
#include "iavf_types.h"
#include <linux/bitmap.h>
#define DEFAULT_DEBUG_LEVEL_SHIFT 3
#define PFX "iavf: "
int iavf_status_to_errno(enum iavf_status status);
int virtchnl_status_to_errno(enum virtchnl_status_code v_status);
/* VSI state flags shared with common code */
enum iavf_vsi_state_t {
__IAVF_VSI_DOWN,
/* This must be last as it determines the size of the BITMAP */
__IAVF_VSI_STATE_SIZE__,
};
/* dummy struct to make common code less painful */
struct iavf_vsi {
struct iavf_adapter *back;
struct net_device *netdev;
u16 seid;
u16 id;
DECLARE_BITMAP(state, __IAVF_VSI_STATE_SIZE__);
int base_vector;
u16 qs_handle;
};
/* How many Rx Buffers do we bundle into one write to the hardware ? */
#define IAVF_RX_BUFFER_WRITE 16 /* Must be power of 2 */
#define IAVF_DEFAULT_TXD 512
#define IAVF_DEFAULT_RXD 512
#define IAVF_MAX_TXD 4096
#define IAVF_MIN_TXD 64
#define IAVF_MAX_RXD 4096
#define IAVF_MIN_RXD 64
#define IAVF_REQ_DESCRIPTOR_MULTIPLE 32
#define IAVF_MAX_AQ_BUF_SIZE 4096
#define IAVF_AQ_LEN 32
#define IAVF_AQ_MAX_ERR 20 /* times to try before resetting AQ */
#define MAXIMUM_ETHERNET_VLAN_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
#define IAVF_RX_DESC(R, i) (&(((struct iavf_rx_desc *)((R)->desc))[i]))
#define IAVF_TX_DESC(R, i) (&(((struct iavf_tx_desc *)((R)->desc))[i]))
#define IAVF_TX_CTXTDESC(R, i) \
(&(((struct iavf_tx_context_desc *)((R)->desc))[i]))
#define IAVF_MAX_REQ_QUEUES 16
#define IAVF_HKEY_ARRAY_SIZE ((IAVF_VFQF_HKEY_MAX_INDEX + 1) * 4)
#define IAVF_HLUT_ARRAY_SIZE ((IAVF_VFQF_HLUT_MAX_INDEX + 1) * 4)
#define IAVF_MBPS_DIVISOR 125000 /* divisor to convert to Mbps */
#define IAVF_MBPS_QUANTA 50
#define IAVF_VIRTCHNL_VF_RESOURCE_SIZE \
virtchnl_struct_size((struct virtchnl_vf_resource *)NULL, \
vsi_res, IAVF_MAX_VF_VSI)
/* MAX_MSIX_Q_VECTORS of these are allocated,
* but we only use one per queue-specific vector.
*/
struct iavf_q_vector {
struct iavf_adapter *adapter;
struct iavf_vsi *vsi;
struct napi_struct napi;
struct iavf_ring_container rx;
struct iavf_ring_container tx;
u32 ring_mask;
u8 itr_countdown; /* when 0 should adjust adaptive ITR */
u8 num_ringpairs; /* total number of ring pairs in vector */
u16 v_idx; /* index in the vsi->q_vector array. */
u16 reg_idx; /* register index of the interrupt */
char name[IFNAMSIZ + 15];
bool arm_wb_state;
};
/* Helper macros to switch between ints/sec and what the register uses.
* And yes, it's the same math going both ways. The lowest value
* supported by all of the iavf hardware is 8.
*/
#define EITR_INTS_PER_SEC_TO_REG(_eitr) \
((_eitr) ? (1000000000 / ((_eitr) * 256)) : 8)
#define EITR_REG_TO_INTS_PER_SEC EITR_INTS_PER_SEC_TO_REG
#define IAVF_DESC_UNUSED(R) \
((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
(R)->next_to_clean - (R)->next_to_use - 1)
#define OTHER_VECTOR 1
#define NONQ_VECS (OTHER_VECTOR)
#define MIN_MSIX_Q_VECTORS 1
#define MIN_MSIX_COUNT (MIN_MSIX_Q_VECTORS + NONQ_VECS)
#define IAVF_QUEUE_END_OF_LIST 0x7FF
#define IAVF_FREE_VECTOR 0x7FFF
struct iavf_mac_filter {
struct list_head list;
u8 macaddr[ETH_ALEN];
struct {
u8 is_new_mac:1; /* filter is new, wait for PF decision */
u8 remove:1; /* filter needs to be removed */
u8 add:1; /* filter needs to be added */
u8 is_primary:1; /* filter is a default VF MAC */
u8 add_handled:1; /* received response for filter add */
u8 padding:3;
};
};
#define IAVF_VLAN(vid, tpid) ((struct iavf_vlan){ vid, tpid })
struct iavf_vlan {
u16 vid;
u16 tpid;
};
enum iavf_vlan_state_t {
IAVF_VLAN_INVALID,
IAVF_VLAN_ADD, /* filter needs to be added */
IAVF_VLAN_ADDING, /* ADD sent to PF, waiting for response */
IAVF_VLAN_ACTIVE, /* PF confirmed, filter is in HW */
IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */
IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */
};
struct iavf_vlan_filter {
struct list_head list;
struct iavf_vlan vlan;
enum iavf_vlan_state_t state;
};
#define IAVF_MAX_TRAFFIC_CLASS 4
/* State of traffic class creation */
enum iavf_tc_state_t {
__IAVF_TC_INVALID, /* no traffic class, default state */
__IAVF_TC_RUNNING, /* traffic classes have been created */
};
/* channel info */
struct iavf_channel_config {
struct virtchnl_channel_info ch_info[IAVF_MAX_TRAFFIC_CLASS];
enum iavf_tc_state_t state;
u8 total_qps;
};
/* State of cloud filter */
enum iavf_cloud_filter_state_t {
__IAVF_CF_INVALID, /* cloud filter not added */
__IAVF_CF_ADD_PENDING, /* cloud filter pending add by the PF */
__IAVF_CF_DEL_PENDING, /* cloud filter pending del by the PF */
__IAVF_CF_ACTIVE, /* cloud filter is active */
};
/* Driver state. The order of these is important! */
enum iavf_state_t {
__IAVF_STARTUP, /* driver loaded, probe complete */
__IAVF_REMOVE, /* driver is being unloaded */
__IAVF_INIT_VERSION_CHECK, /* aq msg sent, awaiting reply */
__IAVF_INIT_GET_RESOURCES, /* aq msg sent, awaiting reply */
__IAVF_INIT_EXTENDED_CAPS, /* process extended caps which require aq msg exchange */
__IAVF_INIT_CONFIG_ADAPTER,
__IAVF_INIT_SW, /* got resources, setting up structs */
__IAVF_INIT_FAILED, /* init failed, restarting procedure */
__IAVF_RESETTING, /* in reset */
__IAVF_COMM_FAILED, /* communication with PF failed */
/* Below here, watchdog is running */
__IAVF_DOWN, /* ready, can be opened */
__IAVF_DOWN_PENDING, /* descending, waiting for watchdog */
__IAVF_TESTING, /* in ethtool self-test */
__IAVF_RUNNING, /* opened, working */
};
enum iavf_critical_section_t {
__IAVF_IN_REMOVE_TASK, /* device being removed */
};
#define IAVF_CLOUD_FIELD_OMAC 0x01
#define IAVF_CLOUD_FIELD_IMAC 0x02
#define IAVF_CLOUD_FIELD_IVLAN 0x04
#define IAVF_CLOUD_FIELD_TEN_ID 0x08
#define IAVF_CLOUD_FIELD_IIP 0x10
#define IAVF_CF_FLAGS_OMAC IAVF_CLOUD_FIELD_OMAC
#define IAVF_CF_FLAGS_IMAC IAVF_CLOUD_FIELD_IMAC
#define IAVF_CF_FLAGS_IMAC_IVLAN (IAVF_CLOUD_FIELD_IMAC |\
IAVF_CLOUD_FIELD_IVLAN)
#define IAVF_CF_FLAGS_IMAC_TEN_ID (IAVF_CLOUD_FIELD_IMAC |\
IAVF_CLOUD_FIELD_TEN_ID)
#define IAVF_CF_FLAGS_OMAC_TEN_ID_IMAC (IAVF_CLOUD_FIELD_OMAC |\
IAVF_CLOUD_FIELD_IMAC |\
IAVF_CLOUD_FIELD_TEN_ID)
#define IAVF_CF_FLAGS_IMAC_IVLAN_TEN_ID (IAVF_CLOUD_FIELD_IMAC |\
IAVF_CLOUD_FIELD_IVLAN |\
IAVF_CLOUD_FIELD_TEN_ID)
#define IAVF_CF_FLAGS_IIP IAVF_CLOUD_FIELD_IIP
/* bookkeeping of cloud filters */
struct iavf_cloud_filter {
enum iavf_cloud_filter_state_t state;
struct list_head list;
struct virtchnl_filter f;
unsigned long cookie;
bool del; /* filter needs to be deleted */
bool add; /* filter needs to be added */
};
#define IAVF_RESET_WAIT_MS 10
#define IAVF_RESET_WAIT_DETECTED_COUNT 500
#define IAVF_RESET_WAIT_COMPLETE_COUNT 2000
#define IAVF_MAX_QOS_TC_NUM 8
#define IAVF_DEFAULT_QUANTA_SIZE 1024
/* board specific private data structure */
struct iavf_adapter {
struct workqueue_struct *wq;
struct work_struct reset_task;
struct work_struct adminq_task;
struct work_struct finish_config;
wait_queue_head_t down_waitqueue;
wait_queue_head_t vc_waitqueue;
struct iavf_q_vector *q_vectors;
struct list_head vlan_filter_list;
int num_vlan_filters;
struct list_head mac_filter_list;
/* Lock to protect accesses to MAC and VLAN lists */
spinlock_t mac_vlan_list_lock;
char misc_vector_name[IFNAMSIZ + 9];
u8 rxdid;
int num_active_queues;
int num_req_queues;
/* TX */
struct iavf_ring *tx_rings;
u32 tx_timeout_count;
u32 tx_desc_count;
/* RX */
struct iavf_ring *rx_rings;
u64 hw_csum_rx_error;
u32 rx_desc_count;
int num_msix_vectors;
struct msix_entry *msix_entries;
u32 flags;
#define IAVF_FLAG_RX_CSUM_ENABLED BIT(0)
#define IAVF_FLAG_PF_COMMS_FAILED BIT(3)
#define IAVF_FLAG_RESET_PENDING BIT(4)
#define IAVF_FLAG_RESET_NEEDED BIT(5)
#define IAVF_FLAG_WB_ON_ITR_CAPABLE BIT(6)
/* BIT(15) is free, was IAVF_FLAG_LEGACY_RX */
#define IAVF_FLAG_REINIT_ITR_NEEDED BIT(16)
#define IAVF_FLAG_QUEUES_DISABLED BIT(17)
#define IAVF_FLAG_SETUP_NETDEV_FEATURES BIT(18)
#define IAVF_FLAG_REINIT_MSIX_NEEDED BIT(20)
#define IAVF_FLAG_FDIR_ENABLED BIT(21)
/* duplicates for common code */
#define IAVF_FLAG_DCB_ENABLED 0
/* flags for admin queue service task */
u64 aq_required;
#define IAVF_FLAG_AQ_ENABLE_QUEUES BIT_ULL(0)
#define IAVF_FLAG_AQ_DISABLE_QUEUES BIT_ULL(1)
#define IAVF_FLAG_AQ_ADD_MAC_FILTER BIT_ULL(2)
#define IAVF_FLAG_AQ_ADD_VLAN_FILTER BIT_ULL(3)
#define IAVF_FLAG_AQ_DEL_MAC_FILTER BIT_ULL(4)
#define IAVF_FLAG_AQ_DEL_VLAN_FILTER BIT_ULL(5)
#define IAVF_FLAG_AQ_CONFIGURE_QUEUES BIT_ULL(6)
#define IAVF_FLAG_AQ_MAP_VECTORS BIT_ULL(7)
#define IAVF_FLAG_AQ_HANDLE_RESET BIT_ULL(8)
#define IAVF_FLAG_AQ_CONFIGURE_RSS BIT_ULL(9) /* direct AQ config */
#define IAVF_FLAG_AQ_GET_CONFIG BIT_ULL(10)
/* Newer style, RSS done by the PF so we can ignore hardware vagaries. */
#define IAVF_FLAG_AQ_GET_RSS_HASHCFG BIT_ULL(11)
#define IAVF_FLAG_AQ_SET_RSS_HASHCFG BIT_ULL(12)
#define IAVF_FLAG_AQ_SET_RSS_KEY BIT_ULL(13)
#define IAVF_FLAG_AQ_SET_RSS_LUT BIT_ULL(14)
#define IAVF_FLAG_AQ_SET_RSS_HFUNC BIT_ULL(15)
#define IAVF_FLAG_AQ_CONFIGURE_PROMISC_MODE BIT_ULL(16)
#define IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING BIT_ULL(19)
#define IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING BIT_ULL(20)
#define IAVF_FLAG_AQ_ENABLE_CHANNELS BIT_ULL(21)
#define IAVF_FLAG_AQ_DISABLE_CHANNELS BIT_ULL(22)
#define IAVF_FLAG_AQ_ADD_CLOUD_FILTER BIT_ULL(23)
#define IAVF_FLAG_AQ_DEL_CLOUD_FILTER BIT_ULL(24)
#define IAVF_FLAG_AQ_ADD_FDIR_FILTER BIT_ULL(25)
#define IAVF_FLAG_AQ_DEL_FDIR_FILTER BIT_ULL(26)
#define IAVF_FLAG_AQ_ADD_ADV_RSS_CFG BIT_ULL(27)
#define IAVF_FLAG_AQ_DEL_ADV_RSS_CFG BIT_ULL(28)
#define IAVF_FLAG_AQ_REQUEST_STATS BIT_ULL(29)
#define IAVF_FLAG_AQ_GET_OFFLOAD_VLAN_V2_CAPS BIT_ULL(30)
#define IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_STRIPPING BIT_ULL(31)
#define IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_STRIPPING BIT_ULL(32)
#define IAVF_FLAG_AQ_ENABLE_STAG_VLAN_STRIPPING BIT_ULL(33)
#define IAVF_FLAG_AQ_DISABLE_STAG_VLAN_STRIPPING BIT_ULL(34)
#define IAVF_FLAG_AQ_ENABLE_CTAG_VLAN_INSERTION BIT_ULL(35)
#define IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_INSERTION BIT_ULL(36)
#define IAVF_FLAG_AQ_ENABLE_STAG_VLAN_INSERTION BIT_ULL(37)
#define IAVF_FLAG_AQ_DISABLE_STAG_VLAN_INSERTION BIT_ULL(38)
#define IAVF_FLAG_AQ_CONFIGURE_QUEUES_BW BIT_ULL(39)
#define IAVF_FLAG_AQ_CFG_QUEUES_QUANTA_SIZE BIT_ULL(40)
#define IAVF_FLAG_AQ_GET_QOS_CAPS BIT_ULL(41)
#define IAVF_FLAG_AQ_GET_SUPPORTED_RXDIDS BIT_ULL(42)
#define IAVF_FLAG_AQ_GET_PTP_CAPS BIT_ULL(43)
#define IAVF_FLAG_AQ_SEND_PTP_CMD BIT_ULL(44)
/* AQ messages that must be sent after IAVF_FLAG_AQ_GET_CONFIG, in
* order to negotiated extended capabilities.
*/
#define IAVF_FLAG_AQ_EXTENDED_CAPS \
(IAVF_FLAG_AQ_GET_OFFLOAD_VLAN_V2_CAPS | \
IAVF_FLAG_AQ_GET_SUPPORTED_RXDIDS | \
IAVF_FLAG_AQ_GET_PTP_CAPS)
/* flags for processing extended capability messages during
* __IAVF_INIT_EXTENDED_CAPS. Each capability exchange requires
* both a SEND and a RECV step, which must be processed in sequence.
*
* During the __IAVF_INIT_EXTENDED_CAPS state, the driver will
* process one flag at a time during each state loop.
*/
u64 extended_caps;
#define IAVF_EXTENDED_CAP_SEND_VLAN_V2 BIT_ULL(0)
#define IAVF_EXTENDED_CAP_RECV_VLAN_V2 BIT_ULL(1)
#define IAVF_EXTENDED_CAP_SEND_RXDID BIT_ULL(2)
#define IAVF_EXTENDED_CAP_RECV_RXDID BIT_ULL(3)
#define IAVF_EXTENDED_CAP_SEND_PTP BIT_ULL(4)
#define IAVF_EXTENDED_CAP_RECV_PTP BIT_ULL(5)
#define IAVF_EXTENDED_CAPS \
(IAVF_EXTENDED_CAP_SEND_VLAN_V2 | \
IAVF_EXTENDED_CAP_RECV_VLAN_V2 | \
IAVF_EXTENDED_CAP_SEND_RXDID | \
IAVF_EXTENDED_CAP_RECV_RXDID | \
IAVF_EXTENDED_CAP_SEND_PTP | \
IAVF_EXTENDED_CAP_RECV_PTP)
/* Lock to prevent possible clobbering of
* current_netdev_promisc_flags
*/
spinlock_t current_netdev_promisc_flags_lock;
netdev_features_t current_netdev_promisc_flags;
/* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
struct iavf_hw hw; /* defined in iavf_type.h */
enum iavf_state_t state;
enum iavf_state_t last_state;
unsigned long crit_section;
struct delayed_work watchdog_task;
bool link_up;
enum virtchnl_link_speed link_speed;
/* This is only populated if the VIRTCHNL_VF_CAP_ADV_LINK_SPEED is set
* in vf_res->vf_cap_flags. Use ADV_LINK_SUPPORT macro to determine if
* this field is valid. This field should be used going forward and the
* enum virtchnl_link_speed above should be considered the legacy way of
* storing/communicating link speeds.
*/
u32 link_speed_mbps;
enum virtchnl_ops current_op;
/* RSS by the PF should be preferred over RSS via other methods. */
#define RSS_PF(_a) ((_a)->vf_res->vf_cap_flags & \
VIRTCHNL_VF_OFFLOAD_RSS_PF)
#define RSS_AQ(_a) ((_a)->vf_res->vf_cap_flags & \
VIRTCHNL_VF_OFFLOAD_RSS_AQ)
#define RSS_REG(_a) (!((_a)->vf_res->vf_cap_flags & \
(VIRTCHNL_VF_OFFLOAD_RSS_AQ | \
VIRTCHNL_VF_OFFLOAD_RSS_PF)))
#define VLAN_ALLOWED(_a) ((_a)->vf_res->vf_cap_flags & \
VIRTCHNL_VF_OFFLOAD_VLAN)
#define VLAN_V2_ALLOWED(_a) ((_a)->vf_res->vf_cap_flags & \
VIRTCHNL_VF_OFFLOAD_VLAN_V2)
#define CRC_OFFLOAD_ALLOWED(_a) ((_a)->vf_res->vf_cap_flags & \
VIRTCHNL_VF_OFFLOAD_CRC)
#define TC_U32_SUPPORT(_a) ((_a)->vf_res->vf_cap_flags & \
VIRTCHNL_VF_OFFLOAD_TC_U32)
#define VLAN_V2_FILTERING_ALLOWED(_a) \
(VLAN_V2_ALLOWED((_a)) && \
((_a)->vlan_v2_caps.filtering.filtering_support.outer || \
(_a)->vlan_v2_caps.filtering.filtering_support.inner))
#define VLAN_FILTERING_ALLOWED(_a) \
(VLAN_ALLOWED((_a)) || VLAN_V2_FILTERING_ALLOWED((_a)))
#define ADV_LINK_SUPPORT(_a) ((_a)->vf_res->vf_cap_flags & \
VIRTCHNL_VF_CAP_ADV_LINK_SPEED)
#define FDIR_FLTR_SUPPORT(_a) ((_a)->vf_res->vf_cap_flags & \
VIRTCHNL_VF_OFFLOAD_FDIR_PF)
#define ADV_RSS_SUPPORT(_a) ((_a)->vf_res->vf_cap_flags & \
VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF)
#define QOS_ALLOWED(_a) ((_a)->vf_res->vf_cap_flags & \
VIRTCHNL_VF_OFFLOAD_QOS)
#define IAVF_RXDID_ALLOWED(a) \
((a)->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC)
#define IAVF_PTP_ALLOWED(a) \
((a)->vf_res->vf_cap_flags & VIRTCHNL_VF_CAP_PTP)
struct virtchnl_vf_resource *vf_res; /* incl. all VSIs */
struct virtchnl_vsi_resource *vsi_res; /* our LAN VSI */
struct virtchnl_version_info pf_version;
#define PF_IS_V11(_a) (((_a)->pf_version.major == 1) && \
((_a)->pf_version.minor == 1))
struct virtchnl_vlan_caps vlan_v2_caps;
u64 supp_rxdids;
struct iavf_ptp ptp;
u16 msg_enable;
struct iavf_eth_stats current_stats;
struct virtchnl_qos_cap_list *qos_caps;
struct iavf_vsi vsi;
u32 aq_wait_count;
/* RSS stuff */
enum virtchnl_rss_algorithm hfunc;
u64 rss_hashcfg;
u16 rss_key_size;
u16 rss_lut_size;
u8 *rss_key;
u8 *rss_lut;
/* ADQ related members */
struct iavf_channel_config ch_config;
u8 num_tc;
struct list_head cloud_filter_list;
/* lock to protect access to the cloud filter list */
spinlock_t cloud_filter_list_lock;
u16 num_cloud_filters;
/* snapshot of "num_active_queues" before setup_tc for qdisc add
* is invoked. This information is useful during qdisc del flow,
* to restore correct number of queues
*/
int orig_num_active_queues;
#define IAVF_MAX_FDIR_FILTERS 128 /* max allowed Flow Director filters */
u16 fdir_active_fltr;
u16 raw_fdir_active_fltr;
struct list_head fdir_list_head;
spinlock_t fdir_fltr_lock; /* protect the Flow Director filter list */
struct list_head adv_rss_list_head;
spinlock_t adv_rss_lock; /* protect the RSS management list */
};
/* Must be called with fdir_fltr_lock lock held */
static inline bool iavf_fdir_max_reached(struct iavf_adapter *adapter)
{
return adapter->fdir_active_fltr + adapter->raw_fdir_active_fltr >=
IAVF_MAX_FDIR_FILTERS;
}
static inline void
iavf_inc_fdir_active_fltr(struct iavf_adapter *adapter,
struct iavf_fdir_fltr *fltr)
{
if (iavf_is_raw_fdir(fltr))
adapter->raw_fdir_active_fltr++;
else
adapter->fdir_active_fltr++;
}
static inline void
iavf_dec_fdir_active_fltr(struct iavf_adapter *adapter,
struct iavf_fdir_fltr *fltr)
{
if (iavf_is_raw_fdir(fltr))
adapter->raw_fdir_active_fltr--;
else
adapter->fdir_active_fltr--;
}
/* Ethtool Private Flags */
/* needed by iavf_ethtool.c */
extern char iavf_driver_name[];
static inline const char *iavf_state_str(enum iavf_state_t state)
{
switch (state) {
case __IAVF_STARTUP:
return "__IAVF_STARTUP";
case __IAVF_REMOVE:
return "__IAVF_REMOVE";
case __IAVF_INIT_VERSION_CHECK:
return "__IAVF_INIT_VERSION_CHECK";
case __IAVF_INIT_GET_RESOURCES:
return "__IAVF_INIT_GET_RESOURCES";
case __IAVF_INIT_EXTENDED_CAPS:
return "__IAVF_INIT_EXTENDED_CAPS";
case __IAVF_INIT_CONFIG_ADAPTER:
return "__IAVF_INIT_CONFIG_ADAPTER";
case __IAVF_INIT_SW:
return "__IAVF_INIT_SW";
case __IAVF_INIT_FAILED:
return "__IAVF_INIT_FAILED";
case __IAVF_RESETTING:
return "__IAVF_RESETTING";
case __IAVF_COMM_FAILED:
return "__IAVF_COMM_FAILED";
case __IAVF_DOWN:
return "__IAVF_DOWN";
case __IAVF_DOWN_PENDING:
return "__IAVF_DOWN_PENDING";
case __IAVF_TESTING:
return "__IAVF_TESTING";
case __IAVF_RUNNING:
return "__IAVF_RUNNING";
default:
return "__IAVF_UNKNOWN_STATE";
}
}
static inline void iavf_change_state(struct iavf_adapter *adapter,
enum iavf_state_t state)
{
if (adapter->state != state) {
adapter->last_state = adapter->state;
adapter->state = state;
}
dev_dbg(&adapter->pdev->dev,
"state transition from:%s to:%s\n",
iavf_state_str(adapter->last_state),
iavf_state_str(adapter->state));
}
void iavf_down(struct iavf_adapter *adapter);
int iavf_process_config(struct iavf_adapter *adapter);
int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter);
void iavf_schedule_reset(struct iavf_adapter *adapter, u64 flags);
void iavf_schedule_aq_request(struct iavf_adapter *adapter, u64 flags);
void iavf_schedule_finish_config(struct iavf_adapter *adapter);
void iavf_set_ethtool_ops(struct net_device *netdev);
void iavf_free_all_tx_resources(struct iavf_adapter *adapter);
void iavf_free_all_rx_resources(struct iavf_adapter *adapter);
int iavf_send_api_ver(struct iavf_adapter *adapter);
int iavf_verify_api_ver(struct iavf_adapter *adapter);
int iavf_send_vf_config_msg(struct iavf_adapter *adapter);
int iavf_get_vf_config(struct iavf_adapter *adapter);
int iavf_get_vf_vlan_v2_caps(struct iavf_adapter *adapter);
int iavf_send_vf_offload_vlan_v2_msg(struct iavf_adapter *adapter);
int iavf_send_vf_supported_rxdids_msg(struct iavf_adapter *adapter);
int iavf_get_vf_supported_rxdids(struct iavf_adapter *adapter);
int iavf_send_vf_ptp_caps_msg(struct iavf_adapter *adapter);
int iavf_get_vf_ptp_caps(struct iavf_adapter *adapter);
void iavf_set_queue_vlan_tag_loc(struct iavf_adapter *adapter);
u16 iavf_get_num_vlans_added(struct iavf_adapter *adapter);
void iavf_irq_enable(struct iavf_adapter *adapter, bool flush);
void iavf_configure_queues(struct iavf_adapter *adapter);
void iavf_enable_queues(struct iavf_adapter *adapter);
void iavf_disable_queues(struct iavf_adapter *adapter);
void iavf_map_queues(struct iavf_adapter *adapter);
void iavf_add_ether_addrs(struct iavf_adapter *adapter);
void iavf_del_ether_addrs(struct iavf_adapter *adapter);
void iavf_add_vlans(struct iavf_adapter *adapter);
void iavf_del_vlans(struct iavf_adapter *adapter);
void iavf_set_promiscuous(struct iavf_adapter *adapter);
bool iavf_promiscuous_mode_changed(struct iavf_adapter *adapter);
void iavf_request_stats(struct iavf_adapter *adapter);
int iavf_request_reset(struct iavf_adapter *adapter);
void iavf_get_rss_hashcfg(struct iavf_adapter *adapter);
void iavf_set_rss_hashcfg(struct iavf_adapter *adapter);
void iavf_set_rss_key(struct iavf_adapter *adapter);
void iavf_set_rss_lut(struct iavf_adapter *adapter);
void iavf_set_rss_hfunc(struct iavf_adapter *adapter);
void iavf_enable_vlan_stripping(struct iavf_adapter *adapter);
void iavf_disable_vlan_stripping(struct iavf_adapter *adapter);
void iavf_virtchnl_completion(struct iavf_adapter *adapter,
enum virtchnl_ops v_opcode,
enum iavf_status v_retval, u8 *msg, u16 msglen);
int iavf_config_rss(struct iavf_adapter *adapter);
void iavf_cfg_queues_bw(struct iavf_adapter *adapter);
void iavf_cfg_queues_quanta_size(struct iavf_adapter *adapter);
void iavf_get_qos_caps(struct iavf_adapter *adapter);
void iavf_enable_channels(struct iavf_adapter *adapter);
void iavf_disable_channels(struct iavf_adapter *adapter);
void iavf_add_cloud_filter(struct iavf_adapter *adapter);
void iavf_del_cloud_filter(struct iavf_adapter *adapter);
void iavf_enable_vlan_stripping_v2(struct iavf_adapter *adapter, u16 tpid);
void iavf_disable_vlan_stripping_v2(struct iavf_adapter *adapter, u16 tpid);
void iavf_enable_vlan_insertion_v2(struct iavf_adapter *adapter, u16 tpid);
void iavf_disable_vlan_insertion_v2(struct iavf_adapter *adapter, u16 tpid);
void iavf_add_fdir_filter(struct iavf_adapter *adapter);
void iavf_del_fdir_filter(struct iavf_adapter *adapter);
void iavf_add_adv_rss_cfg(struct iavf_adapter *adapter);
void iavf_del_adv_rss_cfg(struct iavf_adapter *adapter);
struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
const u8 *macaddr);
void iavf_reset_step(struct iavf_adapter *adapter);
#endif /* _IAVF_H_ */
@@ -0,0 +1,922 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#include "iavf_status.h"
#include "iavf_type.h"
#include "iavf_register.h"
#include "iavf_adminq.h"
#include "iavf_prototype.h"
/**
* iavf_alloc_adminq_asq_ring - Allocate Admin Queue send rings
* @hw: pointer to the hardware structure
**/
static enum iavf_status iavf_alloc_adminq_asq_ring(struct iavf_hw *hw)
{
enum iavf_status ret_code;
ret_code = iavf_allocate_dma_mem(hw, &hw->aq.asq.desc_buf,
iavf_mem_atq_ring,
(hw->aq.num_asq_entries *
sizeof(struct libie_aq_desc)),
IAVF_ADMINQ_DESC_ALIGNMENT);
if (ret_code)
return ret_code;
ret_code = iavf_allocate_virt_mem(hw, &hw->aq.asq.cmd_buf,
(hw->aq.num_asq_entries *
sizeof(struct iavf_asq_cmd_details)));
if (ret_code) {
iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf);
return ret_code;
}
return ret_code;
}
/**
* iavf_alloc_adminq_arq_ring - Allocate Admin Queue receive rings
* @hw: pointer to the hardware structure
**/
static enum iavf_status iavf_alloc_adminq_arq_ring(struct iavf_hw *hw)
{
enum iavf_status ret_code;
ret_code = iavf_allocate_dma_mem(hw, &hw->aq.arq.desc_buf,
iavf_mem_arq_ring,
(hw->aq.num_arq_entries *
sizeof(struct libie_aq_desc)),
IAVF_ADMINQ_DESC_ALIGNMENT);
return ret_code;
}
/**
* iavf_free_adminq_asq - Free Admin Queue send rings
* @hw: pointer to the hardware structure
*
* This assumes the posted send buffers have already been cleaned
* and de-allocated
**/
static void iavf_free_adminq_asq(struct iavf_hw *hw)
{
iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf);
}
/**
* iavf_free_adminq_arq - Free Admin Queue receive rings
* @hw: pointer to the hardware structure
*
* This assumes the posted receive buffers have already been cleaned
* and de-allocated
**/
static void iavf_free_adminq_arq(struct iavf_hw *hw)
{
iavf_free_dma_mem(hw, &hw->aq.arq.desc_buf);
}
/**
* iavf_alloc_arq_bufs - Allocate pre-posted buffers for the receive queue
* @hw: pointer to the hardware structure
**/
static enum iavf_status iavf_alloc_arq_bufs(struct iavf_hw *hw)
{
struct libie_aq_desc *desc;
struct iavf_dma_mem *bi;
enum iavf_status ret_code;
int i;
/* We'll be allocating the buffer info memory first, then we can
* allocate the mapped buffers for the event processing
*/
/* buffer_info structures do not need alignment */
ret_code = iavf_allocate_virt_mem(hw, &hw->aq.arq.dma_head,
(hw->aq.num_arq_entries *
sizeof(struct iavf_dma_mem)));
if (ret_code)
goto alloc_arq_bufs;
hw->aq.arq.r.arq_bi = (struct iavf_dma_mem *)hw->aq.arq.dma_head.va;
/* allocate the mapped buffers */
for (i = 0; i < hw->aq.num_arq_entries; i++) {
bi = &hw->aq.arq.r.arq_bi[i];
ret_code = iavf_allocate_dma_mem(hw, bi,
iavf_mem_arq_buf,
hw->aq.arq_buf_size,
IAVF_ADMINQ_DESC_ALIGNMENT);
if (ret_code)
goto unwind_alloc_arq_bufs;
/* now configure the descriptors for use */
desc = IAVF_ADMINQ_DESC(hw->aq.arq, i);
desc->flags = cpu_to_le16(LIBIE_AQ_FLAG_BUF);
if (hw->aq.arq_buf_size > IAVF_AQ_LARGE_BUF)
desc->flags |= cpu_to_le16(LIBIE_AQ_FLAG_LB);
desc->opcode = 0;
/* This is in accordance with Admin queue design, there is no
* register for buffer size configuration
*/
desc->datalen = cpu_to_le16((u16)bi->size);
desc->retval = 0;
desc->cookie_high = 0;
desc->cookie_low = 0;
desc->params.generic.addr_high =
cpu_to_le32(upper_32_bits(bi->pa));
desc->params.generic.addr_low =
cpu_to_le32(lower_32_bits(bi->pa));
desc->params.generic.param0 = 0;
desc->params.generic.param1 = 0;
}
alloc_arq_bufs:
return ret_code;
unwind_alloc_arq_bufs:
/* don't try to free the one that failed... */
i--;
for (; i >= 0; i--)
iavf_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]);
iavf_free_virt_mem(hw, &hw->aq.arq.dma_head);
return ret_code;
}
/**
* iavf_alloc_asq_bufs - Allocate empty buffer structs for the send queue
* @hw: pointer to the hardware structure
**/
static enum iavf_status iavf_alloc_asq_bufs(struct iavf_hw *hw)
{
struct iavf_dma_mem *bi;
enum iavf_status ret_code;
int i;
/* No mapped memory needed yet, just the buffer info structures */
ret_code = iavf_allocate_virt_mem(hw, &hw->aq.asq.dma_head,
(hw->aq.num_asq_entries *
sizeof(struct iavf_dma_mem)));
if (ret_code)
goto alloc_asq_bufs;
hw->aq.asq.r.asq_bi = (struct iavf_dma_mem *)hw->aq.asq.dma_head.va;
/* allocate the mapped buffers */
for (i = 0; i < hw->aq.num_asq_entries; i++) {
bi = &hw->aq.asq.r.asq_bi[i];
ret_code = iavf_allocate_dma_mem(hw, bi,
iavf_mem_asq_buf,
hw->aq.asq_buf_size,
IAVF_ADMINQ_DESC_ALIGNMENT);
if (ret_code)
goto unwind_alloc_asq_bufs;
}
alloc_asq_bufs:
return ret_code;
unwind_alloc_asq_bufs:
/* don't try to free the one that failed... */
i--;
for (; i >= 0; i--)
iavf_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]);
iavf_free_virt_mem(hw, &hw->aq.asq.dma_head);
return ret_code;
}
/**
* iavf_free_arq_bufs - Free receive queue buffer info elements
* @hw: pointer to the hardware structure
**/
static void iavf_free_arq_bufs(struct iavf_hw *hw)
{
int i;
/* free descriptors */
for (i = 0; i < hw->aq.num_arq_entries; i++)
iavf_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]);
/* free the descriptor memory */
iavf_free_dma_mem(hw, &hw->aq.arq.desc_buf);
/* free the dma header */
iavf_free_virt_mem(hw, &hw->aq.arq.dma_head);
}
/**
* iavf_free_asq_bufs - Free send queue buffer info elements
* @hw: pointer to the hardware structure
**/
static void iavf_free_asq_bufs(struct iavf_hw *hw)
{
int i;
/* only unmap if the address is non-NULL */
for (i = 0; i < hw->aq.num_asq_entries; i++)
if (hw->aq.asq.r.asq_bi[i].pa)
iavf_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]);
/* free the buffer info list */
iavf_free_virt_mem(hw, &hw->aq.asq.cmd_buf);
/* free the descriptor memory */
iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf);
/* free the dma header */
iavf_free_virt_mem(hw, &hw->aq.asq.dma_head);
}
/**
* iavf_config_asq_regs - configure ASQ registers
* @hw: pointer to the hardware structure
*
* Configure base address and length registers for the transmit queue
**/
static enum iavf_status iavf_config_asq_regs(struct iavf_hw *hw)
{
enum iavf_status ret_code = 0;
u32 reg = 0;
/* Clear Head and Tail */
wr32(hw, IAVF_VF_ATQH1, 0);
wr32(hw, IAVF_VF_ATQT1, 0);
/* set starting point */
wr32(hw, IAVF_VF_ATQLEN1, (hw->aq.num_asq_entries |
IAVF_VF_ATQLEN1_ATQENABLE_MASK));
wr32(hw, IAVF_VF_ATQBAL1, lower_32_bits(hw->aq.asq.desc_buf.pa));
wr32(hw, IAVF_VF_ATQBAH1, upper_32_bits(hw->aq.asq.desc_buf.pa));
/* Check one register to verify that config was applied */
reg = rd32(hw, IAVF_VF_ATQBAL1);
if (reg != lower_32_bits(hw->aq.asq.desc_buf.pa))
ret_code = IAVF_ERR_ADMIN_QUEUE_ERROR;
return ret_code;
}
/**
* iavf_config_arq_regs - ARQ register configuration
* @hw: pointer to the hardware structure
*
* Configure base address and length registers for the receive (event queue)
**/
static enum iavf_status iavf_config_arq_regs(struct iavf_hw *hw)
{
enum iavf_status ret_code = 0;
u32 reg = 0;
/* Clear Head and Tail */
wr32(hw, IAVF_VF_ARQH1, 0);
wr32(hw, IAVF_VF_ARQT1, 0);
/* set starting point */
wr32(hw, IAVF_VF_ARQLEN1, (hw->aq.num_arq_entries |
IAVF_VF_ARQLEN1_ARQENABLE_MASK));
wr32(hw, IAVF_VF_ARQBAL1, lower_32_bits(hw->aq.arq.desc_buf.pa));
wr32(hw, IAVF_VF_ARQBAH1, upper_32_bits(hw->aq.arq.desc_buf.pa));
/* Update tail in the HW to post pre-allocated buffers */
wr32(hw, IAVF_VF_ARQT1, hw->aq.num_arq_entries - 1);
/* Check one register to verify that config was applied */
reg = rd32(hw, IAVF_VF_ARQBAL1);
if (reg != lower_32_bits(hw->aq.arq.desc_buf.pa))
ret_code = IAVF_ERR_ADMIN_QUEUE_ERROR;
return ret_code;
}
/**
* iavf_init_asq - main initialization routine for ASQ
* @hw: pointer to the hardware structure
*
* This is the main initialization routine for the Admin Send Queue
* Prior to calling this function, drivers *MUST* set the following fields
* in the hw->aq structure:
* - hw->aq.num_asq_entries
* - hw->aq.arq_buf_size
*
* Do *NOT* hold the lock when calling this as the memory allocation routines
* called are not going to be atomic context safe
**/
static enum iavf_status iavf_init_asq(struct iavf_hw *hw)
{
enum iavf_status ret_code = 0;
int i;
if (hw->aq.asq.count > 0) {
/* queue already initialized */
ret_code = IAVF_ERR_NOT_READY;
goto init_adminq_exit;
}
/* verify input for valid configuration */
if ((hw->aq.num_asq_entries == 0) ||
(hw->aq.asq_buf_size == 0)) {
ret_code = IAVF_ERR_CONFIG;
goto init_adminq_exit;
}
hw->aq.asq.next_to_use = 0;
hw->aq.asq.next_to_clean = 0;
/* allocate the ring memory */
ret_code = iavf_alloc_adminq_asq_ring(hw);
if (ret_code)
goto init_adminq_exit;
/* allocate buffers in the rings */
ret_code = iavf_alloc_asq_bufs(hw);
if (ret_code)
goto init_adminq_free_rings;
/* initialize base registers */
ret_code = iavf_config_asq_regs(hw);
if (ret_code)
goto init_free_asq_bufs;
/* success! */
hw->aq.asq.count = hw->aq.num_asq_entries;
goto init_adminq_exit;
init_free_asq_bufs:
for (i = 0; i < hw->aq.num_asq_entries; i++)
iavf_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]);
iavf_free_virt_mem(hw, &hw->aq.asq.dma_head);
init_adminq_free_rings:
iavf_free_adminq_asq(hw);
init_adminq_exit:
return ret_code;
}
/**
* iavf_init_arq - initialize ARQ
* @hw: pointer to the hardware structure
*
* The main initialization routine for the Admin Receive (Event) Queue.
* Prior to calling this function, drivers *MUST* set the following fields
* in the hw->aq structure:
* - hw->aq.num_asq_entries
* - hw->aq.arq_buf_size
*
* Do *NOT* hold the lock when calling this as the memory allocation routines
* called are not going to be atomic context safe
**/
static enum iavf_status iavf_init_arq(struct iavf_hw *hw)
{
enum iavf_status ret_code = 0;
int i;
if (hw->aq.arq.count > 0) {
/* queue already initialized */
ret_code = IAVF_ERR_NOT_READY;
goto init_adminq_exit;
}
/* verify input for valid configuration */
if ((hw->aq.num_arq_entries == 0) ||
(hw->aq.arq_buf_size == 0)) {
ret_code = IAVF_ERR_CONFIG;
goto init_adminq_exit;
}
hw->aq.arq.next_to_use = 0;
hw->aq.arq.next_to_clean = 0;
/* allocate the ring memory */
ret_code = iavf_alloc_adminq_arq_ring(hw);
if (ret_code)
goto init_adminq_exit;
/* allocate buffers in the rings */
ret_code = iavf_alloc_arq_bufs(hw);
if (ret_code)
goto init_adminq_free_rings;
/* initialize base registers */
ret_code = iavf_config_arq_regs(hw);
if (ret_code)
goto init_free_arq_bufs;
/* success! */
hw->aq.arq.count = hw->aq.num_arq_entries;
goto init_adminq_exit;
init_free_arq_bufs:
for (i = 0; i < hw->aq.num_arq_entries; i++)
iavf_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]);
iavf_free_virt_mem(hw, &hw->aq.arq.dma_head);
init_adminq_free_rings:
iavf_free_adminq_arq(hw);
init_adminq_exit:
return ret_code;
}
/**
* iavf_shutdown_asq - shutdown the ASQ
* @hw: pointer to the hardware structure
*
* The main shutdown routine for the Admin Send Queue
**/
static enum iavf_status iavf_shutdown_asq(struct iavf_hw *hw)
{
enum iavf_status ret_code = 0;
mutex_lock(&hw->aq.asq_mutex);
if (hw->aq.asq.count == 0) {
ret_code = IAVF_ERR_NOT_READY;
goto shutdown_asq_out;
}
/* Stop firmware AdminQ processing */
wr32(hw, IAVF_VF_ATQH1, 0);
wr32(hw, IAVF_VF_ATQT1, 0);
wr32(hw, IAVF_VF_ATQLEN1, 0);
wr32(hw, IAVF_VF_ATQBAL1, 0);
wr32(hw, IAVF_VF_ATQBAH1, 0);
hw->aq.asq.count = 0; /* to indicate uninitialized queue */
/* free ring buffers */
iavf_free_asq_bufs(hw);
shutdown_asq_out:
mutex_unlock(&hw->aq.asq_mutex);
return ret_code;
}
/**
* iavf_shutdown_arq - shutdown ARQ
* @hw: pointer to the hardware structure
*
* The main shutdown routine for the Admin Receive Queue
**/
static enum iavf_status iavf_shutdown_arq(struct iavf_hw *hw)
{
enum iavf_status ret_code = 0;
mutex_lock(&hw->aq.arq_mutex);
if (hw->aq.arq.count == 0) {
ret_code = IAVF_ERR_NOT_READY;
goto shutdown_arq_out;
}
/* Stop firmware AdminQ processing */
wr32(hw, IAVF_VF_ARQH1, 0);
wr32(hw, IAVF_VF_ARQT1, 0);
wr32(hw, IAVF_VF_ARQLEN1, 0);
wr32(hw, IAVF_VF_ARQBAL1, 0);
wr32(hw, IAVF_VF_ARQBAH1, 0);
hw->aq.arq.count = 0; /* to indicate uninitialized queue */
/* free ring buffers */
iavf_free_arq_bufs(hw);
shutdown_arq_out:
mutex_unlock(&hw->aq.arq_mutex);
return ret_code;
}
/**
* iavf_init_adminq - main initialization routine for Admin Queue
* @hw: pointer to the hardware structure
*
* Prior to calling this function, drivers *MUST* set the following fields
* in the hw->aq structure:
* - hw->aq.num_asq_entries
* - hw->aq.num_arq_entries
* - hw->aq.arq_buf_size
* - hw->aq.asq_buf_size
**/
enum iavf_status iavf_init_adminq(struct iavf_hw *hw)
{
enum iavf_status ret_code;
/* verify input for valid configuration */
if ((hw->aq.num_arq_entries == 0) ||
(hw->aq.num_asq_entries == 0) ||
(hw->aq.arq_buf_size == 0) ||
(hw->aq.asq_buf_size == 0)) {
ret_code = IAVF_ERR_CONFIG;
goto init_adminq_exit;
}
/* setup ASQ command write back timeout */
hw->aq.asq_cmd_timeout = IAVF_ASQ_CMD_TIMEOUT;
/* allocate the ASQ */
ret_code = iavf_init_asq(hw);
if (ret_code)
goto init_adminq_destroy_locks;
/* allocate the ARQ */
ret_code = iavf_init_arq(hw);
if (ret_code)
goto init_adminq_free_asq;
/* success! */
goto init_adminq_exit;
init_adminq_free_asq:
iavf_shutdown_asq(hw);
init_adminq_destroy_locks:
init_adminq_exit:
return ret_code;
}
/**
* iavf_shutdown_adminq - shutdown routine for the Admin Queue
* @hw: pointer to the hardware structure
**/
enum iavf_status iavf_shutdown_adminq(struct iavf_hw *hw)
{
if (iavf_check_asq_alive(hw))
iavf_aq_queue_shutdown(hw, true);
iavf_shutdown_asq(hw);
iavf_shutdown_arq(hw);
return 0;
}
/**
* iavf_clean_asq - cleans Admin send queue
* @hw: pointer to the hardware structure
*
* returns the number of free desc
**/
static u16 iavf_clean_asq(struct iavf_hw *hw)
{
struct iavf_adminq_ring *asq = &hw->aq.asq;
struct iavf_asq_cmd_details *details;
u16 ntc = asq->next_to_clean;
struct libie_aq_desc desc_cb;
struct libie_aq_desc *desc;
desc = IAVF_ADMINQ_DESC(*asq, ntc);
details = IAVF_ADMINQ_DETAILS(*asq, ntc);
while (rd32(hw, IAVF_VF_ATQH1) != ntc) {
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"ntc %d head %d.\n", ntc, rd32(hw, IAVF_VF_ATQH1));
if (details->callback) {
IAVF_ADMINQ_CALLBACK cb_func =
(IAVF_ADMINQ_CALLBACK)details->callback;
desc_cb = *desc;
cb_func(hw, &desc_cb);
}
memset((void *)desc, 0, sizeof(struct libie_aq_desc));
memset((void *)details, 0,
sizeof(struct iavf_asq_cmd_details));
ntc++;
if (ntc == asq->count)
ntc = 0;
desc = IAVF_ADMINQ_DESC(*asq, ntc);
details = IAVF_ADMINQ_DETAILS(*asq, ntc);
}
asq->next_to_clean = ntc;
return IAVF_DESC_UNUSED(asq);
}
/**
* iavf_asq_done - check if FW has processed the Admin Send Queue
* @hw: pointer to the hw struct
*
* Returns true if the firmware has processed all descriptors on the
* admin send queue. Returns false if there are still requests pending.
**/
bool iavf_asq_done(struct iavf_hw *hw)
{
/* AQ designers suggest use of head for better
* timing reliability than DD bit
*/
return rd32(hw, IAVF_VF_ATQH1) == hw->aq.asq.next_to_use;
}
/**
* iavf_asq_send_command - send command to Admin Queue
* @hw: pointer to the hw struct
* @desc: prefilled descriptor describing the command (non DMA mem)
* @buff: buffer to use for indirect commands
* @buff_size: size of buffer for indirect commands
* @cmd_details: pointer to command details structure
*
* This is the main send command driver routine for the Admin Queue send
* queue. It runs the queue, cleans the queue, etc
**/
enum iavf_status iavf_asq_send_command(struct iavf_hw *hw,
struct libie_aq_desc *desc,
void *buff, /* can be NULL */
u16 buff_size,
struct iavf_asq_cmd_details *cmd_details)
{
struct iavf_dma_mem *dma_buff = NULL;
struct iavf_asq_cmd_details *details;
struct libie_aq_desc *desc_on_ring;
bool cmd_completed = false;
enum iavf_status status = 0;
u16 retval = 0;
u32 val = 0;
mutex_lock(&hw->aq.asq_mutex);
if (hw->aq.asq.count == 0) {
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Admin queue not initialized.\n");
status = IAVF_ERR_QUEUE_EMPTY;
goto asq_send_command_error;
}
hw->aq.asq_last_status = LIBIE_AQ_RC_OK;
val = rd32(hw, IAVF_VF_ATQH1);
if (val >= hw->aq.num_asq_entries) {
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQTX: head overrun at %d\n", val);
status = IAVF_ERR_QUEUE_EMPTY;
goto asq_send_command_error;
}
details = IAVF_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use);
if (cmd_details) {
*details = *cmd_details;
/* If the cmd_details are defined copy the cookie. The
* cpu_to_le32 is not needed here because the data is ignored
* by the FW, only used by the driver
*/
if (details->cookie) {
desc->cookie_high =
cpu_to_le32(upper_32_bits(details->cookie));
desc->cookie_low =
cpu_to_le32(lower_32_bits(details->cookie));
}
} else {
memset(details, 0, sizeof(struct iavf_asq_cmd_details));
}
/* clear requested flags and then set additional flags if defined */
desc->flags &= ~cpu_to_le16(details->flags_dis);
desc->flags |= cpu_to_le16(details->flags_ena);
if (buff_size > hw->aq.asq_buf_size) {
iavf_debug(hw,
IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Invalid buffer size: %d.\n",
buff_size);
status = IAVF_ERR_INVALID_SIZE;
goto asq_send_command_error;
}
if (details->postpone && !details->async) {
iavf_debug(hw,
IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Async flag not set along with postpone flag");
status = IAVF_ERR_PARAM;
goto asq_send_command_error;
}
/* call clean and check queue available function to reclaim the
* descriptors that were processed by FW, the function returns the
* number of desc available
*/
/* the clean function called here could be called in a separate thread
* in case of asynchronous completions
*/
if (iavf_clean_asq(hw) == 0) {
iavf_debug(hw,
IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Error queue is full.\n");
status = IAVF_ERR_ADMIN_QUEUE_FULL;
goto asq_send_command_error;
}
/* initialize the temp desc pointer with the right desc */
desc_on_ring = IAVF_ADMINQ_DESC(hw->aq.asq, hw->aq.asq.next_to_use);
/* if the desc is available copy the temp desc to the right place */
*desc_on_ring = *desc;
/* if buff is not NULL assume indirect command */
if (buff) {
dma_buff = &hw->aq.asq.r.asq_bi[hw->aq.asq.next_to_use];
/* copy the user buff into the respective DMA buff */
memcpy(dma_buff->va, buff, buff_size);
desc_on_ring->datalen = cpu_to_le16(buff_size);
/* Update the address values in the desc with the pa value
* for respective buffer
*/
desc_on_ring->params.generic.addr_high =
cpu_to_le32(upper_32_bits(dma_buff->pa));
desc_on_ring->params.generic.addr_low =
cpu_to_le32(lower_32_bits(dma_buff->pa));
}
/* bump the tail */
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n");
iavf_debug_aq(hw, IAVF_DEBUG_AQ_COMMAND, (void *)desc_on_ring,
buff, buff_size);
(hw->aq.asq.next_to_use)++;
if (hw->aq.asq.next_to_use == hw->aq.asq.count)
hw->aq.asq.next_to_use = 0;
if (!details->postpone)
wr32(hw, IAVF_VF_ATQT1, hw->aq.asq.next_to_use);
/* if cmd_details are not defined or async flag is not set,
* we need to wait for desc write back
*/
if (!details->async && !details->postpone) {
u32 total_delay = 0;
do {
/* AQ designers suggest use of head for better
* timing reliability than DD bit
*/
if (iavf_asq_done(hw))
break;
udelay(50);
total_delay += 50;
} while (total_delay < hw->aq.asq_cmd_timeout);
}
/* if ready, copy the desc back to temp */
if (iavf_asq_done(hw)) {
*desc = *desc_on_ring;
if (buff)
memcpy(buff, dma_buff->va, buff_size);
retval = le16_to_cpu(desc->retval);
if (retval != 0) {
iavf_debug(hw,
IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Command completed with error 0x%X.\n",
retval);
/* strip off FW internal code */
retval &= 0xff;
}
cmd_completed = true;
if ((enum libie_aq_err)retval == LIBIE_AQ_RC_OK)
status = 0;
else if ((enum libie_aq_err)retval == LIBIE_AQ_RC_EBUSY)
status = IAVF_ERR_NOT_READY;
else
status = IAVF_ERR_ADMIN_QUEUE_ERROR;
hw->aq.asq_last_status = (enum libie_aq_err)retval;
}
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQTX: desc and buffer writeback:\n");
iavf_debug_aq(hw, IAVF_DEBUG_AQ_COMMAND, (void *)desc, buff, buff_size);
/* save writeback aq if requested */
if (details->wb_desc)
*details->wb_desc = *desc_on_ring;
/* update the error if time out occurred */
if ((!cmd_completed) &&
(!details->async && !details->postpone)) {
if (rd32(hw, IAVF_VF_ATQLEN1) & IAVF_VF_ATQLEN1_ATQCRIT_MASK) {
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQTX: AQ Critical error.\n");
status = IAVF_ERR_ADMIN_QUEUE_CRITICAL_ERROR;
} else {
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQTX: Writeback timeout.\n");
status = IAVF_ERR_ADMIN_QUEUE_TIMEOUT;
}
}
asq_send_command_error:
mutex_unlock(&hw->aq.asq_mutex);
return status;
}
/**
* iavf_fill_default_direct_cmd_desc - AQ descriptor helper function
* @desc: pointer to the temp descriptor (non DMA mem)
* @opcode: the opcode can be used to decide which flags to turn off or on
*
* Fill the desc with default values
**/
void iavf_fill_default_direct_cmd_desc(struct libie_aq_desc *desc, u16 opcode)
{
/* zero out the desc */
memset((void *)desc, 0, sizeof(struct libie_aq_desc));
desc->opcode = cpu_to_le16(opcode);
desc->flags = cpu_to_le16(LIBIE_AQ_FLAG_SI);
}
/**
* iavf_clean_arq_element
* @hw: pointer to the hw struct
* @e: event info from the receive descriptor, includes any buffers
* @pending: number of events that could be left to process
*
* This function cleans one Admin Receive Queue element and returns
* the contents through e. It can also return how many events are
* left to process through 'pending'
**/
enum iavf_status iavf_clean_arq_element(struct iavf_hw *hw,
struct iavf_arq_event_info *e,
u16 *pending)
{
u16 ntc = hw->aq.arq.next_to_clean;
struct libie_aq_desc *desc;
enum iavf_status ret_code = 0;
struct iavf_dma_mem *bi;
u16 desc_idx;
u16 datalen;
u16 flags;
u16 ntu;
/* pre-clean the event info */
memset(&e->desc, 0, sizeof(e->desc));
/* take the lock before we start messing with the ring */
mutex_lock(&hw->aq.arq_mutex);
if (hw->aq.arq.count == 0) {
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQRX: Admin queue not initialized.\n");
ret_code = IAVF_ERR_QUEUE_EMPTY;
goto clean_arq_element_err;
}
/* set next_to_use to head */
ntu = rd32(hw, IAVF_VF_ARQH1) & IAVF_VF_ARQH1_ARQH_MASK;
if (ntu == ntc) {
/* nothing to do - shouldn't need to update ring's values */
ret_code = IAVF_ERR_ADMIN_QUEUE_NO_WORK;
goto clean_arq_element_out;
}
/* now clean the next descriptor */
desc = IAVF_ADMINQ_DESC(hw->aq.arq, ntc);
desc_idx = ntc;
hw->aq.arq_last_status =
(enum libie_aq_err)le16_to_cpu(desc->retval);
flags = le16_to_cpu(desc->flags);
if (flags & LIBIE_AQ_FLAG_ERR) {
ret_code = IAVF_ERR_ADMIN_QUEUE_ERROR;
iavf_debug(hw,
IAVF_DEBUG_AQ_MESSAGE,
"AQRX: Event received with error 0x%X.\n",
hw->aq.arq_last_status);
}
e->desc = *desc;
datalen = le16_to_cpu(desc->datalen);
e->msg_len = min(datalen, e->buf_len);
if (e->msg_buf && (e->msg_len != 0))
memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va,
e->msg_len);
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n");
iavf_debug_aq(hw, IAVF_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf,
hw->aq.arq_buf_size);
/* Restore the original datalen and buffer address in the desc,
* FW updates datalen to indicate the event message
* size
*/
bi = &hw->aq.arq.r.arq_bi[ntc];
memset((void *)desc, 0, sizeof(struct libie_aq_desc));
desc->flags = cpu_to_le16(LIBIE_AQ_FLAG_BUF);
if (hw->aq.arq_buf_size > IAVF_AQ_LARGE_BUF)
desc->flags |= cpu_to_le16(LIBIE_AQ_FLAG_LB);
desc->datalen = cpu_to_le16((u16)bi->size);
desc->params.generic.addr_high = cpu_to_le32(upper_32_bits(bi->pa));
desc->params.generic.addr_low = cpu_to_le32(lower_32_bits(bi->pa));
/* set tail = the last cleaned desc index. */
wr32(hw, IAVF_VF_ARQT1, ntc);
/* ntc is updated to tail + 1 */
ntc++;
if (ntc == hw->aq.num_arq_entries)
ntc = 0;
hw->aq.arq.next_to_clean = ntc;
hw->aq.arq.next_to_use = ntu;
clean_arq_element_out:
/* Set pending if needed, unlock and return */
if (pending)
*pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc);
clean_arq_element_err:
mutex_unlock(&hw->aq.arq_mutex);
return ret_code;
}
@@ -0,0 +1,128 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#ifndef _IAVF_ADMINQ_H_
#define _IAVF_ADMINQ_H_
#include "iavf_osdep.h"
#include "iavf_status.h"
#include "iavf_adminq_cmd.h"
#define IAVF_ADMINQ_DESC(R, i) \
(&(((struct libie_aq_desc *)((R).desc_buf.va))[i]))
#define IAVF_ADMINQ_DESC_ALIGNMENT 4096
struct iavf_adminq_ring {
struct iavf_virt_mem dma_head; /* space for dma structures */
struct iavf_dma_mem desc_buf; /* descriptor ring memory */
struct iavf_virt_mem cmd_buf; /* command buffer memory */
union {
struct iavf_dma_mem *asq_bi;
struct iavf_dma_mem *arq_bi;
} r;
u16 count; /* Number of descriptors */
u16 rx_buf_len; /* Admin Receive Queue buffer length */
/* used for interrupt processing */
u16 next_to_use;
u16 next_to_clean;
};
/* ASQ transaction details */
struct iavf_asq_cmd_details {
void *callback; /* cast from type IAVF_ADMINQ_CALLBACK */
u64 cookie;
u16 flags_ena;
u16 flags_dis;
bool async;
bool postpone;
struct libie_aq_desc *wb_desc;
};
#define IAVF_ADMINQ_DETAILS(R, i) \
(&(((struct iavf_asq_cmd_details *)((R).cmd_buf.va))[i]))
/* ARQ event information */
struct iavf_arq_event_info {
struct libie_aq_desc desc;
u16 msg_len;
u16 buf_len;
u8 *msg_buf;
};
/* Admin Queue information */
struct iavf_adminq_info {
struct iavf_adminq_ring arq; /* receive queue */
struct iavf_adminq_ring asq; /* send queue */
u32 asq_cmd_timeout; /* send queue cmd write back timeout*/
u16 num_arq_entries; /* receive queue depth */
u16 num_asq_entries; /* send queue depth */
u16 arq_buf_size; /* receive queue buffer size */
u16 asq_buf_size; /* send queue buffer size */
u16 fw_maj_ver; /* firmware major version */
u16 fw_min_ver; /* firmware minor version */
u32 fw_build; /* firmware build number */
u16 api_maj_ver; /* api major version */
u16 api_min_ver; /* api minor version */
struct mutex asq_mutex; /* Send queue lock */
struct mutex arq_mutex; /* Receive queue lock */
/* last status values on send and receive queues */
enum libie_aq_err asq_last_status;
enum libie_aq_err arq_last_status;
};
/**
* iavf_aq_rc_to_posix - convert errors to user-land codes
* @aq_ret: AdminQ handler error code can override aq_rc
* @aq_rc: AdminQ firmware error code to convert
**/
static inline int iavf_aq_rc_to_posix(int aq_ret, int aq_rc)
{
int aq_to_posix[] = {
0, /* IAVF_AQ_RC_OK */
-EPERM, /* IAVF_AQ_RC_EPERM */
-ENOENT, /* IAVF_AQ_RC_ENOENT */
-ESRCH, /* IAVF_AQ_RC_ESRCH */
-EINTR, /* IAVF_AQ_RC_EINTR */
-EIO, /* IAVF_AQ_RC_EIO */
-ENXIO, /* IAVF_AQ_RC_ENXIO */
-E2BIG, /* IAVF_AQ_RC_E2BIG */
-EAGAIN, /* IAVF_AQ_RC_EAGAIN */
-ENOMEM, /* IAVF_AQ_RC_ENOMEM */
-EACCES, /* IAVF_AQ_RC_EACCES */
-EFAULT, /* IAVF_AQ_RC_EFAULT */
-EBUSY, /* IAVF_AQ_RC_EBUSY */
-EEXIST, /* IAVF_AQ_RC_EEXIST */
-EINVAL, /* IAVF_AQ_RC_EINVAL */
-ENOTTY, /* IAVF_AQ_RC_ENOTTY */
-ENOSPC, /* IAVF_AQ_RC_ENOSPC */
-ENOSYS, /* IAVF_AQ_RC_ENOSYS */
-ERANGE, /* IAVF_AQ_RC_ERANGE */
-EPIPE, /* IAVF_AQ_RC_EFLUSHED */
-ESPIPE, /* IAVF_AQ_RC_BAD_ADDR */
-EROFS, /* IAVF_AQ_RC_EMODE */
-EFBIG, /* IAVF_AQ_RC_EFBIG */
};
/* aq_rc is invalid if AQ timed out */
if (aq_ret == IAVF_ERR_ADMIN_QUEUE_TIMEOUT)
return -EAGAIN;
if (aq_rc >= ARRAY_SIZE(aq_to_posix))
return -ERANGE;
return aq_to_posix[aq_rc];
}
/* general information */
#define IAVF_AQ_LARGE_BUF 512
#define IAVF_ASQ_CMD_TIMEOUT 250000 /* usecs */
void iavf_fill_default_direct_cmd_desc(struct libie_aq_desc *desc, u16 opcode);
#endif /* _IAVF_ADMINQ_H_ */
@@ -0,0 +1,449 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#ifndef _IAVF_ADMINQ_CMD_H_
#define _IAVF_ADMINQ_CMD_H_
#include <linux/net/intel/libie/adminq.h>
/* This header file defines the iavf Admin Queue commands and is shared between
* iavf Firmware and Software.
*
* This file needs to comply with the Linux Kernel coding style.
*/
#define IAVF_FW_API_VERSION_MAJOR 0x0001
#define IAVF_FW_API_VERSION_MINOR_X722 0x0005
#define IAVF_FW_API_VERSION_MINOR_X710 0x0008
#define IAVF_FW_MINOR_VERSION(_h) ((_h)->mac.type == IAVF_MAC_XL710 ? \
IAVF_FW_API_VERSION_MINOR_X710 : \
IAVF_FW_API_VERSION_MINOR_X722)
/* API version 1.7 implements additional link and PHY-specific APIs */
#define IAVF_MINOR_VER_GET_LINK_INFO_XL710 0x0007
/* Admin Queue command opcodes */
enum iavf_admin_queue_opc {
/* aq commands */
iavf_aqc_opc_get_version = 0x0001,
iavf_aqc_opc_driver_version = 0x0002,
iavf_aqc_opc_queue_shutdown = 0x0003,
iavf_aqc_opc_set_pf_context = 0x0004,
/* resource ownership */
iavf_aqc_opc_request_resource = 0x0008,
iavf_aqc_opc_release_resource = 0x0009,
iavf_aqc_opc_list_func_capabilities = 0x000A,
iavf_aqc_opc_list_dev_capabilities = 0x000B,
/* Proxy commands */
iavf_aqc_opc_set_proxy_config = 0x0104,
iavf_aqc_opc_set_ns_proxy_table_entry = 0x0105,
/* LAA */
iavf_aqc_opc_mac_address_read = 0x0107,
iavf_aqc_opc_mac_address_write = 0x0108,
/* PXE */
iavf_aqc_opc_clear_pxe_mode = 0x0110,
/* WoL commands */
iavf_aqc_opc_set_wol_filter = 0x0120,
iavf_aqc_opc_get_wake_reason = 0x0121,
/* internal switch commands */
iavf_aqc_opc_get_switch_config = 0x0200,
iavf_aqc_opc_add_statistics = 0x0201,
iavf_aqc_opc_remove_statistics = 0x0202,
iavf_aqc_opc_set_port_parameters = 0x0203,
iavf_aqc_opc_get_switch_resource_alloc = 0x0204,
iavf_aqc_opc_set_switch_config = 0x0205,
iavf_aqc_opc_rx_ctl_reg_read = 0x0206,
iavf_aqc_opc_rx_ctl_reg_write = 0x0207,
iavf_aqc_opc_add_vsi = 0x0210,
iavf_aqc_opc_update_vsi_parameters = 0x0211,
iavf_aqc_opc_get_vsi_parameters = 0x0212,
iavf_aqc_opc_add_pv = 0x0220,
iavf_aqc_opc_update_pv_parameters = 0x0221,
iavf_aqc_opc_get_pv_parameters = 0x0222,
iavf_aqc_opc_add_veb = 0x0230,
iavf_aqc_opc_update_veb_parameters = 0x0231,
iavf_aqc_opc_get_veb_parameters = 0x0232,
iavf_aqc_opc_delete_element = 0x0243,
iavf_aqc_opc_add_macvlan = 0x0250,
iavf_aqc_opc_remove_macvlan = 0x0251,
iavf_aqc_opc_add_vlan = 0x0252,
iavf_aqc_opc_remove_vlan = 0x0253,
iavf_aqc_opc_set_vsi_promiscuous_modes = 0x0254,
iavf_aqc_opc_add_tag = 0x0255,
iavf_aqc_opc_remove_tag = 0x0256,
iavf_aqc_opc_add_multicast_etag = 0x0257,
iavf_aqc_opc_remove_multicast_etag = 0x0258,
iavf_aqc_opc_update_tag = 0x0259,
iavf_aqc_opc_add_control_packet_filter = 0x025A,
iavf_aqc_opc_remove_control_packet_filter = 0x025B,
iavf_aqc_opc_add_cloud_filters = 0x025C,
iavf_aqc_opc_remove_cloud_filters = 0x025D,
iavf_aqc_opc_clear_wol_switch_filters = 0x025E,
iavf_aqc_opc_add_mirror_rule = 0x0260,
iavf_aqc_opc_delete_mirror_rule = 0x0261,
/* Dynamic Device Personalization */
iavf_aqc_opc_write_personalization_profile = 0x0270,
iavf_aqc_opc_get_personalization_profile_list = 0x0271,
/* DCB commands */
iavf_aqc_opc_dcb_ignore_pfc = 0x0301,
iavf_aqc_opc_dcb_updated = 0x0302,
iavf_aqc_opc_set_dcb_parameters = 0x0303,
/* TX scheduler */
iavf_aqc_opc_configure_vsi_bw_limit = 0x0400,
iavf_aqc_opc_configure_vsi_ets_sla_bw_limit = 0x0406,
iavf_aqc_opc_configure_vsi_tc_bw = 0x0407,
iavf_aqc_opc_query_vsi_bw_config = 0x0408,
iavf_aqc_opc_query_vsi_ets_sla_config = 0x040A,
iavf_aqc_opc_configure_switching_comp_bw_limit = 0x0410,
iavf_aqc_opc_enable_switching_comp_ets = 0x0413,
iavf_aqc_opc_modify_switching_comp_ets = 0x0414,
iavf_aqc_opc_disable_switching_comp_ets = 0x0415,
iavf_aqc_opc_configure_switching_comp_ets_bw_limit = 0x0416,
iavf_aqc_opc_configure_switching_comp_bw_config = 0x0417,
iavf_aqc_opc_query_switching_comp_ets_config = 0x0418,
iavf_aqc_opc_query_port_ets_config = 0x0419,
iavf_aqc_opc_query_switching_comp_bw_config = 0x041A,
iavf_aqc_opc_suspend_port_tx = 0x041B,
iavf_aqc_opc_resume_port_tx = 0x041C,
iavf_aqc_opc_configure_partition_bw = 0x041D,
/* hmc */
iavf_aqc_opc_query_hmc_resource_profile = 0x0500,
iavf_aqc_opc_set_hmc_resource_profile = 0x0501,
/* phy commands*/
iavf_aqc_opc_get_phy_abilities = 0x0600,
iavf_aqc_opc_set_phy_config = 0x0601,
iavf_aqc_opc_set_mac_config = 0x0603,
iavf_aqc_opc_set_link_restart_an = 0x0605,
iavf_aqc_opc_get_link_status = 0x0607,
iavf_aqc_opc_set_phy_int_mask = 0x0613,
iavf_aqc_opc_get_local_advt_reg = 0x0614,
iavf_aqc_opc_set_local_advt_reg = 0x0615,
iavf_aqc_opc_get_partner_advt = 0x0616,
iavf_aqc_opc_set_lb_modes = 0x0618,
iavf_aqc_opc_get_phy_wol_caps = 0x0621,
iavf_aqc_opc_set_phy_debug = 0x0622,
iavf_aqc_opc_upload_ext_phy_fm = 0x0625,
iavf_aqc_opc_run_phy_activity = 0x0626,
iavf_aqc_opc_set_phy_register = 0x0628,
iavf_aqc_opc_get_phy_register = 0x0629,
/* NVM commands */
iavf_aqc_opc_nvm_read = 0x0701,
iavf_aqc_opc_nvm_erase = 0x0702,
iavf_aqc_opc_nvm_update = 0x0703,
iavf_aqc_opc_nvm_config_read = 0x0704,
iavf_aqc_opc_nvm_config_write = 0x0705,
iavf_aqc_opc_oem_post_update = 0x0720,
iavf_aqc_opc_thermal_sensor = 0x0721,
/* virtualization commands */
iavf_aqc_opc_send_msg_to_pf = 0x0801,
iavf_aqc_opc_send_msg_to_vf = 0x0802,
iavf_aqc_opc_send_msg_to_peer = 0x0803,
/* alternate structure */
iavf_aqc_opc_alternate_write = 0x0900,
iavf_aqc_opc_alternate_write_indirect = 0x0901,
iavf_aqc_opc_alternate_read = 0x0902,
iavf_aqc_opc_alternate_read_indirect = 0x0903,
iavf_aqc_opc_alternate_write_done = 0x0904,
iavf_aqc_opc_alternate_set_mode = 0x0905,
iavf_aqc_opc_alternate_clear_port = 0x0906,
/* LLDP commands */
iavf_aqc_opc_lldp_get_mib = 0x0A00,
iavf_aqc_opc_lldp_update_mib = 0x0A01,
iavf_aqc_opc_lldp_add_tlv = 0x0A02,
iavf_aqc_opc_lldp_update_tlv = 0x0A03,
iavf_aqc_opc_lldp_delete_tlv = 0x0A04,
iavf_aqc_opc_lldp_stop = 0x0A05,
iavf_aqc_opc_lldp_start = 0x0A06,
/* Tunnel commands */
iavf_aqc_opc_add_udp_tunnel = 0x0B00,
iavf_aqc_opc_del_udp_tunnel = 0x0B01,
iavf_aqc_opc_set_rss_key = 0x0B02,
iavf_aqc_opc_set_rss_lut = 0x0B03,
iavf_aqc_opc_get_rss_key = 0x0B04,
iavf_aqc_opc_get_rss_lut = 0x0B05,
/* Async Events */
iavf_aqc_opc_event_lan_overflow = 0x1001,
/* OEM commands */
iavf_aqc_opc_oem_parameter_change = 0xFE00,
iavf_aqc_opc_oem_device_status_change = 0xFE01,
iavf_aqc_opc_oem_ocsd_initialize = 0xFE02,
iavf_aqc_opc_oem_ocbb_initialize = 0xFE03,
/* debug commands */
iavf_aqc_opc_debug_read_reg = 0xFF03,
iavf_aqc_opc_debug_write_reg = 0xFF04,
iavf_aqc_opc_debug_modify_reg = 0xFF07,
iavf_aqc_opc_debug_dump_internals = 0xFF08,
};
/* command structures and indirect data structures */
/* Structure naming conventions:
* - no suffix for direct command descriptor structures
* - _data for indirect sent data
* - _resp for indirect return data (data which is both will use _data)
* - _completion for direct return data
* - _element_ for repeated elements (may also be _data or _resp)
*
* Command structures are expected to overlay the params.raw member of the basic
* descriptor, and as such cannot exceed 16 bytes in length.
*/
/* This macro is used to generate a compilation error if a structure
* is not exactly the correct length. It gives a divide by zero error if the
* structure is not of the correct size, otherwise it creates an enum that is
* never used.
*/
#define IAVF_CHECK_STRUCT_LEN(n, X) enum iavf_static_assert_enum_##X \
{ iavf_static_assert_##X = (n) / ((sizeof(struct X) == (n)) ? 1 : 0) }
/* This macro is used extensively to ensure that command structures are 16
* bytes in length as they have to map to the raw array of that size.
*/
#define IAVF_CHECK_CMD_LENGTH(X) IAVF_CHECK_STRUCT_LEN(16, X)
/* Queue Shutdown (direct 0x0003) */
struct iavf_aqc_queue_shutdown {
__le32 driver_unloading;
#define IAVF_AQ_DRIVER_UNLOADING 0x1
u8 reserved[12];
};
IAVF_CHECK_CMD_LENGTH(iavf_aqc_queue_shutdown);
struct iavf_aqc_vsi_properties_data {
/* first 96 byte are written by SW */
__le16 valid_sections;
#define IAVF_AQ_VSI_PROP_SWITCH_VALID 0x0001
#define IAVF_AQ_VSI_PROP_SECURITY_VALID 0x0002
#define IAVF_AQ_VSI_PROP_VLAN_VALID 0x0004
#define IAVF_AQ_VSI_PROP_CAS_PV_VALID 0x0008
#define IAVF_AQ_VSI_PROP_INGRESS_UP_VALID 0x0010
#define IAVF_AQ_VSI_PROP_EGRESS_UP_VALID 0x0020
#define IAVF_AQ_VSI_PROP_QUEUE_MAP_VALID 0x0040
#define IAVF_AQ_VSI_PROP_QUEUE_OPT_VALID 0x0080
#define IAVF_AQ_VSI_PROP_OUTER_UP_VALID 0x0100
#define IAVF_AQ_VSI_PROP_SCHED_VALID 0x0200
/* switch section */
__le16 switch_id; /* 12bit id combined with flags below */
#define IAVF_AQ_VSI_SW_ID_SHIFT 0x0000
#define IAVF_AQ_VSI_SW_ID_MASK (0xFFF << IAVF_AQ_VSI_SW_ID_SHIFT)
#define IAVF_AQ_VSI_SW_ID_FLAG_NOT_STAG 0x1000
#define IAVF_AQ_VSI_SW_ID_FLAG_ALLOW_LB 0x2000
#define IAVF_AQ_VSI_SW_ID_FLAG_LOCAL_LB 0x4000
u8 sw_reserved[2];
/* security section */
u8 sec_flags;
#define IAVF_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD 0x01
#define IAVF_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK 0x02
#define IAVF_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK 0x04
u8 sec_reserved;
/* VLAN section */
__le16 pvid; /* VLANS include priority bits */
__le16 fcoe_pvid;
u8 port_vlan_flags;
#define IAVF_AQ_VSI_PVLAN_MODE_SHIFT 0x00
#define IAVF_AQ_VSI_PVLAN_MODE_MASK (0x03 << \
IAVF_AQ_VSI_PVLAN_MODE_SHIFT)
#define IAVF_AQ_VSI_PVLAN_MODE_TAGGED 0x01
#define IAVF_AQ_VSI_PVLAN_MODE_UNTAGGED 0x02
#define IAVF_AQ_VSI_PVLAN_MODE_ALL 0x03
#define IAVF_AQ_VSI_PVLAN_INSERT_PVID 0x04
#define IAVF_AQ_VSI_PVLAN_EMOD_SHIFT 0x03
#define IAVF_AQ_VSI_PVLAN_EMOD_MASK (0x3 << \
IAVF_AQ_VSI_PVLAN_EMOD_SHIFT)
#define IAVF_AQ_VSI_PVLAN_EMOD_STR_BOTH 0x0
#define IAVF_AQ_VSI_PVLAN_EMOD_STR_UP 0x08
#define IAVF_AQ_VSI_PVLAN_EMOD_STR 0x10
#define IAVF_AQ_VSI_PVLAN_EMOD_NOTHING 0x18
u8 pvlan_reserved[3];
/* ingress egress up sections */
__le32 ingress_table; /* bitmap, 3 bits per up */
#define IAVF_AQ_VSI_UP_TABLE_UP0_SHIFT 0
#define IAVF_AQ_VSI_UP_TABLE_UP0_MASK (0x7 << \
IAVF_AQ_VSI_UP_TABLE_UP0_SHIFT)
#define IAVF_AQ_VSI_UP_TABLE_UP1_SHIFT 3
#define IAVF_AQ_VSI_UP_TABLE_UP1_MASK (0x7 << \
IAVF_AQ_VSI_UP_TABLE_UP1_SHIFT)
#define IAVF_AQ_VSI_UP_TABLE_UP2_SHIFT 6
#define IAVF_AQ_VSI_UP_TABLE_UP2_MASK (0x7 << \
IAVF_AQ_VSI_UP_TABLE_UP2_SHIFT)
#define IAVF_AQ_VSI_UP_TABLE_UP3_SHIFT 9
#define IAVF_AQ_VSI_UP_TABLE_UP3_MASK (0x7 << \
IAVF_AQ_VSI_UP_TABLE_UP3_SHIFT)
#define IAVF_AQ_VSI_UP_TABLE_UP4_SHIFT 12
#define IAVF_AQ_VSI_UP_TABLE_UP4_MASK (0x7 << \
IAVF_AQ_VSI_UP_TABLE_UP4_SHIFT)
#define IAVF_AQ_VSI_UP_TABLE_UP5_SHIFT 15
#define IAVF_AQ_VSI_UP_TABLE_UP5_MASK (0x7 << \
IAVF_AQ_VSI_UP_TABLE_UP5_SHIFT)
#define IAVF_AQ_VSI_UP_TABLE_UP6_SHIFT 18
#define IAVF_AQ_VSI_UP_TABLE_UP6_MASK (0x7 << \
IAVF_AQ_VSI_UP_TABLE_UP6_SHIFT)
#define IAVF_AQ_VSI_UP_TABLE_UP7_SHIFT 21
#define IAVF_AQ_VSI_UP_TABLE_UP7_MASK (0x7 << \
IAVF_AQ_VSI_UP_TABLE_UP7_SHIFT)
__le32 egress_table; /* same defines as for ingress table */
/* cascaded PV section */
__le16 cas_pv_tag;
u8 cas_pv_flags;
#define IAVF_AQ_VSI_CAS_PV_TAGX_SHIFT 0x00
#define IAVF_AQ_VSI_CAS_PV_TAGX_MASK (0x03 << \
IAVF_AQ_VSI_CAS_PV_TAGX_SHIFT)
#define IAVF_AQ_VSI_CAS_PV_TAGX_LEAVE 0x00
#define IAVF_AQ_VSI_CAS_PV_TAGX_REMOVE 0x01
#define IAVF_AQ_VSI_CAS_PV_TAGX_COPY 0x02
#define IAVF_AQ_VSI_CAS_PV_INSERT_TAG 0x10
#define IAVF_AQ_VSI_CAS_PV_ETAG_PRUNE 0x20
#define IAVF_AQ_VSI_CAS_PV_ACCEPT_HOST_TAG 0x40
u8 cas_pv_reserved;
/* queue mapping section */
__le16 mapping_flags;
#define IAVF_AQ_VSI_QUE_MAP_CONTIG 0x0
#define IAVF_AQ_VSI_QUE_MAP_NONCONTIG 0x1
__le16 queue_mapping[16];
#define IAVF_AQ_VSI_QUEUE_SHIFT 0x0
#define IAVF_AQ_VSI_QUEUE_MASK (0x7FF << IAVF_AQ_VSI_QUEUE_SHIFT)
__le16 tc_mapping[8];
#define IAVF_AQ_VSI_TC_QUE_OFFSET_SHIFT 0
#define IAVF_AQ_VSI_TC_QUE_OFFSET_MASK (0x1FF << \
IAVF_AQ_VSI_TC_QUE_OFFSET_SHIFT)
#define IAVF_AQ_VSI_TC_QUE_NUMBER_SHIFT 9
#define IAVF_AQ_VSI_TC_QUE_NUMBER_MASK (0x7 << \
IAVF_AQ_VSI_TC_QUE_NUMBER_SHIFT)
/* queueing option section */
u8 queueing_opt_flags;
#define IAVF_AQ_VSI_QUE_OPT_MULTICAST_UDP_ENA 0x04
#define IAVF_AQ_VSI_QUE_OPT_UNICAST_UDP_ENA 0x08
#define IAVF_AQ_VSI_QUE_OPT_TCP_ENA 0x10
#define IAVF_AQ_VSI_QUE_OPT_FCOE_ENA 0x20
#define IAVF_AQ_VSI_QUE_OPT_RSS_LUT_PF 0x00
#define IAVF_AQ_VSI_QUE_OPT_RSS_LUT_VSI 0x40
u8 queueing_opt_reserved[3];
/* scheduler section */
u8 up_enable_bits;
u8 sched_reserved;
/* outer up section */
__le32 outer_up_table; /* same structure and defines as ingress tbl */
u8 cmd_reserved[8];
/* last 32 bytes are written by FW */
__le16 qs_handle[8];
#define IAVF_AQ_VSI_QS_HANDLE_INVALID 0xFFFF
__le16 stat_counter_idx;
__le16 sched_id;
u8 resp_reserved[12];
};
IAVF_CHECK_STRUCT_LEN(128, iavf_aqc_vsi_properties_data);
/* Get VEB Parameters (direct 0x0232)
* uses iavf_aqc_switch_seid for the descriptor
*/
struct iavf_aqc_get_veb_parameters_completion {
__le16 seid;
__le16 switch_id;
__le16 veb_flags; /* only the first/last flags from 0x0230 is valid */
__le16 statistic_index;
__le16 vebs_used;
__le16 vebs_free;
u8 reserved[4];
};
IAVF_CHECK_CMD_LENGTH(iavf_aqc_get_veb_parameters_completion);
#define IAVF_LINK_SPEED_100MB_SHIFT 0x1
#define IAVF_LINK_SPEED_1000MB_SHIFT 0x2
#define IAVF_LINK_SPEED_10GB_SHIFT 0x3
#define IAVF_LINK_SPEED_40GB_SHIFT 0x4
#define IAVF_LINK_SPEED_20GB_SHIFT 0x5
#define IAVF_LINK_SPEED_25GB_SHIFT 0x6
enum iavf_aq_link_speed {
IAVF_LINK_SPEED_UNKNOWN = 0,
IAVF_LINK_SPEED_100MB = BIT(IAVF_LINK_SPEED_100MB_SHIFT),
IAVF_LINK_SPEED_1GB = BIT(IAVF_LINK_SPEED_1000MB_SHIFT),
IAVF_LINK_SPEED_10GB = BIT(IAVF_LINK_SPEED_10GB_SHIFT),
IAVF_LINK_SPEED_40GB = BIT(IAVF_LINK_SPEED_40GB_SHIFT),
IAVF_LINK_SPEED_20GB = BIT(IAVF_LINK_SPEED_20GB_SHIFT),
IAVF_LINK_SPEED_25GB = BIT(IAVF_LINK_SPEED_25GB_SHIFT),
};
/* Send to PF command (indirect 0x0801) id is only used by PF
* Send to VF command (indirect 0x0802) id is only used by PF
* Send to Peer PF command (indirect 0x0803)
*/
struct iavf_aqc_pf_vf_message {
__le32 id;
u8 reserved[4];
__le32 addr_high;
__le32 addr_low;
};
IAVF_CHECK_CMD_LENGTH(iavf_aqc_pf_vf_message);
struct iavf_aqc_get_set_rss_key {
#define IAVF_AQC_SET_RSS_KEY_VSI_VALID BIT(15)
#define IAVF_AQC_SET_RSS_KEY_VSI_ID_SHIFT 0
#define IAVF_AQC_SET_RSS_KEY_VSI_ID_MASK (0x3FF << \
IAVF_AQC_SET_RSS_KEY_VSI_ID_SHIFT)
__le16 vsi_id;
u8 reserved[6];
__le32 addr_high;
__le32 addr_low;
};
IAVF_CHECK_CMD_LENGTH(iavf_aqc_get_set_rss_key);
struct iavf_aqc_get_set_rss_key_data {
u8 standard_rss_key[0x28];
u8 extended_hash_key[0xc];
};
IAVF_CHECK_STRUCT_LEN(0x34, iavf_aqc_get_set_rss_key_data);
struct iavf_aqc_get_set_rss_lut {
#define IAVF_AQC_SET_RSS_LUT_VSI_VALID BIT(15)
#define IAVF_AQC_SET_RSS_LUT_VSI_ID_SHIFT 0
#define IAVF_AQC_SET_RSS_LUT_VSI_ID_MASK (0x3FF << \
IAVF_AQC_SET_RSS_LUT_VSI_ID_SHIFT)
__le16 vsi_id;
#define IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT 0
#define IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_MASK \
BIT(IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT)
#define IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_VSI 0
#define IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_PF 1
__le16 flags;
u8 reserved[4];
__le32 addr_high;
__le32 addr_low;
};
IAVF_CHECK_CMD_LENGTH(iavf_aqc_get_set_rss_lut);
#endif /* _IAVF_ADMINQ_CMD_H_ */
@@ -0,0 +1,295 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2021, Intel Corporation. */
/* advanced RSS configuration ethtool support for iavf */
#include "iavf.h"
/**
* iavf_fill_adv_rss_ip4_hdr - fill the IPv4 RSS protocol header
* @hdr: the virtchnl message protocol header data structure
* @hash_flds: the RSS configuration protocol hash fields
*/
static void
iavf_fill_adv_rss_ip4_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
{
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV4);
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV4_SA)
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, SRC);
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV4_DA)
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DST);
}
/**
* iavf_fill_adv_rss_ip6_hdr - fill the IPv6 RSS protocol header
* @hdr: the virtchnl message protocol header data structure
* @hash_flds: the RSS configuration protocol hash fields
*/
static void
iavf_fill_adv_rss_ip6_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
{
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV6);
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV6_SA)
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, SRC);
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV6_DA)
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, DST);
}
/**
* iavf_fill_adv_rss_tcp_hdr - fill the TCP RSS protocol header
* @hdr: the virtchnl message protocol header data structure
* @hash_flds: the RSS configuration protocol hash fields
*/
static void
iavf_fill_adv_rss_tcp_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
{
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, TCP);
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT)
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, SRC_PORT);
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT)
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, DST_PORT);
}
/**
* iavf_fill_adv_rss_udp_hdr - fill the UDP RSS protocol header
* @hdr: the virtchnl message protocol header data structure
* @hash_flds: the RSS configuration protocol hash fields
*/
static void
iavf_fill_adv_rss_udp_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
{
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, UDP);
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT)
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, SRC_PORT);
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT)
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, DST_PORT);
}
/**
* iavf_fill_adv_rss_sctp_hdr - fill the SCTP RSS protocol header
* @hdr: the virtchnl message protocol header data structure
* @hash_flds: the RSS configuration protocol hash fields
*/
static void
iavf_fill_adv_rss_sctp_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
{
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, SCTP);
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT)
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, SRC_PORT);
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT)
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, DST_PORT);
}
/**
* iavf_fill_adv_rss_gtp_hdr - Fill GTP-related RSS protocol headers
* @proto_hdrs: pointer to the virtchnl protocol headers structure to populate
* @packet_hdrs: bitmask of packet header types to configure
* @hash_flds: RSS hash field configuration
*
* This function populates the virtchnl protocol header structure with
* appropriate GTP-related header types based on the specified packet_hdrs.
* It supports GTPC, GTPU with extension headers, and uplink/downlink PDU
* types. For certain GTPU types, it also appends an IPv4 header to enable
* hashing on the destination IP address.
*
* Return: 0 on success or -EOPNOTSUPP if the packet_hdrs value is unsupported.
*/
static int
iavf_fill_adv_rss_gtp_hdr(struct virtchnl_proto_hdrs *proto_hdrs,
u32 packet_hdrs, u64 hash_flds)
{
struct virtchnl_proto_hdr *hdr;
hdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];
switch (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_GTP) {
case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPC_TEID:
case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPC:
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, GTPC);
break;
case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_EH:
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, GTPU_EH);
break;
case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_UP:
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, GTPU_EH_PDU_UP);
hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
iavf_fill_adv_rss_ip4_hdr(hdr, IAVF_ADV_RSS_HASH_FLD_IPV4_DA);
break;
case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_DWN:
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, GTPU_EH_PDU_DWN);
fallthrough;
case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_IP:
hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
iavf_fill_adv_rss_ip4_hdr(hdr, IAVF_ADV_RSS_HASH_FLD_IPV4_DA);
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
/**
* iavf_fill_adv_rss_cfg_msg - fill the RSS configuration into virtchnl message
* @rss_cfg: the virtchnl message to be filled with RSS configuration setting
* @packet_hdrs: the RSS configuration protocol header types
* @hash_flds: the RSS configuration protocol hash fields
* @symm: if true, symmetric hash is required
*
* Returns 0 if the RSS configuration virtchnl message is filled successfully
*/
int
iavf_fill_adv_rss_cfg_msg(struct virtchnl_rss_cfg *rss_cfg,
u32 packet_hdrs, u64 hash_flds, bool symm)
{
const u32 packet_l3_hdrs = packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_L3;
const u32 packet_l4_hdrs = packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_L4;
struct virtchnl_proto_hdrs *proto_hdrs = &rss_cfg->proto_hdrs;
struct virtchnl_proto_hdr *hdr;
if (symm)
rss_cfg->rss_algorithm = VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC;
else
rss_cfg->rss_algorithm = VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC;
proto_hdrs->tunnel_level = 0; /* always outer layer */
if (packet_l3_hdrs) {
hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
switch (packet_l3_hdrs) {
case IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4:
iavf_fill_adv_rss_ip4_hdr(hdr, hash_flds);
break;
case IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6:
iavf_fill_adv_rss_ip6_hdr(hdr, hash_flds);
break;
default:
return -EINVAL;
}
}
if (packet_l4_hdrs) {
hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
switch (packet_l4_hdrs) {
case IAVF_ADV_RSS_FLOW_SEG_HDR_TCP:
iavf_fill_adv_rss_tcp_hdr(hdr, hash_flds);
break;
case IAVF_ADV_RSS_FLOW_SEG_HDR_UDP:
iavf_fill_adv_rss_udp_hdr(hdr, hash_flds);
break;
case IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP:
iavf_fill_adv_rss_sctp_hdr(hdr, hash_flds);
break;
default:
return -EINVAL;
}
}
if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_GTP) {
hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
if (iavf_fill_adv_rss_gtp_hdr(proto_hdrs, packet_hdrs, hash_flds))
return -EINVAL;
}
return 0;
}
/**
* iavf_find_adv_rss_cfg_by_hdrs - find RSS configuration with header type
* @adapter: pointer to the VF adapter structure
* @packet_hdrs: protocol header type to find.
*
* Returns pointer to advance RSS configuration if found or null
*/
struct iavf_adv_rss *
iavf_find_adv_rss_cfg_by_hdrs(struct iavf_adapter *adapter, u32 packet_hdrs)
{
struct iavf_adv_rss *rss;
list_for_each_entry(rss, &adapter->adv_rss_list_head, list)
if (rss->packet_hdrs == packet_hdrs)
return rss;
return NULL;
}
/**
* iavf_print_adv_rss_cfg
* @adapter: pointer to the VF adapter structure
* @rss: pointer to the advance RSS configuration to print
* @action: the string description about how to handle the RSS
* @result: the string description about the virtchnl result
*
* Print the advance RSS configuration
**/
void
iavf_print_adv_rss_cfg(struct iavf_adapter *adapter, struct iavf_adv_rss *rss,
const char *action, const char *result)
{
u32 packet_hdrs = rss->packet_hdrs;
u64 hash_flds = rss->hash_flds;
static char hash_opt[300];
const char *proto;
if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_TCP)
proto = "TCP";
else if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_UDP)
proto = "UDP";
else if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP)
proto = "SCTP";
else if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_GTP)
proto = "GTP";
else
return;
memset(hash_opt, 0, sizeof(hash_opt));
strcat(hash_opt, proto);
if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4)
strcat(hash_opt, "v4 ");
else
strcat(hash_opt, "v6 ");
if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_IPV4_SA |
IAVF_ADV_RSS_HASH_FLD_IPV6_SA))
strcat(hash_opt, "IP SA,");
if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_IPV4_DA |
IAVF_ADV_RSS_HASH_FLD_IPV6_DA))
strcat(hash_opt, "IP DA,");
if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT |
IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT |
IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT))
strcat(hash_opt, "src port,");
if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT |
IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT |
IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT))
strcat(hash_opt, "dst port,");
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPC_TEID)
strcat(hash_opt, "gtp-c,");
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPU_IP_TEID)
strcat(hash_opt, "gtp-u ip,");
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPU_EH_TEID)
strcat(hash_opt, "gtp-u ext,");
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPU_UP_TEID)
strcat(hash_opt, "gtp-u ul,");
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPU_DWN_TEID)
strcat(hash_opt, "gtp-u dl,");
if (!action)
action = "";
if (!result)
result = "";
dev_info(&adapter->pdev->dev, "%s %s %s\n", action, hash_opt, result);
}
@@ -0,0 +1,127 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2021, Intel Corporation. */
#ifndef _IAVF_ADV_RSS_H_
#define _IAVF_ADV_RSS_H_
struct iavf_adapter;
/* State of advanced RSS configuration */
enum iavf_adv_rss_state_t {
IAVF_ADV_RSS_ADD_REQUEST, /* User requests to add RSS */
IAVF_ADV_RSS_ADD_PENDING, /* RSS pending add by the PF */
IAVF_ADV_RSS_DEL_REQUEST, /* Driver requests to delete RSS */
IAVF_ADV_RSS_DEL_PENDING, /* RSS pending delete by the PF */
IAVF_ADV_RSS_ACTIVE, /* RSS configuration is active */
};
enum iavf_adv_rss_flow_seg_hdr {
IAVF_ADV_RSS_FLOW_SEG_HDR_NONE = 0x00000000,
IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4 = 0x00000001,
IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6 = 0x00000002,
IAVF_ADV_RSS_FLOW_SEG_HDR_TCP = 0x00000004,
IAVF_ADV_RSS_FLOW_SEG_HDR_UDP = 0x00000008,
IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP = 0x00000010,
IAVF_ADV_RSS_FLOW_SEG_HDR_GTPC = 0x00000400,
IAVF_ADV_RSS_FLOW_SEG_HDR_GTPC_TEID = 0x00000800,
IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_IP = 0x00001000,
IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_EH = 0x00002000,
IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_DWN = 0x00004000,
IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_UP = 0x00008000,
};
#define IAVF_ADV_RSS_FLOW_SEG_HDR_L3 \
(IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4 | \
IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6)
#define IAVF_ADV_RSS_FLOW_SEG_HDR_L4 \
(IAVF_ADV_RSS_FLOW_SEG_HDR_TCP | \
IAVF_ADV_RSS_FLOW_SEG_HDR_UDP | \
IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP)
#define IAVF_ADV_RSS_FLOW_SEG_HDR_GTP \
(IAVF_ADV_RSS_FLOW_SEG_HDR_GTPC | \
IAVF_ADV_RSS_FLOW_SEG_HDR_GTPC_TEID | \
IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_IP | \
IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_EH | \
IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_DWN | \
IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_UP)
enum iavf_adv_rss_flow_field {
/* L3 */
IAVF_ADV_RSS_FLOW_FIELD_IDX_IPV4_SA,
IAVF_ADV_RSS_FLOW_FIELD_IDX_IPV4_DA,
IAVF_ADV_RSS_FLOW_FIELD_IDX_IPV6_SA,
IAVF_ADV_RSS_FLOW_FIELD_IDX_IPV6_DA,
/* L4 */
IAVF_ADV_RSS_FLOW_FIELD_IDX_TCP_SRC_PORT,
IAVF_ADV_RSS_FLOW_FIELD_IDX_TCP_DST_PORT,
IAVF_ADV_RSS_FLOW_FIELD_IDX_UDP_SRC_PORT,
IAVF_ADV_RSS_FLOW_FIELD_IDX_UDP_DST_PORT,
IAVF_ADV_RSS_FLOW_FIELD_IDX_SCTP_SRC_PORT,
IAVF_ADV_RSS_FLOW_FIELD_IDX_SCTP_DST_PORT,
/* GTPC_TEID */
IAVF_ADV_RSS_FLOW_FIELD_IDX_GTPC_TEID,
/* GTPU_IP */
IAVF_ADV_RSS_FLOW_FIELD_IDX_GTPU_IP_TEID,
/* GTPU_EH */
IAVF_ADV_RSS_FLOW_FIELD_IDX_GTPU_EH_TEID,
IAVF_ADV_RSS_FLOW_FIELD_IDX_GTPU_EH_QFI,
/* GTPU_UP */
IAVF_ADV_RSS_FLOW_FIELD_IDX_GTPU_UP_TEID,
/* GTPU_DWN */
IAVF_ADV_RSS_FLOW_FIELD_IDX_GTPU_DWN_TEID,
/* The total number of enums must not exceed 64 */
IAVF_ADV_RSS_FLOW_FIELD_IDX_MAX
};
#define IAVF_ADV_RSS_HASH_INVALID 0
#define IAVF_ADV_RSS_HASH_FLD_IPV4_SA \
BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_IPV4_SA)
#define IAVF_ADV_RSS_HASH_FLD_IPV6_SA \
BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_IPV6_SA)
#define IAVF_ADV_RSS_HASH_FLD_IPV4_DA \
BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_IPV4_DA)
#define IAVF_ADV_RSS_HASH_FLD_IPV6_DA \
BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_IPV6_DA)
#define IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT \
BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_TCP_SRC_PORT)
#define IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT \
BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_TCP_DST_PORT)
#define IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT \
BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_UDP_SRC_PORT)
#define IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT \
BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_UDP_DST_PORT)
#define IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT \
BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_SCTP_SRC_PORT)
#define IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT \
BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_SCTP_DST_PORT)
#define IAVF_ADV_RSS_HASH_FLD_GTPC_TEID BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_GTPC_TEID)
#define IAVF_ADV_RSS_HASH_FLD_GTPU_IP_TEID BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_GTPU_IP_TEID)
#define IAVF_ADV_RSS_HASH_FLD_GTPU_EH_TEID BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_GTPU_EH_TEID)
#define IAVF_ADV_RSS_HASH_FLD_GTPU_UP_TEID BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_GTPU_UP_TEID)
#define IAVF_ADV_RSS_HASH_FLD_GTPU_DWN_TEID \
BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_GTPU_DWN_TEID)
/* bookkeeping of advanced RSS configuration */
struct iavf_adv_rss {
enum iavf_adv_rss_state_t state;
struct list_head list;
u32 packet_hdrs;
u64 hash_flds;
bool symm;
struct virtchnl_rss_cfg cfg_msg;
};
int
iavf_fill_adv_rss_cfg_msg(struct virtchnl_rss_cfg *rss_cfg,
u32 packet_hdrs, u64 hash_flds, bool symm);
struct iavf_adv_rss *
iavf_find_adv_rss_cfg_by_hdrs(struct iavf_adapter *adapter, u32 packet_hdrs);
void
iavf_print_adv_rss_cfg(struct iavf_adapter *adapter, struct iavf_adv_rss *rss,
const char *action, const char *result);
#endif /* _IAVF_ADV_RSS_H_ */
@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#ifndef _IAVF_ALLOC_H_
#define _IAVF_ALLOC_H_
struct iavf_hw;
/* Memory allocation types */
enum iavf_memory_type {
iavf_mem_arq_buf = 0, /* ARQ indirect command buffer */
iavf_mem_asq_buf = 1,
iavf_mem_atq_buf = 2, /* ATQ indirect command buffer */
iavf_mem_arq_ring = 3, /* ARQ descriptor ring */
iavf_mem_atq_ring = 4, /* ATQ descriptor ring */
iavf_mem_pd = 5, /* Page Descriptor */
iavf_mem_bp = 6, /* Backing Page - 4KB */
iavf_mem_bp_jumbo = 7, /* Backing Page - > 4KB */
iavf_mem_reserved
};
/* prototype for functions used for dynamic memory allocation */
enum iavf_status iavf_allocate_dma_mem(struct iavf_hw *hw,
struct iavf_dma_mem *mem,
enum iavf_memory_type type,
u64 size, u32 alignment);
enum iavf_status iavf_free_dma_mem(struct iavf_hw *hw,
struct iavf_dma_mem *mem);
enum iavf_status iavf_allocate_virt_mem(struct iavf_hw *hw,
struct iavf_virt_mem *mem, u32 size);
void iavf_free_virt_mem(struct iavf_hw *hw, struct iavf_virt_mem *mem);
#endif /* _IAVF_ALLOC_H_ */
@@ -0,0 +1,452 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#include <linux/avf/virtchnl.h>
#include <linux/bitfield.h>
#include "iavf_type.h"
#include "iavf_adminq.h"
#include "iavf_prototype.h"
/**
* iavf_stat_str - convert status err code to a string
* @hw: pointer to the HW structure
* @stat_err: the status error code to convert
**/
const char *iavf_stat_str(struct iavf_hw *hw, enum iavf_status stat_err)
{
switch (stat_err) {
case 0:
return "OK";
case IAVF_ERR_NVM:
return "IAVF_ERR_NVM";
case IAVF_ERR_NVM_CHECKSUM:
return "IAVF_ERR_NVM_CHECKSUM";
case IAVF_ERR_PHY:
return "IAVF_ERR_PHY";
case IAVF_ERR_CONFIG:
return "IAVF_ERR_CONFIG";
case IAVF_ERR_PARAM:
return "IAVF_ERR_PARAM";
case IAVF_ERR_MAC_TYPE:
return "IAVF_ERR_MAC_TYPE";
case IAVF_ERR_UNKNOWN_PHY:
return "IAVF_ERR_UNKNOWN_PHY";
case IAVF_ERR_LINK_SETUP:
return "IAVF_ERR_LINK_SETUP";
case IAVF_ERR_ADAPTER_STOPPED:
return "IAVF_ERR_ADAPTER_STOPPED";
case IAVF_ERR_INVALID_MAC_ADDR:
return "IAVF_ERR_INVALID_MAC_ADDR";
case IAVF_ERR_DEVICE_NOT_SUPPORTED:
return "IAVF_ERR_DEVICE_NOT_SUPPORTED";
case IAVF_ERR_PRIMARY_REQUESTS_PENDING:
return "IAVF_ERR_PRIMARY_REQUESTS_PENDING";
case IAVF_ERR_INVALID_LINK_SETTINGS:
return "IAVF_ERR_INVALID_LINK_SETTINGS";
case IAVF_ERR_AUTONEG_NOT_COMPLETE:
return "IAVF_ERR_AUTONEG_NOT_COMPLETE";
case IAVF_ERR_RESET_FAILED:
return "IAVF_ERR_RESET_FAILED";
case IAVF_ERR_SWFW_SYNC:
return "IAVF_ERR_SWFW_SYNC";
case IAVF_ERR_NO_AVAILABLE_VSI:
return "IAVF_ERR_NO_AVAILABLE_VSI";
case IAVF_ERR_NO_MEMORY:
return "IAVF_ERR_NO_MEMORY";
case IAVF_ERR_BAD_PTR:
return "IAVF_ERR_BAD_PTR";
case IAVF_ERR_RING_FULL:
return "IAVF_ERR_RING_FULL";
case IAVF_ERR_INVALID_PD_ID:
return "IAVF_ERR_INVALID_PD_ID";
case IAVF_ERR_INVALID_QP_ID:
return "IAVF_ERR_INVALID_QP_ID";
case IAVF_ERR_INVALID_CQ_ID:
return "IAVF_ERR_INVALID_CQ_ID";
case IAVF_ERR_INVALID_CEQ_ID:
return "IAVF_ERR_INVALID_CEQ_ID";
case IAVF_ERR_INVALID_AEQ_ID:
return "IAVF_ERR_INVALID_AEQ_ID";
case IAVF_ERR_INVALID_SIZE:
return "IAVF_ERR_INVALID_SIZE";
case IAVF_ERR_INVALID_ARP_INDEX:
return "IAVF_ERR_INVALID_ARP_INDEX";
case IAVF_ERR_INVALID_FPM_FUNC_ID:
return "IAVF_ERR_INVALID_FPM_FUNC_ID";
case IAVF_ERR_QP_INVALID_MSG_SIZE:
return "IAVF_ERR_QP_INVALID_MSG_SIZE";
case IAVF_ERR_QP_TOOMANY_WRS_POSTED:
return "IAVF_ERR_QP_TOOMANY_WRS_POSTED";
case IAVF_ERR_INVALID_FRAG_COUNT:
return "IAVF_ERR_INVALID_FRAG_COUNT";
case IAVF_ERR_QUEUE_EMPTY:
return "IAVF_ERR_QUEUE_EMPTY";
case IAVF_ERR_INVALID_ALIGNMENT:
return "IAVF_ERR_INVALID_ALIGNMENT";
case IAVF_ERR_FLUSHED_QUEUE:
return "IAVF_ERR_FLUSHED_QUEUE";
case IAVF_ERR_INVALID_PUSH_PAGE_INDEX:
return "IAVF_ERR_INVALID_PUSH_PAGE_INDEX";
case IAVF_ERR_INVALID_IMM_DATA_SIZE:
return "IAVF_ERR_INVALID_IMM_DATA_SIZE";
case IAVF_ERR_TIMEOUT:
return "IAVF_ERR_TIMEOUT";
case IAVF_ERR_OPCODE_MISMATCH:
return "IAVF_ERR_OPCODE_MISMATCH";
case IAVF_ERR_CQP_COMPL_ERROR:
return "IAVF_ERR_CQP_COMPL_ERROR";
case IAVF_ERR_INVALID_VF_ID:
return "IAVF_ERR_INVALID_VF_ID";
case IAVF_ERR_INVALID_HMCFN_ID:
return "IAVF_ERR_INVALID_HMCFN_ID";
case IAVF_ERR_BACKING_PAGE_ERROR:
return "IAVF_ERR_BACKING_PAGE_ERROR";
case IAVF_ERR_NO_PBLCHUNKS_AVAILABLE:
return "IAVF_ERR_NO_PBLCHUNKS_AVAILABLE";
case IAVF_ERR_INVALID_PBLE_INDEX:
return "IAVF_ERR_INVALID_PBLE_INDEX";
case IAVF_ERR_INVALID_SD_INDEX:
return "IAVF_ERR_INVALID_SD_INDEX";
case IAVF_ERR_INVALID_PAGE_DESC_INDEX:
return "IAVF_ERR_INVALID_PAGE_DESC_INDEX";
case IAVF_ERR_INVALID_SD_TYPE:
return "IAVF_ERR_INVALID_SD_TYPE";
case IAVF_ERR_MEMCPY_FAILED:
return "IAVF_ERR_MEMCPY_FAILED";
case IAVF_ERR_INVALID_HMC_OBJ_INDEX:
return "IAVF_ERR_INVALID_HMC_OBJ_INDEX";
case IAVF_ERR_INVALID_HMC_OBJ_COUNT:
return "IAVF_ERR_INVALID_HMC_OBJ_COUNT";
case IAVF_ERR_INVALID_SRQ_ARM_LIMIT:
return "IAVF_ERR_INVALID_SRQ_ARM_LIMIT";
case IAVF_ERR_SRQ_ENABLED:
return "IAVF_ERR_SRQ_ENABLED";
case IAVF_ERR_ADMIN_QUEUE_ERROR:
return "IAVF_ERR_ADMIN_QUEUE_ERROR";
case IAVF_ERR_ADMIN_QUEUE_TIMEOUT:
return "IAVF_ERR_ADMIN_QUEUE_TIMEOUT";
case IAVF_ERR_BUF_TOO_SHORT:
return "IAVF_ERR_BUF_TOO_SHORT";
case IAVF_ERR_ADMIN_QUEUE_FULL:
return "IAVF_ERR_ADMIN_QUEUE_FULL";
case IAVF_ERR_ADMIN_QUEUE_NO_WORK:
return "IAVF_ERR_ADMIN_QUEUE_NO_WORK";
case IAVF_ERR_BAD_RDMA_CQE:
return "IAVF_ERR_BAD_RDMA_CQE";
case IAVF_ERR_NVM_BLANK_MODE:
return "IAVF_ERR_NVM_BLANK_MODE";
case IAVF_ERR_NOT_IMPLEMENTED:
return "IAVF_ERR_NOT_IMPLEMENTED";
case IAVF_ERR_PE_DOORBELL_NOT_ENABLED:
return "IAVF_ERR_PE_DOORBELL_NOT_ENABLED";
case IAVF_ERR_DIAG_TEST_FAILED:
return "IAVF_ERR_DIAG_TEST_FAILED";
case IAVF_ERR_NOT_READY:
return "IAVF_ERR_NOT_READY";
case IAVF_NOT_SUPPORTED:
return "IAVF_NOT_SUPPORTED";
case IAVF_ERR_FIRMWARE_API_VERSION:
return "IAVF_ERR_FIRMWARE_API_VERSION";
case IAVF_ERR_ADMIN_QUEUE_CRITICAL_ERROR:
return "IAVF_ERR_ADMIN_QUEUE_CRITICAL_ERROR";
}
snprintf(hw->err_str, sizeof(hw->err_str), "%d", stat_err);
return hw->err_str;
}
/**
* iavf_debug_aq
* @hw: debug mask related to admin queue
* @mask: debug mask
* @desc: pointer to admin queue descriptor
* @buffer: pointer to command buffer
* @buf_len: max length of buffer
*
* Dumps debug log about adminq command with descriptor contents.
**/
void iavf_debug_aq(struct iavf_hw *hw, enum iavf_debug_mask mask, void *desc,
void *buffer, u16 buf_len)
{
struct libie_aq_desc *aq_desc = (struct libie_aq_desc *)desc;
u8 *buf = (u8 *)buffer;
if ((!(mask & hw->debug_mask)) || !desc)
return;
iavf_debug(hw, mask,
"AQ CMD: opcode 0x%04X, flags 0x%04X, datalen 0x%04X, retval 0x%04X\n",
le16_to_cpu(aq_desc->opcode),
le16_to_cpu(aq_desc->flags),
le16_to_cpu(aq_desc->datalen),
le16_to_cpu(aq_desc->retval));
iavf_debug(hw, mask, "\tcookie (h,l) 0x%08X 0x%08X\n",
le32_to_cpu(aq_desc->cookie_high),
le32_to_cpu(aq_desc->cookie_low));
iavf_debug(hw, mask, "\tparam (0,1) 0x%08X 0x%08X\n",
le32_to_cpu(aq_desc->params.generic.param0),
le32_to_cpu(aq_desc->params.generic.param1));
iavf_debug(hw, mask, "\taddr (h,l) 0x%08X 0x%08X\n",
le32_to_cpu(aq_desc->params.generic.addr_high),
le32_to_cpu(aq_desc->params.generic.addr_low));
if (buffer && aq_desc->datalen) {
u16 len = le16_to_cpu(aq_desc->datalen);
iavf_debug(hw, mask, "AQ CMD Buffer:\n");
if (buf_len < len)
len = buf_len;
/* write the full 16-byte chunks */
if (hw->debug_mask & mask) {
char prefix[27];
snprintf(prefix, sizeof(prefix),
"iavf %02x:%02x.%x: \t0x",
hw->bus.bus_id,
hw->bus.device,
hw->bus.func);
print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET,
16, 1, buf, len, false);
}
}
}
/**
* iavf_check_asq_alive
* @hw: pointer to the hw struct
*
* Returns true if Queue is enabled else false.
**/
bool iavf_check_asq_alive(struct iavf_hw *hw)
{
/* Check if the queue is initialized */
if (!hw->aq.asq.count)
return false;
return !!(rd32(hw, IAVF_VF_ATQLEN1) & IAVF_VF_ATQLEN1_ATQENABLE_MASK);
}
/**
* iavf_aq_queue_shutdown
* @hw: pointer to the hw struct
* @unloading: is the driver unloading itself
*
* Tell the Firmware that we're shutting down the AdminQ and whether
* or not the driver is unloading as well.
**/
enum iavf_status iavf_aq_queue_shutdown(struct iavf_hw *hw, bool unloading)
{
struct iavf_aqc_queue_shutdown *cmd;
struct libie_aq_desc desc;
enum iavf_status status;
cmd = libie_aq_raw(&desc);
iavf_fill_default_direct_cmd_desc(&desc, iavf_aqc_opc_queue_shutdown);
if (unloading)
cmd->driver_unloading = cpu_to_le32(IAVF_AQ_DRIVER_UNLOADING);
status = iavf_asq_send_command(hw, &desc, NULL, 0, NULL);
return status;
}
/**
* iavf_aq_get_set_rss_lut
* @hw: pointer to the hardware structure
* @vsi_id: vsi fw index
* @pf_lut: for PF table set true, for VSI table set false
* @lut: pointer to the lut buffer provided by the caller
* @lut_size: size of the lut buffer
* @set: set true to set the table, false to get the table
*
* Internal function to get or set RSS look up table
**/
static enum iavf_status iavf_aq_get_set_rss_lut(struct iavf_hw *hw,
u16 vsi_id, bool pf_lut,
u8 *lut, u16 lut_size,
bool set)
{
struct iavf_aqc_get_set_rss_lut *cmd_resp;
struct libie_aq_desc desc;
enum iavf_status status;
u16 flags;
cmd_resp = libie_aq_raw(&desc);
if (set)
iavf_fill_default_direct_cmd_desc(&desc,
iavf_aqc_opc_set_rss_lut);
else
iavf_fill_default_direct_cmd_desc(&desc,
iavf_aqc_opc_get_rss_lut);
/* Indirect command */
desc.flags |= cpu_to_le16((u16)LIBIE_AQ_FLAG_BUF);
desc.flags |= cpu_to_le16((u16)LIBIE_AQ_FLAG_RD);
vsi_id = FIELD_PREP(IAVF_AQC_SET_RSS_LUT_VSI_ID_MASK, vsi_id) |
FIELD_PREP(IAVF_AQC_SET_RSS_LUT_VSI_VALID, 1);
cmd_resp->vsi_id = cpu_to_le16(vsi_id);
if (pf_lut)
flags = FIELD_PREP(IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_MASK,
IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_PF);
else
flags = FIELD_PREP(IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_MASK,
IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_VSI);
cmd_resp->flags = cpu_to_le16(flags);
status = iavf_asq_send_command(hw, &desc, lut, lut_size, NULL);
return status;
}
/**
* iavf_aq_set_rss_lut
* @hw: pointer to the hardware structure
* @vsi_id: vsi fw index
* @pf_lut: for PF table set true, for VSI table set false
* @lut: pointer to the lut buffer provided by the caller
* @lut_size: size of the lut buffer
*
* set the RSS lookup table, PF or VSI type
**/
enum iavf_status iavf_aq_set_rss_lut(struct iavf_hw *hw, u16 vsi_id,
bool pf_lut, u8 *lut, u16 lut_size)
{
return iavf_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, true);
}
/**
* iavf_aq_get_set_rss_key
* @hw: pointer to the hw struct
* @vsi_id: vsi fw index
* @key: pointer to key info struct
* @set: set true to set the key, false to get the key
*
* get the RSS key per VSI
**/
static enum
iavf_status iavf_aq_get_set_rss_key(struct iavf_hw *hw, u16 vsi_id,
struct iavf_aqc_get_set_rss_key_data *key,
bool set)
{
u16 key_size = sizeof(struct iavf_aqc_get_set_rss_key_data);
struct iavf_aqc_get_set_rss_key *cmd_resp;
struct libie_aq_desc desc;
enum iavf_status status;
cmd_resp = libie_aq_raw(&desc);
if (set)
iavf_fill_default_direct_cmd_desc(&desc,
iavf_aqc_opc_set_rss_key);
else
iavf_fill_default_direct_cmd_desc(&desc,
iavf_aqc_opc_get_rss_key);
/* Indirect command */
desc.flags |= cpu_to_le16((u16)LIBIE_AQ_FLAG_BUF);
desc.flags |= cpu_to_le16((u16)LIBIE_AQ_FLAG_RD);
vsi_id = FIELD_PREP(IAVF_AQC_SET_RSS_KEY_VSI_ID_MASK, vsi_id) |
FIELD_PREP(IAVF_AQC_SET_RSS_KEY_VSI_VALID, 1);
cmd_resp->vsi_id = cpu_to_le16(vsi_id);
status = iavf_asq_send_command(hw, &desc, key, key_size, NULL);
return status;
}
/**
* iavf_aq_set_rss_key
* @hw: pointer to the hw struct
* @vsi_id: vsi fw index
* @key: pointer to key info struct
*
* set the RSS key per VSI
**/
enum iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 vsi_id,
struct iavf_aqc_get_set_rss_key_data *key)
{
return iavf_aq_get_set_rss_key(hw, vsi_id, key, true);
}
/**
* iavf_aq_send_msg_to_pf
* @hw: pointer to the hardware structure
* @v_opcode: opcodes for VF-PF communication
* @v_retval: return error code
* @msg: pointer to the msg buffer
* @msglen: msg length
* @cmd_details: pointer to command details
*
* Send message to PF driver using admin queue. By default, this message
* is sent asynchronously, i.e. iavf_asq_send_command() does not wait for
* completion before returning.
**/
enum iavf_status iavf_aq_send_msg_to_pf(struct iavf_hw *hw,
enum virtchnl_ops v_opcode,
enum iavf_status v_retval,
u8 *msg, u16 msglen,
struct iavf_asq_cmd_details *cmd_details)
{
struct iavf_asq_cmd_details details;
struct libie_aq_desc desc;
enum iavf_status status;
iavf_fill_default_direct_cmd_desc(&desc, iavf_aqc_opc_send_msg_to_pf);
desc.flags |= cpu_to_le16((u16)LIBIE_AQ_FLAG_SI);
desc.cookie_high = cpu_to_le32(v_opcode);
desc.cookie_low = cpu_to_le32(v_retval);
if (msglen) {
desc.flags |= cpu_to_le16((u16)(LIBIE_AQ_FLAG_BUF
| LIBIE_AQ_FLAG_RD));
if (msglen > IAVF_AQ_LARGE_BUF)
desc.flags |= cpu_to_le16((u16)LIBIE_AQ_FLAG_LB);
desc.datalen = cpu_to_le16(msglen);
}
if (!cmd_details) {
memset(&details, 0, sizeof(details));
details.async = true;
cmd_details = &details;
}
status = iavf_asq_send_command(hw, &desc, msg, msglen, cmd_details);
return status;
}
/**
* iavf_vf_parse_hw_config
* @hw: pointer to the hardware structure
* @msg: pointer to the virtual channel VF resource structure
*
* Given a VF resource message from the PF, populate the hw struct
* with appropriate information.
**/
void iavf_vf_parse_hw_config(struct iavf_hw *hw,
struct virtchnl_vf_resource *msg)
{
struct virtchnl_vsi_resource *vsi_res;
int i;
vsi_res = &msg->vsi_res[0];
hw->dev_caps.num_vsis = msg->num_vsis;
hw->dev_caps.num_rx_qp = msg->num_queue_pairs;
hw->dev_caps.num_tx_qp = msg->num_queue_pairs;
hw->dev_caps.num_msix_vectors_vf = msg->max_vectors;
hw->dev_caps.dcb = msg->vf_cap_flags &
VIRTCHNL_VF_OFFLOAD_L2;
hw->dev_caps.fcoe = 0;
for (i = 0; i < msg->num_vsis; i++) {
if (vsi_res->vsi_type == VIRTCHNL_VSI_SRIOV) {
ether_addr_copy(hw->mac.perm_addr,
vsi_res->default_mac_addr);
ether_addr_copy(hw->mac.addr,
vsi_res->default_mac_addr);
}
vsi_res++;
}
}
@@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#ifndef _IAVF_DEVIDS_H_
#define _IAVF_DEVIDS_H_
/* Device IDs for the VF driver */
#define IAVF_DEV_ID_VF 0x154C
#define IAVF_DEV_ID_VF_HV 0x1571
#define IAVF_DEV_ID_ADAPTIVE_VF 0x1889
#define IAVF_DEV_ID_X722_VF 0x37CD
#endif /* _IAVF_DEVIDS_H_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,927 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2020, Intel Corporation. */
/* flow director ethtool support for iavf */
#include <linux/bitfield.h>
#include "iavf.h"
#define GTPU_PORT 2152
#define NAT_T_ESP_PORT 4500
#define PFCP_PORT 8805
static const struct in6_addr ipv6_addr_full_mask = {
.in6_u = {
.u6_addr8 = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
}
}
};
static const struct in6_addr ipv6_addr_zero_mask = {
.in6_u = {
.u6_addr8 = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
}
}
};
/**
* iavf_validate_fdir_fltr_masks - validate Flow Director filter fields masks
* @adapter: pointer to the VF adapter structure
* @fltr: Flow Director filter data structure
*
* Returns 0 if all masks of packet fields are either full or empty. Returns
* error on at least one partial mask.
*/
int iavf_validate_fdir_fltr_masks(struct iavf_adapter *adapter,
struct iavf_fdir_fltr *fltr)
{
if (fltr->eth_mask.etype && fltr->eth_mask.etype != htons(U16_MAX))
goto partial_mask;
if (fltr->ip_ver == 4) {
if (fltr->ip_mask.v4_addrs.src_ip &&
fltr->ip_mask.v4_addrs.src_ip != htonl(U32_MAX))
goto partial_mask;
if (fltr->ip_mask.v4_addrs.dst_ip &&
fltr->ip_mask.v4_addrs.dst_ip != htonl(U32_MAX))
goto partial_mask;
if (fltr->ip_mask.tos && fltr->ip_mask.tos != U8_MAX)
goto partial_mask;
} else if (fltr->ip_ver == 6) {
if (memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_zero_mask,
sizeof(struct in6_addr)) &&
memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_full_mask,
sizeof(struct in6_addr)))
goto partial_mask;
if (memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_zero_mask,
sizeof(struct in6_addr)) &&
memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_full_mask,
sizeof(struct in6_addr)))
goto partial_mask;
if (fltr->ip_mask.tclass && fltr->ip_mask.tclass != U8_MAX)
goto partial_mask;
}
if (fltr->ip_mask.proto && fltr->ip_mask.proto != U8_MAX)
goto partial_mask;
if (fltr->ip_mask.src_port && fltr->ip_mask.src_port != htons(U16_MAX))
goto partial_mask;
if (fltr->ip_mask.dst_port && fltr->ip_mask.dst_port != htons(U16_MAX))
goto partial_mask;
if (fltr->ip_mask.spi && fltr->ip_mask.spi != htonl(U32_MAX))
goto partial_mask;
if (fltr->ip_mask.l4_header &&
fltr->ip_mask.l4_header != htonl(U32_MAX))
goto partial_mask;
return 0;
partial_mask:
dev_err(&adapter->pdev->dev, "Failed to add Flow Director filter, partial masks are not supported\n");
return -EOPNOTSUPP;
}
/**
* iavf_pkt_udp_no_pay_len - the length of UDP packet without payload
* @fltr: Flow Director filter data structure
*/
static u16 iavf_pkt_udp_no_pay_len(struct iavf_fdir_fltr *fltr)
{
return sizeof(struct ethhdr) +
(fltr->ip_ver == 4 ? sizeof(struct iphdr) : sizeof(struct ipv6hdr)) +
sizeof(struct udphdr);
}
/**
* iavf_fill_fdir_gtpu_hdr - fill the GTP-U protocol header
* @fltr: Flow Director filter data structure
* @proto_hdrs: Flow Director protocol headers data structure
*
* Returns 0 if the GTP-U protocol header is set successfully
*/
static int
iavf_fill_fdir_gtpu_hdr(struct iavf_fdir_fltr *fltr,
struct virtchnl_proto_hdrs *proto_hdrs)
{
struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];
struct virtchnl_proto_hdr *ghdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
struct virtchnl_proto_hdr *ehdr = NULL; /* Extension Header if it exists */
u16 adj_offs, hdr_offs;
int i;
VIRTCHNL_SET_PROTO_HDR_TYPE(ghdr, GTPU_IP);
adj_offs = iavf_pkt_udp_no_pay_len(fltr);
for (i = 0; i < fltr->flex_cnt; i++) {
#define IAVF_GTPU_HDR_TEID_OFFS0 4
#define IAVF_GTPU_HDR_TEID_OFFS1 6
#define IAVF_GTPU_HDR_N_PDU_AND_NEXT_EXTHDR_OFFS 10
#define IAVF_GTPU_HDR_NEXT_EXTHDR_TYPE_MASK 0x00FF /* skip N_PDU */
/* PDU Session Container Extension Header (PSC) */
#define IAVF_GTPU_PSC_EXTHDR_TYPE 0x85
#define IAVF_GTPU_HDR_PSC_PDU_TYPE_AND_QFI_OFFS 13
#define IAVF_GTPU_HDR_PSC_PDU_QFI_MASK 0x3F /* skip Type */
#define IAVF_GTPU_EH_QFI_IDX 1
if (fltr->flex_words[i].offset < adj_offs)
return -EINVAL;
hdr_offs = fltr->flex_words[i].offset - adj_offs;
switch (hdr_offs) {
case IAVF_GTPU_HDR_TEID_OFFS0:
case IAVF_GTPU_HDR_TEID_OFFS1: {
__be16 *pay_word = (__be16 *)ghdr->buffer;
pay_word[hdr_offs >> 1] = htons(fltr->flex_words[i].word);
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(ghdr, GTPU_IP, TEID);
}
break;
case IAVF_GTPU_HDR_N_PDU_AND_NEXT_EXTHDR_OFFS:
if ((fltr->flex_words[i].word &
IAVF_GTPU_HDR_NEXT_EXTHDR_TYPE_MASK) !=
IAVF_GTPU_PSC_EXTHDR_TYPE)
return -EOPNOTSUPP;
if (!ehdr)
ehdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
VIRTCHNL_SET_PROTO_HDR_TYPE(ehdr, GTPU_EH);
break;
case IAVF_GTPU_HDR_PSC_PDU_TYPE_AND_QFI_OFFS:
if (!ehdr)
return -EINVAL;
ehdr->buffer[IAVF_GTPU_EH_QFI_IDX] =
fltr->flex_words[i].word &
IAVF_GTPU_HDR_PSC_PDU_QFI_MASK;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(ehdr, GTPU_EH, QFI);
break;
default:
return -EINVAL;
}
}
uhdr->field_selector = 0; /* The PF ignores the UDP header fields */
return 0;
}
/**
* iavf_fill_fdir_pfcp_hdr - fill the PFCP protocol header
* @fltr: Flow Director filter data structure
* @proto_hdrs: Flow Director protocol headers data structure
*
* Returns 0 if the PFCP protocol header is set successfully
*/
static int
iavf_fill_fdir_pfcp_hdr(struct iavf_fdir_fltr *fltr,
struct virtchnl_proto_hdrs *proto_hdrs)
{
struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];
struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
u16 adj_offs, hdr_offs;
int i;
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, PFCP);
adj_offs = iavf_pkt_udp_no_pay_len(fltr);
for (i = 0; i < fltr->flex_cnt; i++) {
#define IAVF_PFCP_HDR_SFIELD_AND_MSG_TYPE_OFFS 0
if (fltr->flex_words[i].offset < adj_offs)
return -EINVAL;
hdr_offs = fltr->flex_words[i].offset - adj_offs;
switch (hdr_offs) {
case IAVF_PFCP_HDR_SFIELD_AND_MSG_TYPE_OFFS:
hdr->buffer[0] = (fltr->flex_words[i].word >> 8) & 0xff;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, PFCP, S_FIELD);
break;
default:
return -EINVAL;
}
}
uhdr->field_selector = 0; /* The PF ignores the UDP header fields */
return 0;
}
/**
* iavf_fill_fdir_nat_t_esp_hdr - fill the NAT-T-ESP protocol header
* @fltr: Flow Director filter data structure
* @proto_hdrs: Flow Director protocol headers data structure
*
* Returns 0 if the NAT-T-ESP protocol header is set successfully
*/
static int
iavf_fill_fdir_nat_t_esp_hdr(struct iavf_fdir_fltr *fltr,
struct virtchnl_proto_hdrs *proto_hdrs)
{
struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];
struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
u16 adj_offs, hdr_offs;
u32 spi = 0;
int i;
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ESP);
adj_offs = iavf_pkt_udp_no_pay_len(fltr);
for (i = 0; i < fltr->flex_cnt; i++) {
#define IAVF_NAT_T_ESP_SPI_OFFS0 0
#define IAVF_NAT_T_ESP_SPI_OFFS1 2
if (fltr->flex_words[i].offset < adj_offs)
return -EINVAL;
hdr_offs = fltr->flex_words[i].offset - adj_offs;
switch (hdr_offs) {
case IAVF_NAT_T_ESP_SPI_OFFS0:
spi |= fltr->flex_words[i].word << 16;
break;
case IAVF_NAT_T_ESP_SPI_OFFS1:
spi |= fltr->flex_words[i].word;
break;
default:
return -EINVAL;
}
}
if (!spi)
return -EOPNOTSUPP; /* Not support IKE Header Format with SPI 0 */
*(__be32 *)hdr->buffer = htonl(spi);
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ESP, SPI);
uhdr->field_selector = 0; /* The PF ignores the UDP header fields */
return 0;
}
/**
* iavf_fill_fdir_udp_flex_pay_hdr - fill the UDP payload header
* @fltr: Flow Director filter data structure
* @proto_hdrs: Flow Director protocol headers data structure
*
* Returns 0 if the UDP payload defined protocol header is set successfully
*/
static int
iavf_fill_fdir_udp_flex_pay_hdr(struct iavf_fdir_fltr *fltr,
struct virtchnl_proto_hdrs *proto_hdrs)
{
int err;
switch (ntohs(fltr->ip_data.dst_port)) {
case GTPU_PORT:
err = iavf_fill_fdir_gtpu_hdr(fltr, proto_hdrs);
break;
case NAT_T_ESP_PORT:
err = iavf_fill_fdir_nat_t_esp_hdr(fltr, proto_hdrs);
break;
case PFCP_PORT:
err = iavf_fill_fdir_pfcp_hdr(fltr, proto_hdrs);
break;
default:
err = -EOPNOTSUPP;
break;
}
return err;
}
/**
* iavf_fill_fdir_ip4_hdr - fill the IPv4 protocol header
* @fltr: Flow Director filter data structure
* @proto_hdrs: Flow Director protocol headers data structure
*
* Returns 0 if the IPv4 protocol header is set successfully
*/
static int
iavf_fill_fdir_ip4_hdr(struct iavf_fdir_fltr *fltr,
struct virtchnl_proto_hdrs *proto_hdrs)
{
struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
struct iphdr *iph = (struct iphdr *)hdr->buffer;
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV4);
if (fltr->ip_mask.tos == U8_MAX) {
iph->tos = fltr->ip_data.tos;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DSCP);
}
if (fltr->ip_mask.proto == U8_MAX) {
iph->protocol = fltr->ip_data.proto;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, PROT);
}
if (fltr->ip_mask.v4_addrs.src_ip == htonl(U32_MAX)) {
iph->saddr = fltr->ip_data.v4_addrs.src_ip;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, SRC);
}
if (fltr->ip_mask.v4_addrs.dst_ip == htonl(U32_MAX)) {
iph->daddr = fltr->ip_data.v4_addrs.dst_ip;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DST);
}
return 0;
}
/**
* iavf_fill_fdir_ip6_hdr - fill the IPv6 protocol header
* @fltr: Flow Director filter data structure
* @proto_hdrs: Flow Director protocol headers data structure
*
* Returns 0 if the IPv6 protocol header is set successfully
*/
static int
iavf_fill_fdir_ip6_hdr(struct iavf_fdir_fltr *fltr,
struct virtchnl_proto_hdrs *proto_hdrs)
{
struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
struct ipv6hdr *iph = (struct ipv6hdr *)hdr->buffer;
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV6);
if (fltr->ip_mask.tclass == U8_MAX) {
iph->priority = (fltr->ip_data.tclass >> 4) & 0xF;
iph->flow_lbl[0] = FIELD_PREP(0xF0, fltr->ip_data.tclass);
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, TC);
}
if (fltr->ip_mask.proto == U8_MAX) {
iph->nexthdr = fltr->ip_data.proto;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, PROT);
}
if (!memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_full_mask,
sizeof(struct in6_addr))) {
memcpy(&iph->saddr, &fltr->ip_data.v6_addrs.src_ip,
sizeof(struct in6_addr));
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, SRC);
}
if (!memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_full_mask,
sizeof(struct in6_addr))) {
memcpy(&iph->daddr, &fltr->ip_data.v6_addrs.dst_ip,
sizeof(struct in6_addr));
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, DST);
}
return 0;
}
/**
* iavf_fill_fdir_tcp_hdr - fill the TCP protocol header
* @fltr: Flow Director filter data structure
* @proto_hdrs: Flow Director protocol headers data structure
*
* Returns 0 if the TCP protocol header is set successfully
*/
static int
iavf_fill_fdir_tcp_hdr(struct iavf_fdir_fltr *fltr,
struct virtchnl_proto_hdrs *proto_hdrs)
{
struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
struct tcphdr *tcph = (struct tcphdr *)hdr->buffer;
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, TCP);
if (fltr->ip_mask.src_port == htons(U16_MAX)) {
tcph->source = fltr->ip_data.src_port;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, SRC_PORT);
}
if (fltr->ip_mask.dst_port == htons(U16_MAX)) {
tcph->dest = fltr->ip_data.dst_port;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, DST_PORT);
}
return 0;
}
/**
* iavf_fill_fdir_udp_hdr - fill the UDP protocol header
* @fltr: Flow Director filter data structure
* @proto_hdrs: Flow Director protocol headers data structure
*
* Returns 0 if the UDP protocol header is set successfully
*/
static int
iavf_fill_fdir_udp_hdr(struct iavf_fdir_fltr *fltr,
struct virtchnl_proto_hdrs *proto_hdrs)
{
struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
struct udphdr *udph = (struct udphdr *)hdr->buffer;
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, UDP);
if (fltr->ip_mask.src_port == htons(U16_MAX)) {
udph->source = fltr->ip_data.src_port;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, SRC_PORT);
}
if (fltr->ip_mask.dst_port == htons(U16_MAX)) {
udph->dest = fltr->ip_data.dst_port;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, DST_PORT);
}
if (!fltr->flex_cnt)
return 0;
return iavf_fill_fdir_udp_flex_pay_hdr(fltr, proto_hdrs);
}
/**
* iavf_fill_fdir_sctp_hdr - fill the SCTP protocol header
* @fltr: Flow Director filter data structure
* @proto_hdrs: Flow Director protocol headers data structure
*
* Returns 0 if the SCTP protocol header is set successfully
*/
static int
iavf_fill_fdir_sctp_hdr(struct iavf_fdir_fltr *fltr,
struct virtchnl_proto_hdrs *proto_hdrs)
{
struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
struct sctphdr *sctph = (struct sctphdr *)hdr->buffer;
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, SCTP);
if (fltr->ip_mask.src_port == htons(U16_MAX)) {
sctph->source = fltr->ip_data.src_port;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, SRC_PORT);
}
if (fltr->ip_mask.dst_port == htons(U16_MAX)) {
sctph->dest = fltr->ip_data.dst_port;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, DST_PORT);
}
return 0;
}
/**
* iavf_fill_fdir_ah_hdr - fill the AH protocol header
* @fltr: Flow Director filter data structure
* @proto_hdrs: Flow Director protocol headers data structure
*
* Returns 0 if the AH protocol header is set successfully
*/
static int
iavf_fill_fdir_ah_hdr(struct iavf_fdir_fltr *fltr,
struct virtchnl_proto_hdrs *proto_hdrs)
{
struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
struct ip_auth_hdr *ah = (struct ip_auth_hdr *)hdr->buffer;
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, AH);
if (fltr->ip_mask.spi == htonl(U32_MAX)) {
ah->spi = fltr->ip_data.spi;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, AH, SPI);
}
return 0;
}
/**
* iavf_fill_fdir_esp_hdr - fill the ESP protocol header
* @fltr: Flow Director filter data structure
* @proto_hdrs: Flow Director protocol headers data structure
*
* Returns 0 if the ESP protocol header is set successfully
*/
static int
iavf_fill_fdir_esp_hdr(struct iavf_fdir_fltr *fltr,
struct virtchnl_proto_hdrs *proto_hdrs)
{
struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
struct ip_esp_hdr *esph = (struct ip_esp_hdr *)hdr->buffer;
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ESP);
if (fltr->ip_mask.spi == htonl(U32_MAX)) {
esph->spi = fltr->ip_data.spi;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ESP, SPI);
}
return 0;
}
/**
* iavf_fill_fdir_l4_hdr - fill the L4 protocol header
* @fltr: Flow Director filter data structure
* @proto_hdrs: Flow Director protocol headers data structure
*
* Returns 0 if the L4 protocol header is set successfully
*/
static int
iavf_fill_fdir_l4_hdr(struct iavf_fdir_fltr *fltr,
struct virtchnl_proto_hdrs *proto_hdrs)
{
struct virtchnl_proto_hdr *hdr;
__be32 *l4_4_data;
if (!fltr->ip_mask.proto) /* IPv4/IPv6 header only */
return 0;
hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
l4_4_data = (__be32 *)hdr->buffer;
/* L2TPv3 over IP with 'Session ID' */
if (fltr->ip_data.proto == 115 && fltr->ip_mask.l4_header == htonl(U32_MAX)) {
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, L2TPV3);
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, L2TPV3, SESS_ID);
*l4_4_data = fltr->ip_data.l4_header;
} else {
return -EOPNOTSUPP;
}
return 0;
}
/**
* iavf_fill_fdir_eth_hdr - fill the Ethernet protocol header
* @fltr: Flow Director filter data structure
* @proto_hdrs: Flow Director protocol headers data structure
*
* Returns 0 if the Ethernet protocol header is set successfully
*/
static int
iavf_fill_fdir_eth_hdr(struct iavf_fdir_fltr *fltr,
struct virtchnl_proto_hdrs *proto_hdrs)
{
struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
struct ethhdr *ehdr = (struct ethhdr *)hdr->buffer;
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ETH);
if (fltr->eth_mask.etype == htons(U16_MAX)) {
if (fltr->eth_data.etype == htons(ETH_P_IP) ||
fltr->eth_data.etype == htons(ETH_P_IPV6))
return -EOPNOTSUPP;
ehdr->h_proto = fltr->eth_data.etype;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ETH, ETHERTYPE);
}
return 0;
}
/**
* iavf_fill_fdir_add_msg - fill the Flow Director filter into virtchnl message
* @adapter: pointer to the VF adapter structure
* @fltr: Flow Director filter data structure
*
* Returns 0 if the add Flow Director virtchnl message is filled successfully
*/
int iavf_fill_fdir_add_msg(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
{
struct virtchnl_fdir_add *vc_msg = &fltr->vc_add_msg;
struct virtchnl_proto_hdrs *proto_hdrs;
int err;
proto_hdrs = &vc_msg->rule_cfg.proto_hdrs;
err = iavf_fill_fdir_eth_hdr(fltr, proto_hdrs); /* L2 always exists */
if (err)
return err;
switch (fltr->flow_type) {
case IAVF_FDIR_FLOW_IPV4_TCP:
err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_tcp_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_IPV4_UDP:
err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_udp_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_IPV4_SCTP:
err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_sctp_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_IPV4_AH:
err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_ah_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_IPV4_ESP:
err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_esp_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_IPV4_OTHER:
err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_l4_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_IPV6_TCP:
err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_tcp_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_IPV6_UDP:
err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_udp_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_IPV6_SCTP:
err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_sctp_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_IPV6_AH:
err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_ah_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_IPV6_ESP:
err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_esp_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_IPV6_OTHER:
err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_l4_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_NON_IP_L2:
break;
default:
err = -EINVAL;
break;
}
if (err)
return err;
vc_msg->vsi_id = adapter->vsi.id;
vc_msg->rule_cfg.action_set.count = 1;
vc_msg->rule_cfg.action_set.actions[0].type = fltr->action;
vc_msg->rule_cfg.action_set.actions[0].act_conf.queue.index = fltr->q_index;
return 0;
}
/**
* iavf_fdir_flow_proto_name - get the flow protocol name
* @flow_type: Flow Director filter flow type
**/
static const char *iavf_fdir_flow_proto_name(enum iavf_fdir_flow_type flow_type)
{
switch (flow_type) {
case IAVF_FDIR_FLOW_IPV4_TCP:
case IAVF_FDIR_FLOW_IPV6_TCP:
return "TCP";
case IAVF_FDIR_FLOW_IPV4_UDP:
case IAVF_FDIR_FLOW_IPV6_UDP:
return "UDP";
case IAVF_FDIR_FLOW_IPV4_SCTP:
case IAVF_FDIR_FLOW_IPV6_SCTP:
return "SCTP";
case IAVF_FDIR_FLOW_IPV4_AH:
case IAVF_FDIR_FLOW_IPV6_AH:
return "AH";
case IAVF_FDIR_FLOW_IPV4_ESP:
case IAVF_FDIR_FLOW_IPV6_ESP:
return "ESP";
case IAVF_FDIR_FLOW_IPV4_OTHER:
case IAVF_FDIR_FLOW_IPV6_OTHER:
return "Other";
case IAVF_FDIR_FLOW_NON_IP_L2:
return "Ethernet";
default:
return NULL;
}
}
/**
* iavf_print_fdir_fltr
* @adapter: adapter structure
* @fltr: Flow Director filter to print
*
* Print the Flow Director filter
**/
void iavf_print_fdir_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
{
const char *proto = iavf_fdir_flow_proto_name(fltr->flow_type);
if (!proto)
return;
switch (fltr->flow_type) {
case IAVF_FDIR_FLOW_IPV4_TCP:
case IAVF_FDIR_FLOW_IPV4_UDP:
case IAVF_FDIR_FLOW_IPV4_SCTP:
dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 %s: dst_port %hu src_port %hu\n",
fltr->loc,
&fltr->ip_data.v4_addrs.dst_ip,
&fltr->ip_data.v4_addrs.src_ip,
proto,
ntohs(fltr->ip_data.dst_port),
ntohs(fltr->ip_data.src_port));
break;
case IAVF_FDIR_FLOW_IPV4_AH:
case IAVF_FDIR_FLOW_IPV4_ESP:
dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 %s: SPI %u\n",
fltr->loc,
&fltr->ip_data.v4_addrs.dst_ip,
&fltr->ip_data.v4_addrs.src_ip,
proto,
ntohl(fltr->ip_data.spi));
break;
case IAVF_FDIR_FLOW_IPV4_OTHER:
dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 proto: %u L4_bytes: 0x%x\n",
fltr->loc,
&fltr->ip_data.v4_addrs.dst_ip,
&fltr->ip_data.v4_addrs.src_ip,
fltr->ip_data.proto,
ntohl(fltr->ip_data.l4_header));
break;
case IAVF_FDIR_FLOW_IPV6_TCP:
case IAVF_FDIR_FLOW_IPV6_UDP:
case IAVF_FDIR_FLOW_IPV6_SCTP:
dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 %s: dst_port %hu src_port %hu\n",
fltr->loc,
&fltr->ip_data.v6_addrs.dst_ip,
&fltr->ip_data.v6_addrs.src_ip,
proto,
ntohs(fltr->ip_data.dst_port),
ntohs(fltr->ip_data.src_port));
break;
case IAVF_FDIR_FLOW_IPV6_AH:
case IAVF_FDIR_FLOW_IPV6_ESP:
dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 %s: SPI %u\n",
fltr->loc,
&fltr->ip_data.v6_addrs.dst_ip,
&fltr->ip_data.v6_addrs.src_ip,
proto,
ntohl(fltr->ip_data.spi));
break;
case IAVF_FDIR_FLOW_IPV6_OTHER:
dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 proto: %u L4_bytes: 0x%x\n",
fltr->loc,
&fltr->ip_data.v6_addrs.dst_ip,
&fltr->ip_data.v6_addrs.src_ip,
fltr->ip_data.proto,
ntohl(fltr->ip_data.l4_header));
break;
case IAVF_FDIR_FLOW_NON_IP_L2:
dev_info(&adapter->pdev->dev, "Rule ID: %u eth_type: 0x%x\n",
fltr->loc,
ntohs(fltr->eth_data.etype));
break;
default:
break;
}
}
/**
* iavf_fdir_is_dup_fltr - test if filter is already in list
* @adapter: pointer to the VF adapter structure
* @fltr: Flow Director filter data structure
*
* Returns true if the filter is found in the list
*/
bool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
{
struct iavf_fdir_fltr *tmp;
bool ret = false;
spin_lock_bh(&adapter->fdir_fltr_lock);
list_for_each_entry(tmp, &adapter->fdir_list_head, list) {
if (iavf_is_raw_fdir(fltr))
continue;
if (tmp->flow_type != fltr->flow_type)
continue;
if (!memcmp(&tmp->eth_data, &fltr->eth_data,
sizeof(fltr->eth_data)) &&
!memcmp(&tmp->ip_data, &fltr->ip_data,
sizeof(fltr->ip_data)) &&
!memcmp(&tmp->ext_data, &fltr->ext_data,
sizeof(fltr->ext_data))) {
ret = true;
break;
}
}
spin_unlock_bh(&adapter->fdir_fltr_lock);
return ret;
}
/**
* iavf_find_fdir_fltr - find FDIR filter
* @adapter: pointer to the VF adapter structure
* @is_raw: filter type, is raw (tc u32) or not (ethtool)
* @data: data to ID the filter, type dependent
*
* Returns: pointer to Flow Director filter if found or NULL. Lock must be held.
*/
struct iavf_fdir_fltr *iavf_find_fdir_fltr(struct iavf_adapter *adapter,
bool is_raw, u32 data)
{
struct iavf_fdir_fltr *rule;
list_for_each_entry(rule, &adapter->fdir_list_head, list) {
if ((is_raw && rule->cls_u32_handle == data) ||
(!is_raw && rule->loc == data))
return rule;
}
return NULL;
}
/**
* iavf_fdir_add_fltr - add a new node to the flow director filter list
* @adapter: pointer to the VF adapter structure
* @fltr: filter node to add to structure
*
* Return: 0 on success or negative errno on failure.
*/
int iavf_fdir_add_fltr(struct iavf_adapter *adapter,
struct iavf_fdir_fltr *fltr)
{
struct iavf_fdir_fltr *rule, *parent = NULL;
spin_lock_bh(&adapter->fdir_fltr_lock);
if (iavf_fdir_max_reached(adapter)) {
spin_unlock_bh(&adapter->fdir_fltr_lock);
dev_err(&adapter->pdev->dev,
"Unable to add Flow Director filter (limit (%u) reached)\n",
IAVF_MAX_FDIR_FILTERS);
return -ENOSPC;
}
list_for_each_entry(rule, &adapter->fdir_list_head, list) {
if (iavf_is_raw_fdir(fltr))
break;
if (rule->loc >= fltr->loc)
break;
parent = rule;
}
if (parent)
list_add(&fltr->list, &parent->list);
else
list_add(&fltr->list, &adapter->fdir_list_head);
iavf_inc_fdir_active_fltr(adapter, fltr);
if (adapter->link_up)
fltr->state = IAVF_FDIR_FLTR_ADD_REQUEST;
else
fltr->state = IAVF_FDIR_FLTR_INACTIVE;
spin_unlock_bh(&adapter->fdir_fltr_lock);
if (adapter->link_up)
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_FDIR_FILTER);
return 0;
}
/**
* iavf_fdir_del_fltr - delete a flow director filter from the list
* @adapter: pointer to the VF adapter structure
* @is_raw: filter type, is raw (tc u32) or not (ethtool)
* @data: data to ID the filter, type dependent
*
* Return: 0 on success or negative errno on failure.
*/
int iavf_fdir_del_fltr(struct iavf_adapter *adapter, bool is_raw, u32 data)
{
struct iavf_fdir_fltr *fltr = NULL;
int err = 0;
spin_lock_bh(&adapter->fdir_fltr_lock);
fltr = iavf_find_fdir_fltr(adapter, is_raw, data);
if (fltr) {
if (fltr->state == IAVF_FDIR_FLTR_ACTIVE) {
fltr->state = IAVF_FDIR_FLTR_DEL_REQUEST;
} else if (fltr->state == IAVF_FDIR_FLTR_INACTIVE) {
list_del(&fltr->list);
iavf_dec_fdir_active_fltr(adapter, fltr);
kfree(fltr);
fltr = NULL;
} else {
err = -EBUSY;
}
} else if (adapter->fdir_active_fltr) {
err = -EINVAL;
}
if (fltr && fltr->state == IAVF_FDIR_FLTR_DEL_REQUEST)
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_DEL_FDIR_FILTER);
spin_unlock_bh(&adapter->fdir_fltr_lock);
return err;
}
@@ -0,0 +1,142 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2021, Intel Corporation. */
#ifndef _IAVF_FDIR_H_
#define _IAVF_FDIR_H_
struct iavf_adapter;
/* State of Flow Director filter
*
* *_REQUEST states are used to mark filter to be sent to PF driver to perform
* an action (either add or delete filter). *_PENDING states are an indication
* that request was sent to PF and the driver is waiting for response.
*
* Both DELETE and DISABLE states are being used to delete a filter in PF.
* The difference is that after a successful response filter in DEL_PENDING
* state is being deleted from VF driver as well and filter in DIS_PENDING state
* is being changed to INACTIVE state.
*/
enum iavf_fdir_fltr_state_t {
IAVF_FDIR_FLTR_ADD_REQUEST, /* User requests to add filter */
IAVF_FDIR_FLTR_ADD_PENDING, /* Filter pending add by the PF */
IAVF_FDIR_FLTR_DEL_REQUEST, /* User requests to delete filter */
IAVF_FDIR_FLTR_DEL_PENDING, /* Filter pending delete by the PF */
IAVF_FDIR_FLTR_DIS_REQUEST, /* Filter scheduled to be disabled */
IAVF_FDIR_FLTR_DIS_PENDING, /* Filter pending disable by the PF */
IAVF_FDIR_FLTR_INACTIVE, /* Filter inactive on link down */
IAVF_FDIR_FLTR_ACTIVE, /* Filter is active */
};
enum iavf_fdir_flow_type {
/* NONE - used for undef/error */
IAVF_FDIR_FLOW_NONE = 0,
IAVF_FDIR_FLOW_IPV4_TCP,
IAVF_FDIR_FLOW_IPV4_UDP,
IAVF_FDIR_FLOW_IPV4_SCTP,
IAVF_FDIR_FLOW_IPV4_AH,
IAVF_FDIR_FLOW_IPV4_ESP,
IAVF_FDIR_FLOW_IPV4_OTHER,
IAVF_FDIR_FLOW_IPV6_TCP,
IAVF_FDIR_FLOW_IPV6_UDP,
IAVF_FDIR_FLOW_IPV6_SCTP,
IAVF_FDIR_FLOW_IPV6_AH,
IAVF_FDIR_FLOW_IPV6_ESP,
IAVF_FDIR_FLOW_IPV6_OTHER,
IAVF_FDIR_FLOW_NON_IP_L2,
/* MAX - this must be last and add anything new just above it */
IAVF_FDIR_FLOW_PTYPE_MAX,
};
/* Must not exceed the array element number of '__be32 data[2]' in the ethtool
* 'struct ethtool_rx_flow_spec.m_ext.data[2]' to express the flex-byte (word).
*/
#define IAVF_FLEX_WORD_NUM 2
struct iavf_flex_word {
u16 offset;
u16 word;
};
struct iavf_ipv4_addrs {
__be32 src_ip;
__be32 dst_ip;
};
struct iavf_ipv6_addrs {
struct in6_addr src_ip;
struct in6_addr dst_ip;
};
struct iavf_fdir_eth {
__be16 etype;
};
struct iavf_fdir_ip {
union {
struct iavf_ipv4_addrs v4_addrs;
struct iavf_ipv6_addrs v6_addrs;
};
__be16 src_port;
__be16 dst_port;
__be32 l4_header; /* first 4 bytes of the layer 4 header */
__be32 spi; /* security parameter index for AH/ESP */
union {
u8 tos;
u8 tclass;
};
u8 proto;
};
struct iavf_fdir_extra {
u32 usr_def[IAVF_FLEX_WORD_NUM];
};
/* bookkeeping of Flow Director filters */
struct iavf_fdir_fltr {
enum iavf_fdir_fltr_state_t state;
struct list_head list;
enum iavf_fdir_flow_type flow_type;
struct iavf_fdir_eth eth_data;
struct iavf_fdir_eth eth_mask;
struct iavf_fdir_ip ip_data;
struct iavf_fdir_ip ip_mask;
struct iavf_fdir_extra ext_data;
struct iavf_fdir_extra ext_mask;
enum virtchnl_action action;
/* flex byte filter data */
u8 ip_ver; /* used to adjust the flex offset, 4 : IPv4, 6 : IPv6 */
u8 flex_cnt;
struct iavf_flex_word flex_words[IAVF_FLEX_WORD_NUM];
u32 flow_id;
u32 cls_u32_handle; /* for FDIR added via tc u32 */
u32 loc; /* Rule location inside the flow table */
u32 q_index;
struct virtchnl_fdir_add vc_add_msg;
};
static inline bool iavf_is_raw_fdir(struct iavf_fdir_fltr *fltr)
{
return !fltr->vc_add_msg.rule_cfg.proto_hdrs.count;
}
int iavf_validate_fdir_fltr_masks(struct iavf_adapter *adapter,
struct iavf_fdir_fltr *fltr);
int iavf_fill_fdir_add_msg(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr);
void iavf_print_fdir_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr);
bool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr);
int iavf_fdir_add_fltr(struct iavf_adapter *adapter,
struct iavf_fdir_fltr *fltr);
int iavf_fdir_del_fltr(struct iavf_adapter *adapter, bool is_raw, u32 data);
struct iavf_fdir_fltr *iavf_find_fdir_fltr(struct iavf_adapter *adapter,
bool is_raw, u32 data);
#endif /* _IAVF_FDIR_H_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,46 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#ifndef _IAVF_OSDEP_H_
#define _IAVF_OSDEP_H_
#include <linux/types.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/tcp.h>
#include <linux/pci.h>
/* get readq/writeq support for 32 bit kernels, use the low-first version */
#include <linux/io-64-nonatomic-lo-hi.h>
#define wr32(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
#define rd32(a, reg) readl((a)->hw_addr + (reg))
#define wr64(a, reg, value) writeq((value), ((a)->hw_addr + (reg)))
#define rd64(a, reg) readq((a)->hw_addr + (reg))
#define iavf_flush(a) readl((a)->hw_addr + IAVF_VFGEN_RSTAT)
/* memory allocation tracking */
struct iavf_dma_mem {
void *va;
dma_addr_t pa;
u32 size;
};
#define iavf_allocate_dma_mem(h, m, unused, s, a) \
iavf_allocate_dma_mem_d(h, m, s, a)
struct iavf_virt_mem {
void *va;
u32 size;
};
#define iavf_debug(h, m, s, ...) \
do { \
if (((m) & (h)->debug_mask)) \
pr_info("iavf %02x:%02x.%x " s, \
(h)->bus.bus_id, (h)->bus.device, \
(h)->bus.func, ##__VA_ARGS__); \
} while (0)
#endif /* _IAVF_OSDEP_H_ */
@@ -0,0 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#ifndef _IAVF_PROTOTYPE_H_
#define _IAVF_PROTOTYPE_H_
#include "iavf_type.h"
#include "iavf_alloc.h"
#include <linux/avf/virtchnl.h>
/* Prototypes for shared code functions that are not in
* the standard function pointer structures. These are
* mostly because they are needed even before the init
* has happened and will assist in the early SW and FW
* setup.
*/
/* adminq functions */
enum iavf_status iavf_init_adminq(struct iavf_hw *hw);
enum iavf_status iavf_shutdown_adminq(struct iavf_hw *hw);
enum iavf_status iavf_clean_arq_element(struct iavf_hw *hw,
struct iavf_arq_event_info *e,
u16 *events_pending);
enum iavf_status iavf_asq_send_command(struct iavf_hw *hw,
struct libie_aq_desc *desc,
void *buff, /* can be NULL */
u16 buff_size,
struct iavf_asq_cmd_details *cmd_details);
bool iavf_asq_done(struct iavf_hw *hw);
/* debug function for adminq */
void iavf_debug_aq(struct iavf_hw *hw, enum iavf_debug_mask mask,
void *desc, void *buffer, u16 buf_len);
bool iavf_check_asq_alive(struct iavf_hw *hw);
enum iavf_status iavf_aq_queue_shutdown(struct iavf_hw *hw, bool unloading);
const char *iavf_stat_str(struct iavf_hw *hw, enum iavf_status stat_err);
enum iavf_status iavf_aq_set_rss_lut(struct iavf_hw *hw, u16 seid,
bool pf_lut, u8 *lut, u16 lut_size);
enum iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 seid,
struct iavf_aqc_get_set_rss_key_data *key);
void iavf_vf_parse_hw_config(struct iavf_hw *hw,
struct virtchnl_vf_resource *msg);
enum iavf_status iavf_aq_send_msg_to_pf(struct iavf_hw *hw,
enum virtchnl_ops v_opcode,
enum iavf_status v_retval,
u8 *msg, u16 msglen,
struct iavf_asq_cmd_details *cmd_details);
#endif /* _IAVF_PROTOTYPE_H_ */
@@ -0,0 +1,492 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2024 Intel Corporation. */
#include "iavf.h"
#include "iavf_ptp.h"
#define iavf_clock_to_adapter(info) \
container_of_const(info, struct iavf_adapter, ptp.info)
/**
* iavf_ptp_disable_rx_tstamp - Disable timestamping in Rx rings
* @adapter: private adapter structure
*
* Disable timestamp reporting for all Rx rings.
*/
static void iavf_ptp_disable_rx_tstamp(struct iavf_adapter *adapter)
{
for (u32 i = 0; i < adapter->num_active_queues; i++)
adapter->rx_rings[i].flags &= ~IAVF_TXRX_FLAGS_HW_TSTAMP;
}
/**
* iavf_ptp_enable_rx_tstamp - Enable timestamping in Rx rings
* @adapter: private adapter structure
*
* Enable timestamp reporting for all Rx rings.
*/
static void iavf_ptp_enable_rx_tstamp(struct iavf_adapter *adapter)
{
for (u32 i = 0; i < adapter->num_active_queues; i++)
adapter->rx_rings[i].flags |= IAVF_TXRX_FLAGS_HW_TSTAMP;
}
/**
* iavf_ptp_set_timestamp_mode - Set device timestamping mode
* @adapter: private adapter structure
* @config: pointer to kernel_hwtstamp_config
*
* Set the timestamping mode requested from the userspace.
*
* Note: this function always translates Rx timestamp requests for any packet
* category into HWTSTAMP_FILTER_ALL.
*
* Return: 0 on success, negative error code otherwise.
*/
static int iavf_ptp_set_timestamp_mode(struct iavf_adapter *adapter,
struct kernel_hwtstamp_config *config)
{
/* Reserved for future extensions. */
if (config->flags)
return -EINVAL;
switch (config->tx_type) {
case HWTSTAMP_TX_OFF:
break;
case HWTSTAMP_TX_ON:
return -EOPNOTSUPP;
default:
return -ERANGE;
}
if (config->rx_filter == HWTSTAMP_FILTER_NONE) {
iavf_ptp_disable_rx_tstamp(adapter);
return 0;
} else if (config->rx_filter > HWTSTAMP_FILTER_NTP_ALL) {
return -ERANGE;
} else if (!(iavf_ptp_cap_supported(adapter,
VIRTCHNL_1588_PTP_CAP_RX_TSTAMP))) {
return -EOPNOTSUPP;
}
config->rx_filter = HWTSTAMP_FILTER_ALL;
iavf_ptp_enable_rx_tstamp(adapter);
return 0;
}
/**
* iavf_ptp_set_ts_config - Set timestamping configuration
* @adapter: private adapter structure
* @config: pointer to kernel_hwtstamp_config structure
* @extack: pointer to netlink_ext_ack structure
*
* Program the requested timestamping configuration to the device.
*
* Return: 0 on success, negative error code otherwise.
*/
int iavf_ptp_set_ts_config(struct iavf_adapter *adapter,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack)
{
int err;
err = iavf_ptp_set_timestamp_mode(adapter, config);
if (err)
return err;
/* Save successful settings for future reference */
adapter->ptp.hwtstamp_config = *config;
return 0;
}
/**
* iavf_ptp_cap_supported - Check if a PTP capability is supported
* @adapter: private adapter structure
* @cap: the capability bitmask to check
*
* Return: true if every capability set in cap is also set in the enabled
* capabilities reported by the PF, false otherwise.
*/
bool iavf_ptp_cap_supported(const struct iavf_adapter *adapter, u32 cap)
{
if (!IAVF_PTP_ALLOWED(adapter))
return false;
/* Only return true if every bit in cap is set in hw_caps.caps */
return (adapter->ptp.hw_caps.caps & cap) == cap;
}
/**
* iavf_allocate_ptp_cmd - Allocate a PTP command message structure
* @v_opcode: the virtchnl opcode
* @msglen: length in bytes of the associated virtchnl structure
*
* Allocates a PTP command message and pre-fills it with the provided message
* length and opcode.
*
* Return: allocated PTP command.
*/
static struct iavf_ptp_aq_cmd *iavf_allocate_ptp_cmd(enum virtchnl_ops v_opcode,
u16 msglen)
{
struct iavf_ptp_aq_cmd *cmd;
cmd = kzalloc_flex(*cmd, msg, msglen);
if (!cmd)
return NULL;
cmd->v_opcode = v_opcode;
cmd->msglen = msglen;
return cmd;
}
/**
* iavf_queue_ptp_cmd - Queue PTP command for sending over virtchnl
* @adapter: private adapter structure
* @cmd: the command structure to send
*
* Queue the given command structure into the PTP virtchnl command queue tos
* end to the PF.
*/
static void iavf_queue_ptp_cmd(struct iavf_adapter *adapter,
struct iavf_ptp_aq_cmd *cmd)
{
mutex_lock(&adapter->ptp.aq_cmd_lock);
list_add_tail(&cmd->list, &adapter->ptp.aq_cmds);
mutex_unlock(&adapter->ptp.aq_cmd_lock);
adapter->aq_required |= IAVF_FLAG_AQ_SEND_PTP_CMD;
mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
}
/**
* iavf_send_phc_read - Send request to read PHC time
* @adapter: private adapter structure
*
* Send a request to obtain the PTP hardware clock time. This allocates the
* VIRTCHNL_OP_1588_PTP_GET_TIME message and queues it up to send to
* indirectly read the PHC time.
*
* This function does not wait for the reply from the PF.
*
* Return: 0 if success, error code otherwise.
*/
static int iavf_send_phc_read(struct iavf_adapter *adapter)
{
struct iavf_ptp_aq_cmd *cmd;
if (!adapter->ptp.clock)
return -EOPNOTSUPP;
cmd = iavf_allocate_ptp_cmd(VIRTCHNL_OP_1588_PTP_GET_TIME,
sizeof(struct virtchnl_phc_time));
if (!cmd)
return -ENOMEM;
iavf_queue_ptp_cmd(adapter, cmd);
return 0;
}
/**
* iavf_read_phc_indirect - Indirectly read the PHC time via virtchnl
* @adapter: private adapter structure
* @ts: storage for the timestamp value
* @sts: system timestamp values before and after the read
*
* Used when the device does not have direct register access to the PHC time.
* Indirectly reads the time via the VIRTCHNL_OP_1588_PTP_GET_TIME, and waits
* for the reply from the PF.
*
* Based on some simple measurements using ftrace and phc2sys, this clock
* access method has about a ~110 usec latency even when the system is not
* under load. In order to achieve acceptable results when using phc2sys with
* the indirect clock access method, it is recommended to use more
* conservative proportional and integration constants with the P/I servo.
*
* Return: 0 if success, error code otherwise.
*/
static int iavf_read_phc_indirect(struct iavf_adapter *adapter,
struct timespec64 *ts,
struct ptp_system_timestamp *sts)
{
long ret;
int err;
adapter->ptp.phc_time_ready = false;
ptp_read_system_prets(sts);
err = iavf_send_phc_read(adapter);
if (err)
return err;
ret = wait_event_interruptible_timeout(adapter->ptp.phc_time_waitqueue,
adapter->ptp.phc_time_ready,
HZ);
ptp_read_system_postts(sts);
if (ret < 0)
return ret;
else if (!ret)
return -EBUSY;
*ts = ns_to_timespec64(adapter->ptp.cached_phc_time);
return 0;
}
static int iavf_ptp_gettimex64(struct ptp_clock_info *info,
struct timespec64 *ts,
struct ptp_system_timestamp *sts)
{
struct iavf_adapter *adapter = iavf_clock_to_adapter(info);
if (!adapter->ptp.clock)
return -EOPNOTSUPP;
return iavf_read_phc_indirect(adapter, ts, sts);
}
static int iavf_ptp_settime64(struct ptp_clock_info *info,
const struct timespec64 *ts)
{
return -EOPNOTSUPP;
}
/**
* iavf_ptp_cache_phc_time - Cache PHC time for performing timestamp extension
* @adapter: private adapter structure
*
* Periodically cache the PHC time in order to allow for timestamp extension.
* This is required because the Tx and Rx timestamps only contain 32bits of
* nanoseconds. Timestamp extension allows calculating the corrected 64bit
* timestamp. This algorithm relies on the cached time being within ~1 second
* of the timestamp.
*/
static void iavf_ptp_cache_phc_time(struct iavf_adapter *adapter)
{
if (!time_is_before_jiffies(adapter->ptp.cached_phc_updated + HZ))
return;
/* The response from virtchnl will store the time into
* cached_phc_time.
*/
iavf_send_phc_read(adapter);
}
/**
* iavf_ptp_do_aux_work - Perform periodic work required for PTP support
* @info: PTP clock info structure
*
* Handler to take care of periodic work required for PTP operation. This
* includes the following tasks:
*
* 1) updating cached_phc_time
*
* cached_phc_time is used by the Tx and Rx timestamp flows in order to
* perform timestamp extension, by carefully comparing the timestamp
* 32bit nanosecond timestamps and determining the corrected 64bit
* timestamp value to report to userspace. This algorithm only works if
* the cached_phc_time is within ~1 second of the Tx or Rx timestamp
* event. This task periodically reads the PHC time and stores it, to
* ensure that timestamp extension operates correctly.
*
* Returns: time in jiffies until the periodic task should be re-scheduled.
*/
static long iavf_ptp_do_aux_work(struct ptp_clock_info *info)
{
struct iavf_adapter *adapter = iavf_clock_to_adapter(info);
iavf_ptp_cache_phc_time(adapter);
/* Check work about twice a second */
return msecs_to_jiffies(500);
}
/**
* iavf_ptp_register_clock - Register a new PTP for userspace
* @adapter: private adapter structure
*
* Allocate and register a new PTP clock device if necessary.
*
* Return: 0 if success, error otherwise.
*/
static int iavf_ptp_register_clock(struct iavf_adapter *adapter)
{
struct ptp_clock_info *ptp_info = &adapter->ptp.info;
struct device *dev = &adapter->pdev->dev;
struct ptp_clock *clock;
snprintf(ptp_info->name, sizeof(ptp_info->name), "%s-%s-clk",
KBUILD_MODNAME, dev_name(dev));
ptp_info->owner = THIS_MODULE;
ptp_info->gettimex64 = iavf_ptp_gettimex64;
ptp_info->settime64 = iavf_ptp_settime64;
ptp_info->do_aux_work = iavf_ptp_do_aux_work;
clock = ptp_clock_register(ptp_info, dev);
if (IS_ERR(clock))
return PTR_ERR(clock);
adapter->ptp.clock = clock;
dev_dbg(&adapter->pdev->dev, "PTP clock %s registered\n",
adapter->ptp.info.name);
return 0;
}
/**
* iavf_ptp_init - Initialize PTP support if capability was negotiated
* @adapter: private adapter structure
*
* Initialize PTP functionality, based on the capabilities that the PF has
* enabled for this VF.
*/
void iavf_ptp_init(struct iavf_adapter *adapter)
{
int err;
if (!iavf_ptp_cap_supported(adapter, VIRTCHNL_1588_PTP_CAP_READ_PHC)) {
pci_notice(adapter->pdev,
"Device does not have PTP clock support\n");
return;
}
err = iavf_ptp_register_clock(adapter);
if (err) {
pci_err(adapter->pdev,
"Failed to register PTP clock device (%p)\n",
ERR_PTR(err));
return;
}
for (int i = 0; i < adapter->num_active_queues; i++) {
struct iavf_ring *rx_ring = &adapter->rx_rings[i];
rx_ring->ptp = &adapter->ptp;
}
ptp_schedule_worker(adapter->ptp.clock, 0);
}
/**
* iavf_ptp_release - Disable PTP support
* @adapter: private adapter structure
*
* Release all PTP resources that were previously initialized.
*/
void iavf_ptp_release(struct iavf_adapter *adapter)
{
struct iavf_ptp_aq_cmd *cmd, *tmp;
if (!adapter->ptp.clock)
return;
pci_dbg(adapter->pdev, "removing PTP clock %s\n",
adapter->ptp.info.name);
ptp_clock_unregister(adapter->ptp.clock);
adapter->ptp.clock = NULL;
/* Cancel any remaining uncompleted PTP clock commands */
mutex_lock(&adapter->ptp.aq_cmd_lock);
list_for_each_entry_safe(cmd, tmp, &adapter->ptp.aq_cmds, list) {
list_del(&cmd->list);
kfree(cmd);
}
adapter->aq_required &= ~IAVF_FLAG_AQ_SEND_PTP_CMD;
mutex_unlock(&adapter->ptp.aq_cmd_lock);
adapter->ptp.hwtstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
iavf_ptp_disable_rx_tstamp(adapter);
}
/**
* iavf_ptp_process_caps - Handle change in PTP capabilities
* @adapter: private adapter structure
*
* Handle any state changes necessary due to change in PTP capabilities, such
* as after a device reset or change in configuration from the PF.
*/
void iavf_ptp_process_caps(struct iavf_adapter *adapter)
{
bool phc = iavf_ptp_cap_supported(adapter, VIRTCHNL_1588_PTP_CAP_READ_PHC);
/* Check if the device gained or lost necessary access to support the
* PTP hardware clock. If so, driver must respond appropriately by
* creating or destroying the PTP clock device.
*/
if (adapter->ptp.clock && !phc)
iavf_ptp_release(adapter);
else if (!adapter->ptp.clock && phc)
iavf_ptp_init(adapter);
/* Check if the device lost access to Rx timestamp incoming packets */
if (!iavf_ptp_cap_supported(adapter, VIRTCHNL_1588_PTP_CAP_RX_TSTAMP)) {
adapter->ptp.hwtstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
iavf_ptp_disable_rx_tstamp(adapter);
}
}
/**
* iavf_ptp_extend_32b_timestamp - Convert a 32b nanoseconds timestamp to 64b
* nanoseconds
* @cached_phc_time: recently cached copy of PHC time
* @in_tstamp: Ingress/egress 32b nanoseconds timestamp value
*
* Hardware captures timestamps which contain only 32 bits of nominal
* nanoseconds, as opposed to the 64bit timestamps that the stack expects.
*
* Extend the 32bit nanosecond timestamp using the following algorithm and
* assumptions:
*
* 1) have a recently cached copy of the PHC time
* 2) assume that the in_tstamp was captured 2^31 nanoseconds (~2.1
* seconds) before or after the PHC time was captured.
* 3) calculate the delta between the cached time and the timestamp
* 4) if the delta is smaller than 2^31 nanoseconds, then the timestamp was
* captured after the PHC time. In this case, the full timestamp is just
* the cached PHC time plus the delta.
* 5) otherwise, if the delta is larger than 2^31 nanoseconds, then the
* timestamp was captured *before* the PHC time, i.e. because the PHC
* cache was updated after the timestamp was captured by hardware. In this
* case, the full timestamp is the cached time minus the inverse delta.
*
* This algorithm works even if the PHC time was updated after a Tx timestamp
* was requested, but before the Tx timestamp event was reported from
* hardware.
*
* This calculation primarily relies on keeping the cached PHC time up to
* date. If the timestamp was captured more than 2^31 nanoseconds after the
* PHC time, it is possible that the lower 32bits of PHC time have
* overflowed more than once, and we might generate an incorrect timestamp.
*
* This is prevented by (a) periodically updating the cached PHC time once
* a second, and (b) discarding any Tx timestamp packet if it has waited for
* a timestamp for more than one second.
*
* Return: extended timestamp (to 64b).
*/
u64 iavf_ptp_extend_32b_timestamp(u64 cached_phc_time, u32 in_tstamp)
{
u32 low = lower_32_bits(cached_phc_time);
u32 delta = in_tstamp - low;
u64 ns;
/* Do not assume that the in_tstamp is always more recent than the
* cached PHC time. If the delta is large, it indicates that the
* in_tstamp was taken in the past, and should be converted
* forward.
*/
if (delta > S32_MAX)
ns = cached_phc_time - (low - in_tstamp);
else
ns = cached_phc_time + delta;
return ns;
}
@@ -0,0 +1,47 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2024 Intel Corporation. */
#ifndef _IAVF_PTP_H_
#define _IAVF_PTP_H_
#include "iavf_types.h"
/* bit indicating whether a 40bit timestamp is valid */
#define IAVF_PTP_40B_TSTAMP_VALID BIT(24)
#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
void iavf_ptp_init(struct iavf_adapter *adapter);
void iavf_ptp_release(struct iavf_adapter *adapter);
void iavf_ptp_process_caps(struct iavf_adapter *adapter);
bool iavf_ptp_cap_supported(const struct iavf_adapter *adapter, u32 cap);
void iavf_virtchnl_send_ptp_cmd(struct iavf_adapter *adapter);
int iavf_ptp_set_ts_config(struct iavf_adapter *adapter,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack);
u64 iavf_ptp_extend_32b_timestamp(u64 cached_phc_time, u32 in_tstamp);
#else /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */
static inline void iavf_ptp_init(struct iavf_adapter *adapter) { }
static inline void iavf_ptp_release(struct iavf_adapter *adapter) { }
static inline void iavf_ptp_process_caps(struct iavf_adapter *adapter) { }
static inline bool iavf_ptp_cap_supported(const struct iavf_adapter *adapter,
u32 cap)
{
return false;
}
static inline void iavf_virtchnl_send_ptp_cmd(struct iavf_adapter *adapter) { }
static inline int iavf_ptp_set_ts_config(struct iavf_adapter *adapter,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack)
{
return -1;
}
static inline u64 iavf_ptp_extend_32b_timestamp(u64 cached_phc_time,
u32 in_tstamp)
{
return 0;
}
#endif /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */
#endif /* _IAVF_PTP_H_ */
@@ -0,0 +1,68 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#ifndef _IAVF_REGISTER_H_
#define _IAVF_REGISTER_H_
#define IAVF_VF_ARQBAH1 0x00006000 /* Reset: EMPR */
#define IAVF_VF_ARQBAL1 0x00006C00 /* Reset: EMPR */
#define IAVF_VF_ARQH1 0x00007400 /* Reset: EMPR */
#define IAVF_VF_ARQH1_ARQH_SHIFT 0
#define IAVF_VF_ARQH1_ARQH_MASK IAVF_MASK(0x3FF, IAVF_VF_ARQH1_ARQH_SHIFT)
#define IAVF_VF_ARQLEN1 0x00008000 /* Reset: EMPR */
#define IAVF_VF_ARQLEN1_ARQVFE_SHIFT 28
#define IAVF_VF_ARQLEN1_ARQVFE_MASK IAVF_MASK(0x1, IAVF_VF_ARQLEN1_ARQVFE_SHIFT)
#define IAVF_VF_ARQLEN1_ARQOVFL_SHIFT 29
#define IAVF_VF_ARQLEN1_ARQOVFL_MASK IAVF_MASK(0x1, IAVF_VF_ARQLEN1_ARQOVFL_SHIFT)
#define IAVF_VF_ARQLEN1_ARQCRIT_SHIFT 30
#define IAVF_VF_ARQLEN1_ARQCRIT_MASK IAVF_MASK(0x1, IAVF_VF_ARQLEN1_ARQCRIT_SHIFT)
#define IAVF_VF_ARQLEN1_ARQENABLE_SHIFT 31
#define IAVF_VF_ARQLEN1_ARQENABLE_MASK IAVF_MASK(0x1, IAVF_VF_ARQLEN1_ARQENABLE_SHIFT)
#define IAVF_VF_ARQT1 0x00007000 /* Reset: EMPR */
#define IAVF_VF_ATQBAH1 0x00007800 /* Reset: EMPR */
#define IAVF_VF_ATQBAL1 0x00007C00 /* Reset: EMPR */
#define IAVF_VF_ATQH1 0x00006400 /* Reset: EMPR */
#define IAVF_VF_ATQLEN1 0x00006800 /* Reset: EMPR */
#define IAVF_VF_ATQLEN1_ATQVFE_SHIFT 28
#define IAVF_VF_ATQLEN1_ATQVFE_MASK IAVF_MASK(0x1, IAVF_VF_ATQLEN1_ATQVFE_SHIFT)
#define IAVF_VF_ATQLEN1_ATQOVFL_SHIFT 29
#define IAVF_VF_ATQLEN1_ATQOVFL_MASK IAVF_MASK(0x1, IAVF_VF_ATQLEN1_ATQOVFL_SHIFT)
#define IAVF_VF_ATQLEN1_ATQCRIT_SHIFT 30
#define IAVF_VF_ATQLEN1_ATQCRIT_MASK IAVF_MASK(0x1, IAVF_VF_ATQLEN1_ATQCRIT_SHIFT)
#define IAVF_VF_ATQLEN1_ATQENABLE_SHIFT 31
#define IAVF_VF_ATQLEN1_ATQENABLE_MASK IAVF_MASK(0x1, IAVF_VF_ATQLEN1_ATQENABLE_SHIFT)
#define IAVF_VF_ATQT1 0x00008400 /* Reset: EMPR */
#define IAVF_VFGEN_RSTAT 0x00008800 /* Reset: VFR */
#define IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT 0
#define IAVF_VFGEN_RSTAT_VFR_STATE_MASK IAVF_MASK(0x3, IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT)
#define IAVF_VFINT_DYN_CTL01 0x00005C00 /* Reset: VFR */
#define IAVF_VFINT_DYN_CTL01_INTENA_SHIFT 0
#define IAVF_VFINT_DYN_CTL01_INTENA_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTL01_INTENA_SHIFT)
#define IAVF_VFINT_DYN_CTL01_ITR_INDX_SHIFT 3
#define IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK IAVF_MASK(0x3, IAVF_VFINT_DYN_CTL01_ITR_INDX_SHIFT)
#define IAVF_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) /* _i=0...63 */ /* Reset: VFR */
#define IAVF_VFINT_DYN_CTLN1_INTENA_SHIFT 0
#define IAVF_VFINT_DYN_CTLN1_INTENA_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTLN1_INTENA_SHIFT)
#define IAVF_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT 2
#define IAVF_VFINT_DYN_CTLN1_SWINT_TRIG_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT)
#define IAVF_VFINT_DYN_CTLN1_ITR_INDX_SHIFT 3
#define IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK IAVF_MASK(0x3, IAVF_VFINT_DYN_CTLN1_ITR_INDX_SHIFT)
#define IAVF_VFINT_DYN_CTLN1_INTERVAL_SHIFT 5
#define IAVF_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT 24
#define IAVF_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT)
#define IAVF_VFINT_ICR0_ENA1 0x00005000 /* Reset: CORER */
#define IAVF_VFINT_ICR0_ENA1_ADMINQ_SHIFT 30
#define IAVF_VFINT_ICR0_ENA1_ADMINQ_MASK IAVF_MASK(0x1, IAVF_VFINT_ICR0_ENA1_ADMINQ_SHIFT)
#define IAVF_VFINT_ICR0_ENA1_RSVD_SHIFT 31
#define IAVF_VFINT_ICR01 0x00004800 /* Reset: CORER */
#define IAVF_VFINT_ITRN1(_i, _INTVF) (0x00002800 + ((_i) * 64 + (_INTVF) * 4)) /* _i=0...2, _INTVF=0...15 */ /* Reset: VFR */
#define IAVF_QRX_TAIL1(_Q) (0x00002000 + ((_Q) * 4)) /* _i=0...15 */ /* Reset: CORER */
#define IAVF_QTX_TAIL1(_Q) (0x00000000 + ((_Q) * 4)) /* _i=0...15 */ /* Reset: PFR */
#define IAVF_VFQF_HENA(_i) (0x0000C400 + ((_i) * 4)) /* _i=0...1 */ /* Reset: CORER */
#define IAVF_VFQF_HKEY(_i) (0x0000CC00 + ((_i) * 4)) /* _i=0...12 */ /* Reset: CORER */
#define IAVF_VFQF_HKEY_MAX_INDEX 12
#define IAVF_VFQF_HLUT(_i) (0x0000D000 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */
#define IAVF_VFQF_HLUT_MAX_INDEX 15
#define IAVF_VFINT_DYN_CTLN1_WB_ON_ITR_SHIFT 30
#define IAVF_VFINT_DYN_CTLN1_WB_ON_ITR_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTLN1_WB_ON_ITR_SHIFT)
#endif /* _IAVF_REGISTER_H_ */
@@ -0,0 +1,78 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#ifndef _IAVF_STATUS_H_
#define _IAVF_STATUS_H_
/* Error Codes */
enum iavf_status {
IAVF_SUCCESS = 0,
IAVF_ERR_NVM = -1,
IAVF_ERR_NVM_CHECKSUM = -2,
IAVF_ERR_PHY = -3,
IAVF_ERR_CONFIG = -4,
IAVF_ERR_PARAM = -5,
IAVF_ERR_MAC_TYPE = -6,
IAVF_ERR_UNKNOWN_PHY = -7,
IAVF_ERR_LINK_SETUP = -8,
IAVF_ERR_ADAPTER_STOPPED = -9,
IAVF_ERR_INVALID_MAC_ADDR = -10,
IAVF_ERR_DEVICE_NOT_SUPPORTED = -11,
IAVF_ERR_PRIMARY_REQUESTS_PENDING = -12,
IAVF_ERR_INVALID_LINK_SETTINGS = -13,
IAVF_ERR_AUTONEG_NOT_COMPLETE = -14,
IAVF_ERR_RESET_FAILED = -15,
IAVF_ERR_SWFW_SYNC = -16,
IAVF_ERR_NO_AVAILABLE_VSI = -17,
IAVF_ERR_NO_MEMORY = -18,
IAVF_ERR_BAD_PTR = -19,
IAVF_ERR_RING_FULL = -20,
IAVF_ERR_INVALID_PD_ID = -21,
IAVF_ERR_INVALID_QP_ID = -22,
IAVF_ERR_INVALID_CQ_ID = -23,
IAVF_ERR_INVALID_CEQ_ID = -24,
IAVF_ERR_INVALID_AEQ_ID = -25,
IAVF_ERR_INVALID_SIZE = -26,
IAVF_ERR_INVALID_ARP_INDEX = -27,
IAVF_ERR_INVALID_FPM_FUNC_ID = -28,
IAVF_ERR_QP_INVALID_MSG_SIZE = -29,
IAVF_ERR_QP_TOOMANY_WRS_POSTED = -30,
IAVF_ERR_INVALID_FRAG_COUNT = -31,
IAVF_ERR_QUEUE_EMPTY = -32,
IAVF_ERR_INVALID_ALIGNMENT = -33,
IAVF_ERR_FLUSHED_QUEUE = -34,
IAVF_ERR_INVALID_PUSH_PAGE_INDEX = -35,
IAVF_ERR_INVALID_IMM_DATA_SIZE = -36,
IAVF_ERR_TIMEOUT = -37,
IAVF_ERR_OPCODE_MISMATCH = -38,
IAVF_ERR_CQP_COMPL_ERROR = -39,
IAVF_ERR_INVALID_VF_ID = -40,
IAVF_ERR_INVALID_HMCFN_ID = -41,
IAVF_ERR_BACKING_PAGE_ERROR = -42,
IAVF_ERR_NO_PBLCHUNKS_AVAILABLE = -43,
IAVF_ERR_INVALID_PBLE_INDEX = -44,
IAVF_ERR_INVALID_SD_INDEX = -45,
IAVF_ERR_INVALID_PAGE_DESC_INDEX = -46,
IAVF_ERR_INVALID_SD_TYPE = -47,
IAVF_ERR_MEMCPY_FAILED = -48,
IAVF_ERR_INVALID_HMC_OBJ_INDEX = -49,
IAVF_ERR_INVALID_HMC_OBJ_COUNT = -50,
IAVF_ERR_INVALID_SRQ_ARM_LIMIT = -51,
IAVF_ERR_SRQ_ENABLED = -52,
IAVF_ERR_ADMIN_QUEUE_ERROR = -53,
IAVF_ERR_ADMIN_QUEUE_TIMEOUT = -54,
IAVF_ERR_BUF_TOO_SHORT = -55,
IAVF_ERR_ADMIN_QUEUE_FULL = -56,
IAVF_ERR_ADMIN_QUEUE_NO_WORK = -57,
IAVF_ERR_BAD_RDMA_CQE = -58,
IAVF_ERR_NVM_BLANK_MODE = -59,
IAVF_ERR_NOT_IMPLEMENTED = -60,
IAVF_ERR_PE_DOORBELL_NOT_ENABLED = -61,
IAVF_ERR_DIAG_TEST_FAILED = -62,
IAVF_ERR_NOT_READY = -63,
IAVF_NOT_SUPPORTED = -64,
IAVF_ERR_FIRMWARE_API_VERSION = -65,
IAVF_ERR_ADMIN_QUEUE_CRITICAL_ERROR = -66,
};
#endif /* _IAVF_STATUS_H_ */
@@ -0,0 +1,209 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
/* Modeled on trace-events-sample.h */
/* The trace subsystem name for iavf will be "iavf".
*
* This file is named iavf_trace.h.
*
* Since this include file's name is different from the trace
* subsystem name, we'll have to define TRACE_INCLUDE_FILE at the end
* of this file.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM iavf
/* See trace-events-sample.h for a detailed description of why this
* guard clause is different from most normal include files.
*/
#if !defined(_IAVF_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
#define _IAVF_TRACE_H_
#include <linux/tracepoint.h>
/*
* iavf_trace() macro enables shared code to refer to trace points
* like:
*
* trace_iavf{,vf}_example(args...)
*
* ... as:
*
* iavf_trace(example, args...)
*
* ... to resolve to the PF or VF version of the tracepoint without
* ifdefs, and to allow tracepoints to be disabled entirely at build
* time.
*
* Trace point should always be referred to in the driver via this
* macro.
*
* Similarly, iavf_trace_enabled(trace_name) wraps references to
* trace_iavf{,vf}_<trace_name>_enabled() functions.
*/
#define _IAVF_TRACE_NAME(trace_name) (trace_ ## iavf ## _ ## trace_name)
#define IAVF_TRACE_NAME(trace_name) _IAVF_TRACE_NAME(trace_name)
#define iavf_trace(trace_name, args...) IAVF_TRACE_NAME(trace_name)(args)
#define iavf_trace_enabled(trace_name) IAVF_TRACE_NAME(trace_name##_enabled)()
/* Events common to PF and VF. Corresponding versions will be defined
* for both, named trace_iavf_* and trace_iavf_*. The iavf_trace()
* macro above will select the right trace point name for the driver
* being built from shared code.
*/
/* Events related to a vsi & ring */
DECLARE_EVENT_CLASS(
iavf_tx_template,
TP_PROTO(struct iavf_ring *ring,
struct iavf_tx_desc *desc,
struct iavf_tx_buffer *buf),
TP_ARGS(ring, desc, buf),
/* The convention here is to make the first fields in the
* TP_STRUCT match the TP_PROTO exactly. This enables the use
* of the args struct generated by the tplist tool (from the
* bcc-tools package) to be used for those fields. To access
* fields other than the tracepoint args will require the
* tplist output to be adjusted.
*/
TP_STRUCT__entry(
__field(void*, ring)
__field(void*, desc)
__field(void*, buf)
__string(devname, ring->netdev->name)
),
TP_fast_assign(
__entry->ring = ring;
__entry->desc = desc;
__entry->buf = buf;
__assign_str(devname);
),
TP_printk(
"netdev: %s ring: %p desc: %p buf %p",
__get_str(devname), __entry->ring,
__entry->desc, __entry->buf)
);
DEFINE_EVENT(
iavf_tx_template, iavf_clean_tx_irq,
TP_PROTO(struct iavf_ring *ring,
struct iavf_tx_desc *desc,
struct iavf_tx_buffer *buf),
TP_ARGS(ring, desc, buf));
DEFINE_EVENT(
iavf_tx_template, iavf_clean_tx_irq_unmap,
TP_PROTO(struct iavf_ring *ring,
struct iavf_tx_desc *desc,
struct iavf_tx_buffer *buf),
TP_ARGS(ring, desc, buf));
DECLARE_EVENT_CLASS(
iavf_rx_template,
TP_PROTO(struct iavf_ring *ring,
struct iavf_rx_desc *desc,
struct sk_buff *skb),
TP_ARGS(ring, desc, skb),
TP_STRUCT__entry(
__field(void*, ring)
__field(void*, desc)
__field(void*, skb)
__string(devname, ring->netdev->name)
),
TP_fast_assign(
__entry->ring = ring;
__entry->desc = desc;
__entry->skb = skb;
__assign_str(devname);
),
TP_printk(
"netdev: %s ring: %p desc: %p skb %p",
__get_str(devname), __entry->ring,
__entry->desc, __entry->skb)
);
DEFINE_EVENT(
iavf_rx_template, iavf_clean_rx_irq,
TP_PROTO(struct iavf_ring *ring,
struct iavf_rx_desc *desc,
struct sk_buff *skb),
TP_ARGS(ring, desc, skb));
DEFINE_EVENT(
iavf_rx_template, iavf_clean_rx_irq_rx,
TP_PROTO(struct iavf_ring *ring,
struct iavf_rx_desc *desc,
struct sk_buff *skb),
TP_ARGS(ring, desc, skb));
DECLARE_EVENT_CLASS(
iavf_xmit_template,
TP_PROTO(struct sk_buff *skb,
struct iavf_ring *ring),
TP_ARGS(skb, ring),
TP_STRUCT__entry(
__field(void*, skb)
__field(void*, ring)
__string(devname, ring->netdev->name)
),
TP_fast_assign(
__entry->skb = skb;
__entry->ring = ring;
__assign_str(devname);
),
TP_printk(
"netdev: %s skb: %p ring: %p",
__get_str(devname), __entry->skb,
__entry->ring)
);
DEFINE_EVENT(
iavf_xmit_template, iavf_xmit_frame_ring,
TP_PROTO(struct sk_buff *skb,
struct iavf_ring *ring),
TP_ARGS(skb, ring));
DEFINE_EVENT(
iavf_xmit_template, iavf_xmit_frame_ring_drop,
TP_PROTO(struct sk_buff *skb,
struct iavf_ring *ring),
TP_ARGS(skb, ring));
/* Events unique to the VF. */
#endif /* _IAVF_TRACE_H_ */
/* This must be outside ifdef _IAVF_TRACE_H */
/* This trace include file is not located in the .../include/trace
* with the kernel tracepoint definitions, because we're a loadable
* module.
*/
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE iavf_trace
#include <trace/define_trace.h>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,392 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#ifndef _IAVF_TXRX_H_
#define _IAVF_TXRX_H_
#include <linux/net/intel/libie/pctype.h>
/* Interrupt Throttling and Rate Limiting Goodies */
#define IAVF_DEFAULT_IRQ_WORK 256
/* The datasheet for the X710 and XL710 indicate that the maximum value for
* the ITR is 8160usec which is then called out as 0xFF0 with a 2usec
* resolution. 8160 is 0x1FE0 when written out in hex. So instead of storing
* the register value which is divided by 2 lets use the actual values and
* avoid an excessive amount of translation.
*/
#define IAVF_ITR_DYNAMIC 0x8000 /* use top bit as a flag */
#define IAVF_ITR_MASK 0x1FFE /* mask for ITR register value */
#define IAVF_ITR_100K 10 /* all values below must be even */
#define IAVF_ITR_50K 20
#define IAVF_ITR_20K 50
#define IAVF_ITR_18K 60
#define IAVF_ITR_8K 122
#define IAVF_MAX_ITR 8160 /* maximum value as per datasheet */
#define ITR_TO_REG(setting) ((setting) & ~IAVF_ITR_DYNAMIC)
#define ITR_REG_ALIGN(setting) __ALIGN_MASK(setting, ~IAVF_ITR_MASK)
#define ITR_IS_DYNAMIC(setting) (!!((setting) & IAVF_ITR_DYNAMIC))
#define IAVF_ITR_RX_DEF (IAVF_ITR_20K | IAVF_ITR_DYNAMIC)
#define IAVF_ITR_TX_DEF (IAVF_ITR_20K | IAVF_ITR_DYNAMIC)
/* 0x40 is the enable bit for interrupt rate limiting, and must be set if
* the value of the rate limit is non-zero
*/
#define INTRL_ENA BIT(6)
#define IAVF_MAX_INTRL 0x3B /* reg uses 4 usec resolution */
#define INTRL_REG_TO_USEC(intrl) ((intrl & ~INTRL_ENA) << 2)
#define INTRL_USEC_TO_REG(set) ((set) ? ((set) >> 2) | INTRL_ENA : 0)
#define IAVF_INTRL_8K 125 /* 8000 ints/sec */
#define IAVF_INTRL_62K 16 /* 62500 ints/sec */
#define IAVF_INTRL_83K 12 /* 83333 ints/sec */
#define IAVF_QUEUE_END_OF_LIST 0x7FF
/* this enum matches hardware bits and is meant to be used by DYN_CTLN
* registers and QINT registers or more generally anywhere in the manual
* mentioning ITR_INDX, ITR_NONE cannot be used as an index 'n' into any
* register but instead is a special value meaning "don't update" ITR0/1/2.
*/
enum iavf_dyn_idx_t {
IAVF_IDX_ITR0 = 0,
IAVF_IDX_ITR1 = 1,
IAVF_IDX_ITR2 = 2,
IAVF_ITR_NONE = 3 /* ITR_NONE must not be used as an index */
};
/* these are indexes into ITRN registers */
#define IAVF_RX_ITR IAVF_IDX_ITR0
#define IAVF_TX_ITR IAVF_IDX_ITR1
#define IAVF_PE_ITR IAVF_IDX_ITR2
/* Supported RSS offloads */
#define IAVF_DEFAULT_RSS_HASHCFG ( \
BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_UDP) | \
BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_SCTP) | \
BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_TCP) | \
BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_OTHER) | \
BIT_ULL(LIBIE_FILTER_PCTYPE_FRAG_IPV4) | \
BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_UDP) | \
BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_TCP) | \
BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_SCTP) | \
BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_OTHER) | \
BIT_ULL(LIBIE_FILTER_PCTYPE_FRAG_IPV6) | \
BIT_ULL(LIBIE_FILTER_PCTYPE_L2_PAYLOAD))
#define IAVF_DEFAULT_RSS_HASHCFG_EXPANDED (IAVF_DEFAULT_RSS_HASHCFG | \
BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK) | \
BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) | \
BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) | \
BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK) | \
BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) | \
BIT_ULL(LIBIE_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP))
/* How many Rx Buffers do we bundle into one write to the hardware ? */
#define IAVF_RX_INCREMENT(r, i) \
do { \
(i)++; \
if ((i) == (r)->count) \
i = 0; \
r->next_to_clean = i; \
} while (0)
#define IAVF_RX_NEXT_DESC(r, i, n) \
do { \
(i)++; \
if ((i) == (r)->count) \
i = 0; \
(n) = IAVF_RX_DESC((r), (i)); \
} while (0)
#define IAVF_RX_NEXT_DESC_PREFETCH(r, i, n) \
do { \
IAVF_RX_NEXT_DESC((r), (i), (n)); \
prefetch((n)); \
} while (0)
#define IAVF_MAX_BUFFER_TXD 8
#define IAVF_MIN_TX_LEN 17
/* The size limit for a transmit buffer in a descriptor is (16K - 1).
* In order to align with the read requests we will align the value to
* the nearest 4K which represents our maximum read request size.
*/
#define IAVF_MAX_READ_REQ_SIZE 4096
#define IAVF_MAX_DATA_PER_TXD (16 * 1024 - 1)
#define IAVF_MAX_DATA_PER_TXD_ALIGNED \
(IAVF_MAX_DATA_PER_TXD & ~(IAVF_MAX_READ_REQ_SIZE - 1))
/**
* iavf_txd_use_count - estimate the number of descriptors needed for Tx
* @size: transmit request size in bytes
*
* Due to hardware alignment restrictions (4K alignment), we need to
* assume that we can have no more than 12K of data per descriptor, even
* though each descriptor can take up to 16K - 1 bytes of aligned memory.
* Thus, we need to divide by 12K. But division is slow! Instead,
* we decompose the operation into shifts and one relatively cheap
* multiply operation.
*
* To divide by 12K, we first divide by 4K, then divide by 3:
* To divide by 4K, shift right by 12 bits
* To divide by 3, multiply by 85, then divide by 256
* (Divide by 256 is done by shifting right by 8 bits)
* Finally, we add one to round up. Because 256 isn't an exact multiple of
* 3, we'll underestimate near each multiple of 12K. This is actually more
* accurate as we have 4K - 1 of wiggle room that we can fit into the last
* segment. For our purposes this is accurate out to 1M which is orders of
* magnitude greater than our largest possible GSO size.
*
* This would then be implemented as:
* return (((size >> 12) * 85) >> 8) + 1;
*
* Since multiplication and division are commutative, we can reorder
* operations into:
* return ((size * 85) >> 20) + 1;
*/
static inline unsigned int iavf_txd_use_count(unsigned int size)
{
return ((size * 85) >> 20) + 1;
}
/* Tx Descriptors needed, worst case */
#define DESC_NEEDED (MAX_SKB_FRAGS + 6)
#define IAVF_MIN_DESC_PENDING 4
#define IAVF_TX_FLAGS_HW_VLAN BIT(1)
#define IAVF_TX_FLAGS_SW_VLAN BIT(2)
#define IAVF_TX_FLAGS_TSO BIT(3)
#define IAVF_TX_FLAGS_IPV4 BIT(4)
#define IAVF_TX_FLAGS_IPV6 BIT(5)
#define IAVF_TX_FLAGS_FCCRC BIT(6)
#define IAVF_TX_FLAGS_FSO BIT(7)
#define IAVF_TX_FLAGS_FD_SB BIT(9)
#define IAVF_TX_FLAGS_VXLAN_TUNNEL BIT(10)
#define IAVF_TX_FLAGS_HW_OUTER_SINGLE_VLAN BIT(11)
#define IAVF_TX_FLAGS_VLAN_MASK 0xffff0000
#define IAVF_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000
#define IAVF_TX_FLAGS_VLAN_PRIO_SHIFT 29
#define IAVF_TX_FLAGS_VLAN_SHIFT 16
struct iavf_tx_buffer {
struct iavf_tx_desc *next_to_watch;
union {
struct sk_buff *skb;
void *raw_buf;
};
unsigned int bytecount;
unsigned short gso_segs;
DEFINE_DMA_UNMAP_ADDR(dma);
DEFINE_DMA_UNMAP_LEN(len);
u32 tx_flags;
};
struct iavf_queue_stats {
u64 packets;
u64 bytes;
};
struct iavf_tx_queue_stats {
u64 restart_queue;
u64 tx_busy;
u64 tx_done_old;
u64 tx_linearize;
u64 tx_force_wb;
u64 tx_lost_interrupt;
};
struct iavf_rx_queue_stats {
u64 non_eop_descs;
u64 alloc_page_failed;
u64 alloc_buff_failed;
};
/* some useful defines for virtchannel interface, which
* is the only remaining user of header split
*/
#define IAVF_RX_DTYPE_NO_SPLIT 0
#define IAVF_RX_DTYPE_HEADER_SPLIT 1
#define IAVF_RX_DTYPE_SPLIT_ALWAYS 2
#define IAVF_RX_SPLIT_L2 0x1
#define IAVF_RX_SPLIT_IP 0x2
#define IAVF_RX_SPLIT_TCP_UDP 0x4
#define IAVF_RX_SPLIT_SCTP 0x8
/* struct that defines a descriptor ring, associated with a VSI */
struct iavf_ring {
struct iavf_ring *next; /* pointer to next ring in q_vector */
void *desc; /* Descriptor ring memory */
union {
struct page_pool *pp; /* Used on Rx for buffer management */
struct device *dev; /* Used on Tx for DMA mapping */
};
struct net_device *netdev; /* netdev ring maps to */
union {
struct libeth_fqe *rx_fqes;
struct iavf_tx_buffer *tx_bi;
};
u8 __iomem *tail;
u32 truesize;
u16 queue_index; /* Queue number of ring */
/* high bit set means dynamic, use accessors routines to read/write.
* hardware only supports 2us resolution for the ITR registers.
* these values always store the USER setting, and must be converted
* before programming to a register.
*/
u16 itr_setting;
u16 count; /* Number of descriptors */
/* used in interrupt processing */
u16 next_to_use;
u16 next_to_clean;
u16 rxdid; /* Rx descriptor format */
u16 flags;
#define IAVF_TXR_FLAGS_WB_ON_ITR BIT(0)
#define IAVF_TXR_FLAGS_ARM_WB BIT(1)
/* BIT(2) is free */
#define IAVF_TXRX_FLAGS_VLAN_TAG_LOC_L2TAG1 BIT(3)
#define IAVF_TXR_FLAGS_VLAN_TAG_LOC_L2TAG2 BIT(4)
#define IAVF_RXR_FLAGS_VLAN_TAG_LOC_L2TAG2_2 BIT(5)
#define IAVF_TXRX_FLAGS_HW_TSTAMP BIT(6)
/* stats structs */
struct iavf_queue_stats stats;
struct u64_stats_sync syncp;
union {
struct iavf_tx_queue_stats tx_stats;
struct iavf_rx_queue_stats rx_stats;
};
int prev_pkt_ctr; /* For Tx stall detection */
unsigned int size; /* length of descriptor ring in bytes */
dma_addr_t dma; /* physical address of ring */
struct iavf_vsi *vsi; /* Backreference to associated VSI */
struct iavf_q_vector *q_vector; /* Backreference to associated vector */
struct rcu_head rcu; /* to avoid race on free */
struct sk_buff *skb; /* When iavf_clean_rx_ring_irq() must
* return before it sees the EOP for
* the current packet, we save that skb
* here and resume receiving this
* packet the next time
* iavf_clean_rx_ring_irq() is called
* for this ring.
*/
struct iavf_ptp *ptp;
u32 rx_buf_len;
struct net_shaper q_shaper;
bool q_shaper_update;
} ____cacheline_internodealigned_in_smp;
#define IAVF_ITR_ADAPTIVE_MIN_INC 0x0002
#define IAVF_ITR_ADAPTIVE_MIN_USECS 0x0002
#define IAVF_ITR_ADAPTIVE_MAX_USECS 0x007e
#define IAVF_ITR_ADAPTIVE_LATENCY 0x8000
#define IAVF_ITR_ADAPTIVE_BULK 0x0000
#define ITR_IS_BULK(x) (!((x) & IAVF_ITR_ADAPTIVE_LATENCY))
struct iavf_ring_container {
struct iavf_ring *ring; /* pointer to linked list of ring(s) */
unsigned long next_update; /* jiffies value of next update */
unsigned int total_bytes; /* total bytes processed this int */
unsigned int total_packets; /* total packets processed this int */
u16 count;
u16 target_itr; /* target ITR setting for ring(s) */
u16 current_itr; /* current ITR setting for ring(s) */
};
/* iterator for handling rings in ring container */
#define iavf_for_each_ring(pos, head) \
for (pos = (head).ring; pos != NULL; pos = pos->next)
bool iavf_alloc_rx_buffers(struct iavf_ring *rxr, u16 cleaned_count);
netdev_tx_t iavf_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
int iavf_setup_tx_descriptors(struct iavf_ring *tx_ring);
int iavf_setup_rx_descriptors(struct iavf_ring *rx_ring);
void iavf_free_tx_resources(struct iavf_ring *tx_ring);
void iavf_free_rx_resources(struct iavf_ring *rx_ring);
int iavf_napi_poll(struct napi_struct *napi, int budget);
void iavf_detect_recover_hung(struct iavf_vsi *vsi);
int __iavf_maybe_stop_tx(struct iavf_ring *tx_ring, int size);
bool __iavf_chk_linearize(struct sk_buff *skb);
/**
* iavf_xmit_descriptor_count - calculate number of Tx descriptors needed
* @skb: send buffer
*
* Returns number of data descriptors needed for this skb. Returns 0 to indicate
* there is not enough descriptors available in this ring since we need at least
* one descriptor.
**/
static inline int iavf_xmit_descriptor_count(struct sk_buff *skb)
{
const skb_frag_t *frag = &skb_shinfo(skb)->frags[0];
unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
int count = 0, size = skb_headlen(skb);
for (;;) {
count += iavf_txd_use_count(size);
if (!nr_frags--)
break;
size = skb_frag_size(frag++);
}
return count;
}
/**
* iavf_maybe_stop_tx - 1st level check for Tx stop conditions
* @tx_ring: the ring to be checked
* @size: the size buffer we want to assure is available
*
* Returns 0 if stop is not needed
**/
static inline int iavf_maybe_stop_tx(struct iavf_ring *tx_ring, int size)
{
if (likely(IAVF_DESC_UNUSED(tx_ring) >= size))
return 0;
return __iavf_maybe_stop_tx(tx_ring, size);
}
/**
* iavf_chk_linearize - Check if there are more than 8 fragments per packet
* @skb: send buffer
* @count: number of buffers used
*
* Note: Our HW can't scatter-gather more than 8 fragments to build
* a packet on the wire and so we need to figure out the cases where we
* need to linearize the skb.
**/
static inline bool iavf_chk_linearize(struct sk_buff *skb, int count)
{
/* Both TSO and single send will work if count is less than 8 */
if (likely(count < IAVF_MAX_BUFFER_TXD))
return false;
if (skb_is_gso(skb))
return __iavf_chk_linearize(skb);
/* we can support up to 8 data buffers for a single send */
return count != IAVF_MAX_BUFFER_TXD;
}
/**
* txring_txq - helper to convert from a ring to a queue
* @ring: Tx ring to find the netdev equivalent of
**/
static inline struct netdev_queue *txring_txq(const struct iavf_ring *ring)
{
return netdev_get_tx_queue(ring->netdev, ring->queue_index);
}
#endif /* _IAVF_TXRX_H_ */
@@ -0,0 +1,530 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#ifndef _IAVF_TYPE_H_
#define _IAVF_TYPE_H_
#include "iavf_status.h"
#include "iavf_osdep.h"
#include "iavf_register.h"
#include "iavf_adminq.h"
#include "iavf_devids.h"
/* IAVF_MASK is a macro used on 32 bit registers */
#define IAVF_MASK(mask, shift) ((u32)(mask) << (shift))
#define IAVF_MAX_VSI_QP 16
#define IAVF_MAX_VF_VSI 3
#define IAVF_MAX_CHAINED_RX_BUFFERS 5
/* forward declaration */
struct iavf_hw;
typedef void (*IAVF_ADMINQ_CALLBACK)(struct iavf_hw *, struct libie_aq_desc *);
/* Data type manipulation macros. */
#define IAVF_DESC_UNUSED(R) \
((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
(R)->next_to_clean - (R)->next_to_use - 1)
/* bitfields for Tx queue mapping in QTX_CTL */
#define IAVF_QTX_CTL_VF_QUEUE 0x0
#define IAVF_QTX_CTL_VM_QUEUE 0x1
#define IAVF_QTX_CTL_PF_QUEUE 0x2
/* debug masks - set these bits in hw->debug_mask to control output */
enum iavf_debug_mask {
IAVF_DEBUG_INIT = 0x00000001,
IAVF_DEBUG_RELEASE = 0x00000002,
IAVF_DEBUG_LINK = 0x00000010,
IAVF_DEBUG_PHY = 0x00000020,
IAVF_DEBUG_HMC = 0x00000040,
IAVF_DEBUG_NVM = 0x00000080,
IAVF_DEBUG_LAN = 0x00000100,
IAVF_DEBUG_FLOW = 0x00000200,
IAVF_DEBUG_DCB = 0x00000400,
IAVF_DEBUG_DIAG = 0x00000800,
IAVF_DEBUG_FD = 0x00001000,
IAVF_DEBUG_PACKAGE = 0x00002000,
IAVF_DEBUG_AQ_MESSAGE = 0x01000000,
IAVF_DEBUG_AQ_DESCRIPTOR = 0x02000000,
IAVF_DEBUG_AQ_DESC_BUFFER = 0x04000000,
IAVF_DEBUG_AQ_COMMAND = 0x06000000,
IAVF_DEBUG_AQ = 0x0F000000,
IAVF_DEBUG_USER = 0xF0000000,
IAVF_DEBUG_ALL = 0xFFFFFFFF
};
/* These are structs for managing the hardware information and the operations.
* The structures of function pointers are filled out at init time when we
* know for sure exactly which hardware we're working with. This gives us the
* flexibility of using the same main driver code but adapting to slightly
* different hardware needs as new parts are developed. For this architecture,
* the Firmware and AdminQ are intended to insulate the driver from most of the
* future changes, but these structures will also do part of the job.
*/
enum iavf_vsi_type {
IAVF_VSI_MAIN = 0,
IAVF_VSI_VMDQ1 = 1,
IAVF_VSI_VMDQ2 = 2,
IAVF_VSI_CTRL = 3,
IAVF_VSI_FCOE = 4,
IAVF_VSI_MIRROR = 5,
IAVF_VSI_SRIOV = 6,
IAVF_VSI_FDIR = 7,
IAVF_VSI_TYPE_UNKNOWN
};
enum iavf_queue_type {
IAVF_QUEUE_TYPE_RX = 0,
IAVF_QUEUE_TYPE_TX,
IAVF_QUEUE_TYPE_PE_CEQ,
IAVF_QUEUE_TYPE_UNKNOWN
};
#define IAVF_HW_CAP_MAX_GPIO 30
/* Capabilities of a PF or a VF or the whole device */
struct iavf_hw_capabilities {
bool dcb;
bool fcoe;
u32 num_vsis;
u32 num_rx_qp;
u32 num_tx_qp;
u32 base_queue;
u32 num_msix_vectors_vf;
};
struct iavf_mac_info {
u8 addr[ETH_ALEN];
u8 perm_addr[ETH_ALEN];
};
/* PCI bus types */
enum iavf_bus_type {
iavf_bus_type_unknown = 0,
iavf_bus_type_pci,
iavf_bus_type_pcix,
iavf_bus_type_pci_express,
iavf_bus_type_reserved
};
/* PCI bus speeds */
enum iavf_bus_speed {
iavf_bus_speed_unknown = 0,
iavf_bus_speed_33 = 33,
iavf_bus_speed_66 = 66,
iavf_bus_speed_100 = 100,
iavf_bus_speed_120 = 120,
iavf_bus_speed_133 = 133,
iavf_bus_speed_2500 = 2500,
iavf_bus_speed_5000 = 5000,
iavf_bus_speed_8000 = 8000,
iavf_bus_speed_reserved
};
/* PCI bus widths */
enum iavf_bus_width {
iavf_bus_width_unknown = 0,
iavf_bus_width_pcie_x1 = 1,
iavf_bus_width_pcie_x2 = 2,
iavf_bus_width_pcie_x4 = 4,
iavf_bus_width_pcie_x8 = 8,
iavf_bus_width_32 = 32,
iavf_bus_width_64 = 64,
iavf_bus_width_reserved
};
/* Bus parameters */
struct iavf_bus_info {
enum iavf_bus_speed speed;
enum iavf_bus_width width;
enum iavf_bus_type type;
u16 func;
u16 device;
u16 lan_id;
u16 bus_id;
};
#define IAVF_MAX_USER_PRIORITY 8
/* Port hardware description */
struct iavf_hw {
u8 __iomem *hw_addr;
void *back;
/* subsystem structs */
struct iavf_mac_info mac;
struct iavf_bus_info bus;
/* pci info */
u16 device_id;
u16 vendor_id;
u16 subsystem_device_id;
u16 subsystem_vendor_id;
u8 revision_id;
/* capabilities for entire device and PCI func */
struct iavf_hw_capabilities dev_caps;
/* Admin Queue info */
struct iavf_adminq_info aq;
/* debug mask */
u32 debug_mask;
char err_str[16];
};
/**
* struct iavf_rx_desc - Receive descriptor (both legacy and flexible)
* @qw0: quad word 0 fields:
* Legacy: Descriptor Type; Mirror ID; L2TAG1P (S-TAG); Filter Status
* Flex: Descriptor Type; Mirror ID; UMBCAST; Packet Type; Flexible Flags
* Section 0; Packet Length; Header Length; Split Header Flag;
* Flexible Flags section 1 / Extended Status
* @qw1: quad word 1 fields:
* Legacy: Status Field; Error Field; Packet Type; Packet Length (packet,
* header, Split Header Flag)
* Flex: Status / Error 0 Field; L2TAG1P (S-TAG); Flexible Metadata
* Container #0; Flexible Metadata Container #1
* @qw2: quad word 2 fields:
* Legacy: Extended Status; 1st L2TAG2P (C-TAG); 2nd L2TAG2P (C-TAG)
* Flex: Status / Error 1 Field; Flexible Flags section 2; Timestamp Low;
* 1st L2TAG2 (C-TAG); 2nd L2TAG2 (C-TAG)
* @qw3: quad word 3 fields:
* Legacy: FD Filter ID / Flexible Bytes
* Flex: Flexible Metadata Container #2; Flexible Metadata Container #3;
* Flexible Metadata Container #4 / Timestamp High 0; Flexible
* Metadata Container #5 / Timestamp High 1;
*/
struct iavf_rx_desc {
aligned_le64 qw0;
/* The hash signature (RSS) */
#define IAVF_RXD_LEGACY_RSS_M GENMASK_ULL(63, 32)
/* Stripped C-TAG VLAN from the receive packet */
#define IAVF_RXD_LEGACY_L2TAG1_M GENMASK_ULL(33, 16)
/* Packet type */
#define IAVF_RXD_FLEX_PTYPE_M GENMASK_ULL(25, 16)
/* Packet length */
#define IAVF_RXD_FLEX_PKT_LEN_M GENMASK_ULL(45, 32)
aligned_le64 qw1;
/* Descriptor done indication flag. */
#define IAVF_RXD_LEGACY_DD_M BIT(0)
/* End of packet. Set to 1 if this descriptor is the last one of the packet */
#define IAVF_RXD_LEGACY_EOP_M BIT(1)
/* L2 TAG 1 presence indication */
#define IAVF_RXD_LEGACY_L2TAG1P_M BIT(2)
/* Detectable L3 and L4 integrity check is processed by the HW */
#define IAVF_RXD_LEGACY_L3L4P_M BIT(3)
/* Set when an IPv6 packet contains a Destination Options Header or a Routing
* Header.
*/
#define IAVF_RXD_LEGACY_IPV6EXADD_M BIT(15)
/* Receive MAC Errors: CRC; Alignment; Oversize; Undersizes; Length error */
#define IAVF_RXD_LEGACY_RXE_M BIT(19)
/* Checksum reports:
* - IPE: IP checksum error
* - L4E: L4 integrity error
* - EIPE: External IP header (tunneled packets)
*/
#define IAVF_RXD_LEGACY_IPE_M BIT(22)
#define IAVF_RXD_LEGACY_L4E_M BIT(23)
#define IAVF_RXD_LEGACY_EIPE_M BIT(24)
/* Set for packets that skip checksum calculation in pre-parser */
#define IAVF_RXD_LEGACY_PPRS_M BIT(26)
/* Indicates the content in the Filter Status field */
#define IAVF_RXD_LEGACY_FLTSTAT_M GENMASK_ULL(13, 12)
/* Packet type */
#define IAVF_RXD_LEGACY_PTYPE_M GENMASK_ULL(37, 30)
/* Packet length */
#define IAVF_RXD_LEGACY_LENGTH_M GENMASK_ULL(51, 38)
/* Descriptor done indication flag */
#define IAVF_RXD_FLEX_DD_M BIT(0)
/* End of packet. Set to 1 if this descriptor is the last one of the packet */
#define IAVF_RXD_FLEX_EOP_M BIT(1)
/* Detectable L3 and L4 integrity check is processed by the HW */
#define IAVF_RXD_FLEX_L3L4P_M BIT(3)
/* Checksum reports:
* - IPE: IP checksum error
* - L4E: L4 integrity error
* - EIPE: External IP header (tunneled packets)
* - EUDPE: External UDP checksum error (tunneled packets)
*/
#define IAVF_RXD_FLEX_XSUM_IPE_M BIT(4)
#define IAVF_RXD_FLEX_XSUM_L4E_M BIT(5)
#define IAVF_RXD_FLEX_XSUM_EIPE_M BIT(6)
#define IAVF_RXD_FLEX_XSUM_EUDPE_M BIT(7)
/* Set when an IPv6 packet contains a Destination Options Header or a Routing
* Header.
*/
#define IAVF_RXD_FLEX_IPV6EXADD_M BIT(9)
/* Receive MAC Errors: CRC; Alignment; Oversize; Undersizes; Length error */
#define IAVF_RXD_FLEX_RXE_M BIT(10)
/* Indicates that the RSS/HASH result is valid */
#define IAVF_RXD_FLEX_RSS_VALID_M BIT(12)
/* L2 TAG 1 presence indication */
#define IAVF_RXD_FLEX_L2TAG1P_M BIT(13)
/* Stripped L2 Tag from the receive packet */
#define IAVF_RXD_FLEX_L2TAG1_M GENMASK_ULL(31, 16)
/* The hash signature (RSS) */
#define IAVF_RXD_FLEX_RSS_HASH_M GENMASK_ULL(63, 32)
aligned_le64 qw2;
/* L2 Tag 2 Presence */
#define IAVF_RXD_LEGACY_L2TAG2P_M BIT(0)
/* Stripped S-TAG VLAN from the receive packet */
#define IAVF_RXD_LEGACY_L2TAG2_M GENMASK_ULL(63, 48)
/* Stripped S-TAG VLAN from the receive packet */
#define IAVF_RXD_FLEX_L2TAG2_2_M GENMASK_ULL(63, 48)
/* The packet is a UDP tunneled packet */
#define IAVF_RXD_FLEX_NAT_M BIT(4)
/* L2 Tag 2 Presence */
#define IAVF_RXD_FLEX_L2TAG2P_M BIT(11)
aligned_le64 qw3;
#define IAVF_RXD_FLEX_QW3_TSTAMP_HIGH_M GENMASK_ULL(63, 32)
} __aligned(4 * sizeof(__le64));
static_assert(sizeof(struct iavf_rx_desc) == 32);
#define IAVF_RXD_QW1_STATUS_TSYNINDX_SHIFT IAVF_RX_DESC_STATUS_TSYNINDX_SHIFT
#define IAVF_RXD_QW1_STATUS_TSYNINDX_MASK (0x3UL << \
IAVF_RXD_QW1_STATUS_TSYNINDX_SHIFT)
#define IAVF_RXD_QW1_STATUS_TSYNVALID_SHIFT IAVF_RX_DESC_STATUS_TSYNVALID_SHIFT
#define IAVF_RXD_QW1_STATUS_TSYNVALID_MASK \
BIT_ULL(IAVF_RXD_QW1_STATUS_TSYNVALID_SHIFT)
enum iavf_rx_desc_fltstat_values {
IAVF_RX_DESC_FLTSTAT_NO_DATA = 0,
IAVF_RX_DESC_FLTSTAT_RSV_FD_ID = 1, /* 16byte desc? FD_ID : RSV */
IAVF_RX_DESC_FLTSTAT_RSV = 2,
IAVF_RX_DESC_FLTSTAT_RSS_HASH = 3,
};
enum iavf_rx_desc_error_l3l4e_fcoe_masks {
IAVF_RX_DESC_ERROR_L3L4E_NONE = 0,
IAVF_RX_DESC_ERROR_L3L4E_PROT = 1,
IAVF_RX_DESC_ERROR_L3L4E_FC = 2,
IAVF_RX_DESC_ERROR_L3L4E_DMAC_ERR = 3,
IAVF_RX_DESC_ERROR_L3L4E_DMAC_WARN = 4
};
#define IAVF_RXD_QW1_LENGTH_HBUF_SHIFT 52
#define IAVF_RXD_QW1_LENGTH_HBUF_MASK (0x7FFULL << \
IAVF_RXD_QW1_LENGTH_HBUF_SHIFT)
#define IAVF_RXD_QW1_LENGTH_SPH_SHIFT 63
#define IAVF_RXD_QW1_LENGTH_SPH_MASK BIT_ULL(IAVF_RXD_QW1_LENGTH_SPH_SHIFT)
enum iavf_rx_desc_ext_status_bits {
/* Note: These are predefined bit offsets */
IAVF_RX_DESC_EXT_STATUS_L2TAG2P_SHIFT = 0,
IAVF_RX_DESC_EXT_STATUS_L2TAG3P_SHIFT = 1,
IAVF_RX_DESC_EXT_STATUS_FLEXBL_SHIFT = 2, /* 2 BITS */
IAVF_RX_DESC_EXT_STATUS_FLEXBH_SHIFT = 4, /* 2 BITS */
IAVF_RX_DESC_EXT_STATUS_FDLONGB_SHIFT = 9,
IAVF_RX_DESC_EXT_STATUS_FCOELONGB_SHIFT = 10,
IAVF_RX_DESC_EXT_STATUS_PELONGB_SHIFT = 11,
};
#define IAVF_RX_DESC_EXT_STATUS_L2TAG2P_M BIT(IAVF_RX_DESC_EXT_STATUS_L2TAG2P_SHIFT)
enum iavf_rx_desc_pe_status_bits {
/* Note: These are predefined bit offsets */
IAVF_RX_DESC_PE_STATUS_QPID_SHIFT = 0, /* 18 BITS */
IAVF_RX_DESC_PE_STATUS_L4PORT_SHIFT = 0, /* 16 BITS */
IAVF_RX_DESC_PE_STATUS_IPINDEX_SHIFT = 16, /* 8 BITS */
IAVF_RX_DESC_PE_STATUS_QPIDHIT_SHIFT = 24,
IAVF_RX_DESC_PE_STATUS_APBVTHIT_SHIFT = 25,
IAVF_RX_DESC_PE_STATUS_PORTV_SHIFT = 26,
IAVF_RX_DESC_PE_STATUS_URG_SHIFT = 27,
IAVF_RX_DESC_PE_STATUS_IPFRAG_SHIFT = 28,
IAVF_RX_DESC_PE_STATUS_IPOPT_SHIFT = 29
};
#define IAVF_RX_PROG_STATUS_DESC_LENGTH_SHIFT 38
#define IAVF_RX_PROG_STATUS_DESC_LENGTH 0x2000000
#define IAVF_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT 2
#define IAVF_RX_PROG_STATUS_DESC_QW1_PROGID_MASK (0x7UL << \
IAVF_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT)
#define IAVF_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT 19
#define IAVF_RX_PROG_STATUS_DESC_QW1_ERROR_MASK (0x3FUL << \
IAVF_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT)
enum iavf_rx_prog_status_desc_status_bits {
/* Note: These are predefined bit offsets */
IAVF_RX_PROG_STATUS_DESC_DD_SHIFT = 0,
IAVF_RX_PROG_STATUS_DESC_PROG_ID_SHIFT = 2 /* 3 BITS */
};
enum iavf_rx_prog_status_desc_prog_id_masks {
IAVF_RX_PROG_STATUS_DESC_FD_FILTER_STATUS = 1,
IAVF_RX_PROG_STATUS_DESC_FCOE_CTXT_PROG_STATUS = 2,
IAVF_RX_PROG_STATUS_DESC_FCOE_CTXT_INVL_STATUS = 4,
};
enum iavf_rx_prog_status_desc_error_bits {
/* Note: These are predefined bit offsets */
IAVF_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT = 0,
IAVF_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT = 1,
IAVF_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT = 2,
IAVF_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT = 3
};
/* TX Descriptor */
struct iavf_tx_desc {
__le64 buffer_addr; /* Address of descriptor's data buf */
__le64 cmd_type_offset_bsz;
};
#define IAVF_TXD_QW1_DTYPE_SHIFT 0
#define IAVF_TXD_QW1_DTYPE_MASK (0xFUL << IAVF_TXD_QW1_DTYPE_SHIFT)
enum iavf_tx_desc_dtype_value {
IAVF_TX_DESC_DTYPE_DATA = 0x0,
IAVF_TX_DESC_DTYPE_NOP = 0x1, /* same as Context desc */
IAVF_TX_DESC_DTYPE_CONTEXT = 0x1,
IAVF_TX_DESC_DTYPE_FCOE_CTX = 0x2,
IAVF_TX_DESC_DTYPE_FILTER_PROG = 0x8,
IAVF_TX_DESC_DTYPE_DDP_CTX = 0x9,
IAVF_TX_DESC_DTYPE_FLEX_DATA = 0xB,
IAVF_TX_DESC_DTYPE_FLEX_CTX_1 = 0xC,
IAVF_TX_DESC_DTYPE_FLEX_CTX_2 = 0xD,
IAVF_TX_DESC_DTYPE_DESC_DONE = 0xF
};
#define IAVF_TXD_QW1_CMD_SHIFT 4
#define IAVF_TXD_QW1_CMD_MASK (0x3FFUL << IAVF_TXD_QW1_CMD_SHIFT)
enum iavf_tx_desc_cmd_bits {
IAVF_TX_DESC_CMD_EOP = 0x0001,
IAVF_TX_DESC_CMD_RS = 0x0002,
IAVF_TX_DESC_CMD_ICRC = 0x0004,
IAVF_TX_DESC_CMD_IL2TAG1 = 0x0008,
IAVF_TX_DESC_CMD_DUMMY = 0x0010,
IAVF_TX_DESC_CMD_IIPT_NONIP = 0x0000, /* 2 BITS */
IAVF_TX_DESC_CMD_IIPT_IPV6 = 0x0020, /* 2 BITS */
IAVF_TX_DESC_CMD_IIPT_IPV4 = 0x0040, /* 2 BITS */
IAVF_TX_DESC_CMD_IIPT_IPV4_CSUM = 0x0060, /* 2 BITS */
IAVF_TX_DESC_CMD_FCOET = 0x0080,
IAVF_TX_DESC_CMD_L4T_EOFT_UNK = 0x0000, /* 2 BITS */
IAVF_TX_DESC_CMD_L4T_EOFT_TCP = 0x0100, /* 2 BITS */
IAVF_TX_DESC_CMD_L4T_EOFT_SCTP = 0x0200, /* 2 BITS */
IAVF_TX_DESC_CMD_L4T_EOFT_UDP = 0x0300, /* 2 BITS */
IAVF_TX_DESC_CMD_L4T_EOFT_EOF_N = 0x0000, /* 2 BITS */
IAVF_TX_DESC_CMD_L4T_EOFT_EOF_T = 0x0100, /* 2 BITS */
IAVF_TX_DESC_CMD_L4T_EOFT_EOF_NI = 0x0200, /* 2 BITS */
IAVF_TX_DESC_CMD_L4T_EOFT_EOF_A = 0x0300, /* 2 BITS */
};
#define IAVF_TXD_QW1_OFFSET_SHIFT 16
#define IAVF_TXD_QW1_OFFSET_MASK (0x3FFFFULL << \
IAVF_TXD_QW1_OFFSET_SHIFT)
enum iavf_tx_desc_length_fields {
/* Note: These are predefined bit offsets */
IAVF_TX_DESC_LENGTH_MACLEN_SHIFT = 0, /* 7 BITS */
IAVF_TX_DESC_LENGTH_IPLEN_SHIFT = 7, /* 7 BITS */
IAVF_TX_DESC_LENGTH_L4_FC_LEN_SHIFT = 14 /* 4 BITS */
};
#define IAVF_TXD_QW1_TX_BUF_SZ_SHIFT 34
#define IAVF_TXD_QW1_TX_BUF_SZ_MASK (0x3FFFULL << \
IAVF_TXD_QW1_TX_BUF_SZ_SHIFT)
#define IAVF_TXD_QW1_L2TAG1_SHIFT 48
#define IAVF_TXD_QW1_L2TAG1_MASK (0xFFFFULL << IAVF_TXD_QW1_L2TAG1_SHIFT)
/* Context descriptors */
struct iavf_tx_context_desc {
__le32 tunneling_params;
__le16 l2tag2;
__le16 rsvd;
__le64 type_cmd_tso_mss;
};
#define IAVF_TXD_CTX_QW1_CMD_SHIFT 4
#define IAVF_TXD_CTX_QW1_CMD_MASK (0xFFFFUL << IAVF_TXD_CTX_QW1_CMD_SHIFT)
enum iavf_tx_ctx_desc_cmd_bits {
IAVF_TX_CTX_DESC_TSO = 0x01,
IAVF_TX_CTX_DESC_TSYN = 0x02,
IAVF_TX_CTX_DESC_IL2TAG2 = 0x04,
IAVF_TX_CTX_DESC_IL2TAG2_IL2H = 0x08,
IAVF_TX_CTX_DESC_SWTCH_NOTAG = 0x00,
IAVF_TX_CTX_DESC_SWTCH_UPLINK = 0x10,
IAVF_TX_CTX_DESC_SWTCH_LOCAL = 0x20,
IAVF_TX_CTX_DESC_SWTCH_VSI = 0x30,
IAVF_TX_CTX_DESC_SWPE = 0x40
};
#define IAVF_TXD_CTX_QW1_TSO_LEN_SHIFT 30
#define IAVF_TXD_CTX_QW1_TSO_LEN_MASK (0x3FFFFULL << \
IAVF_TXD_CTX_QW1_TSO_LEN_SHIFT)
#define IAVF_TXD_CTX_QW1_MSS_SHIFT 50
#define IAVF_TXD_CTX_QW1_MSS_MASK (0x3FFFULL << \
IAVF_TXD_CTX_QW1_MSS_SHIFT)
#define IAVF_TXD_CTX_QW1_VSI_SHIFT 50
#define IAVF_TXD_CTX_QW1_VSI_MASK (0x1FFULL << IAVF_TXD_CTX_QW1_VSI_SHIFT)
#define IAVF_TXD_CTX_QW0_EXT_IP_SHIFT 0
#define IAVF_TXD_CTX_QW0_EXT_IP_MASK (0x3ULL << \
IAVF_TXD_CTX_QW0_EXT_IP_SHIFT)
enum iavf_tx_ctx_desc_eipt_offload {
IAVF_TX_CTX_EXT_IP_NONE = 0x0,
IAVF_TX_CTX_EXT_IP_IPV6 = 0x1,
IAVF_TX_CTX_EXT_IP_IPV4_NO_CSUM = 0x2,
IAVF_TX_CTX_EXT_IP_IPV4 = 0x3
};
#define IAVF_TXD_CTX_QW0_EXT_IPLEN_SHIFT 2
#define IAVF_TXD_CTX_QW0_EXT_IPLEN_MASK (0x3FULL << \
IAVF_TXD_CTX_QW0_EXT_IPLEN_SHIFT)
#define IAVF_TXD_CTX_QW0_NATT_SHIFT 9
#define IAVF_TXD_CTX_QW0_NATT_MASK (0x3ULL << IAVF_TXD_CTX_QW0_NATT_SHIFT)
#define IAVF_TXD_CTX_UDP_TUNNELING BIT_ULL(IAVF_TXD_CTX_QW0_NATT_SHIFT)
#define IAVF_TXD_CTX_GRE_TUNNELING (0x2ULL << IAVF_TXD_CTX_QW0_NATT_SHIFT)
#define IAVF_TXD_CTX_QW0_EIP_NOINC_SHIFT 11
#define IAVF_TXD_CTX_QW0_EIP_NOINC_MASK \
BIT_ULL(IAVF_TXD_CTX_QW0_EIP_NOINC_SHIFT)
#define IAVF_TXD_CTX_EIP_NOINC_IPID_CONST IAVF_TXD_CTX_QW0_EIP_NOINC_MASK
#define IAVF_TXD_CTX_QW0_NATLEN_SHIFT 12
#define IAVF_TXD_CTX_QW0_NATLEN_MASK (0X7FULL << \
IAVF_TXD_CTX_QW0_NATLEN_SHIFT)
#define IAVF_TXD_CTX_QW0_DECTTL_SHIFT 19
#define IAVF_TXD_CTX_QW0_DECTTL_MASK (0xFULL << \
IAVF_TXD_CTX_QW0_DECTTL_SHIFT)
#define IAVF_TXD_CTX_QW0_L4T_CS_SHIFT 23
#define IAVF_TXD_CTX_QW0_L4T_CS_MASK BIT_ULL(IAVF_TXD_CTX_QW0_L4T_CS_SHIFT)
/* Statistics collected by each port, VSI, VEB, and S-channel */
struct iavf_eth_stats {
u64 rx_bytes; /* gorc */
u64 rx_unicast; /* uprc */
u64 rx_multicast; /* mprc */
u64 rx_broadcast; /* bprc */
u64 rx_discards; /* rdpc */
u64 rx_unknown_protocol; /* rupp */
u64 tx_bytes; /* gotc */
u64 tx_unicast; /* uptc */
u64 tx_multicast; /* mptc */
u64 tx_broadcast; /* bptc */
u64 tx_discards; /* tdpc */
u64 tx_errors; /* tepc */
};
#endif /* _IAVF_TYPE_H_ */
@@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2024 Intel Corporation. */
#ifndef _IAVF_TYPES_H_
#define _IAVF_TYPES_H_
#include "iavf_types.h"
#include <linux/avf/virtchnl.h>
#include <linux/ptp_clock_kernel.h>
/* structure used to queue PTP commands for processing */
struct iavf_ptp_aq_cmd {
struct list_head list;
enum virtchnl_ops v_opcode:16;
u16 msglen;
u8 msg[] __counted_by(msglen);
};
struct iavf_ptp {
wait_queue_head_t phc_time_waitqueue;
struct virtchnl_ptp_caps hw_caps;
struct ptp_clock_info info;
struct ptp_clock *clock;
struct list_head aq_cmds;
u64 cached_phc_time;
unsigned long cached_phc_updated;
/* Lock protecting access to the AQ command list */
struct mutex aq_cmd_lock;
struct kernel_hwtstamp_config hwtstamp_config;
bool phc_time_ready:1;
};
#endif /* _IAVF_TYPES_H_ */
File diff suppressed because it is too large Load Diff