Commit 418e0721 authored by David S. Miller's avatar David S. Miller
Browse files

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: default avatarJesse Brandeburg <jesse.brandeburg@intel.com&gt;'>
Changes in v2:
- Changed the subject to include 'gve:'
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d9e8da55 a5affbd8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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 */
+20 −1
Original line number Diff line number Diff line
@@ -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;
+51 −0
Original line number Diff line number Diff line
@@ -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;
+5 −0
Original line number Diff line number Diff line
@@ -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 */
+52 −0
Original line number Diff line number Diff line
@@ -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;

Loading