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

Reply via email to