mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 16:24:13 +08:00
Merge branch 'gve-alternate-missed-completions'
Jeroen de Borst says: ==================== gve: Handle alternate miss-completions Some versions of the virtual NIC present miss-completions in an alternative way. Let the diver handle these alternate completions and announce this capability to the device. The capability is announced uing a new AdminQ command that sends driver information to the device. The device can refuse a driver if it is lacking support for a capability, or it can adopt it's behavior to work around OS specific issues. Changed in v5: - Removed comments in fucntion calls - Switched ENOTSUPP back to EOPNOTSUPP and made sure it gets passed Changed in v4: - Clarified new AdminQ command in cover letter - Changed EOPNOTSUPP to ENOTSUPP to match device's response Changed in v3: - Rewording cover letter - Added 'Reviewed-by: Jesse Brandeburg <jesse.brandeburg@intel.com>' Changes in v2: - Changed the subject to include 'gve:' ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
418e0721d4
@ -563,6 +563,7 @@ struct gve_priv {
|
||||
u32 adminq_report_stats_cnt;
|
||||
u32 adminq_report_link_speed_cnt;
|
||||
u32 adminq_get_ptype_map_cnt;
|
||||
u32 adminq_verify_driver_compatibility_cnt;
|
||||
|
||||
/* Global stats */
|
||||
u32 interface_up_cnt; /* count of times interface turned up since last reset */
|
||||
|
@ -289,7 +289,7 @@ static int gve_adminq_parse_err(struct gve_priv *priv, u32 status)
|
||||
case GVE_ADMINQ_COMMAND_ERROR_RESOURCE_EXHAUSTED:
|
||||
return -ENOMEM;
|
||||
case GVE_ADMINQ_COMMAND_ERROR_UNIMPLEMENTED:
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
default:
|
||||
dev_err(&priv->pdev->dev, "parse_aq_err: unknown status code %d\n", status);
|
||||
return -EINVAL;
|
||||
@ -407,6 +407,9 @@ static int gve_adminq_issue_cmd(struct gve_priv *priv,
|
||||
case GVE_ADMINQ_GET_PTYPE_MAP:
|
||||
priv->adminq_get_ptype_map_cnt++;
|
||||
break;
|
||||
case GVE_ADMINQ_VERIFY_DRIVER_COMPATIBILITY:
|
||||
priv->adminq_verify_driver_compatibility_cnt++;
|
||||
break;
|
||||
default:
|
||||
dev_err(&priv->pdev->dev, "unknown AQ command opcode %d\n", opcode);
|
||||
}
|
||||
@ -878,6 +881,22 @@ int gve_adminq_report_stats(struct gve_priv *priv, u64 stats_report_len,
|
||||
return gve_adminq_execute_cmd(priv, &cmd);
|
||||
}
|
||||
|
||||
int gve_adminq_verify_driver_compatibility(struct gve_priv *priv,
|
||||
u64 driver_info_len,
|
||||
dma_addr_t driver_info_addr)
|
||||
{
|
||||
union gve_adminq_command cmd;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.opcode = cpu_to_be32(GVE_ADMINQ_VERIFY_DRIVER_COMPATIBILITY);
|
||||
cmd.verify_driver_compatibility = (struct gve_adminq_verify_driver_compatibility) {
|
||||
.driver_info_len = cpu_to_be64(driver_info_len),
|
||||
.driver_info_addr = cpu_to_be64(driver_info_addr),
|
||||
};
|
||||
|
||||
return gve_adminq_execute_cmd(priv, &cmd);
|
||||
}
|
||||
|
||||
int gve_adminq_report_link_speed(struct gve_priv *priv)
|
||||
{
|
||||
union gve_adminq_command gvnic_cmd;
|
||||
|
@ -24,6 +24,7 @@ enum gve_adminq_opcodes {
|
||||
GVE_ADMINQ_REPORT_STATS = 0xC,
|
||||
GVE_ADMINQ_REPORT_LINK_SPEED = 0xD,
|
||||
GVE_ADMINQ_GET_PTYPE_MAP = 0xE,
|
||||
GVE_ADMINQ_VERIFY_DRIVER_COMPATIBILITY = 0xF,
|
||||
};
|
||||
|
||||
/* Admin queue status codes */
|
||||
@ -146,6 +147,51 @@ enum gve_sup_feature_mask {
|
||||
|
||||
#define GVE_DEV_OPT_LEN_GQI_RAW_ADDRESSING 0x0
|
||||
|
||||
#define GVE_VERSION_STR_LEN 128
|
||||
|
||||
enum gve_driver_capbility {
|
||||
gve_driver_capability_gqi_qpl = 0,
|
||||
gve_driver_capability_gqi_rda = 1,
|
||||
gve_driver_capability_dqo_qpl = 2, /* reserved for future use */
|
||||
gve_driver_capability_dqo_rda = 3,
|
||||
gve_driver_capability_alt_miss_compl = 4,
|
||||
};
|
||||
|
||||
#define GVE_CAP1(a) BIT((int)a)
|
||||
#define GVE_CAP2(a) BIT(((int)a) - 64)
|
||||
#define GVE_CAP3(a) BIT(((int)a) - 128)
|
||||
#define GVE_CAP4(a) BIT(((int)a) - 192)
|
||||
|
||||
#define GVE_DRIVER_CAPABILITY_FLAGS1 \
|
||||
(GVE_CAP1(gve_driver_capability_gqi_qpl) | \
|
||||
GVE_CAP1(gve_driver_capability_gqi_rda) | \
|
||||
GVE_CAP1(gve_driver_capability_dqo_rda) | \
|
||||
GVE_CAP1(gve_driver_capability_alt_miss_compl))
|
||||
|
||||
#define GVE_DRIVER_CAPABILITY_FLAGS2 0x0
|
||||
#define GVE_DRIVER_CAPABILITY_FLAGS3 0x0
|
||||
#define GVE_DRIVER_CAPABILITY_FLAGS4 0x0
|
||||
|
||||
struct gve_driver_info {
|
||||
u8 os_type; /* 0x01 = Linux */
|
||||
u8 driver_major;
|
||||
u8 driver_minor;
|
||||
u8 driver_sub;
|
||||
__be32 os_version_major;
|
||||
__be32 os_version_minor;
|
||||
__be32 os_version_sub;
|
||||
__be64 driver_capability_flags[4];
|
||||
u8 os_version_str1[GVE_VERSION_STR_LEN];
|
||||
u8 os_version_str2[GVE_VERSION_STR_LEN];
|
||||
};
|
||||
|
||||
struct gve_adminq_verify_driver_compatibility {
|
||||
__be64 driver_info_len;
|
||||
__be64 driver_info_addr;
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct gve_adminq_verify_driver_compatibility) == 16);
|
||||
|
||||
struct gve_adminq_configure_device_resources {
|
||||
__be64 counter_array;
|
||||
__be64 irq_db_addr;
|
||||
@ -345,6 +391,8 @@ union gve_adminq_command {
|
||||
struct gve_adminq_report_stats report_stats;
|
||||
struct gve_adminq_report_link_speed report_link_speed;
|
||||
struct gve_adminq_get_ptype_map get_ptype_map;
|
||||
struct gve_adminq_verify_driver_compatibility
|
||||
verify_driver_compatibility;
|
||||
};
|
||||
};
|
||||
u8 reserved[64];
|
||||
@ -372,6 +420,9 @@ int gve_adminq_unregister_page_list(struct gve_priv *priv, u32 page_list_id);
|
||||
int gve_adminq_set_mtu(struct gve_priv *priv, u64 mtu);
|
||||
int gve_adminq_report_stats(struct gve_priv *priv, u64 stats_report_len,
|
||||
dma_addr_t stats_report_addr, u64 interval);
|
||||
int gve_adminq_verify_driver_compatibility(struct gve_priv *priv,
|
||||
u64 driver_info_len,
|
||||
dma_addr_t driver_info_addr);
|
||||
int gve_adminq_report_link_speed(struct gve_priv *priv);
|
||||
|
||||
struct gve_ptype_lut;
|
||||
|
@ -176,6 +176,11 @@ static_assert(sizeof(struct gve_tx_compl_desc) == 8);
|
||||
#define GVE_COMPL_TYPE_DQO_MISS 0x1 /* Miss path completion */
|
||||
#define GVE_COMPL_TYPE_DQO_REINJECTION 0x3 /* Re-injection completion */
|
||||
|
||||
/* The most significant bit in the completion tag can change the completion
|
||||
* type from packet completion to miss path completion.
|
||||
*/
|
||||
#define GVE_ALT_MISS_COMPL_BIT BIT(15)
|
||||
|
||||
/* Descriptor to post buffers to HW on buffer queue. */
|
||||
struct gve_rx_desc_dqo {
|
||||
__le16 buf_id; /* ID returned in Rx completion descriptor */
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/version.h>
|
||||
#include <net/sch_generic.h>
|
||||
#include "gve.h"
|
||||
#include "gve_dqo.h"
|
||||
@ -30,6 +32,49 @@
|
||||
const char gve_version_str[] = GVE_VERSION;
|
||||
static const char gve_version_prefix[] = GVE_VERSION_PREFIX;
|
||||
|
||||
static int gve_verify_driver_compatibility(struct gve_priv *priv)
|
||||
{
|
||||
int err;
|
||||
struct gve_driver_info *driver_info;
|
||||
dma_addr_t driver_info_bus;
|
||||
|
||||
driver_info = dma_alloc_coherent(&priv->pdev->dev,
|
||||
sizeof(struct gve_driver_info),
|
||||
&driver_info_bus, GFP_KERNEL);
|
||||
if (!driver_info)
|
||||
return -ENOMEM;
|
||||
|
||||
*driver_info = (struct gve_driver_info) {
|
||||
.os_type = 1, /* Linux */
|
||||
.os_version_major = cpu_to_be32(LINUX_VERSION_MAJOR),
|
||||
.os_version_minor = cpu_to_be32(LINUX_VERSION_SUBLEVEL),
|
||||
.os_version_sub = cpu_to_be32(LINUX_VERSION_PATCHLEVEL),
|
||||
.driver_capability_flags = {
|
||||
cpu_to_be64(GVE_DRIVER_CAPABILITY_FLAGS1),
|
||||
cpu_to_be64(GVE_DRIVER_CAPABILITY_FLAGS2),
|
||||
cpu_to_be64(GVE_DRIVER_CAPABILITY_FLAGS3),
|
||||
cpu_to_be64(GVE_DRIVER_CAPABILITY_FLAGS4),
|
||||
},
|
||||
};
|
||||
strscpy(driver_info->os_version_str1, utsname()->release,
|
||||
sizeof(driver_info->os_version_str1));
|
||||
strscpy(driver_info->os_version_str2, utsname()->version,
|
||||
sizeof(driver_info->os_version_str2));
|
||||
|
||||
err = gve_adminq_verify_driver_compatibility(priv,
|
||||
sizeof(struct gve_driver_info),
|
||||
driver_info_bus);
|
||||
|
||||
/* It's ok if the device doesn't support this */
|
||||
if (err == -EOPNOTSUPP)
|
||||
err = 0;
|
||||
|
||||
dma_free_coherent(&priv->pdev->dev,
|
||||
sizeof(struct gve_driver_info),
|
||||
driver_info, driver_info_bus);
|
||||
return err;
|
||||
}
|
||||
|
||||
static netdev_tx_t gve_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct gve_priv *priv = netdev_priv(dev);
|
||||
@ -1368,6 +1413,13 @@ static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = gve_verify_driver_compatibility(priv);
|
||||
if (err) {
|
||||
dev_err(&priv->pdev->dev,
|
||||
"Could not verify driver compatibility: err=%d\n", err);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (skip_describe_device)
|
||||
goto setup_device;
|
||||
|
||||
|
@ -953,12 +953,18 @@ int gve_clean_tx_done_dqo(struct gve_priv *priv, struct gve_tx_ring *tx,
|
||||
atomic_set_release(&tx->dqo_compl.hw_tx_head, tx_head);
|
||||
} else if (type == GVE_COMPL_TYPE_DQO_PKT) {
|
||||
u16 compl_tag = le16_to_cpu(compl_desc->completion_tag);
|
||||
|
||||
gve_handle_packet_completion(priv, tx, !!napi,
|
||||
compl_tag,
|
||||
&pkt_compl_bytes,
|
||||
&pkt_compl_pkts,
|
||||
/*is_reinjection=*/false);
|
||||
if (compl_tag & GVE_ALT_MISS_COMPL_BIT) {
|
||||
compl_tag &= ~GVE_ALT_MISS_COMPL_BIT;
|
||||
gve_handle_miss_completion(priv, tx, compl_tag,
|
||||
&miss_compl_bytes,
|
||||
&miss_compl_pkts);
|
||||
} else {
|
||||
gve_handle_packet_completion(priv, tx, !!napi,
|
||||
compl_tag,
|
||||
&pkt_compl_bytes,
|
||||
&pkt_compl_pkts,
|
||||
false);
|
||||
}
|
||||
} else if (type == GVE_COMPL_TYPE_DQO_MISS) {
|
||||
u16 compl_tag = le16_to_cpu(compl_desc->completion_tag);
|
||||
|
||||
@ -972,7 +978,7 @@ int gve_clean_tx_done_dqo(struct gve_priv *priv, struct gve_tx_ring *tx,
|
||||
compl_tag,
|
||||
&reinject_compl_bytes,
|
||||
&reinject_compl_pkts,
|
||||
/*is_reinjection=*/true);
|
||||
true);
|
||||
}
|
||||
|
||||
tx->dqo_compl.head =
|
||||
|
Loading…
Reference in New Issue
Block a user