Check whether the driver is compatible with the device presented. Signed-off-by: Rushil Gupta <rush...@google.com> Signed-off-by: Jordan Kimbrough <jr...@google.com> Signed-off-by: Junfeng Guo <junfeng....@intel.com> Signed-off-by: Jeroen de Borst <jeroe...@google.com> --- drivers/net/gve/base/gve_adminq.c | 19 ++++++++++ drivers/net/gve/base/gve_adminq.h | 48 +++++++++++++++++++++++++ drivers/net/gve/base/gve_osdep.h | 8 +++++ drivers/net/gve/gve_ethdev.c | 60 +++++++++++++++++++++++++++++++ drivers/net/gve/gve_ethdev.h | 1 + 5 files changed, 136 insertions(+)
diff --git a/drivers/net/gve/base/gve_adminq.c b/drivers/net/gve/base/gve_adminq.c index e963f910a0..5576990cb1 100644 --- a/drivers/net/gve/base/gve_adminq.c +++ b/drivers/net/gve/base/gve_adminq.c @@ -401,6 +401,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: PMD_DRV_LOG(ERR, "unknown AQ command opcode %d", opcode); } @@ -859,6 +862,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) { struct gve_dma_mem link_speed_region_dma_mem; diff --git a/drivers/net/gve/base/gve_adminq.h b/drivers/net/gve/base/gve_adminq.h index 05550119de..c82e02405c 100644 --- a/drivers/net/gve/base/gve_adminq.h +++ b/drivers/net/gve/base/gve_adminq.h @@ -23,6 +23,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 */ @@ -145,6 +146,48 @@ 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; +}; + +GVE_CHECK_STRUCT_LEN(16, gve_adminq_verify_driver_compatibility); struct gve_adminq_configure_device_resources { __be64 counter_array; @@ -345,6 +388,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]; @@ -377,5 +422,8 @@ int gve_adminq_report_link_speed(struct gve_priv *priv); struct gve_ptype_lut; int gve_adminq_get_ptype_map_dqo(struct gve_priv *priv, struct gve_ptype_lut *ptype_lut); +int gve_adminq_verify_driver_compatibility(struct gve_priv *priv, + u64 driver_info_len, + dma_addr_t driver_info_addr); #endif /* _GVE_ADMINQ_H */ diff --git a/drivers/net/gve/base/gve_osdep.h b/drivers/net/gve/base/gve_osdep.h index abf3d379ae..a8feae18f4 100644 --- a/drivers/net/gve/base/gve_osdep.h +++ b/drivers/net/gve/base/gve_osdep.h @@ -21,6 +21,9 @@ #include <rte_malloc.h> #include <rte_memcpy.h> #include <rte_memzone.h> +#include <rte_version.h> +#include <linux/version.h> +#include <sys/utsname.h> #include "../gve_logs.h" @@ -82,6 +85,11 @@ typedef rte_iova_t dma_addr_t; { gve_static_assert_##X = (n) / ((sizeof(struct X) == (n)) ? 1 : 0) } #define GVE_CHECK_UNION_LEN(n, X) enum gve_static_asset_enum_##X \ { gve_static_assert_##X = (n) / ((sizeof(union X) == (n)) ? 1 : 0) } +#ifndef LINUX_VERSION_MAJOR +#define LINUX_VERSION_MAJOR (((LINUX_VERSION_CODE) >> 16) & 0xff) +#define LINUX_VERSION_SUBLEVEL (((LINUX_VERSION_CODE) >> 8) & 0xff) +#define LINUX_VERSION_PATCHLEVEL ((LINUX_VERSION_CODE) & 0xff) +#endif static __rte_always_inline u8 readb(volatile void *addr) diff --git a/drivers/net/gve/gve_ethdev.c b/drivers/net/gve/gve_ethdev.c index fae00305f9..096f7c2d60 100644 --- a/drivers/net/gve/gve_ethdev.c +++ b/drivers/net/gve/gve_ethdev.c @@ -314,6 +314,60 @@ gve_dev_close(struct rte_eth_dev *dev) return err; } +static int +gve_verify_driver_compatibility(struct gve_priv *priv) +{ + const struct rte_memzone *driver_info_bus; + struct gve_driver_info *driver_info; + struct utsname uts; + char *release; + int err; + + driver_info_bus = rte_memzone_reserve_aligned("verify_driver_compatibility", + sizeof(struct gve_driver_info), + rte_socket_id(), + RTE_MEMZONE_IOVA_CONTIG, + PAGE_SIZE); + if (driver_info_bus == NULL) { + PMD_DRV_LOG(ERR, "Could not alloc memzone for driver compatibility"); + return -ENOMEM; + } + driver_info = (struct gve_driver_info *)driver_info_bus->addr; + *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), + }, + }; + + if (uname(&uts) > 0) + release = uts.release; + + /* OS version */ + rte_strscpy((char *)driver_info->os_version_str1, release, + sizeof(driver_info->os_version_str1)); + /* DPDK version */ + rte_strscpy((char *)driver_info->os_version_str2, rte_version(), + sizeof(driver_info->os_version_str2)); + + err = gve_adminq_verify_driver_compatibility(priv, + sizeof(struct gve_driver_info), + (dma_addr_t)driver_info_bus); + + /* It's ok if the device doesn't support this */ + if (err == -EOPNOTSUPP) + err = 0; + + rte_memzone_free(driver_info_bus); + return err; +} + static int gve_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) { @@ -625,6 +679,12 @@ gve_init_priv(struct gve_priv *priv, bool skip_describe_device) return err; } + err = gve_verify_driver_compatibility(priv); + if (err) { + PMD_DRV_LOG(ERR, "Could not verify driver compatibility: err=%d", err); + goto free_adminq; + } + if (skip_describe_device) goto setup_device; diff --git a/drivers/net/gve/gve_ethdev.h b/drivers/net/gve/gve_ethdev.h index 608a2f2fb4..cd26225c19 100644 --- a/drivers/net/gve/gve_ethdev.h +++ b/drivers/net/gve/gve_ethdev.h @@ -250,6 +250,7 @@ struct gve_priv { uint32_t adminq_report_stats_cnt; uint32_t adminq_report_link_speed_cnt; uint32_t adminq_get_ptype_map_cnt; + uint32_t adminq_verify_driver_compatibility_cnt; volatile uint32_t state_flags; -- 2.34.1