Commit e0304f58 authored by David S. Miller's avatar David S. Miller

Merge branch '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue

Jeff Kirsher says:

====================
40GbE Intel Wired LAN Driver Updates 2017-03-15

This series contains updates to i40e and i40evf only.

Aaron fixes an issue on x710 devices where simultaneous read accesses
were interfering with each other, so make sure all devices acquire the
NVM lock before reads on all devices.

Shannon adds Wake On LAN support feature for x722 devices and cleaned
up the opcodes so that they are in numerical order.

Mitch adds a client interface to the VF driver, in preparation for the
upcoming RDMA-capable hardware (and client driver).  Cleaned up the
client interface in the PF driver, since it was originally over
engineered to handle multiple clients on multiple netdevs, but that
did not happen and now there will be one client per driver, so apply
the "KISS" (Keep It Simple & Stupid) to the i40e client interface.
Bumped the number of MAC filters an untrusted VF can create.

Jake fixes an issue where a recent refactor of queue pairs accidentally
added all remaining vecotrs to the num_lan_msix which can adversely
affect performance.

Lihong fixes an ethtool issue with x722 devices where "-e" will error
out since its EEPROM has a scope limit at offset 0x5B9FFF, so set the
EEPROM length to the scope limit.  Also fixed an issue where RSS
offloading only worked on PF0.

Filip cleans up and clarifies code comment so there is no confusion
about MAC/VLAN filter initialization routine.

Alex adds support for DMA_ATTR_SKIP_CPU_SYNC and DMA_ATTR_WEAK_ORDERING,
which improves performance on architectures that implement either one.

Harshitha cleans up confusion on flags disabled due to hardware limitation
versus featured disabled by the user, so rename auto_disable_flags to
hw_disabled_flags to avoid the confusion.

v2: Merged patch #1 and #4 in first version to make patch #3 in this
    series based on feedback from David Miller.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 101c4314 b77ac975
