Skip to content

Commit

Permalink
gve: Adding a new AdminQ command to verify driver
Browse files Browse the repository at this point in the history
Check whether the driver is compatible with the device
presented.

Signed-off-by: Jeroen de Borst <jeroendb@google.com>
Reviewed-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jeroen de Borst authored and David S. Miller committed Nov 21, 2022
1 parent d9e8da5 commit c2a0c3e
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 1 deletion.
1 change: 1 addition & 0 deletions drivers/net/ethernet/google/gve/gve.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
21 changes: 20 additions & 1 deletion drivers/net/ethernet/google/gve/gve_adminq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down
49 changes: 49 additions & 0 deletions drivers/net/ethernet/google/gve/gve_adminq.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -146,6 +147,49 @@ 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,
};

#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))

#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;
Expand Down Expand Up @@ -345,6 +389,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];
Expand Down Expand Up @@ -372,6 +418,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;
Expand Down
52 changes: 52 additions & 0 deletions drivers/net/ethernet/google/gve/gve_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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);
Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit c2a0c3e

Please sign in to comment.