...@@ -348,16 +348,23 @@ struct i40e_pf { ...@@ -348,16 +348,23 @@ struct i40e_pf {
#define I40E_FLAG_TRUE_PROMISC_SUPPORT BIT_ULL(51) #define I40E_FLAG_TRUE_PROMISC_SUPPORT BIT_ULL(51)
#define I40E_FLAG_HAVE_CRT_RETIMER BIT_ULL(52) #define I40E_FLAG_HAVE_CRT_RETIMER BIT_ULL(52)
#define I40E_FLAG_PTP_L4_CAPABLE BIT_ULL(53) #define I40E_FLAG_PTP_L4_CAPABLE BIT_ULL(53)
#define I40E_FLAG_WOL_MC_MAGIC_PKT_WAKE BIT_ULL(54) #define I40E_FLAG_CLIENT_RESET BIT_ULL(54)
#define I40E_FLAG_TEMP_LINK_POLLING BIT_ULL(55) #define I40E_FLAG_TEMP_LINK_POLLING BIT_ULL(55)
#define I40E_FLAG_CLIENT_L2_CHANGE BIT_ULL(56)
#define I40E_FLAG_WOL_MC_MAGIC_PKT_WAKE BIT_ULL(57)
/* tracks features that get auto disabled by errors */ /* Tracks features that are disabled due to hw limitations.
u64 auto_disable_flags; * If a bit is set here, it means that the corresponding
* bit in the 'flags' field is cleared i.e that feature
* is disabled
*/
u64 hw_disabled_flags;
#ifdef I40E_FCOE #ifdef I40E_FCOE
struct i40e_fcoe fcoe; struct i40e_fcoe fcoe;
#endif /* I40E_FCOE */ #endif /* I40E_FCOE */
struct i40e_client_instance *cinst;
bool stat_offsets_loaded; bool stat_offsets_loaded;
struct i40e_hw_port_stats stats; struct i40e_hw_port_stats stats;
struct i40e_hw_port_stats stats_offsets; struct i40e_hw_port_stats stats_offsets;
...@@ -813,8 +820,7 @@ void i40e_notify_client_of_l2_param_changes(struct i40e_vsi *vsi); ...@@ -813,8 +820,7 @@ void i40e_notify_client_of_l2_param_changes(struct i40e_vsi *vsi);
void i40e_notify_client_of_netdev_close(struct i40e_vsi *vsi, bool reset); void i40e_notify_client_of_netdev_close(struct i40e_vsi *vsi, bool reset);
void i40e_notify_client_of_vf_enable(struct i40e_pf *pf, u32 num_vfs); void i40e_notify_client_of_vf_enable(struct i40e_pf *pf, u32 num_vfs);
void i40e_notify_client_of_vf_reset(struct i40e_pf *pf, u32 vf_id); void i40e_notify_client_of_vf_reset(struct i40e_pf *pf, u32 vf_id);
int i40e_vf_client_capable(struct i40e_pf *pf, u32 vf_id, int i40e_vf_client_capable(struct i40e_pf *pf, u32 vf_id);
enum i40e_client_type type);
/** /**
* i40e_irq_dynamic_enable - Enable default interrupt generation settings * i40e_irq_dynamic_enable - Enable default interrupt generation settings
* @vsi: pointer to a vsi * @vsi: pointer to a vsi
......
...@@ -132,6 +132,10 @@ enum i40e_admin_queue_opc { ...@@ -132,6 +132,10 @@ enum i40e_admin_queue_opc {
i40e_aqc_opc_list_func_capabilities = 0x000A, i40e_aqc_opc_list_func_capabilities = 0x000A,
i40e_aqc_opc_list_dev_capabilities = 0x000B, i40e_aqc_opc_list_dev_capabilities = 0x000B,
/* Proxy commands */
i40e_aqc_opc_set_proxy_config = 0x0104,
i40e_aqc_opc_set_ns_proxy_table_entry = 0x0105,
/* LAA */ /* LAA */
i40e_aqc_opc_mac_address_read = 0x0107, i40e_aqc_opc_mac_address_read = 0x0107,
i40e_aqc_opc_mac_address_write = 0x0108, i40e_aqc_opc_mac_address_write = 0x0108,
...@@ -139,6 +143,10 @@ enum i40e_admin_queue_opc { ...@@ -139,6 +143,10 @@ enum i40e_admin_queue_opc {
/* PXE */ /* PXE */
i40e_aqc_opc_clear_pxe_mode = 0x0110, i40e_aqc_opc_clear_pxe_mode = 0x0110,
/* WoL commands */
i40e_aqc_opc_set_wol_filter = 0x0120,
i40e_aqc_opc_get_wake_reason = 0x0121,
/* internal switch commands */ /* internal switch commands */
i40e_aqc_opc_get_switch_config = 0x0200, i40e_aqc_opc_get_switch_config = 0x0200,
i40e_aqc_opc_add_statistics = 0x0201, i40e_aqc_opc_add_statistics = 0x0201,
...@@ -177,6 +185,7 @@ enum i40e_admin_queue_opc { ...@@ -177,6 +185,7 @@ enum i40e_admin_queue_opc {
i40e_aqc_opc_remove_control_packet_filter = 0x025B, i40e_aqc_opc_remove_control_packet_filter = 0x025B,
i40e_aqc_opc_add_cloud_filters = 0x025C, i40e_aqc_opc_add_cloud_filters = 0x025C,
i40e_aqc_opc_remove_cloud_filters = 0x025D, i40e_aqc_opc_remove_cloud_filters = 0x025D,
i40e_aqc_opc_clear_wol_switch_filters = 0x025E,
i40e_aqc_opc_add_mirror_rule = 0x0260, i40e_aqc_opc_add_mirror_rule = 0x0260,
i40e_aqc_opc_delete_mirror_rule = 0x0261, i40e_aqc_opc_delete_mirror_rule = 0x0261,
...@@ -563,6 +572,56 @@ struct i40e_aqc_clear_pxe { ...@@ -563,6 +572,56 @@ struct i40e_aqc_clear_pxe {
I40E_CHECK_CMD_LENGTH(i40e_aqc_clear_pxe); I40E_CHECK_CMD_LENGTH(i40e_aqc_clear_pxe);
/* Set WoL Filter (0x0120) */
struct i40e_aqc_set_wol_filter {
__le16 filter_index;
#define I40E_AQC_MAX_NUM_WOL_FILTERS 8
#define I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_SHIFT 15
#define I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_MASK (0x1 << \
I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_SHIFT)
#define I40E_AQC_SET_WOL_FILTER_INDEX_SHIFT 0
#define I40E_AQC_SET_WOL_FILTER_INDEX_MASK (0x7 << \
I40E_AQC_SET_WOL_FILTER_INDEX_SHIFT)
__le16 cmd_flags;
#define I40E_AQC_SET_WOL_FILTER 0x8000
#define I40E_AQC_SET_WOL_FILTER_NO_TCO_WOL 0x4000
#define I40E_AQC_SET_WOL_FILTER_ACTION_CLEAR 0
#define I40E_AQC_SET_WOL_FILTER_ACTION_SET 1
__le16 valid_flags;
#define I40E_AQC_SET_WOL_FILTER_ACTION_VALID 0x8000
#define I40E_AQC_SET_WOL_FILTER_NO_TCO_ACTION_VALID 0x4000
u8 reserved[2];
__le32 address_high;
__le32 address_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_set_wol_filter);
struct i40e_aqc_set_wol_filter_data {
u8 filter[128];
u8 mask[16];
};
I40E_CHECK_STRUCT_LEN(0x90, i40e_aqc_set_wol_filter_data);
/* Get Wake Reason (0x0121) */
struct i40e_aqc_get_wake_reason_completion {
u8 reserved_1[2];
__le16 wake_reason;
#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_SHIFT 0
#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_MASK (0xFF << \
I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_SHIFT)
#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_SHIFT 8
#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_MASK (0xFF << \
I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_SHIFT)
u8 reserved_2[12];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_get_wake_reason_completion);
/* Switch configuration commands (0x02xx) */ /* Switch configuration commands (0x02xx) */
/* Used by many indirect commands that only pass an seid and a buffer in the /* Used by many indirect commands that only pass an seid and a buffer in the
...@@ -645,6 +704,8 @@ struct i40e_aqc_set_port_parameters { ...@@ -645,6 +704,8 @@ struct i40e_aqc_set_port_parameters {
#define I40E_AQ_SET_P_PARAMS_PAD_SHORT_PACKETS 2 /* must set! */ #define I40E_AQ_SET_P_PARAMS_PAD_SHORT_PACKETS 2 /* must set! */
#define I40E_AQ_SET_P_PARAMS_DOUBLE_VLAN_ENA 4 #define I40E_AQ_SET_P_PARAMS_DOUBLE_VLAN_ENA 4
__le16 bad_frame_vsi; __le16 bad_frame_vsi;
#define I40E_AQ_SET_P_PARAMS_BFRAME_SEID_SHIFT 0x0
#define I40E_AQ_SET_P_PARAMS_BFRAME_SEID_MASK 0x3FF
__le16 default_seid; /* reserved for command */ __le16 default_seid; /* reserved for command */
u8 reserved[10]; u8 reserved[10];
}; };
...@@ -696,6 +757,7 @@ I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp); ...@@ -696,6 +757,7 @@ I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp);
/* Set Switch Configuration (direct 0x0205) */ /* Set Switch Configuration (direct 0x0205) */
struct i40e_aqc_set_switch_config { struct i40e_aqc_set_switch_config {
__le16 flags; __le16 flags;
/* flags used for both fields below */
#define I40E_AQ_SET_SWITCH_CFG_PROMISC 0x0001 #define I40E_AQ_SET_SWITCH_CFG_PROMISC 0x0001
#define I40E_AQ_SET_SWITCH_CFG_L2_FILTER 0x0002 #define I40E_AQ_SET_SWITCH_CFG_L2_FILTER 0x0002
__le16 valid_flags; __le16 valid_flags;
...@@ -1844,11 +1906,12 @@ struct i40e_aqc_get_link_status { ...@@ -1844,11 +1906,12 @@ struct i40e_aqc_get_link_status {
#define I40E_AQ_CONFIG_FEC_RS_ENA 0x02 #define I40E_AQ_CONFIG_FEC_RS_ENA 0x02
#define I40E_AQ_CONFIG_CRC_ENA 0x04 #define I40E_AQ_CONFIG_CRC_ENA 0x04
#define I40E_AQ_CONFIG_PACING_MASK 0x78 #define I40E_AQ_CONFIG_PACING_MASK 0x78
u8 external_power_ability; u8 power_desc;
#define I40E_AQ_LINK_POWER_CLASS_1 0x00 #define I40E_AQ_LINK_POWER_CLASS_1 0x00
#define I40E_AQ_LINK_POWER_CLASS_2 0x01 #define I40E_AQ_LINK_POWER_CLASS_2 0x01
#define I40E_AQ_LINK_POWER_CLASS_3 0x02 #define I40E_AQ_LINK_POWER_CLASS_3 0x02
#define I40E_AQ_LINK_POWER_CLASS_4 0x03 #define I40E_AQ_LINK_POWER_CLASS_4 0x03
#define I40E_AQ_PWR_CLASS_MASK 0x03
u8 reserved[4]; u8 reserved[4];
}; };
......
...@@ -32,16 +32,10 @@ ...@@ -32,16 +32,10 @@
#include "i40e_client.h" #include "i40e_client.h"
static const char i40e_client_interface_version_str[] = I40E_CLIENT_VERSION_STR; static const char i40e_client_interface_version_str[] = I40E_CLIENT_VERSION_STR;
static struct i40e_client *registered_client;
static LIST_HEAD(i40e_devices); static LIST_HEAD(i40e_devices);
static DEFINE_MUTEX(i40e_device_mutex); static DEFINE_MUTEX(i40e_device_mutex);
static LIST_HEAD(i40e_clients);
static DEFINE_MUTEX(i40e_client_mutex);
static LIST_HEAD(i40e_client_instances);
static DEFINE_MUTEX(i40e_client_instance_mutex);
static int i40e_client_virtchnl_send(struct i40e_info *ldev, static int i40e_client_virtchnl_send(struct i40e_info *ldev,
struct i40e_client *client, struct i40e_client *client,
u32 vf_id, u8 *msg, u16 len); u32 vf_id, u8 *msg, u16 len);
...@@ -66,28 +60,6 @@ static struct i40e_ops i40e_lan_ops = { ...@@ -66,28 +60,6 @@ static struct i40e_ops i40e_lan_ops = {
.update_vsi_ctxt = i40e_client_update_vsi_ctxt, .update_vsi_ctxt = i40e_client_update_vsi_ctxt,
}; };
/**
* i40e_client_type_to_vsi_type - convert client type to vsi type
* @client_type: the i40e_client type
*
* returns the related vsi type value
**/
static
enum i40e_vsi_type i40e_client_type_to_vsi_type(enum i40e_client_type type)
{
switch (type) {
case I40E_CLIENT_IWARP:
return I40E_VSI_IWARP;
case I40E_CLIENT_VMDQ2:
return I40E_VSI_VMDQ2;
default:
pr_err("i40e: Client type unknown\n");
return I40E_VSI_TYPE_UNKNOWN;
}
}
/** /**
* i40e_client_get_params - Get the params that can change at runtime * i40e_client_get_params - Get the params that can change at runtime
* @vsi: the VSI with the message * @vsi: the VSI with the message
...@@ -134,31 +106,22 @@ int i40e_client_get_params(struct i40e_vsi *vsi, struct i40e_params *params) ...@@ -134,31 +106,22 @@ int i40e_client_get_params(struct i40e_vsi *vsi, struct i40e_params *params)
void void
i40e_notify_client_of_vf_msg(struct i40e_vsi *vsi, u32 vf_id, u8 *msg, u16 len) i40e_notify_client_of_vf_msg(struct i40e_vsi *vsi, u32 vf_id, u8 *msg, u16 len)
{ {
struct i40e_client_instance *cdev; struct i40e_pf *pf = vsi->back;
struct i40e_client_instance *cdev = pf->cinst;
if (!vsi) if (!cdev || !cdev->client)
return;
if (!cdev->client->ops || !cdev->client->ops->virtchnl_receive) {
dev_dbg(&pf->pdev->dev,
"Cannot locate client instance virtual channel receive routine\n");
return;
}
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
dev_dbg(&pf->pdev->dev, "Client is not open, abort virtchnl_receive\n");
return; return;
mutex_lock(&i40e_client_instance_mutex);
list_for_each_entry(cdev, &i40e_client_instances, list) {
if (cdev->lan_info.pf == vsi->back) {
if (!cdev->client ||
!cdev->client->ops ||
!cdev->client->ops->virtchnl_receive) {
dev_dbg(&vsi->back->pdev->dev,
"Cannot locate client instance virtual channel receive routine\n");
continue;
}
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED,
&cdev->state)) {
dev_dbg(&vsi->back->pdev->dev, "Client is not open, abort virtchnl_receive\n");
continue;
}
cdev->client->ops->virtchnl_receive(&cdev->lan_info,
cdev->client,
vf_id, msg, len);
}
} }
mutex_unlock(&i40e_client_instance_mutex); cdev->client->ops->virtchnl_receive(&cdev->lan_info, cdev->client,
vf_id, msg, len);
} }
/** /**
...@@ -169,39 +132,28 @@ i40e_notify_client_of_vf_msg(struct i40e_vsi *vsi, u32 vf_id, u8 *msg, u16 len) ...@@ -169,39 +132,28 @@ i40e_notify_client_of_vf_msg(struct i40e_vsi *vsi, u32 vf_id, u8 *msg, u16 len)
**/ **/
void i40e_notify_client_of_l2_param_changes(struct i40e_vsi *vsi) void i40e_notify_client_of_l2_param_changes(struct i40e_vsi *vsi)
{ {
struct i40e_client_instance *cdev; struct i40e_pf *pf = vsi->back;
struct i40e_client_instance *cdev = pf->cinst;
struct i40e_params params; struct i40e_params params;
if (!vsi) if (!cdev || !cdev->client)
return;
if (!cdev->client->ops || !cdev->client->ops->l2_param_change) {
dev_dbg(&vsi->back->pdev->dev,
"Cannot locate client instance l2_param_change routine\n");
return;
}
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
dev_dbg(&vsi->back->pdev->dev, "Client is not open, abort l2 param change\n");
return; return;
mutex_lock(&i40e_client_instance_mutex);
list_for_each_entry(cdev, &i40e_client_instances, list) {
if (cdev->lan_info.pf == vsi->back) {
if (!cdev->client ||
!cdev->client->ops ||
!cdev->client->ops->l2_param_change) {
dev_dbg(&vsi->back->pdev->dev,
"Cannot locate client instance l2_param_change routine\n");
continue;
}
memset(&params, 0, sizeof(params));
i40e_client_get_params(vsi, &params);
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED,
&cdev->state)) {
dev_dbg(&vsi->back->pdev->dev, "Client is not open, abort l2 param change\n");
continue;
}
cdev->lan_info.params = params;
cdev->client->ops->l2_param_change(&cdev->lan_info,
cdev->client,
&params);
}
} }
mutex_unlock(&i40e_client_instance_mutex); memcpy(&cdev->lan_info.params, &params, sizeof(struct i40e_params));
cdev->client->ops->l2_param_change(&cdev->lan_info, cdev->client,
&params);
} }
/** /**
* i40e_client_release_qvlist * i40e_client_release_qvlist - release MSI-X vector mapping for client
* @ldev: pointer to L2 context. * @ldev: pointer to L2 context.
* *
**/ **/
...@@ -237,26 +189,19 @@ static void i40e_client_release_qvlist(struct i40e_info *ldev) ...@@ -237,26 +189,19 @@ static void i40e_client_release_qvlist(struct i40e_info *ldev)
**/ **/
void i40e_notify_client_of_netdev_close(struct i40e_vsi *vsi, bool reset) void i40e_notify_client_of_netdev_close(struct i40e_vsi *vsi, bool reset)
{ {
struct i40e_client_instance *cdev; struct i40e_pf *pf = vsi->back;
struct i40e_client_instance *cdev = pf->cinst;
if (!vsi) if (!cdev || !cdev->client)
return;
if (!cdev->client->ops || !cdev->client->ops->close) {
dev_dbg(&vsi->back->pdev->dev,
"Cannot locate client instance close routine\n");
return; return;
mutex_lock(&i40e_client_instance_mutex);
list_for_each_entry(cdev, &i40e_client_instances, list) {
if (cdev->lan_info.netdev == vsi->netdev) {
if (!cdev->client ||
!cdev->client->ops || !cdev->client->ops->close) {
dev_dbg(&vsi->back->pdev->dev,
"Cannot locate client instance close routine\n");
continue;
}
cdev->client->ops->close(&cdev->lan_info, cdev->client,
reset);
clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);
i40e_client_release_qvlist(&cdev->lan_info);
}
} }
mutex_unlock(&i40e_client_instance_mutex); cdev->client->ops->close(&cdev->lan_info, cdev->client, reset);
clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);
i40e_client_release_qvlist(&cdev->lan_info);
} }
/** /**
...@@ -268,30 +213,20 @@ void i40e_notify_client_of_netdev_close(struct i40e_vsi *vsi, bool reset) ...@@ -268,30 +213,20 @@ void i40e_notify_client_of_netdev_close(struct i40e_vsi *vsi, bool reset)
**/ **/
void i40e_notify_client_of_vf_reset(struct i40e_pf *pf, u32 vf_id) void i40e_notify_client_of_vf_reset(struct i40e_pf *pf, u32 vf_id)
{ {
struct i40e_client_instance *cdev; struct i40e_client_instance *cdev = pf->cinst;
if (!pf) if (!cdev || !cdev->client)
return;
if (!cdev->client->ops || !cdev->client->ops->vf_reset) {
dev_dbg(&pf->pdev->dev,
"Cannot locate client instance VF reset routine\n");
return;
}
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
dev_dbg(&pf->pdev->dev, "Client is not open, abort vf-reset\n");
return; return;
mutex_lock(&i40e_client_instance_mutex);
list_for_each_entry(cdev, &i40e_client_instances, list) {
if (cdev->lan_info.pf == pf) {
if (!cdev->client ||
!cdev->client->ops ||
!cdev->client->ops->vf_reset) {
dev_dbg(&pf->pdev->dev,
"Cannot locate client instance VF reset routine\n");
continue;
}
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED,
&cdev->state)) {
dev_dbg(&pf->pdev->dev, "Client is not open, abort vf-reset\n");
continue;
}
cdev->client->ops->vf_reset(&cdev->lan_info,
cdev->client, vf_id);
}
} }
mutex_unlock(&i40e_client_instance_mutex); cdev->client->ops->vf_reset(&cdev->lan_info, cdev->client, vf_id);
} }
/** /**
...@@ -303,30 +238,21 @@ void i40e_notify_client_of_vf_reset(struct i40e_pf *pf, u32 vf_id) ...@@ -303,30 +238,21 @@ void i40e_notify_client_of_vf_reset(struct i40e_pf *pf, u32 vf_id)
**/ **/
void i40e_notify_client_of_vf_enable(struct i40e_pf *pf, u32 num_vfs) void i40e_notify_client_of_vf_enable(struct i40e_pf *pf, u32 num_vfs)
{ {
struct i40e_client_instance *cdev; struct i40e_client_instance *cdev = pf->cinst;
if (!pf) if (!cdev || !cdev->client)
return;
if (!cdev->client->ops || !cdev->client->ops->vf_enable) {
dev_dbg(&pf->pdev->dev,
"Cannot locate client instance VF enable routine\n");
return;
}
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED,
&cdev->state)) {
dev_dbg(&pf->pdev->dev, "Client is not open, abort vf-enable\n");
return; return;
mutex_lock(&i40e_client_instance_mutex);
list_for_each_entry(cdev, &i40e_client_instances, list) {
if (cdev->lan_info.pf == pf) {
if (!cdev->client ||
!cdev->client->ops ||
!cdev->client->ops->vf_enable) {
dev_dbg(&pf->pdev->dev,
"Cannot locate client instance VF enable routine\n");
continue;
}
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED,
&cdev->state)) {
dev_dbg(&pf->pdev->dev, "Client is not open, abort vf-enable\n");
continue;
}
cdev->client->ops->vf_enable(&cdev->lan_info,
cdev->client, num_vfs);
}
} }
mutex_unlock(&i40e_client_instance_mutex); cdev->client->ops->vf_enable(&cdev->lan_info, cdev->client, num_vfs);
} }
/** /**
...@@ -337,37 +263,25 @@ void i40e_notify_client_of_vf_enable(struct i40e_pf *pf, u32 num_vfs) ...@@ -337,37 +263,25 @@ void i40e_notify_client_of_vf_enable(struct i40e_pf *pf, u32 num_vfs)
* If there is a client of the specified type attached to this PF, call * If there is a client of the specified type attached to this PF, call
* its vf_capable routine * its vf_capable routine
**/ **/
int i40e_vf_client_capable(struct i40e_pf *pf, u32 vf_id, int i40e_vf_client_capable(struct i40e_pf *pf, u32 vf_id)
enum i40e_client_type type)
{ {
struct i40e_client_instance *cdev; struct i40e_client_instance *cdev = pf->cinst;
int capable = false; int capable = false;
if (!pf) if (!cdev || !cdev->client)
return false; goto out;
mutex_lock(&i40e_client_instance_mutex); if (!cdev->client->ops || !cdev->client->ops->vf_capable) {
list_for_each_entry(cdev, &i40e_client_instances, list) { dev_info(&pf->pdev->dev,
if (cdev->lan_info.pf == pf) { "Cannot locate client instance VF capability routine\n");
if (!cdev->client || goto out;
!cdev->client->ops ||
!cdev->client->ops->vf_capable ||
!(cdev->client->type == type)) {
dev_dbg(&pf->pdev->dev,
"Cannot locate client instance VF capability routine\n");
continue;
}
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED,
&cdev->state)) {
dev_dbg(&pf->pdev->dev, "Client is not open, abort vf-capable\n");
continue;
}
capable = cdev->client->ops->vf_capable(&cdev->lan_info,
cdev->client,
vf_id);
break;
}
} }
mutex_unlock(&i40e_client_instance_mutex); if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state))
goto out;
capable = cdev->client->ops->vf_capable(&cdev->lan_info,
cdev->client,
vf_id);
out:
return capable; return capable;
} }
...@@ -377,27 +291,19 @@ int i40e_vf_client_capable(struct i40e_pf *pf, u32 vf_id, ...@@ -377,27 +291,19 @@ int i40e_vf_client_capable(struct i40e_pf *pf, u32 vf_id,
* @client: pointer to a client struct in the client list. * @client: pointer to a client struct in the client list.
* @existing: if there was already an existing instance * @existing: if there was already an existing instance
* *
* Returns cdev ptr on success or if already exists, NULL on failure
**/ **/
static static void i40e_client_add_instance(struct i40e_pf *pf)
struct i40e_client_instance *i40e_client_add_instance(struct i40e_pf *pf,
struct i40e_client *client,
bool *existing)
{ {
struct i40e_client_instance *cdev; struct i40e_client_instance *cdev = NULL;
struct netdev_hw_addr *mac = NULL; struct netdev_hw_addr *mac = NULL;
struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi]; struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
mutex_lock(&i40e_client_instance_mutex); if (!registered_client || pf->cinst)
list_for_each_entry(cdev, &i40e_client_instances, list) { return;
if ((cdev->lan_info.pf == pf) && (cdev->client == client)) {
*existing = true;
goto out;
}
}
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev) if (!cdev)
goto out; return;
cdev->lan_info.pf = (void *)pf; cdev->lan_info.pf = (void *)pf;
cdev->lan_info.netdev = vsi->netdev; cdev->lan_info.netdev = vsi->netdev;
...@@ -417,7 +323,7 @@ struct i40e_client_instance *i40e_client_add_instance(struct i40e_pf *pf, ...@@ -417,7 +323,7 @@ struct i40e_client_instance *i40e_client_add_instance(struct i40e_pf *pf,
if (i40e_client_get_params(vsi, &cdev->lan_info.params)) { if (i40e_client_get_params(vsi, &cdev->lan_info.params)) {
kfree(cdev); kfree(cdev);
cdev = NULL; cdev = NULL;
goto out; return;
} }
cdev->lan_info.msix_count = pf->num_iwarp_msix; cdev->lan_info.msix_count = pf->num_iwarp_msix;
...@@ -430,41 +336,20 @@ struct i40e_client_instance *i40e_client_add_instance(struct i40e_pf *pf, ...@@ -430,41 +336,20 @@ struct i40e_client_instance *i40e_client_add_instance(struct i40e_pf *pf,
else else
dev_err(&pf->pdev->dev, "MAC address list is empty!\n"); dev_err(&pf->pdev->dev, "MAC address list is empty!\n");
cdev->client = client; cdev->client = registered_client;
INIT_LIST_HEAD(&cdev->list); pf->cinst = cdev;
list_add(&cdev->list, &i40e_client_instances);
out:
mutex_unlock(&i40e_client_instance_mutex);
return cdev;
} }
/** /**
* i40e_client_del_instance - removes a client instance from the list * i40e_client_del_instance - removes a client instance from the list
* @pf: pointer to the board struct * @pf: pointer to the board struct
* *
* Returns 0 on success or non-0 on error
**/ **/
static static
int i40e_client_del_instance(struct i40e_pf *pf, struct i40e_client *client) void i40e_client_del_instance(struct i40e_pf *pf)
{ {
struct i40e_client_instance *cdev, *tmp; kfree(pf->cinst);
int ret = -ENODEV; pf->cinst = NULL;
mutex_lock(&i40e_client_instance_mutex);
list_for_each_entry_safe(cdev, tmp, &i40e_client_instances, list) {
if ((cdev->lan_info.pf != pf) || (cdev->client != client))
continue;
dev_info(&pf->pdev->dev, "Deleted instance of Client %s, of dev %d bus=0x%02x func=0x%02x)\n",
client->name, pf->hw.pf_id,
pf->hw.bus.device, pf->hw.bus.func);
list_del(&cdev->list);
kfree(cdev);
ret = 0;
break;
}
mutex_unlock(&i40e_client_instance_mutex);
return ret;
} }
/** /**
...@@ -473,67 +358,50 @@ int i40e_client_del_instance(struct i40e_pf *pf, struct i40e_client *client) ...@@ -473,67 +358,50 @@ int i40e_client_del_instance(struct i40e_pf *pf, struct i40e_client *client)
**/ **/
void i40e_client_subtask(struct i40e_pf *pf) void i40e_client_subtask(struct i40e_pf *pf)
{ {
struct i40e_client *client = registered_client;
struct i40e_client_instance *cdev; struct i40e_client_instance *cdev;
struct i40e_client *client; struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
bool existing = false;
int ret = 0; int ret = 0;
if (!(pf->flags & I40E_FLAG_SERVICE_CLIENT_REQUESTED)) if (!(pf->flags & I40E_FLAG_SERVICE_CLIENT_REQUESTED))
return; return;
pf->flags &= ~I40E_FLAG_SERVICE_CLIENT_REQUESTED; pf->flags &= ~I40E_FLAG_SERVICE_CLIENT_REQUESTED;
cdev = pf->cinst;
/* If we're down or resetting, just bail */ /* If we're down or resetting, just bail */
if (test_bit(__I40E_DOWN, &pf->state) || if (test_bit(__I40E_DOWN, &pf->state) ||
test_bit(__I40E_CONFIG_BUSY, &pf->state)) test_bit(__I40E_CONFIG_BUSY, &pf->state))
return; return;
/* Check client state and instantiate client if client registered */ if (!client || !cdev)
mutex_lock(&i40e_client_mutex); return;
list_for_each_entry(client, &i40e_clients, list) {
/* first check client is registered */
if (!test_bit(__I40E_CLIENT_REGISTERED, &client->state))
continue;
/* Do we also need the LAN VSI to be up, to create instance */
if (!(client->flags & I40E_CLIENT_FLAGS_LAUNCH_ON_PROBE)) {
/* check if L2 VSI is up, if not we are not ready */
if (test_bit(__I40E_DOWN, &pf->vsi[pf->lan_vsi]->state))
continue;
} else {
dev_warn(&pf->pdev->dev, "This client %s is being instantiated at probe\n",
client->name);
}
/* Add the client instance to the instance list */
cdev = i40e_client_add_instance(pf, client, &existing);
if (!cdev)
continue;
if (!existing) {
dev_info(&pf->pdev->dev, "Added instance of Client %s to PF%d bus=0x%02x dev=0x%02x func=0x%02x\n",
client->name, pf->hw.pf_id,
pf->hw.bus.bus_id, pf->hw.bus.device,
pf->hw.bus.func);
}
mutex_lock(&i40e_client_instance_mutex); /* Here we handle client opens. If the client is down, but
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, * the netdev is up, then open the client.
&cdev->state)) { */
/* Send an Open request to the client */ if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
if (client->ops && client->ops->open) if (!test_bit(__I40E_DOWN, &vsi->state) &&
ret = client->ops->open(&cdev->lan_info, client->ops && client->ops->open) {
client); set_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);
if (!ret) { ret = client->ops->open(&cdev->lan_info, client);
set_bit(__I40E_CLIENT_INSTANCE_OPENED, if (ret) {
&cdev->state); /* Remove failed client instance */
} else { clear_bit(__I40E_CLIENT_INSTANCE_OPENED,
/* remove client instance */ &cdev->state);
i40e_client_del_instance(pf, client); i40e_client_del_instance(pf);
} }
} }
mutex_unlock(&i40e_client_instance_mutex); } else {
/* Likewise for client close. If the client is up, but the netdev
* is down, then close the client.
*/
if (test_bit(__I40E_DOWN, &vsi->state) &&
client->ops && client->ops->close) {
clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state);
client->ops->close(&cdev->lan_info, client, false);
i40e_client_release_qvlist(&cdev->lan_info);
}
} }
mutex_unlock(&i40e_client_mutex);
} }
/** /**
...@@ -601,7 +469,6 @@ int i40e_lan_del_device(struct i40e_pf *pf) ...@@ -601,7 +469,6 @@ int i40e_lan_del_device(struct i40e_pf *pf)
break; break;
} }
} }
mutex_unlock(&i40e_device_mutex); mutex_unlock(&i40e_device_mutex);
return ret; return ret;
} }
...@@ -610,22 +477,24 @@ int i40e_lan_del_device(struct i40e_pf *pf) ...@@ -610,22 +477,24 @@ int i40e_lan_del_device(struct i40e_pf *pf)
* i40e_client_release - release client specific resources * i40e_client_release - release client specific resources
* @client: pointer to the registered client * @client: pointer to the registered client
* *
* Return 0 on success or < 0 on error
**/ **/
static int i40e_client_release(struct i40e_client *client) static void i40e_client_release(struct i40e_client *client)
{ {
struct i40e_client_instance *cdev, *tmp; struct i40e_client_instance *cdev;
struct i40e_device *ldev;
struct i40e_pf *pf; struct i40e_pf *pf;
int ret = 0;
LIST_HEAD(cdevs_tmp); mutex_lock(&i40e_device_mutex);
list_for_each_entry(ldev, &i40e_devices, list) {
mutex_lock(&i40e_client_instance_mutex); pf = ldev->pf;
list_for_each_entry_safe(cdev, tmp, &i40e_client_instances, list) { cdev = pf->cinst;
if (strncmp(cdev->client->name, client->name, if (!cdev)
I40E_CLIENT_STR_LENGTH))
continue; continue;
pf = (struct i40e_pf *)cdev->lan_info.pf;
while (test_and_set_bit(__I40E_SERVICE_SCHED,
&pf->state))
usleep_range(500, 1000);
if (test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) { if (test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cdev->state)) {
if (client->ops && client->ops->close) if (client->ops && client->ops->close)
client->ops->close(&cdev->lan_info, client, client->ops->close(&cdev->lan_info, client,
...@@ -637,18 +506,13 @@ static int i40e_client_release(struct i40e_client *client) ...@@ -637,18 +506,13 @@ static int i40e_client_release(struct i40e_client *client)
"Client %s instance for PF id %d closed\n", "Client %s instance for PF id %d closed\n",
client->name, pf->hw.pf_id); client->name, pf->hw.pf_id);
} }
/* delete the client instance from the list */ /* delete the client instance */
list_move(&cdev->list, &cdevs_tmp); i40e_client_del_instance(pf);
dev_info(&pf->pdev->dev, "Deleted client instance of Client %s\n", dev_info(&pf->pdev->dev, "Deleted client instance of Client %s\n",
client->name); client->name);
clear_bit(__I40E_SERVICE_SCHED, &pf->state);
} }
mutex_unlock(&i40e_client_instance_mutex); mutex_unlock(&i40e_device_mutex);
/* free the client device and release its vsi */
list_for_each_entry_safe(cdev, tmp, &cdevs_tmp, list) {
kfree(cdev);
}
return ret;
} }
/** /**
...@@ -664,6 +528,7 @@ static void i40e_client_prepare(struct i40e_client *client) ...@@ -664,6 +528,7 @@ static void i40e_client_prepare(struct i40e_client *client)
mutex_lock(&i40e_device_mutex); mutex_lock(&i40e_device_mutex);
list_for_each_entry(ldev, &i40e_devices, list) { list_for_each_entry(ldev, &i40e_devices, list) {
pf = ldev->pf; pf = ldev->pf;
i40e_client_add_instance(pf);
/* Start the client subtask */ /* Start the client subtask */
pf->flags |= I40E_FLAG_SERVICE_CLIENT_REQUESTED; pf->flags |= I40E_FLAG_SERVICE_CLIENT_REQUESTED;
i40e_service_event_schedule(pf); i40e_service_event_schedule(pf);
...@@ -792,8 +657,8 @@ static void i40e_client_request_reset(struct i40e_info *ldev, ...@@ -792,8 +657,8 @@ static void i40e_client_request_reset(struct i40e_info *ldev,
break; break;
default: default:
dev_warn(&pf->pdev->dev, dev_warn(&pf->pdev->dev,
"Client %s instance for PF id %d request an unsupported reset: %d.\n", "Client for PF id %d requested an unsupported reset: %d.\n",
client->name, pf->hw.pf_id, reset_level); pf->hw.pf_id, reset_level);
break; break;
} }
...@@ -852,8 +717,8 @@ static int i40e_client_update_vsi_ctxt(struct i40e_info *ldev, ...@@ -852,8 +717,8 @@ static int i40e_client_update_vsi_ctxt(struct i40e_info *ldev,
} else { } else {
update = false; update = false;
dev_warn(&pf->pdev->dev, dev_warn(&pf->pdev->dev,
"Client %s instance for PF id %d request an unsupported Config: %x.\n", "Client for PF id %d request an unsupported Config: %x.\n",
client->name, pf->hw.pf_id, flag); pf->hw.pf_id, flag);
} }
if (update) { if (update) {
...@@ -878,7 +743,6 @@ static int i40e_client_update_vsi_ctxt(struct i40e_info *ldev, ...@@ -878,7 +743,6 @@ static int i40e_client_update_vsi_ctxt(struct i40e_info *ldev,
int i40e_register_client(struct i40e_client *client) int i40e_register_client(struct i40e_client *client)
{ {
int ret = 0; int ret = 0;
enum i40e_vsi_type vsi_type;
if (!client) { if (!client) {
ret = -EIO; ret = -EIO;
...@@ -891,11 +755,9 @@ int i40e_register_client(struct i40e_client *client) ...@@ -891,11 +755,9 @@ int i40e_register_client(struct i40e_client *client)
goto out; goto out;
} }
mutex_lock(&i40e_client_mutex); if (registered_client) {
if (i40e_client_is_registered(client)) {
pr_info("i40e: Client %s has already been registered!\n", pr_info("i40e: Client %s has already been registered!\n",
client->name); client->name);
mutex_unlock(&i40e_client_mutex);
ret = -EEXIST; ret = -EEXIST;
goto out; goto out;
} }
...@@ -908,22 +770,11 @@ int i40e_register_client(struct i40e_client *client) ...@@ -908,22 +770,11 @@ int i40e_register_client(struct i40e_client *client)
client->version.major, client->version.minor, client->version.major, client->version.minor,
client->version.build, client->version.build,
i40e_client_interface_version_str); i40e_client_interface_version_str);
mutex_unlock(&i40e_client_mutex);
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
vsi_type = i40e_client_type_to_vsi_type(client->type); registered_client = client;
if (vsi_type == I40E_VSI_TYPE_UNKNOWN) {
pr_info("i40e: Failed to register client %s due to unknown client type %d\n",
client->name, client->type);
mutex_unlock(&i40e_client_mutex);
ret = -EIO;
goto out;
}
list_add(&client->list, &i40e_clients);
set_bit(__I40E_CLIENT_REGISTERED, &client->state);
mutex_unlock(&i40e_client_mutex);
i40e_client_prepare(client); i40e_client_prepare(client);
...@@ -943,29 +794,21 @@ int i40e_unregister_client(struct i40e_client *client) ...@@ -943,29 +794,21 @@ int i40e_unregister_client(struct i40e_client *client)
{ {
int ret = 0; int ret = 0;
/* When a unregister request comes through we would have to send if (registered_client != client) {
* a close for each of the client instances that were opened.
* client_release function is called to handle this.
*/
mutex_lock(&i40e_client_mutex);
if (!client || i40e_client_release(client)) {
ret = -EIO;
goto out;
}
/* TODO: check if device is in reset, or if that matters? */
if (!i40e_client_is_registered(client)) {
pr_info("i40e: Client %s has not been registered\n", pr_info("i40e: Client %s has not been registered\n",
client->name); client->name);
ret = -ENODEV; ret = -ENODEV;
goto out; goto out;
} }
clear_bit(__I40E_CLIENT_REGISTERED, &client->state); registered_client = NULL;
list_del(&client->list); /* When a unregister request comes through we would have to send
pr_info("i40e: Unregistered client %s with return code %d\n", * a close for each of the client instances that were opened.
client->name, ret); * client_release function is called to handle this.
*/
i40e_client_release(client);
pr_info("i40e: Unregistered client %s\n", client->name);
out: out:
mutex_unlock(&i40e_client_mutex);
return ret; return ret;
} }
EXPORT_SYMBOL(i40e_unregister_client); EXPORT_SYMBOL(i40e_unregister_client);
...@@ -57,11 +57,6 @@ enum i40e_client_instance_state { ...@@ -57,11 +57,6 @@ enum i40e_client_instance_state {
__I40E_CLIENT_INSTANCE_OPENED, __I40E_CLIENT_INSTANCE_OPENED,
}; };
enum i40e_client_type {
I40E_CLIENT_IWARP,
I40E_CLIENT_VMDQ2
};
struct i40e_ops; struct i40e_ops;
struct i40e_client; struct i40e_client;
...@@ -214,7 +209,8 @@ struct i40e_client { ...@@ -214,7 +209,8 @@ struct i40e_client {
u32 flags; u32 flags;
#define I40E_CLIENT_FLAGS_LAUNCH_ON_PROBE BIT(0) #define I40E_CLIENT_FLAGS_LAUNCH_ON_PROBE BIT(0)
#define I40E_TX_FLAGS_NOTIFY_OTHER_EVENTS BIT(2) #define I40E_TX_FLAGS_NOTIFY_OTHER_EVENTS BIT(2)
enum i40e_client_type type; u8 type;
#define I40E_CLIENT_IWARP 0
const struct i40e_client_ops *ops; /* client ops provided by the client */ const struct i40e_client_ops *ops; /* client ops provided by the client */
}; };
......
...@@ -1165,6 +1165,11 @@ static int i40e_get_eeprom_len(struct net_device *netdev) ...@@ -1165,6 +1165,11 @@ static int i40e_get_eeprom_len(struct net_device *netdev)
struct i40e_hw *hw = &np->vsi->back->hw; struct i40e_hw *hw = &np->vsi->back->hw;
u32 val; u32 val;
#define X722_EEPROM_SCOPE_LIMIT 0x5B9FFF
if (hw->mac.type == I40E_MAC_X722) {
val = X722_EEPROM_SCOPE_LIMIT + 1;
return val;
}
val = (rd32(hw, I40E_GLPCI_LBARCTRL) val = (rd32(hw, I40E_GLPCI_LBARCTRL)
& I40E_GLPCI_LBARCTRL_FL_SIZE_MASK) & I40E_GLPCI_LBARCTRL_FL_SIZE_MASK)
>> I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT; >> I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT;
...@@ -2712,7 +2717,7 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi, ...@@ -2712,7 +2717,7 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED)) if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED) if (pf->hw_disabled_flags & I40E_FLAG_FD_SB_ENABLED)
return -ENOSPC; return -ENOSPC;
if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) || if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) ||
...@@ -3054,7 +3059,7 @@ static u32 i40e_get_priv_flags(struct net_device *dev) ...@@ -3054,7 +3059,7 @@ static u32 i40e_get_priv_flags(struct net_device *dev)
I40E_PRIV_FLAGS_FD_ATR : 0; I40E_PRIV_FLAGS_FD_ATR : 0;
ret_flags |= pf->flags & I40E_FLAG_VEB_STATS_ENABLED ? ret_flags |= pf->flags & I40E_FLAG_VEB_STATS_ENABLED ?
I40E_PRIV_FLAGS_VEB_STATS : 0; I40E_PRIV_FLAGS_VEB_STATS : 0;
ret_flags |= pf->auto_disable_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE ? ret_flags |= pf->hw_disabled_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE ?
0 : I40E_PRIV_FLAGS_HW_ATR_EVICT; 0 : I40E_PRIV_FLAGS_HW_ATR_EVICT;
if (pf->hw.pf_id == 0) { if (pf->hw.pf_id == 0) {
ret_flags |= pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT ? ret_flags |= pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT ?
...@@ -3094,7 +3099,7 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) ...@@ -3094,7 +3099,7 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
pf->flags |= I40E_FLAG_FD_ATR_ENABLED; pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
} else { } else {
pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED; pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
pf->auto_disable_flags |= I40E_FLAG_FD_ATR_ENABLED; pf->hw_disabled_flags |= I40E_FLAG_FD_ATR_ENABLED;
/* flush current ATR settings */ /* flush current ATR settings */
set_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state); set_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state);
...@@ -3139,9 +3144,9 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) ...@@ -3139,9 +3144,9 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
if ((flags & I40E_PRIV_FLAGS_HW_ATR_EVICT) && if ((flags & I40E_PRIV_FLAGS_HW_ATR_EVICT) &&
(pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE)) (pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE))
pf->auto_disable_flags &= ~I40E_FLAG_HW_ATR_EVICT_CAPABLE; pf->hw_disabled_flags &= ~I40E_FLAG_HW_ATR_EVICT_CAPABLE;
else else
pf->auto_disable_flags |= I40E_FLAG_HW_ATR_EVICT_CAPABLE; pf->hw_disabled_flags |= I40E_FLAG_HW_ATR_EVICT_CAPABLE;
/* if needed, issue reset to cause things to take effect */ /* if needed, issue reset to cause things to take effect */
if (reset_required) if (reset_required)
......
...@@ -39,9 +39,9 @@ static const char i40e_driver_string[] = ...@@ -39,9 +39,9 @@ static const char i40e_driver_string[] =
#define DRV_KERN "-k" #define DRV_KERN "-k"
#define DRV_VERSION_MAJOR 1 #define DRV_VERSION_MAJOR 2
#define DRV_VERSION_MINOR 6 #define DRV_VERSION_MINOR 1
#define DRV_VERSION_BUILD 27 #define DRV_VERSION_BUILD 7
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
__stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_MINOR) "." \
__stringify(DRV_VERSION_BUILD) DRV_KERN __stringify(DRV_VERSION_BUILD) DRV_KERN
...@@ -1101,13 +1101,13 @@ static void i40e_update_pf_stats(struct i40e_pf *pf) ...@@ -1101,13 +1101,13 @@ static void i40e_update_pf_stats(struct i40e_pf *pf)
&osd->rx_lpi_count, &nsd->rx_lpi_count); &osd->rx_lpi_count, &nsd->rx_lpi_count);
if (pf->flags & I40E_FLAG_FD_SB_ENABLED && if (pf->flags & I40E_FLAG_FD_SB_ENABLED &&
!(pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) !(pf->hw_disabled_flags & I40E_FLAG_FD_SB_ENABLED))
nsd->fd_sb_status = true; nsd->fd_sb_status = true;
else else
nsd->fd_sb_status = false; nsd->fd_sb_status = false;
if (pf->flags & I40E_FLAG_FD_ATR_ENABLED && if (pf->flags & I40E_FLAG_FD_ATR_ENABLED &&
!(pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) !(pf->hw_disabled_flags & I40E_FLAG_FD_ATR_ENABLED))
nsd->fd_atr_status = true; nsd->fd_atr_status = true;
else else
nsd->fd_atr_status = false; nsd->fd_atr_status = false;
...@@ -2487,13 +2487,15 @@ static int i40e_change_mtu(struct net_device *netdev, int new_mtu) ...@@ -2487,13 +2487,15 @@ static int i40e_change_mtu(struct net_device *netdev, int new_mtu)
{ {
struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_netdev_priv *np = netdev_priv(netdev);
struct i40e_vsi *vsi = np->vsi; struct i40e_vsi *vsi = np->vsi;
struct i40e_pf *pf = vsi->back;
netdev_info(netdev, "changing MTU from %d to %d\n", netdev_info(netdev, "changing MTU from %d to %d\n",
netdev->mtu, new_mtu); netdev->mtu, new_mtu);
netdev->mtu = new_mtu; netdev->mtu = new_mtu;
if (netif_running(netdev)) if (netif_running(netdev))
i40e_vsi_reinit_locked(vsi); i40e_vsi_reinit_locked(vsi);
i40e_notify_client_of_l2_param_changes(vsi); pf->flags |= (I40E_FLAG_SERVICE_CLIENT_REQUESTED |
I40E_FLAG_CLIENT_L2_CHANGE);
return 0; return 0;
} }
...@@ -4463,17 +4465,16 @@ static void i40e_napi_disable_all(struct i40e_vsi *vsi) ...@@ -4463,17 +4465,16 @@ static void i40e_napi_disable_all(struct i40e_vsi *vsi)
**/ **/
static void i40e_vsi_close(struct i40e_vsi *vsi) static void i40e_vsi_close(struct i40e_vsi *vsi)
{ {
bool reset = false; struct i40e_pf *pf = vsi->back;
if (!test_and_set_bit(__I40E_DOWN, &vsi->state)) if (!test_and_set_bit(__I40E_DOWN, &vsi->state))
i40e_down(vsi); i40e_down(vsi);
i40e_vsi_free_irq(vsi); i40e_vsi_free_irq(vsi);
i40e_vsi_free_tx_resources(vsi); i40e_vsi_free_tx_resources(vsi);
i40e_vsi_free_rx_resources(vsi); i40e_vsi_free_rx_resources(vsi);
vsi->current_netdev_flags = 0; vsi->current_netdev_flags = 0;
if (test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state)) pf->flags |= I40E_FLAG_SERVICE_CLIENT_REQUESTED;
reset = true; if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state))
i40e_notify_client_of_netdev_close(vsi, reset); pf->flags |= I40E_FLAG_CLIENT_RESET;
} }
/** /**
...@@ -5466,7 +5467,7 @@ static int i40e_up_complete(struct i40e_vsi *vsi) ...@@ -5466,7 +5467,7 @@ static int i40e_up_complete(struct i40e_vsi *vsi)
/* reset fd counters */ /* reset fd counters */
pf->fd_add_err = pf->fd_atr_cnt = 0; pf->fd_add_err = pf->fd_atr_cnt = 0;
if (pf->fd_tcp_rule > 0) { if (pf->fd_tcp_rule > 0) {
pf->auto_disable_flags |= I40E_FLAG_FD_ATR_ENABLED; pf->hw_disabled_flags |= I40E_FLAG_FD_ATR_ENABLED;
if (I40E_DEBUG_FD & pf->hw.debug_mask) if (I40E_DEBUG_FD & pf->hw.debug_mask)
dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 exist\n"); dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 exist\n");
pf->fd_tcp_rule = 0; pf->fd_tcp_rule = 0;
...@@ -5542,8 +5543,6 @@ void i40e_down(struct i40e_vsi *vsi) ...@@ -5542,8 +5543,6 @@ void i40e_down(struct i40e_vsi *vsi)
i40e_clean_rx_ring(vsi->rx_rings[i]); i40e_clean_rx_ring(vsi->rx_rings[i]);
} }
i40e_notify_client_of_netdev_close(vsi, false);
} }
/** /**
...@@ -6021,8 +6020,8 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf, ...@@ -6021,8 +6020,8 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
i40e_service_event_schedule(pf); i40e_service_event_schedule(pf);
} else { } else {
i40e_pf_unquiesce_all_vsi(pf); i40e_pf_unquiesce_all_vsi(pf);
/* Notify the client for the DCB changes */ pf->flags |= (I40E_FLAG_SERVICE_CLIENT_REQUESTED |
i40e_notify_client_of_l2_param_changes(pf->vsi[pf->lan_vsi]); I40E_FLAG_CLIENT_L2_CHANGE);
} }
exit: exit:
...@@ -6144,8 +6143,8 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf) ...@@ -6144,8 +6143,8 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
(pf->fd_add_err == 0) || (pf->fd_add_err == 0) ||
(i40e_get_current_atr_cnt(pf) < pf->fd_atr_cnt)) { (i40e_get_current_atr_cnt(pf) < pf->fd_atr_cnt)) {
if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) && if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
(pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) { (pf->hw_disabled_flags & I40E_FLAG_FD_SB_ENABLED)) {
pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED; pf->hw_disabled_flags &= ~I40E_FLAG_FD_SB_ENABLED;
if (I40E_DEBUG_FD & pf->hw.debug_mask) if (I40E_DEBUG_FD & pf->hw.debug_mask)
dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n"); dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n");
} }
...@@ -6156,9 +6155,9 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf) ...@@ -6156,9 +6155,9 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
*/ */
if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM * 2)) { if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM * 2)) {
if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) && if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
(pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED) && (pf->hw_disabled_flags & I40E_FLAG_FD_ATR_ENABLED) &&
(pf->fd_tcp_rule == 0)) { (pf->fd_tcp_rule == 0)) {
pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED; pf->hw_disabled_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
if (I40E_DEBUG_FD & pf->hw.debug_mask) if (I40E_DEBUG_FD & pf->hw.debug_mask)
dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table and there are no conflicting ntuple rules\n"); dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table and there are no conflicting ntuple rules\n");
} }
...@@ -6210,7 +6209,7 @@ static void i40e_fdir_flush_and_replay(struct i40e_pf *pf) ...@@ -6210,7 +6209,7 @@ static void i40e_fdir_flush_and_replay(struct i40e_pf *pf)
} }
pf->fd_flush_timestamp = jiffies; pf->fd_flush_timestamp = jiffies;
pf->auto_disable_flags |= I40E_FLAG_FD_ATR_ENABLED; pf->hw_disabled_flags |= I40E_FLAG_FD_ATR_ENABLED;
/* flush all filters */ /* flush all filters */
wr32(&pf->hw, I40E_PFQF_CTL_1, wr32(&pf->hw, I40E_PFQF_CTL_1,
I40E_PFQF_CTL_1_CLEARFDTABLE_MASK); I40E_PFQF_CTL_1_CLEARFDTABLE_MASK);
...@@ -6230,7 +6229,7 @@ static void i40e_fdir_flush_and_replay(struct i40e_pf *pf) ...@@ -6230,7 +6229,7 @@ static void i40e_fdir_flush_and_replay(struct i40e_pf *pf)
/* replay sideband filters */ /* replay sideband filters */
i40e_fdir_filter_restore(pf->vsi[pf->lan_vsi]); i40e_fdir_filter_restore(pf->vsi[pf->lan_vsi]);
if (!disable_atr) if (!disable_atr)
pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED; pf->hw_disabled_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
clear_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state); clear_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state);
if (I40E_DEBUG_FD & pf->hw.debug_mask) if (I40E_DEBUG_FD & pf->hw.debug_mask)
dev_info(&pf->pdev->dev, "FD Filter table flushed and FD-SB replayed.\n"); dev_info(&pf->pdev->dev, "FD Filter table flushed and FD-SB replayed.\n");
...@@ -7411,7 +7410,18 @@ static void i40e_service_task(struct work_struct *work) ...@@ -7411,7 +7410,18 @@ static void i40e_service_task(struct work_struct *work)
i40e_vc_process_vflr_event(pf); i40e_vc_process_vflr_event(pf);
i40e_watchdog_subtask(pf); i40e_watchdog_subtask(pf);
i40e_fdir_reinit_subtask(pf); i40e_fdir_reinit_subtask(pf);
i40e_client_subtask(pf); if (pf->flags & I40E_FLAG_CLIENT_RESET) {
/* Client subtask will reopen next time through. */
i40e_notify_client_of_netdev_close(pf->vsi[pf->lan_vsi], true);
pf->flags &= ~I40E_FLAG_CLIENT_RESET;
} else {
i40e_client_subtask(pf);
if (pf->flags & I40E_FLAG_CLIENT_L2_CHANGE) {
i40e_notify_client_of_l2_param_changes(
pf->vsi[pf->lan_vsi]);
pf->flags &= ~I40E_FLAG_CLIENT_L2_CHANGE;
}
}
i40e_sync_filters_subtask(pf); i40e_sync_filters_subtask(pf);
i40e_sync_udp_filters_subtask(pf); i40e_sync_udp_filters_subtask(pf);
i40e_clean_adminq_subtask(pf); i40e_clean_adminq_subtask(pf);
...@@ -7809,6 +7819,7 @@ static int i40e_reserve_msix_vectors(struct i40e_pf *pf, int vectors) ...@@ -7809,6 +7819,7 @@ static int i40e_reserve_msix_vectors(struct i40e_pf *pf, int vectors)
static int i40e_init_msix(struct i40e_pf *pf) static int i40e_init_msix(struct i40e_pf *pf)
{ {
struct i40e_hw *hw = &pf->hw; struct i40e_hw *hw = &pf->hw;
int cpus, extra_vectors;
int vectors_left; int vectors_left;
int v_budget, i; int v_budget, i;
int v_actual; int v_actual;
...@@ -7844,10 +7855,16 @@ static int i40e_init_msix(struct i40e_pf *pf) ...@@ -7844,10 +7855,16 @@ static int i40e_init_msix(struct i40e_pf *pf)
vectors_left--; vectors_left--;
} }
/* reserve vectors for the main PF traffic queues */ /* reserve some vectors for the main PF traffic queues. Initially we
pf->num_lan_msix = min_t(int, num_online_cpus(), vectors_left); * only reserve at most 50% of the available vectors, in the case that
* the number of online CPUs is large. This ensures that we can enable
* extra features as well. Once we've enabled the other features, we
* will use any remaining vectors to reach as close as we can to the
* number of online CPUs.
*/
cpus = num_online_cpus();
pf->num_lan_msix = min_t(int, cpus, vectors_left / 2);
vectors_left -= pf->num_lan_msix; vectors_left -= pf->num_lan_msix;
v_budget += pf->num_lan_msix;
/* reserve one vector for sideband flow director */ /* reserve one vector for sideband flow director */
if (pf->flags & I40E_FLAG_FD_SB_ENABLED) { if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
...@@ -7910,6 +7927,23 @@ static int i40e_init_msix(struct i40e_pf *pf) ...@@ -7910,6 +7927,23 @@ static int i40e_init_msix(struct i40e_pf *pf)
} }
} }
/* On systems with a large number of SMP cores, we previously limited
* the number of vectors for num_lan_msix to be at most 50% of the
* available vectors, to allow for other features. Now, we add back
* the remaining vectors. However, we ensure that the total
* num_lan_msix will not exceed num_online_cpus(). To do this, we
* calculate the number of vectors we can add without going over the
* cap of CPUs. For systems with a small number of CPUs this will be
* zero.
*/
extra_vectors = min_t(int, cpus - pf->num_lan_msix, vectors_left);
pf->num_lan_msix += extra_vectors;
vectors_left -= extra_vectors;
WARN(vectors_left < 0,
"Calculation of remaining vectors underflowed. This is an accounting bug when determining total MSI-X vectors.\n");
v_budget += pf->num_lan_msix;
pf->msix_entries = kcalloc(v_budget, sizeof(struct msix_entry), pf->msix_entries = kcalloc(v_budget, sizeof(struct msix_entry),
GFP_KERNEL); GFP_KERNEL);
if (!pf->msix_entries) if (!pf->msix_entries)
...@@ -8360,13 +8394,10 @@ static int i40e_config_rss_reg(struct i40e_vsi *vsi, const u8 *seed, ...@@ -8360,13 +8394,10 @@ static int i40e_config_rss_reg(struct i40e_vsi *vsi, const u8 *seed,
if (vsi->type == I40E_VSI_MAIN) { if (vsi->type == I40E_VSI_MAIN) {
for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++) for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
i40e_write_rx_ctl(hw, I40E_PFQF_HKEY(i), wr32(hw, I40E_PFQF_HKEY(i), seed_dw[i]);
seed_dw[i]);
} else if (vsi->type == I40E_VSI_SRIOV) { } else if (vsi->type == I40E_VSI_SRIOV) {
for (i = 0; i <= I40E_VFQF_HKEY1_MAX_INDEX; i++) for (i = 0; i <= I40E_VFQF_HKEY1_MAX_INDEX; i++)
i40e_write_rx_ctl(hw, wr32(hw, I40E_VFQF_HKEY1(i, vf_id), seed_dw[i]);
I40E_VFQF_HKEY1(i, vf_id),
seed_dw[i]);
} else { } else {
dev_err(&pf->pdev->dev, "Cannot set RSS seed - invalid VSI type\n"); dev_err(&pf->pdev->dev, "Cannot set RSS seed - invalid VSI type\n");
} }
...@@ -8384,9 +8415,7 @@ static int i40e_config_rss_reg(struct i40e_vsi *vsi, const u8 *seed, ...@@ -8384,9 +8415,7 @@ static int i40e_config_rss_reg(struct i40e_vsi *vsi, const u8 *seed,
if (lut_size != I40E_VF_HLUT_ARRAY_SIZE) if (lut_size != I40E_VF_HLUT_ARRAY_SIZE)
return -EINVAL; return -EINVAL;
for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++)
i40e_write_rx_ctl(hw, wr32(hw, I40E_VFQF_HLUT1(i, vf_id), lut_dw[i]);
I40E_VFQF_HLUT1(i, vf_id),
lut_dw[i]);
} else { } else {
dev_err(&pf->pdev->dev, "Cannot set RSS LUT - invalid VSI type\n"); dev_err(&pf->pdev->dev, "Cannot set RSS LUT - invalid VSI type\n");
} }
...@@ -8843,9 +8872,9 @@ static int i40e_sw_init(struct i40e_pf *pf) ...@@ -8843,9 +8872,9 @@ static int i40e_sw_init(struct i40e_pf *pf)
(pf->hw.aq.api_min_ver > 4))) { (pf->hw.aq.api_min_ver > 4))) {
/* Supported in FW API version higher than 1.4 */ /* Supported in FW API version higher than 1.4 */
pf->flags |= I40E_FLAG_GENEVE_OFFLOAD_CAPABLE; pf->flags |= I40E_FLAG_GENEVE_OFFLOAD_CAPABLE;
pf->auto_disable_flags = I40E_FLAG_HW_ATR_EVICT_CAPABLE; pf->hw_disabled_flags = I40E_FLAG_HW_ATR_EVICT_CAPABLE;
} else { } else {
pf->auto_disable_flags = I40E_FLAG_HW_ATR_EVICT_CAPABLE; pf->hw_disabled_flags = I40E_FLAG_HW_ATR_EVICT_CAPABLE;
} }
pf->eeprom_version = 0xDEAD; pf->eeprom_version = 0xDEAD;
...@@ -8906,14 +8935,14 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features) ...@@ -8906,14 +8935,14 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)
i40e_fdir_filter_exit(pf); i40e_fdir_filter_exit(pf);
} }
pf->flags &= ~I40E_FLAG_FD_SB_ENABLED; pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED; pf->hw_disabled_flags &= ~I40E_FLAG_FD_SB_ENABLED;
/* reset fd counters */ /* reset fd counters */
pf->fd_add_err = pf->fd_atr_cnt = pf->fd_tcp_rule = 0; pf->fd_add_err = pf->fd_atr_cnt = pf->fd_tcp_rule = 0;
pf->fdir_pf_active_filters = 0; pf->fdir_pf_active_filters = 0;
/* if ATR was auto disabled it can be re-enabled. */ /* if ATR was auto disabled it can be re-enabled. */
if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) && if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
(pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) { (pf->hw_disabled_flags & I40E_FLAG_FD_ATR_ENABLED)) {
pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED; pf->hw_disabled_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
if (I40E_DEBUG_FD & pf->hw.debug_mask) if (I40E_DEBUG_FD & pf->hw.debug_mask)
dev_info(&pf->pdev->dev, "ATR re-enabled.\n"); dev_info(&pf->pdev->dev, "ATR re-enabled.\n");
} }
...@@ -9432,10 +9461,10 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) ...@@ -9432,10 +9461,10 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
if (vsi->type == I40E_VSI_MAIN) { if (vsi->type == I40E_VSI_MAIN) {
SET_NETDEV_DEV(netdev, &pf->pdev->dev); SET_NETDEV_DEV(netdev, &pf->pdev->dev);
ether_addr_copy(mac_addr, hw->mac.perm_addr); ether_addr_copy(mac_addr, hw->mac.perm_addr);
/* The following steps are necessary to prevent reception /* The following steps are necessary to properly keep track of
* of tagged packets - some older NVM configurations load a * MAC-VLAN filters loaded into firmware - first we remove
* default a MAC-VLAN filter that accepts any tagged packet * filter that is automatically generated by firmware and then
* which must be replaced by a normal filter. * add new filter both to the driver hash table and firmware.
*/ */
i40e_rm_default_mac_filter(vsi, mac_addr); i40e_rm_default_mac_filter(vsi, mac_addr);
spin_lock_bh(&vsi->mac_filter_hash_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
......
...@@ -292,14 +292,14 @@ i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, ...@@ -292,14 +292,14 @@ i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
{ {
enum i40e_status_code ret_code = 0; enum i40e_status_code ret_code = 0;
if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) { ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); if (!ret_code) {
if (!ret_code) { if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) {
ret_code = i40e_read_nvm_word_aq(hw, offset, data); ret_code = i40e_read_nvm_word_aq(hw, offset, data);
i40e_release_nvm(hw); } else {
ret_code = i40e_read_nvm_word_srctl(hw, offset, data);
} }
} else { i40e_release_nvm(hw);
ret_code = i40e_read_nvm_word_srctl(hw, offset, data);
} }
return ret_code; return ret_code;
} }
......
...@@ -291,7 +291,7 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, ...@@ -291,7 +291,7 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) && if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
I40E_DEBUG_FD & pf->hw.debug_mask) I40E_DEBUG_FD & pf->hw.debug_mask)
dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n"); dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n");
pf->auto_disable_flags |= I40E_FLAG_FD_ATR_ENABLED; pf->hw_disabled_flags |= I40E_FLAG_FD_ATR_ENABLED;
} else { } else {
pf->fd_tcp_rule = (pf->fd_tcp_rule > 0) ? pf->fd_tcp_rule = (pf->fd_tcp_rule > 0) ?
(pf->fd_tcp_rule - 1) : 0; (pf->fd_tcp_rule - 1) : 0;
...@@ -299,7 +299,7 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, ...@@ -299,7 +299,7 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) && if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
I40E_DEBUG_FD & pf->hw.debug_mask) I40E_DEBUG_FD & pf->hw.debug_mask)
dev_info(&pf->pdev->dev, "ATR re-enabled due to no sideband TCP/IPv4 rules\n"); dev_info(&pf->pdev->dev, "ATR re-enabled due to no sideband TCP/IPv4 rules\n");
pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED; pf->hw_disabled_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
} }
} }
...@@ -484,8 +484,8 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring, ...@@ -484,8 +484,8 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
pf->fd_atr_cnt = i40e_get_current_atr_cnt(pf); pf->fd_atr_cnt = i40e_get_current_atr_cnt(pf);
if ((rx_desc->wb.qword0.hi_dword.fd_id == 0) && if ((rx_desc->wb.qword0.hi_dword.fd_id == 0) &&
(pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) { (pf->hw_disabled_flags & I40E_FLAG_FD_SB_ENABLED)) {
pf->auto_disable_flags |= I40E_FLAG_FD_ATR_ENABLED; pf->hw_disabled_flags |= I40E_FLAG_FD_ATR_ENABLED;
set_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state); set_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state);
} }
...@@ -498,11 +498,11 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring, ...@@ -498,11 +498,11 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
*/ */
if (fcnt_prog >= (fcnt_avail - I40E_FDIR_BUFFER_FULL_MARGIN)) { if (fcnt_prog >= (fcnt_avail - I40E_FDIR_BUFFER_FULL_MARGIN)) {
if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) && if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
!(pf->auto_disable_flags & !(pf->hw_disabled_flags &
I40E_FLAG_FD_SB_ENABLED)) { I40E_FLAG_FD_SB_ENABLED)) {
if (I40E_DEBUG_FD & pf->hw.debug_mask) if (I40E_DEBUG_FD & pf->hw.debug_mask)
dev_warn(&pdev->dev, "FD filter space full, new ntuple rules will not be added\n"); dev_warn(&pdev->dev, "FD filter space full, new ntuple rules will not be added\n");
pf->auto_disable_flags |= pf->hw_disabled_flags |=
I40E_FLAG_FD_SB_ENABLED; I40E_FLAG_FD_SB_ENABLED;
} }
} }
...@@ -1010,7 +1010,6 @@ int i40e_setup_tx_descriptors(struct i40e_ring *tx_ring) ...@@ -1010,7 +1010,6 @@ int i40e_setup_tx_descriptors(struct i40e_ring *tx_ring)
**/ **/
void i40e_clean_rx_ring(struct i40e_ring *rx_ring) void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
{ {
struct device *dev = rx_ring->dev;
unsigned long bi_size; unsigned long bi_size;
u16 i; u16 i;
...@@ -1030,7 +1029,20 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring) ...@@ -1030,7 +1029,20 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
if (!rx_bi->page) if (!rx_bi->page)
continue; continue;
dma_unmap_page(dev, rx_bi->dma, PAGE_SIZE, DMA_FROM_DEVICE); /* Invalidate cache lines that may have been written to by
* device so that we avoid corrupting memory.
*/
dma_sync_single_range_for_cpu(rx_ring->dev,
rx_bi->dma,
rx_bi->page_offset,
I40E_RXBUFFER_2048,
DMA_FROM_DEVICE);
/* free resources associated with mapping */
dma_unmap_page_attrs(rx_ring->dev, rx_bi->dma,
PAGE_SIZE,
DMA_FROM_DEVICE,
I40E_RX_DMA_ATTR);
__free_pages(rx_bi->page, 0); __free_pages(rx_bi->page, 0);
rx_bi->page = NULL; rx_bi->page = NULL;
...@@ -1159,7 +1171,10 @@ static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring, ...@@ -1159,7 +1171,10 @@ static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring,
} }
/* map page for use */ /* map page for use */
dma = dma_map_page(rx_ring->dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE); dma = dma_map_page_attrs(rx_ring->dev, page, 0,
PAGE_SIZE,
DMA_FROM_DEVICE,
I40E_RX_DMA_ATTR);
/* if mapping failed free memory back to system since /* if mapping failed free memory back to system since
* there isn't much point in holding memory we can't use * there isn't much point in holding memory we can't use
...@@ -1219,6 +1234,12 @@ bool i40e_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count) ...@@ -1219,6 +1234,12 @@ bool i40e_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count)
if (!i40e_alloc_mapped_page(rx_ring, bi)) if (!i40e_alloc_mapped_page(rx_ring, bi))
goto no_buffers; goto no_buffers;
/* sync the buffer for use by the device */
dma_sync_single_range_for_device(rx_ring->dev, bi->dma,
bi->page_offset,
I40E_RXBUFFER_2048,
DMA_FROM_DEVICE);
/* Refresh the desc even if buffer_addrs didn't change /* Refresh the desc even if buffer_addrs didn't change
* because each write-back erases this info. * because each write-back erases this info.
*/ */
...@@ -1685,8 +1706,8 @@ struct sk_buff *i40e_fetch_rx_buffer(struct i40e_ring *rx_ring, ...@@ -1685,8 +1706,8 @@ struct sk_buff *i40e_fetch_rx_buffer(struct i40e_ring *rx_ring,
rx_ring->rx_stats.page_reuse_count++; rx_ring->rx_stats.page_reuse_count++;
} else { } else {
/* we are not reusing the buffer so unmap it */ /* we are not reusing the buffer so unmap it */
dma_unmap_page(rx_ring->dev, rx_buffer->dma, PAGE_SIZE, dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma, PAGE_SIZE,
DMA_FROM_DEVICE); DMA_FROM_DEVICE, I40E_RX_DMA_ATTR);
} }
/* clear contents of buffer_info */ /* clear contents of buffer_info */
...@@ -2079,7 +2100,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb, ...@@ -2079,7 +2100,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
if (!(pf->flags & I40E_FLAG_FD_ATR_ENABLED)) if (!(pf->flags & I40E_FLAG_FD_ATR_ENABLED))
return; return;
if ((pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) if ((pf->hw_disabled_flags & I40E_FLAG_FD_ATR_ENABLED))
return; return;
/* if sampling is disabled do nothing */ /* if sampling is disabled do nothing */
...@@ -2113,10 +2134,10 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb, ...@@ -2113,10 +2134,10 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
th = (struct tcphdr *)(hdr.network + hlen); th = (struct tcphdr *)(hdr.network + hlen);
/* Due to lack of space, no more new filters can be programmed */ /* Due to lack of space, no more new filters can be programmed */
if (th->syn && (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) if (th->syn && (pf->hw_disabled_flags & I40E_FLAG_FD_ATR_ENABLED))
return; return;
if ((pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE) && if ((pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE) &&
(!(pf->auto_disable_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE))) { (!(pf->hw_disabled_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE))) {
/* HW ATR eviction will take care of removing filters on FIN /* HW ATR eviction will take care of removing filters on FIN
* and RST packets. * and RST packets.
*/ */
...@@ -2179,7 +2200,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb, ...@@ -2179,7 +2200,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
I40E_TXD_FLTR_QW1_CNTINDEX_MASK; I40E_TXD_FLTR_QW1_CNTINDEX_MASK;
if ((pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE) && if ((pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE) &&
(!(pf->auto_disable_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE))) (!(pf->hw_disabled_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE)))
dtype_cmd |= I40E_TXD_FLTR_QW1_ATR_MASK; dtype_cmd |= I40E_TXD_FLTR_QW1_ATR_MASK;
fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(flex_ptype); fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(flex_ptype);
......
...@@ -133,6 +133,9 @@ enum i40e_dyn_idx_t { ...@@ -133,6 +133,9 @@ enum i40e_dyn_idx_t {
#define I40E_RX_HDR_SIZE I40E_RXBUFFER_256 #define I40E_RX_HDR_SIZE I40E_RXBUFFER_256
#define i40e_rx_desc i40e_32byte_rx_desc #define i40e_rx_desc i40e_32byte_rx_desc
#define I40E_RX_DMA_ATTR \
(DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
/** /**
* i40e_test_staterr - tests bits in Rx descriptor status and error fields * i40e_test_staterr - tests bits in Rx descriptor status and error fields
* @rx_desc: pointer to receive descriptor (in le64 format) * @rx_desc: pointer to receive descriptor (in le64 format)
......
...@@ -702,10 +702,8 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) ...@@ -702,10 +702,8 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"Could not allocate VF broadcast filter\n"); "Could not allocate VF broadcast filter\n");
spin_unlock_bh(&vsi->mac_filter_hash_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
i40e_write_rx_ctl(&pf->hw, I40E_VFQF_HENA1(0, vf->vf_id), wr32(&pf->hw, I40E_VFQF_HENA1(0, vf->vf_id), (u32)hena);
(u32)hena); wr32(&pf->hw, I40E_VFQF_HENA1(1, vf->vf_id), (u32)(hena >> 32));
i40e_write_rx_ctl(&pf->hw, I40E_VFQF_HENA1(1, vf->vf_id),
(u32)(hena >> 32));
} }
/* program mac filter */ /* program mac filter */
...@@ -1359,7 +1357,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) ...@@ -1359,7 +1357,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
if (!vsi->info.pvid) if (!vsi->info.pvid)
vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_VLAN; vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_VLAN;
if (i40e_vf_client_capable(pf, vf->vf_id, I40E_CLIENT_IWARP) && if (i40e_vf_client_capable(pf, vf->vf_id) &&
(vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_IWARP)) { (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_IWARP)) {
vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_IWARP; vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_IWARP;
set_bit(I40E_VF_STAT_IWARPENA, &vf->vf_states); set_bit(I40E_VF_STAT_IWARPENA, &vf->vf_states);
...@@ -1853,7 +1851,7 @@ static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) ...@@ -1853,7 +1851,7 @@ static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
} }
/* If the VF is not trusted restrict the number of MAC/VLAN it can program */ /* If the VF is not trusted restrict the number of MAC/VLAN it can program */
#define I40E_VC_MAX_MAC_ADDR_PER_VF 8 #define I40E_VC_MAX_MAC_ADDR_PER_VF 12
#define I40E_VC_MAX_VLAN_PER_VF 8 #define I40E_VC_MAX_VLAN_PER_VF 8
/** /**
......
...@@ -32,5 +32,5 @@ ...@@ -32,5 +32,5 @@
obj-$(CONFIG_I40EVF) += i40evf.o obj-$(CONFIG_I40EVF) += i40evf.o
i40evf-objs := i40evf_main.o i40evf_ethtool.o i40evf_virtchnl.o \ i40evf-objs := i40evf_main.o i40evf_ethtool.o i40evf_virtchnl.o \
i40e_txrx.o i40e_common.o i40e_adminq.o i40e_txrx.o i40e_common.o i40e_adminq.o i40evf_client.o
...@@ -132,6 +132,10 @@ enum i40e_admin_queue_opc { ...@@ -132,6 +132,10 @@ enum i40e_admin_queue_opc {
i40e_aqc_opc_list_func_capabilities = 0x000A, i40e_aqc_opc_list_func_capabilities = 0x000A,
i40e_aqc_opc_list_dev_capabilities = 0x000B, i40e_aqc_opc_list_dev_capabilities = 0x000B,
/* Proxy commands */
i40e_aqc_opc_set_proxy_config = 0x0104,
i40e_aqc_opc_set_ns_proxy_table_entry = 0x0105,
/* LAA */ /* LAA */
i40e_aqc_opc_mac_address_read = 0x0107, i40e_aqc_opc_mac_address_read = 0x0107,
i40e_aqc_opc_mac_address_write = 0x0108, i40e_aqc_opc_mac_address_write = 0x0108,
...@@ -139,6 +143,10 @@ enum i40e_admin_queue_opc { ...@@ -139,6 +143,10 @@ enum i40e_admin_queue_opc {
/* PXE */ /* PXE */
i40e_aqc_opc_clear_pxe_mode = 0x0110, i40e_aqc_opc_clear_pxe_mode = 0x0110,
/* WoL commands */
i40e_aqc_opc_set_wol_filter = 0x0120,
i40e_aqc_opc_get_wake_reason = 0x0121,
/* internal switch commands */ /* internal switch commands */
i40e_aqc_opc_get_switch_config = 0x0200, i40e_aqc_opc_get_switch_config = 0x0200,
i40e_aqc_opc_add_statistics = 0x0201, i40e_aqc_opc_add_statistics = 0x0201,
...@@ -177,6 +185,7 @@ enum i40e_admin_queue_opc { ...@@ -177,6 +185,7 @@ enum i40e_admin_queue_opc {
i40e_aqc_opc_remove_control_packet_filter = 0x025B, i40e_aqc_opc_remove_control_packet_filter = 0x025B,
i40e_aqc_opc_add_cloud_filters = 0x025C, i40e_aqc_opc_add_cloud_filters = 0x025C,
i40e_aqc_opc_remove_cloud_filters = 0x025D, i40e_aqc_opc_remove_cloud_filters = 0x025D,
i40e_aqc_opc_clear_wol_switch_filters = 0x025E,
i40e_aqc_opc_add_mirror_rule = 0x0260, i40e_aqc_opc_add_mirror_rule = 0x0260,
i40e_aqc_opc_delete_mirror_rule = 0x0261, i40e_aqc_opc_delete_mirror_rule = 0x0261,
...@@ -558,6 +567,56 @@ struct i40e_aqc_clear_pxe { ...@@ -558,6 +567,56 @@ struct i40e_aqc_clear_pxe {
I40E_CHECK_CMD_LENGTH(i40e_aqc_clear_pxe); I40E_CHECK_CMD_LENGTH(i40e_aqc_clear_pxe);
/* Set WoL Filter (0x0120) */
struct i40e_aqc_set_wol_filter {
__le16 filter_index;
#define I40E_AQC_MAX_NUM_WOL_FILTERS 8
#define I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_SHIFT 15
#define I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_MASK (0x1 << \
I40E_AQC_SET_WOL_FILTER_TYPE_MAGIC_SHIFT)
#define I40E_AQC_SET_WOL_FILTER_INDEX_SHIFT 0
#define I40E_AQC_SET_WOL_FILTER_INDEX_MASK (0x7 << \
I40E_AQC_SET_WOL_FILTER_INDEX_SHIFT)
__le16 cmd_flags;
#define I40E_AQC_SET_WOL_FILTER 0x8000
#define I40E_AQC_SET_WOL_FILTER_NO_TCO_WOL 0x4000
#define I40E_AQC_SET_WOL_FILTER_ACTION_CLEAR 0
#define I40E_AQC_SET_WOL_FILTER_ACTION_SET 1
__le16 valid_flags;
#define I40E_AQC_SET_WOL_FILTER_ACTION_VALID 0x8000
#define I40E_AQC_SET_WOL_FILTER_NO_TCO_ACTION_VALID 0x4000
u8 reserved[2];
__le32 address_high;
__le32 address_low;
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_set_wol_filter);
struct i40e_aqc_set_wol_filter_data {
u8 filter[128];
u8 mask[16];
};
I40E_CHECK_STRUCT_LEN(0x90, i40e_aqc_set_wol_filter_data);
/* Get Wake Reason (0x0121) */
struct i40e_aqc_get_wake_reason_completion {
u8 reserved_1[2];
__le16 wake_reason;
#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_SHIFT 0
#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_MASK (0xFF << \
I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_MATCHED_INDEX_SHIFT)
#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_SHIFT 8
#define I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_MASK (0xFF << \
I40E_AQC_GET_WAKE_UP_REASON_WOL_REASON_RESERVED_SHIFT)
u8 reserved_2[12];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_get_wake_reason_completion);
/* Switch configuration commands (0x02xx) */ /* Switch configuration commands (0x02xx) */
/* Used by many indirect commands that only pass an seid and a buffer in the /* Used by many indirect commands that only pass an seid and a buffer in the
...@@ -640,6 +699,8 @@ struct i40e_aqc_set_port_parameters { ...@@ -640,6 +699,8 @@ struct i40e_aqc_set_port_parameters {
#define I40E_AQ_SET_P_PARAMS_PAD_SHORT_PACKETS 2 /* must set! */ #define I40E_AQ_SET_P_PARAMS_PAD_SHORT_PACKETS 2 /* must set! */
#define I40E_AQ_SET_P_PARAMS_DOUBLE_VLAN_ENA 4 #define I40E_AQ_SET_P_PARAMS_DOUBLE_VLAN_ENA 4
__le16 bad_frame_vsi; __le16 bad_frame_vsi;
#define I40E_AQ_SET_P_PARAMS_BFRAME_SEID_SHIFT 0x0
#define I40E_AQ_SET_P_PARAMS_BFRAME_SEID_MASK 0x3FF
__le16 default_seid; /* reserved for command */ __le16 default_seid; /* reserved for command */
u8 reserved[10]; u8 reserved[10];
}; };
...@@ -691,6 +752,7 @@ I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp); ...@@ -691,6 +752,7 @@ I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp);
/* Set Switch Configuration (direct 0x0205) */ /* Set Switch Configuration (direct 0x0205) */
struct i40e_aqc_set_switch_config { struct i40e_aqc_set_switch_config {
__le16 flags; __le16 flags;
/* flags used for both fields below */
#define I40E_AQ_SET_SWITCH_CFG_PROMISC 0x0001 #define I40E_AQ_SET_SWITCH_CFG_PROMISC 0x0001
#define I40E_AQ_SET_SWITCH_CFG_L2_FILTER 0x0002 #define I40E_AQ_SET_SWITCH_CFG_L2_FILTER 0x0002
__le16 valid_flags; __le16 valid_flags;
...@@ -1839,11 +1901,12 @@ struct i40e_aqc_get_link_status { ...@@ -1839,11 +1901,12 @@ struct i40e_aqc_get_link_status {
#define I40E_AQ_CONFIG_FEC_RS_ENA 0x02 #define I40E_AQ_CONFIG_FEC_RS_ENA 0x02
#define I40E_AQ_CONFIG_CRC_ENA 0x04 #define I40E_AQ_CONFIG_CRC_ENA 0x04
#define I40E_AQ_CONFIG_PACING_MASK 0x78 #define I40E_AQ_CONFIG_PACING_MASK 0x78
u8 external_power_ability; u8 power_desc;
#define I40E_AQ_LINK_POWER_CLASS_1 0x00 #define I40E_AQ_LINK_POWER_CLASS_1 0x00
#define I40E_AQ_LINK_POWER_CLASS_2 0x01 #define I40E_AQ_LINK_POWER_CLASS_2 0x01
#define I40E_AQ_LINK_POWER_CLASS_3 0x02 #define I40E_AQ_LINK_POWER_CLASS_3 0x02
#define I40E_AQ_LINK_POWER_CLASS_4 0x03 #define I40E_AQ_LINK_POWER_CLASS_4 0x03
#define I40E_AQ_PWR_CLASS_MASK 0x03
u8 reserved[4]; u8 reserved[4];
}; };
......
...@@ -493,7 +493,6 @@ int i40evf_setup_tx_descriptors(struct i40e_ring *tx_ring) ...@@ -493,7 +493,6 @@ int i40evf_setup_tx_descriptors(struct i40e_ring *tx_ring)
**/ **/
void i40evf_clean_rx_ring(struct i40e_ring *rx_ring) void i40evf_clean_rx_ring(struct i40e_ring *rx_ring)
{ {
struct device *dev = rx_ring->dev;
unsigned long bi_size; unsigned long bi_size;
u16 i; u16 i;
...@@ -513,7 +512,20 @@ void i40evf_clean_rx_ring(struct i40e_ring *rx_ring) ...@@ -513,7 +512,20 @@ void i40evf_clean_rx_ring(struct i40e_ring *rx_ring)
if (!rx_bi->page) if (!rx_bi->page)
continue; continue;
dma_unmap_page(dev, rx_bi->dma, PAGE_SIZE, DMA_FROM_DEVICE); /* Invalidate cache lines that may have been written to by
* device so that we avoid corrupting memory.
*/
dma_sync_single_range_for_cpu(rx_ring->dev,
rx_bi->dma,
rx_bi->page_offset,
I40E_RXBUFFER_2048,
DMA_FROM_DEVICE);
/* free resources associated with mapping */
dma_unmap_page_attrs(rx_ring->dev, rx_bi->dma,
PAGE_SIZE,
DMA_FROM_DEVICE,
I40E_RX_DMA_ATTR);
__free_pages(rx_bi->page, 0); __free_pages(rx_bi->page, 0);
rx_bi->page = NULL; rx_bi->page = NULL;
...@@ -642,7 +654,10 @@ static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring, ...@@ -642,7 +654,10 @@ static bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring,
} }
/* map page for use */ /* map page for use */
dma = dma_map_page(rx_ring->dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE); dma = dma_map_page_attrs(rx_ring->dev, page, 0,
PAGE_SIZE,
DMA_FROM_DEVICE,
I40E_RX_DMA_ATTR);
/* if mapping failed free memory back to system since /* if mapping failed free memory back to system since
* there isn't much point in holding memory we can't use * there isn't much point in holding memory we can't use
...@@ -702,6 +717,12 @@ bool i40evf_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count) ...@@ -702,6 +717,12 @@ bool i40evf_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count)
if (!i40e_alloc_mapped_page(rx_ring, bi)) if (!i40e_alloc_mapped_page(rx_ring, bi))
goto no_buffers; goto no_buffers;
/* sync the buffer for use by the device */
dma_sync_single_range_for_device(rx_ring->dev, bi->dma,
bi->page_offset,
I40E_RXBUFFER_2048,
DMA_FROM_DEVICE);
/* Refresh the desc even if buffer_addrs didn't change /* Refresh the desc even if buffer_addrs didn't change
* because each write-back erases this info. * because each write-back erases this info.
*/ */
...@@ -1158,8 +1179,8 @@ struct sk_buff *i40evf_fetch_rx_buffer(struct i40e_ring *rx_ring, ...@@ -1158,8 +1179,8 @@ struct sk_buff *i40evf_fetch_rx_buffer(struct i40e_ring *rx_ring,
rx_ring->rx_stats.page_reuse_count++; rx_ring->rx_stats.page_reuse_count++;
} else { } else {
/* we are not reusing the buffer so unmap it */ /* we are not reusing the buffer so unmap it */
dma_unmap_page(rx_ring->dev, rx_buffer->dma, PAGE_SIZE, dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma, PAGE_SIZE,
DMA_FROM_DEVICE); DMA_FROM_DEVICE, I40E_RX_DMA_ATTR);
} }
/* clear contents of buffer_info */ /* clear contents of buffer_info */
......
...@@ -120,6 +120,9 @@ enum i40e_dyn_idx_t { ...@@ -120,6 +120,9 @@ enum i40e_dyn_idx_t {
#define I40E_RX_HDR_SIZE I40E_RXBUFFER_256 #define I40E_RX_HDR_SIZE I40E_RXBUFFER_256
#define i40e_rx_desc i40e_32byte_rx_desc #define i40e_rx_desc i40e_32byte_rx_desc
#define I40E_RX_DMA_ATTR \
(DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING)
/** /**
* i40e_test_staterr - tests bits in Rx descriptor status and error fields * i40e_test_staterr - tests bits in Rx descriptor status and error fields
* @rx_desc: pointer to receive descriptor (in le64 format) * @rx_desc: pointer to receive descriptor (in le64 format)
......
...@@ -81,7 +81,9 @@ enum i40e_virtchnl_ops { ...@@ -81,7 +81,9 @@ enum i40e_virtchnl_ops {
I40E_VIRTCHNL_OP_GET_STATS = 15, I40E_VIRTCHNL_OP_GET_STATS = 15,
I40E_VIRTCHNL_OP_FCOE = 16, I40E_VIRTCHNL_OP_FCOE = 16,
I40E_VIRTCHNL_OP_EVENT = 17, /* must ALWAYS be 17 */ I40E_VIRTCHNL_OP_EVENT = 17, /* must ALWAYS be 17 */
I40E_VIRTCHNL_OP_IWARP = 20,
I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP = 21, I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP = 21,
I40E_VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP = 22,
I40E_VIRTCHNL_OP_CONFIG_RSS_KEY = 23, I40E_VIRTCHNL_OP_CONFIG_RSS_KEY = 23,
I40E_VIRTCHNL_OP_CONFIG_RSS_LUT = 24, I40E_VIRTCHNL_OP_CONFIG_RSS_LUT = 24,
I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS = 25, I40E_VIRTCHNL_OP_GET_RSS_HENA_CAPS = 25,
...@@ -393,6 +395,37 @@ struct i40e_virtchnl_pf_event { ...@@ -393,6 +395,37 @@ struct i40e_virtchnl_pf_event {
int severity; int severity;
}; };
/* I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP
* VF uses this message to request PF to map IWARP vectors to IWARP queues.
* The request for this originates from the VF IWARP driver through
* a client interface between VF LAN and VF IWARP driver.
* A vector could have an AEQ and CEQ attached to it although
* there is a single AEQ per VF IWARP instance in which case
* most vectors will have an INVALID_IDX for aeq and valid idx for ceq.
* There will never be a case where there will be multiple CEQs attached
* to a single vector.
* PF configures interrupt mapping and returns status.
*/
/* HW does not define a type value for AEQ; only for RX/TX and CEQ.
* In order for us to keep the interface simple, SW will define a
* unique type value for AEQ.
*/
#define I40E_QUEUE_TYPE_PE_AEQ 0x80
#define I40E_QUEUE_INVALID_IDX 0xFFFF
struct i40e_virtchnl_iwarp_qv_info {
u32 v_idx; /* msix_vector */
u16 ceq_idx;
u16 aeq_idx;
u8 itr_idx;
};
struct i40e_virtchnl_iwarp_qvlist_info {
u32 num_vectors;
struct i40e_virtchnl_iwarp_qv_info qv_info[1];
};
/* VF reset states - these are written into the RSTAT register: /* VF reset states - these are written into the RSTAT register:
* I40E_VFGEN_RSTAT1 on the PF * I40E_VFGEN_RSTAT1 on the PF
* I40E_VFGEN_RSTAT on the VF * I40E_VFGEN_RSTAT on the VF
......
...@@ -60,6 +60,7 @@ struct i40e_vsi { ...@@ -60,6 +60,7 @@ struct i40e_vsi {
int base_vector; int base_vector;
u16 work_limit; u16 work_limit;
u16 qs_handle; u16 qs_handle;
void *priv; /* client driver data reference. */
}; };
/* How many Rx Buffers do we bundle into one write to the hardware ? */ /* How many Rx Buffers do we bundle into one write to the hardware ? */
...@@ -169,6 +170,7 @@ enum i40evf_state_t { ...@@ -169,6 +170,7 @@ enum i40evf_state_t {
enum i40evf_critical_section_t { enum i40evf_critical_section_t {
__I40EVF_IN_CRITICAL_TASK, /* cannot be interrupted */ __I40EVF_IN_CRITICAL_TASK, /* cannot be interrupted */
__I40EVF_IN_CLIENT_TASK,
}; };
/* make common code happy */ /* make common code happy */
#define __I40E_DOWN __I40EVF_DOWN #define __I40E_DOWN __I40EVF_DOWN
...@@ -178,6 +180,7 @@ struct i40evf_adapter { ...@@ -178,6 +180,7 @@ struct i40evf_adapter {
struct timer_list watchdog_timer; struct timer_list watchdog_timer;
struct work_struct reset_task; struct work_struct reset_task;
struct work_struct adminq_task; struct work_struct adminq_task;
struct delayed_work client_task;
struct delayed_work init_task; struct delayed_work init_task;
struct i40e_q_vector *q_vectors; struct i40e_q_vector *q_vectors;
struct list_head vlan_filter_list; struct list_head vlan_filter_list;
...@@ -195,7 +198,10 @@ struct i40evf_adapter { ...@@ -195,7 +198,10 @@ struct i40evf_adapter {
u64 hw_csum_rx_error; u64 hw_csum_rx_error;
u32 rx_desc_count; u32 rx_desc_count;
int num_msix_vectors; int num_msix_vectors;
int num_iwarp_msix;
int iwarp_base_vector;
u32 client_pending; u32 client_pending;
struct i40e_client_instance *cinst;
struct msix_entry *msix_entries; struct msix_entry *msix_entries;
u32 flags; u32 flags;
...@@ -211,8 +217,11 @@ struct i40evf_adapter { ...@@ -211,8 +217,11 @@ struct i40evf_adapter {
#define I40EVF_FLAG_OUTER_UDP_CSUM_CAPABLE BIT(12) #define I40EVF_FLAG_OUTER_UDP_CSUM_CAPABLE BIT(12)
#define I40EVF_FLAG_ADDR_SET_BY_PF BIT(13) #define I40EVF_FLAG_ADDR_SET_BY_PF BIT(13)
#define I40EVF_FLAG_SERVICE_CLIENT_REQUESTED BIT(14) #define I40EVF_FLAG_SERVICE_CLIENT_REQUESTED BIT(14)
#define I40EVF_FLAG_PROMISC_ON BIT(15) #define I40EVF_FLAG_CLIENT_NEEDS_OPEN BIT(15)
#define I40EVF_FLAG_ALLMULTI_ON BIT(16) #define I40EVF_FLAG_CLIENT_NEEDS_CLOSE BIT(16)
#define I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS BIT(17)
#define I40EVF_FLAG_PROMISC_ON BIT(18)
#define I40EVF_FLAG_ALLMULTI_ON BIT(19)
/* duplicates for common code */ /* duplicates for common code */
#define I40E_FLAG_FDIR_ATR_ENABLED 0 #define I40E_FLAG_FDIR_ATR_ENABLED 0
#define I40E_FLAG_DCB_ENABLED 0 #define I40E_FLAG_DCB_ENABLED 0
...@@ -258,10 +267,11 @@ struct i40evf_adapter { ...@@ -258,10 +267,11 @@ struct i40evf_adapter {
bool link_up; bool link_up;
enum i40e_aq_link_speed link_speed; enum i40e_aq_link_speed link_speed;
enum i40e_virtchnl_ops current_op; enum i40e_virtchnl_ops current_op;
#define CLIENT_ENABLED(_a) ((_a)->vf_res ? \ #define CLIENT_ALLOWED(_a) ((_a)->vf_res ? \
(_a)->vf_res->vf_offload_flags & \ (_a)->vf_res->vf_offload_flags & \
I40E_VIRTCHNL_VF_OFFLOAD_IWARP : \ I40E_VIRTCHNL_VF_OFFLOAD_IWARP : \
0) 0)
#define CLIENT_ENABLED(_a) ((_a)->cinst)
/* RSS by the PF should be preferred over RSS via other methods. */ /* RSS by the PF should be preferred over RSS via other methods. */
#define RSS_PF(_a) ((_a)->vf_res->vf_offload_flags & \ #define RSS_PF(_a) ((_a)->vf_res->vf_offload_flags & \
I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF) I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF)
...@@ -292,6 +302,12 @@ struct i40evf_adapter { ...@@ -292,6 +302,12 @@ struct i40evf_adapter {
/* Ethtool Private Flags */ /* Ethtool Private Flags */
/* lan device */
struct i40e_device {
struct list_head list;
struct i40evf_adapter *vf;
};
/* needed by i40evf_ethtool.c */ /* needed by i40evf_ethtool.c */
extern char i40evf_driver_name[]; extern char i40evf_driver_name[];
extern const char i40evf_driver_version[]; extern const char i40evf_driver_version[];
...@@ -337,4 +353,11 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, ...@@ -337,4 +353,11 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
enum i40e_virtchnl_ops v_opcode, enum i40e_virtchnl_ops v_opcode,
i40e_status v_retval, u8 *msg, u16 msglen); i40e_status v_retval, u8 *msg, u16 msglen);
int i40evf_config_rss(struct i40evf_adapter *adapter); int i40evf_config_rss(struct i40evf_adapter *adapter);
int i40evf_lan_add_device(struct i40evf_adapter *adapter);
int i40evf_lan_del_device(struct i40evf_adapter *adapter);
void i40evf_client_subtask(struct i40evf_adapter *adapter);
void i40evf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len);
void i40evf_notify_client_l2_params(struct i40e_vsi *vsi);
void i40evf_notify_client_open(struct i40e_vsi *vsi);
void i40evf_notify_client_close(struct i40e_vsi *vsi, bool reset);
#endif /* _I40EVF_H_ */ #endif /* _I40EVF_H_ */
#include <linux/list.h>
#include <linux/errno.h>
#include "i40evf.h"
#include "i40e_prototype.h"
#include "i40evf_client.h"
static
const char i40evf_client_interface_version_str[] = I40EVF_CLIENT_VERSION_STR;
static struct i40e_client *vf_registered_client;
static LIST_HEAD(i40evf_devices);
static DEFINE_MUTEX(i40evf_device_mutex);
static u32 i40evf_client_virtchnl_send(struct i40e_info *ldev,
struct i40e_client *client,
u8 *msg, u16 len);
static int i40evf_client_setup_qvlist(struct i40e_info *ldev,
struct i40e_client *client,
struct i40e_qvlist_info *qvlist_info);
static struct i40e_ops i40evf_lan_ops = {
.virtchnl_send = i40evf_client_virtchnl_send,
.setup_qvlist = i40evf_client_setup_qvlist,
};
/**
* i40evf_notify_client_message - call the client message receive callback
* @vsi: the VSI associated with this client
* @msg: message buffer
* @len: length of message
*
* If there is a client to this VSI, call the client
**/
void i40evf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len)
{
struct i40evf_adapter *adapter = vsi->back;
struct i40e_client_instance *cinst = adapter->cinst;
if (!vsi)
return;
if (!cinst || !cinst->client || !cinst->client->ops ||
!cinst->client->ops->virtchnl_receive) {
dev_dbg(&vsi->back->pdev->dev,
"Cannot locate client instance virtchnl_receive function\n");
return;
}
cinst->client->ops->virtchnl_receive(&cinst->lan_info, cinst->client,
msg, len);
}
/**
* i40evf_notify_client_l2_params - call the client notify callback
* @vsi: the VSI with l2 param changes
*
* If there is a client to this VSI, call the client
**/
void i40evf_notify_client_l2_params(struct i40e_vsi *vsi)
{
struct i40evf_adapter *adapter = vsi->back;
struct i40e_client_instance *cinst = adapter->cinst;
struct i40e_params params;
if (!vsi)
return;
memset(&params, 0, sizeof(params));
params.mtu = vsi->netdev->mtu;
params.link_up = vsi->back->link_up;
params.qos.prio_qos[0].qs_handle = vsi->qs_handle;
if (!cinst || !cinst->client || !cinst->client->ops ||
!cinst->client->ops->l2_param_change) {
dev_dbg(&vsi->back->pdev->dev,
"Cannot locate client instance l2_param_change function\n");
return;
}
cinst->client->ops->l2_param_change(&cinst->lan_info, cinst->client,
&params);
}
/**
* i40evf_notify_client_open - call the client open callback
* @vsi: the VSI with netdev opened
*
* If there is a client to this netdev, call the client with open
**/
void i40evf_notify_client_open(struct i40e_vsi *vsi)
{
struct i40evf_adapter *adapter = vsi->back;
struct i40e_client_instance *cinst = adapter->cinst;
int ret;
if (!cinst || !cinst->client || !cinst->client->ops ||
!cinst->client->ops->open) {
dev_dbg(&vsi->back->pdev->dev,
"Cannot locate client instance open function\n");
return;
}
if (!(test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state))) {
ret = cinst->client->ops->open(&cinst->lan_info, cinst->client);
if (!ret)
set_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state);
}
}
/**
* i40evf_client_release_qvlist - send a message to the PF to release iwarp qv map
* @ldev: pointer to L2 context.
*
* Return 0 on success or < 0 on error
**/
static int i40evf_client_release_qvlist(struct i40e_info *ldev)
{
struct i40evf_adapter *adapter = ldev->vf;
i40e_status err;
if (adapter->aq_required)
return -EAGAIN;
err = i40e_aq_send_msg_to_pf(&adapter->hw,
I40E_VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP,
I40E_SUCCESS, NULL, 0, NULL);
if (err)
dev_err(&adapter->pdev->dev,
"Unable to send iWarp vector release message to PF, error %d, aq status %d\n",
err, adapter->hw.aq.asq_last_status);
return err;
}
/**
* i40evf_notify_client_close - call the client close callback
* @vsi: the VSI with netdev closed
* @reset: true when close called due to reset pending
*
* If there is a client to this netdev, call the client with close
**/
void i40evf_notify_client_close(struct i40e_vsi *vsi, bool reset)
{
struct i40evf_adapter *adapter = vsi->back;
struct i40e_client_instance *cinst = adapter->cinst;
if (!cinst || !cinst->client || !cinst->client->ops ||
!cinst->client->ops->close) {
dev_dbg(&vsi->back->pdev->dev,
"Cannot locate client instance close function\n");
return;
}
cinst->client->ops->close(&cinst->lan_info, cinst->client, reset);
i40evf_client_release_qvlist(&cinst->lan_info);
clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state);
}
/**
* i40evf_client_add_instance - add a client instance to the instance list
* @adapter: pointer to the board struct
* @client: pointer to a client struct in the client list.
*
* Returns cinst ptr on success, NULL on failure
**/
static struct i40e_client_instance *
i40evf_client_add_instance(struct i40evf_adapter *adapter)
{
struct i40e_client_instance *cinst = NULL;
struct netdev_hw_addr *mac = NULL;
struct i40e_vsi *vsi = &adapter->vsi;
int i;
if (!vf_registered_client)
goto out;
if (adapter->cinst) {
cinst = adapter->cinst;
goto out;
}
cinst = kzalloc(sizeof(*cinst), GFP_KERNEL);
if (!cinst)
goto out;
cinst->lan_info.vf = (void *)adapter;
cinst->lan_info.netdev = vsi->netdev;
cinst->lan_info.pcidev = adapter->pdev;
cinst->lan_info.fid = 0;
cinst->lan_info.ftype = I40E_CLIENT_FTYPE_VF;
cinst->lan_info.hw_addr = adapter->hw.hw_addr;
cinst->lan_info.ops = &i40evf_lan_ops;
cinst->lan_info.version.major = I40EVF_CLIENT_VERSION_MAJOR;
cinst->lan_info.version.minor = I40EVF_CLIENT_VERSION_MINOR;
cinst->lan_info.version.build = I40EVF_CLIENT_VERSION_BUILD;
set_bit(__I40E_CLIENT_INSTANCE_NONE, &cinst->state);
cinst->lan_info.msix_count = adapter->num_iwarp_msix;
cinst->lan_info.msix_entries =
&adapter->msix_entries[adapter->iwarp_base_vector];
for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
cinst->lan_info.params.qos.prio_qos[i].tc = 0;
cinst->lan_info.params.qos.prio_qos[i].qs_handle =
vsi->qs_handle;
}
mac = list_first_entry(&cinst->lan_info.netdev->dev_addrs.list,
struct netdev_hw_addr, list);
if (mac)
ether_addr_copy(cinst->lan_info.lanmac, mac->addr);
else
dev_err(&adapter->pdev->dev, "MAC address list is empty!\n");
cinst->client = vf_registered_client;
adapter->cinst = cinst;
out:
return cinst;
}
/**
* i40evf_client_del_instance - removes a client instance from the list
* @adapter: pointer to the board struct
* @client: pointer to the client struct
*
**/
static
void i40evf_client_del_instance(struct i40evf_adapter *adapter)
{
kfree(adapter->cinst);
adapter->cinst = NULL;
}
/**
* i40evf_client_subtask - client maintenance work
* @adapter: board private structure
**/
void i40evf_client_subtask(struct i40evf_adapter *adapter)
{
struct i40e_client *client = vf_registered_client;
struct i40e_client_instance *cinst;
int ret = 0;
if (adapter->state < __I40EVF_DOWN)
return;
/* first check client is registered */
if (!client)
return;
/* Add the client instance to the instance list */
cinst = i40evf_client_add_instance(adapter);
if (!cinst)
return;
dev_info(&adapter->pdev->dev, "Added instance of Client %s\n",
client->name);
if (!test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state)) {
/* Send an Open request to the client */
if (client->ops && client->ops->open)
ret = client->ops->open(&cinst->lan_info, client);
if (!ret)
set_bit(__I40E_CLIENT_INSTANCE_OPENED,
&cinst->state);
else
/* remove client instance */
i40evf_client_del_instance(adapter);
}
}
/**
* i40evf_lan_add_device - add a lan device struct to the list of lan devices
* @adapter: pointer to the board struct
*
* Returns 0 on success or none 0 on error
**/
int i40evf_lan_add_device(struct i40evf_adapter *adapter)
{
struct i40e_device *ldev;
int ret = 0;
mutex_lock(&i40evf_device_mutex);
list_for_each_entry(ldev, &i40evf_devices, list) {
if (ldev->vf == adapter) {
ret = -EEXIST;
goto out;
}
}
ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
if (!ldev) {
ret = -ENOMEM;
goto out;
}
ldev->vf = adapter;
INIT_LIST_HEAD(&ldev->list);
list_add(&ldev->list, &i40evf_devices);
dev_info(&adapter->pdev->dev, "Added LAN device bus=0x%02x dev=0x%02x func=0x%02x\n",
adapter->hw.bus.bus_id, adapter->hw.bus.device,
adapter->hw.bus.func);
/* Since in some cases register may have happened before a device gets
* added, we can schedule a subtask to go initiate the clients.
*/
adapter->flags |= I40EVF_FLAG_SERVICE_CLIENT_REQUESTED;
out:
mutex_unlock(&i40evf_device_mutex);
return ret;
}
/**
* i40evf_lan_del_device - removes a lan device from the device list
* @adapter: pointer to the board struct
*
* Returns 0 on success or non-0 on error
**/
int i40evf_lan_del_device(struct i40evf_adapter *adapter)
{
struct i40e_device *ldev, *tmp;
int ret = -ENODEV;
mutex_lock(&i40evf_device_mutex);
list_for_each_entry_safe(ldev, tmp, &i40evf_devices, list) {
if (ldev->vf == adapter) {
dev_info(&adapter->pdev->dev,
"Deleted LAN device bus=0x%02x dev=0x%02x func=0x%02x\n",
adapter->hw.bus.bus_id, adapter->hw.bus.device,
adapter->hw.bus.func);
list_del(&ldev->list);
kfree(ldev);
ret = 0;
break;
}
}
mutex_unlock(&i40evf_device_mutex);
return ret;
}
/**
* i40evf_client_release - release client specific resources
* @client: pointer to the registered client
*
**/
static void i40evf_client_release(struct i40e_client *client)
{
struct i40e_client_instance *cinst;
struct i40e_device *ldev;
struct i40evf_adapter *adapter;
mutex_lock(&i40evf_device_mutex);
list_for_each_entry(ldev, &i40evf_devices, list) {
adapter = ldev->vf;
cinst = adapter->cinst;
if (!cinst)
continue;
if (test_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state)) {
if (client->ops && client->ops->close)
client->ops->close(&cinst->lan_info, client,
false);
i40evf_client_release_qvlist(&cinst->lan_info);
clear_bit(__I40E_CLIENT_INSTANCE_OPENED, &cinst->state);
dev_warn(&adapter->pdev->dev,
"Client %s instance closed\n", client->name);
}
/* delete the client instance */
i40evf_client_del_instance(adapter);
dev_info(&adapter->pdev->dev, "Deleted client instance of Client %s\n",
client->name);
}
mutex_unlock(&i40evf_device_mutex);
}
/**
* i40evf_client_prepare - prepare client specific resources
* @client: pointer to the registered client
*
**/
static void i40evf_client_prepare(struct i40e_client *client)
{
struct i40e_device *ldev;
struct i40evf_adapter *adapter;
mutex_lock(&i40evf_device_mutex);
list_for_each_entry(ldev, &i40evf_devices, list) {
adapter = ldev->vf;
/* Signal the watchdog to service the client */
adapter->flags |= I40EVF_FLAG_SERVICE_CLIENT_REQUESTED;
}
mutex_unlock(&i40evf_device_mutex);
}
/**
* i40evf_client_virtchnl_send - send a message to the PF instance
* @ldev: pointer to L2 context.
* @client: Client pointer.
* @msg: pointer to message buffer
* @len: message length
*
* Return 0 on success or < 0 on error
**/
static u32 i40evf_client_virtchnl_send(struct i40e_info *ldev,
struct i40e_client *client,
u8 *msg, u16 len)
{
struct i40evf_adapter *adapter = ldev->vf;
i40e_status err;
if (adapter->aq_required)
return -EAGAIN;
err = i40e_aq_send_msg_to_pf(&adapter->hw, I40E_VIRTCHNL_OP_IWARP,
I40E_SUCCESS, msg, len, NULL);
if (err)
dev_err(&adapter->pdev->dev, "Unable to send iWarp message to PF, error %d, aq status %d\n",
err, adapter->hw.aq.asq_last_status);
return err;
}
/**
* i40evf_client_setup_qvlist - send a message to the PF to setup iwarp qv map
* @ldev: pointer to L2 context.
* @client: Client pointer.
* @qv_info: queue and vector list
*
* Return 0 on success or < 0 on error
**/
static int i40evf_client_setup_qvlist(struct i40e_info *ldev,
struct i40e_client *client,
struct i40e_qvlist_info *qvlist_info)
{
struct i40e_virtchnl_iwarp_qvlist_info *v_qvlist_info;
struct i40evf_adapter *adapter = ldev->vf;
struct i40e_qv_info *qv_info;
i40e_status err;
u32 v_idx, i;
u32 msg_size;
if (adapter->aq_required)
return -EAGAIN;
/* A quick check on whether the vectors belong to the client */
for (i = 0; i < qvlist_info->num_vectors; i++) {
qv_info = &qvlist_info->qv_info[i];
if (!qv_info)
continue;
v_idx = qv_info->v_idx;
if ((v_idx >=
(adapter->iwarp_base_vector + adapter->num_iwarp_msix)) ||
(v_idx < adapter->iwarp_base_vector))
return -EINVAL;
}
v_qvlist_info = (struct i40e_virtchnl_iwarp_qvlist_info *)qvlist_info;
msg_size = sizeof(struct i40e_virtchnl_iwarp_qvlist_info) +
(sizeof(struct i40e_virtchnl_iwarp_qv_info) *
(v_qvlist_info->num_vectors - 1));
adapter->client_pending |= BIT(I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP);
err = i40e_aq_send_msg_to_pf(&adapter->hw,
I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP,
I40E_SUCCESS, (u8 *)v_qvlist_info, msg_size, NULL);
if (err) {
dev_err(&adapter->pdev->dev,
"Unable to send iWarp vector config message to PF, error %d, aq status %d\n",
err, adapter->hw.aq.asq_last_status);
goto out;
}
err = -EBUSY;
for (i = 0; i < 5; i++) {
msleep(100);
if (!(adapter->client_pending &
BIT(I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP))) {
err = 0;
break;
}
}
out:
return err;
}
/**
* i40evf_register_client - Register a i40e client driver with the L2 driver
* @client: pointer to the i40e_client struct
*
* Returns 0 on success or non-0 on error
**/
int i40evf_register_client(struct i40e_client *client)
{
int ret = 0;
if (!client) {
ret = -EIO;
goto out;
}
if (strlen(client->name) == 0) {
pr_info("i40evf: Failed to register client with no name\n");
ret = -EIO;
goto out;
}
if (vf_registered_client) {
pr_info("i40evf: Client %s has already been registered!\n",
client->name);
ret = -EEXIST;
goto out;
}
if ((client->version.major != I40EVF_CLIENT_VERSION_MAJOR) ||
(client->version.minor != I40EVF_CLIENT_VERSION_MINOR)) {
pr_info("i40evf: Failed to register client %s due to mismatched client interface version\n",
client->name);
pr_info("Client is using version: %02d.%02d.%02d while LAN driver supports %s\n",
client->version.major, client->version.minor,
client->version.build,
i40evf_client_interface_version_str);
ret = -EIO;
goto out;
}
vf_registered_client = client;
i40evf_client_prepare(client);
pr_info("i40evf: Registered client %s with return code %d\n",
client->name, ret);
out:
return ret;
}
EXPORT_SYMBOL(i40evf_register_client);
/**
* i40evf_unregister_client - Unregister a i40e client driver with the L2 driver
* @client: pointer to the i40e_client struct
*
* Returns 0 on success or non-0 on error
**/
int i40evf_unregister_client(struct i40e_client *client)
{
int ret = 0;
/* When a unregister request comes through we would have to send
* a close for each of the client instances that were opened.
* client_release function is called to handle this.
*/
i40evf_client_release(client);
if (vf_registered_client != client) {
pr_info("i40evf: Client %s has not been registered\n",
client->name);
ret = -ENODEV;
goto out;
}
vf_registered_client = NULL;
pr_info("i40evf: Unregistered client %s\n", client->name);
out:
return ret;
}
EXPORT_SYMBOL(i40evf_unregister_client);
#ifndef _I40E_CLIENT_H_
#define _I40E_CLIENT_H_
#define I40EVF_CLIENT_STR_LENGTH 10
/* Client interface version should be updated anytime there is a change in the
* existing APIs or data structures.
*/
#define I40EVF_CLIENT_VERSION_MAJOR 0
#define I40EVF_CLIENT_VERSION_MINOR 01
#define I40EVF_CLIENT_VERSION_BUILD 00
#define I40EVF_CLIENT_VERSION_STR \
__stringify(I40EVF_CLIENT_VERSION_MAJOR) "." \
__stringify(I40EVF_CLIENT_VERSION_MINOR) "." \
__stringify(I40EVF_CLIENT_VERSION_BUILD)
struct i40e_client_version {
u8 major;
u8 minor;
u8 build;
u8 rsvd;
};
enum i40e_client_state {
__I40E_CLIENT_NULL,
__I40E_CLIENT_REGISTERED
};
enum i40e_client_instance_state {
__I40E_CLIENT_INSTANCE_NONE,
__I40E_CLIENT_INSTANCE_OPENED,
};
struct i40e_ops;
struct i40e_client;
/* HW does not define a type value for AEQ; only for RX/TX and CEQ.
* In order for us to keep the interface simple, SW will define a
* unique type value for AEQ.
*/
#define I40E_QUEUE_TYPE_PE_AEQ 0x80
#define I40E_QUEUE_INVALID_IDX 0xFFFF
struct i40e_qv_info {
u32 v_idx; /* msix_vector */
u16 ceq_idx;
u16 aeq_idx;
u8 itr_idx;
};
struct i40e_qvlist_info {
u32 num_vectors;
struct i40e_qv_info qv_info[1];
};
#define I40E_CLIENT_MSIX_ALL 0xFFFFFFFF
/* set of LAN parameters useful for clients managed by LAN */
/* Struct to hold per priority info */
struct i40e_prio_qos_params {
u16 qs_handle; /* qs handle for prio */
u8 tc; /* TC mapped to prio */
u8 reserved;
};
#define I40E_CLIENT_MAX_USER_PRIORITY 8
/* Struct to hold Client QoS */
struct i40e_qos_params {
struct i40e_prio_qos_params prio_qos[I40E_CLIENT_MAX_USER_PRIORITY];
};
struct i40e_params {
struct i40e_qos_params qos;
u16 mtu;
u16 link_up; /* boolean */
};
/* Structure to hold LAN device info for a client device */
struct i40e_info {
struct i40e_client_version version;
u8 lanmac[6];
struct net_device *netdev;
struct pci_dev *pcidev;
u8 __iomem *hw_addr;
u8 fid; /* function id, PF id or VF id */
#define I40E_CLIENT_FTYPE_PF 0
#define I40E_CLIENT_FTYPE_VF 1
u8 ftype; /* function type, PF or VF */
void *vf; /* cast to i40evf_adapter */
/* All L2 params that could change during the life span of the device
* and needs to be communicated to the client when they change
*/
struct i40e_params params;
struct i40e_ops *ops;
u16 msix_count; /* number of msix vectors*/
/* Array down below will be dynamically allocated based on msix_count */
struct msix_entry *msix_entries;
u16 itr_index; /* Which ITR index the PE driver is suppose to use */
};
struct i40e_ops {
/* setup_q_vector_list enables queues with a particular vector */
int (*setup_qvlist)(struct i40e_info *ldev, struct i40e_client *client,
struct i40e_qvlist_info *qv_info);
u32 (*virtchnl_send)(struct i40e_info *ldev, struct i40e_client *client,
u8 *msg, u16 len);
/* If the PE Engine is unresponsive, RDMA driver can request a reset.*/
void (*request_reset)(struct i40e_info *ldev,
struct i40e_client *client);
};
struct i40e_client_ops {
/* Should be called from register_client() or whenever the driver is
* ready to create a specific client instance.
*/
int (*open)(struct i40e_info *ldev, struct i40e_client *client);
/* Should be closed when netdev is unavailable or when unregister
* call comes in. If the close happens due to a reset, set the reset
* bit to true.
*/
void (*close)(struct i40e_info *ldev, struct i40e_client *client,
bool reset);
/* called when some l2 managed parameters changes - mss */
void (*l2_param_change)(struct i40e_info *ldev,
struct i40e_client *client,
struct i40e_params *params);
/* called when a message is received from the PF */
int (*virtchnl_receive)(struct i40e_info *ldev,
struct i40e_client *client,
u8 *msg, u16 len);
};
/* Client device */
struct i40e_client_instance {
struct list_head list;
struct i40e_info lan_info;
struct i40e_client *client;
unsigned long state;
};
struct i40e_client {
struct list_head list; /* list of registered clients */
char name[I40EVF_CLIENT_STR_LENGTH];
struct i40e_client_version version;
unsigned long state; /* client state */
atomic_t ref_cnt; /* Count of all the client devices of this kind */
u32 flags;
#define I40E_CLIENT_FLAGS_LAUNCH_ON_PROBE BIT(0)
#define I40E_TX_FLAGS_NOTIFY_OTHER_EVENTS BIT(2)
u8 type;
#define I40E_CLIENT_IWARP 0
struct i40e_client_ops *ops; /* client ops provided by the client */
};
/* used by clients */
int i40evf_register_client(struct i40e_client *client);
int i40evf_unregister_client(struct i40e_client *client);
#endif /* _I40E_CLIENT_H_ */
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "i40evf.h" #include "i40evf.h"
#include "i40e_prototype.h" #include "i40e_prototype.h"
#include "i40evf_client.h"
static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter); static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter);
static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter); static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter);
static int i40evf_close(struct net_device *netdev); static int i40evf_close(struct net_device *netdev);
...@@ -36,9 +37,9 @@ static const char i40evf_driver_string[] = ...@@ -36,9 +37,9 @@ static const char i40evf_driver_string[] =
#define DRV_KERN "-k" #define DRV_KERN "-k"
#define DRV_VERSION_MAJOR 1 #define DRV_VERSION_MAJOR 2
#define DRV_VERSION_MINOR 6 #define DRV_VERSION_MINOR 1
#define DRV_VERSION_BUILD 27 #define DRV_VERSION_BUILD 7
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
__stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_MINOR) "." \
__stringify(DRV_VERSION_BUILD) \ __stringify(DRV_VERSION_BUILD) \
...@@ -1058,6 +1059,8 @@ static void i40evf_up_complete(struct i40evf_adapter *adapter) ...@@ -1058,6 +1059,8 @@ static void i40evf_up_complete(struct i40evf_adapter *adapter)
i40evf_napi_enable_all(adapter); i40evf_napi_enable_all(adapter);
adapter->aq_required |= I40EVF_FLAG_AQ_ENABLE_QUEUES; adapter->aq_required |= I40EVF_FLAG_AQ_ENABLE_QUEUES;
if (CLIENT_ENABLED(adapter))
adapter->flags |= I40EVF_FLAG_CLIENT_NEEDS_OPEN;
mod_timer_pending(&adapter->watchdog_timer, jiffies + 1); mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
} }
...@@ -1685,6 +1688,7 @@ static void i40evf_watchdog_task(struct work_struct *work) ...@@ -1685,6 +1688,7 @@ static void i40evf_watchdog_task(struct work_struct *work)
i40evf_set_promiscuous(adapter, 0); i40evf_set_promiscuous(adapter, 0);
goto watchdog_done; goto watchdog_done;
} }
schedule_delayed_work(&adapter->client_task, msecs_to_jiffies(5));
if (adapter->state == __I40EVF_RUNNING) if (adapter->state == __I40EVF_RUNNING)
i40evf_request_stats(adapter); i40evf_request_stats(adapter);
...@@ -1773,10 +1777,17 @@ static void i40evf_reset_task(struct work_struct *work) ...@@ -1773,10 +1777,17 @@ static void i40evf_reset_task(struct work_struct *work)
u32 reg_val; u32 reg_val;
int i = 0, err; int i = 0, err;
while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, while (test_and_set_bit(__I40EVF_IN_CLIENT_TASK,
&adapter->crit_section)) &adapter->crit_section))
usleep_range(500, 1000); usleep_range(500, 1000);
if (CLIENT_ENABLED(adapter)) {
adapter->flags &= ~(I40EVF_FLAG_CLIENT_NEEDS_OPEN |
I40EVF_FLAG_CLIENT_NEEDS_CLOSE |
I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS |
I40EVF_FLAG_SERVICE_CLIENT_REQUESTED);
cancel_delayed_work_sync(&adapter->client_task);
i40evf_notify_client_close(&adapter->vsi, true);
}
i40evf_misc_irq_disable(adapter); i40evf_misc_irq_disable(adapter);
if (adapter->flags & I40EVF_FLAG_RESET_NEEDED) { if (adapter->flags & I40EVF_FLAG_RESET_NEEDED) {
adapter->flags &= ~I40EVF_FLAG_RESET_NEEDED; adapter->flags &= ~I40EVF_FLAG_RESET_NEEDED;
...@@ -1819,6 +1830,7 @@ static void i40evf_reset_task(struct work_struct *work) ...@@ -1819,6 +1830,7 @@ static void i40evf_reset_task(struct work_struct *work)
dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n", dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n",
reg_val); reg_val);
i40evf_disable_vf(adapter); i40evf_disable_vf(adapter);
clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section);
return; /* Do not attempt to reinit. It's dead, Jim. */ return; /* Do not attempt to reinit. It's dead, Jim. */
} }
...@@ -1861,9 +1873,8 @@ static void i40evf_reset_task(struct work_struct *work) ...@@ -1861,9 +1873,8 @@ static void i40evf_reset_task(struct work_struct *work)
} }
adapter->aq_required |= I40EVF_FLAG_AQ_ADD_MAC_FILTER; adapter->aq_required |= I40EVF_FLAG_AQ_ADD_MAC_FILTER;
adapter->aq_required |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER; adapter->aq_required |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER;
/* Open RDMA Client again */
adapter->aq_required |= I40EVF_FLAG_SERVICE_CLIENT_REQUESTED;
clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section);
i40evf_misc_irq_enable(adapter); i40evf_misc_irq_enable(adapter);
mod_timer(&adapter->watchdog_timer, jiffies + 2); mod_timer(&adapter->watchdog_timer, jiffies + 2);
...@@ -1979,6 +1990,48 @@ static void i40evf_adminq_task(struct work_struct *work) ...@@ -1979,6 +1990,48 @@ static void i40evf_adminq_task(struct work_struct *work)
i40evf_misc_irq_enable(adapter); i40evf_misc_irq_enable(adapter);
} }
/**
* i40evf_client_task - worker thread to perform client work
* @work: pointer to work_struct containing our data
*
* This task handles client interactions. Because client calls can be
* reentrant, we can't handle them in the watchdog.
**/
static void i40evf_client_task(struct work_struct *work)
{
struct i40evf_adapter *adapter =
container_of(work, struct i40evf_adapter, client_task.work);
/* If we can't get the client bit, just give up. We'll be rescheduled
* later.
*/
if (test_and_set_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section))
return;
if (adapter->flags & I40EVF_FLAG_SERVICE_CLIENT_REQUESTED) {
i40evf_client_subtask(adapter);
adapter->flags &= ~I40EVF_FLAG_SERVICE_CLIENT_REQUESTED;
goto out;
}
if (adapter->flags & I40EVF_FLAG_CLIENT_NEEDS_CLOSE) {
i40evf_notify_client_close(&adapter->vsi, false);
adapter->flags &= ~I40EVF_FLAG_CLIENT_NEEDS_CLOSE;
goto out;
}
if (adapter->flags & I40EVF_FLAG_CLIENT_NEEDS_OPEN) {
i40evf_notify_client_open(&adapter->vsi);
adapter->flags &= ~I40EVF_FLAG_CLIENT_NEEDS_OPEN;
goto out;
}
if (adapter->flags & I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS) {
i40evf_notify_client_l2_params(&adapter->vsi);
adapter->flags &= ~I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS;
}
out:
clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section);
}
/** /**
* i40evf_free_all_tx_resources - Free Tx Resources for All Queues * i40evf_free_all_tx_resources - Free Tx Resources for All Queues
* @adapter: board private structure * @adapter: board private structure
...@@ -2148,6 +2201,8 @@ static int i40evf_close(struct net_device *netdev) ...@@ -2148,6 +2201,8 @@ static int i40evf_close(struct net_device *netdev)
set_bit(__I40E_DOWN, &adapter->vsi.state); set_bit(__I40E_DOWN, &adapter->vsi.state);
if (CLIENT_ENABLED(adapter))
adapter->flags |= I40EVF_FLAG_CLIENT_NEEDS_CLOSE;
i40evf_down(adapter); i40evf_down(adapter);
adapter->state = __I40EVF_DOWN_PENDING; adapter->state = __I40EVF_DOWN_PENDING;
...@@ -2188,6 +2243,10 @@ static int i40evf_change_mtu(struct net_device *netdev, int new_mtu) ...@@ -2188,6 +2243,10 @@ static int i40evf_change_mtu(struct net_device *netdev, int new_mtu)
struct i40evf_adapter *adapter = netdev_priv(netdev); struct i40evf_adapter *adapter = netdev_priv(netdev);
netdev->mtu = new_mtu; netdev->mtu = new_mtu;
if (CLIENT_ENABLED(adapter)) {
i40evf_notify_client_l2_params(&adapter->vsi);
adapter->flags |= I40EVF_FLAG_SERVICE_CLIENT_REQUESTED;
}
adapter->flags |= I40EVF_FLAG_RESET_NEEDED; adapter->flags |= I40EVF_FLAG_RESET_NEEDED;
schedule_work(&adapter->reset_task); schedule_work(&adapter->reset_task);
...@@ -2581,6 +2640,12 @@ static void i40evf_init_task(struct work_struct *work) ...@@ -2581,6 +2640,12 @@ static void i40evf_init_task(struct work_struct *work)
adapter->netdev_registered = true; adapter->netdev_registered = true;
netif_tx_stop_all_queues(netdev); netif_tx_stop_all_queues(netdev);
if (CLIENT_ALLOWED(adapter)) {
err = i40evf_lan_add_device(adapter);
if (err)
dev_info(&pdev->dev, "Failed to add VF to client API service list: %d\n",
err);
}
dev_info(&pdev->dev, "MAC address: %pM\n", adapter->hw.mac.addr); dev_info(&pdev->dev, "MAC address: %pM\n", adapter->hw.mac.addr);
if (netdev->features & NETIF_F_GRO) if (netdev->features & NETIF_F_GRO)
...@@ -2745,6 +2810,7 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -2745,6 +2810,7 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
INIT_WORK(&adapter->reset_task, i40evf_reset_task); INIT_WORK(&adapter->reset_task, i40evf_reset_task);
INIT_WORK(&adapter->adminq_task, i40evf_adminq_task); INIT_WORK(&adapter->adminq_task, i40evf_adminq_task);
INIT_WORK(&adapter->watchdog_task, i40evf_watchdog_task); INIT_WORK(&adapter->watchdog_task, i40evf_watchdog_task);
INIT_DELAYED_WORK(&adapter->client_task, i40evf_client_task);
INIT_DELAYED_WORK(&adapter->init_task, i40evf_init_task); INIT_DELAYED_WORK(&adapter->init_task, i40evf_init_task);
schedule_delayed_work(&adapter->init_task, schedule_delayed_work(&adapter->init_task,
msecs_to_jiffies(5 * (pdev->devfn & 0x07))); msecs_to_jiffies(5 * (pdev->devfn & 0x07)));
...@@ -2857,14 +2923,21 @@ static void i40evf_remove(struct pci_dev *pdev) ...@@ -2857,14 +2923,21 @@ static void i40evf_remove(struct pci_dev *pdev)
struct i40evf_adapter *adapter = netdev_priv(netdev); struct i40evf_adapter *adapter = netdev_priv(netdev);
struct i40evf_mac_filter *f, *ftmp; struct i40evf_mac_filter *f, *ftmp;
struct i40e_hw *hw = &adapter->hw; struct i40e_hw *hw = &adapter->hw;
int err;
cancel_delayed_work_sync(&adapter->init_task); cancel_delayed_work_sync(&adapter->init_task);
cancel_work_sync(&adapter->reset_task); cancel_work_sync(&adapter->reset_task);
cancel_delayed_work_sync(&adapter->client_task);
if (adapter->netdev_registered) { if (adapter->netdev_registered) {
unregister_netdev(netdev); unregister_netdev(netdev);
adapter->netdev_registered = false; adapter->netdev_registered = false;
} }
if (CLIENT_ALLOWED(adapter)) {
err = i40evf_lan_del_device(adapter);
if (err)
dev_warn(&pdev->dev, "Failed to delete client device: %d\n",
err);
}
/* Shut down all the garbage mashers on the detention level */ /* Shut down all the garbage mashers on the detention level */
adapter->state = __I40EVF_REMOVE; adapter->state = __I40EVF_REMOVE;
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "i40evf.h" #include "i40evf.h"
#include "i40e_prototype.h" #include "i40e_prototype.h"
#include "i40evf_client.h"
/* busy wait delay in msec */ /* busy wait delay in msec */
#define I40EVF_BUSY_WAIT_DELAY 10 #define I40EVF_BUSY_WAIT_DELAY 10
...@@ -999,6 +1000,16 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, ...@@ -999,6 +1000,16 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
if (v_opcode != adapter->current_op) if (v_opcode != adapter->current_op)
return; return;
break; break;
case I40E_VIRTCHNL_OP_IWARP:
/* Gobble zero-length replies from the PF. They indicate that
* a previous message was received OK, and the client doesn't
* care about that.
*/
if (msglen && CLIENT_ENABLED(adapter))
i40evf_notify_client_message(&adapter->vsi,
msg, msglen);
break;
case I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP: case I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP:
adapter->client_pending &= adapter->client_pending &=
~(BIT(I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP)); ~(BIT(I40E_VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP));
...@@ -1014,7 +1025,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, ...@@ -1014,7 +1025,7 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
} }
break; break;
default: default:
if (v_opcode != adapter->current_op) if (adapter->current_op && (v_opcode != adapter->current_op))
dev_warn(&adapter->pdev->dev, "Expected response %d from PF, received %d\n", dev_warn(&adapter->pdev->dev, "Expected response %d from PF, received %d\n",
adapter->current_op, v_opcode); adapter->current_op, v_opcode);
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment