net: ena: ethtool: add extra properties retrieval via get_priv_flags
authorArthur Kiyanovski <akiyano@amazon.com>
Mon, 3 Jun 2019 14:43:20 +0000 (17:43 +0300)
committerDavid S. Miller <davem@davemloft.net>
Mon, 3 Jun 2019 20:30:38 +0000 (13:30 -0700)
This commit adds a mechanism for exposing different device
properties via ethtool's priv_flags. The strings are provided
by the device and copied to user space through the driver.

In this commit we:

Add commands, structs and defines necessary for handling
extra properties

Add functions for:
Allocation/destruction of a buffer for extra properties strings.
Retreival of extra properties strings and flags from the network device.

Handle the allocation of a buffer for extra properties strings.

* Initialize buffer with extra properties strings from the
  network device at driver startup.

Use ethtool's get_priv_flags to expose extra properties of
the ENA device

Signed-off-by: Arthur Kiyanovski <akiyano@amazon.com>
Signed-off-by: Sameeh Jubran <sameehj@amazon.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/amazon/ena/ena_admin_defs.h
drivers/net/ethernet/amazon/ena/ena_com.c
drivers/net/ethernet/amazon/ena/ena_com.h
drivers/net/ethernet/amazon/ena/ena_ethtool.c
drivers/net/ethernet/amazon/ena/ena_netdev.c
drivers/net/ethernet/amazon/ena/ena_netdev.h

index 82cff1e120f8168a30940c2723aa4e8bc4c7a2a1..414bae989e10992094f24cf91dcfd1f92950567f 100644 (file)
@@ -32,6 +32,8 @@
 #ifndef _ENA_ADMIN_H_
 #define _ENA_ADMIN_H_
 
+#define ENA_ADMIN_EXTRA_PROPERTIES_STRING_LEN 32
+#define ENA_ADMIN_EXTRA_PROPERTIES_COUNT     32
 
 enum ena_admin_aq_opcode {
        ENA_ADMIN_CREATE_SQ                         = 1,
@@ -60,6 +62,8 @@ enum ena_admin_aq_feature_id {
        ENA_ADMIN_MAX_QUEUES_NUM                    = 2,
        ENA_ADMIN_HW_HINTS                          = 3,
        ENA_ADMIN_LLQ                               = 4,
+       ENA_ADMIN_EXTRA_PROPERTIES_STRINGS          = 5,
+       ENA_ADMIN_EXTRA_PROPERTIES_FLAGS            = 6,
        ENA_ADMIN_RSS_HASH_FUNCTION                 = 10,
        ENA_ADMIN_STATELESS_OFFLOAD_CONFIG          = 11,
        ENA_ADMIN_RSS_REDIRECTION_TABLE_CONFIG      = 12,
@@ -560,6 +564,14 @@ struct ena_admin_set_feature_mtu_desc {
        u32 mtu;
 };
 
+struct ena_admin_get_extra_properties_strings_desc {
+       u32 count;
+};
+
+struct ena_admin_get_extra_properties_flags_desc {
+       u32 flags;
+};
+
 struct ena_admin_set_feature_host_attr_desc {
        /* host OS info base address in OS memory. host info is 4KB of
         * physically contiguous
@@ -864,6 +876,10 @@ struct ena_admin_get_feat_resp {
                struct ena_admin_feature_intr_moder_desc intr_moderation;
 
                struct ena_admin_ena_hw_hints hw_hints;
+
+               struct ena_admin_get_extra_properties_strings_desc extra_properties_strings;
+
+               struct ena_admin_get_extra_properties_flags_desc extra_properties_flags;
        } u;
 };
 
index bd0d785b211e182f20c852c0b6b136614d2f5af2..935e8fa8d7576dc457f3bba21fc0ed4eb614e79c 100644 (file)
@@ -1877,6 +1877,62 @@ int ena_com_get_link_params(struct ena_com_dev *ena_dev,
        return ena_com_get_feature(ena_dev, resp, ENA_ADMIN_LINK_CONFIG);
 }
 
+int ena_com_extra_properties_strings_init(struct ena_com_dev *ena_dev)
+{
+       struct ena_admin_get_feat_resp resp;
+       struct ena_extra_properties_strings *extra_properties_strings =
+                       &ena_dev->extra_properties_strings;
+       u32 rc;
+
+       extra_properties_strings->size = ENA_ADMIN_EXTRA_PROPERTIES_COUNT *
+               ENA_ADMIN_EXTRA_PROPERTIES_STRING_LEN;
+
+       extra_properties_strings->virt_addr =
+               dma_alloc_coherent(ena_dev->dmadev,
+                                  extra_properties_strings->size,
+                                  &extra_properties_strings->dma_addr,
+                                  GFP_KERNEL);
+       if (unlikely(!extra_properties_strings->virt_addr)) {
+               pr_err("Failed to allocate extra properties strings\n");
+               return 0;
+       }
+
+       rc = ena_com_get_feature_ex(ena_dev, &resp,
+                                   ENA_ADMIN_EXTRA_PROPERTIES_STRINGS,
+                                   extra_properties_strings->dma_addr,
+                                   extra_properties_strings->size);
+       if (rc) {
+               pr_debug("Failed to get extra properties strings\n");
+               goto err;
+       }
+
+       return resp.u.extra_properties_strings.count;
+err:
+       ena_com_delete_extra_properties_strings(ena_dev);
+       return 0;
+}
+
+void ena_com_delete_extra_properties_strings(struct ena_com_dev *ena_dev)
+{
+       struct ena_extra_properties_strings *extra_properties_strings =
+                               &ena_dev->extra_properties_strings;
+
+       if (extra_properties_strings->virt_addr) {
+               dma_free_coherent(ena_dev->dmadev,
+                                 extra_properties_strings->size,
+                                 extra_properties_strings->virt_addr,
+                                 extra_properties_strings->dma_addr);
+               extra_properties_strings->virt_addr = NULL;
+       }
+}
+
+int ena_com_get_extra_properties_flags(struct ena_com_dev *ena_dev,
+                                      struct ena_admin_get_feat_resp *resp)
+{
+       return ena_com_get_feature(ena_dev, resp,
+                                  ENA_ADMIN_EXTRA_PROPERTIES_FLAGS);
+}
+
 int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev,
                              struct ena_com_dev_get_features_ctx *get_feat_ctx)
 {
index f0cb043afcc3d89063f731af9278da9bebe98f2b..ce36444c3c3054321d91703a043541475887a24d 100644 (file)
@@ -347,6 +347,12 @@ struct ena_host_attribute {
        dma_addr_t host_info_dma_addr;
 };
 
+struct ena_extra_properties_strings {
+       u8 *virt_addr;
+       dma_addr_t dma_addr;
+       u32 size;
+};
+
 /* Each ena_dev is a PCI function. */
 struct ena_com_dev {
        struct ena_com_admin_queue admin_queue;
@@ -375,6 +381,7 @@ struct ena_com_dev {
        struct ena_intr_moder_entry *intr_moder_tbl;
 
        struct ena_com_llq_info llq_info;
+       struct ena_extra_properties_strings extra_properties_strings;
 };
 
 struct ena_com_dev_get_features_ctx {
@@ -596,6 +603,31 @@ int ena_com_validate_version(struct ena_com_dev *ena_dev);
 int ena_com_get_link_params(struct ena_com_dev *ena_dev,
                            struct ena_admin_get_feat_resp *resp);
 
+/* ena_com_extra_properties_strings_init - Initialize the extra properties strings buffer.
+ * @ena_dev: ENA communication layer struct
+ *
+ * Initialize the extra properties strings buffer.
+ */
+int ena_com_extra_properties_strings_init(struct ena_com_dev *ena_dev);
+
+/* ena_com_delete_extra_properties_strings - Free the extra properties strings buffer.
+ * @ena_dev: ENA communication layer struct
+ *
+ * Free the allocated extra properties strings buffer.
+ */
+void ena_com_delete_extra_properties_strings(struct ena_com_dev *ena_dev);
+
+/* ena_com_get_extra_properties_flags - Retrieve extra properties flags.
+ * @ena_dev: ENA communication layer struct
+ * @resp: Extra properties flags.
+ *
+ * Retrieve the extra properties flags.
+ *
+ * @return - 0 on Success negative value otherwise.
+ */
+int ena_com_get_extra_properties_flags(struct ena_com_dev *ena_dev,
+                                      struct ena_admin_get_feat_resp *resp);
+
 /* ena_com_get_dma_width - Retrieve physical dma address width the device
  * supports.
  * @ena_dev: ENA communication layer struct
index fe596bc30a96b0043d62698607a4c9b364fb5679..28fe4c6ef420f3a5ada58407eaf33e0d1f14152e 100644 (file)
@@ -197,15 +197,24 @@ static void ena_get_ethtool_stats(struct net_device *netdev,
        ena_dev_admin_queue_stats(adapter, &data);
 }
 
+static int get_stats_sset_count(struct ena_adapter *adapter)
+{
+       return  adapter->num_queues * (ENA_STATS_ARRAY_TX + ENA_STATS_ARRAY_RX)
+               + ENA_STATS_ARRAY_GLOBAL + ENA_STATS_ARRAY_ENA_COM;
+}
+
 int ena_get_sset_count(struct net_device *netdev, int sset)
 {
        struct ena_adapter *adapter = netdev_priv(netdev);
 
-       if (sset != ETH_SS_STATS)
+       switch (sset) {
+       case ETH_SS_STATS:
+               return get_stats_sset_count(adapter);
+       case ETH_SS_PRIV_FLAGS:
+               return adapter->ena_extra_properties_count;
+       default:
                return -EOPNOTSUPP;
-
-       return  adapter->num_queues * (ENA_STATS_ARRAY_TX + ENA_STATS_ARRAY_RX)
-               + ENA_STATS_ARRAY_GLOBAL + ENA_STATS_ARRAY_ENA_COM;
+       }
 }
 
 static void ena_queue_strings(struct ena_adapter *adapter, u8 **data)
@@ -247,26 +256,54 @@ static void ena_com_dev_strings(u8 **data)
        }
 }
 
-static void ena_get_strings(struct net_device *netdev, u32 sset, u8 *data)
+static void get_stats_strings(struct ena_adapter *adapter, u8 *data)
 {
-       struct ena_adapter *adapter = netdev_priv(netdev);
        const struct ena_stats *ena_stats;
        int i;
 
-       if (sset != ETH_SS_STATS)
-               return;
-
        for (i = 0; i < ENA_STATS_ARRAY_GLOBAL; i++) {
                ena_stats = &ena_stats_global_strings[i];
-
                memcpy(data, ena_stats->name, ETH_GSTRING_LEN);
                data += ETH_GSTRING_LEN;
        }
-
        ena_queue_strings(adapter, &data);
        ena_com_dev_strings(&data);
 }
 
+static void get_private_flags_strings(struct ena_adapter *adapter, u8 *data)
+{
+       struct ena_com_dev *ena_dev = adapter->ena_dev;
+       u8 *strings = ena_dev->extra_properties_strings.virt_addr;
+       int i;
+
+       if (unlikely(!strings)) {
+               adapter->ena_extra_properties_count = 0;
+               return;
+       }
+
+       for (i = 0; i < adapter->ena_extra_properties_count; i++) {
+               strlcpy(data, strings + ENA_ADMIN_EXTRA_PROPERTIES_STRING_LEN * i,
+                       ETH_GSTRING_LEN);
+               data += ETH_GSTRING_LEN;
+       }
+}
+
+static void ena_get_strings(struct net_device *netdev, u32 sset, u8 *data)
+{
+       struct ena_adapter *adapter = netdev_priv(netdev);
+
+       switch (sset) {
+       case ETH_SS_STATS:
+               get_stats_strings(adapter, data);
+               break;
+       case ETH_SS_PRIV_FLAGS:
+               get_private_flags_strings(adapter, data);
+               break;
+       default:
+               break;
+       }
+}
+
 static int ena_get_link_ksettings(struct net_device *netdev,
                                  struct ethtool_link_ksettings *link_ksettings)
 {
@@ -441,6 +478,7 @@ static void ena_get_drvinfo(struct net_device *dev,
        strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
        strlcpy(info->bus_info, pci_name(adapter->pdev),
                sizeof(info->bus_info));
+       info->n_priv_flags = adapter->ena_extra_properties_count;
 }
 
 static void ena_get_ringparam(struct net_device *netdev,
@@ -798,6 +836,20 @@ static int ena_set_tunable(struct net_device *netdev,
        return ret;
 }
 
+static u32 ena_get_priv_flags(struct net_device *netdev)
+{
+       struct ena_adapter *adapter = netdev_priv(netdev);
+       struct ena_com_dev *ena_dev = adapter->ena_dev;
+       struct ena_admin_get_feat_resp get_resp;
+       u32 rc;
+
+       rc = ena_com_get_extra_properties_flags(ena_dev, &get_resp);
+       if (!rc)
+               return get_resp.u.extra_properties_flags.flags;
+
+       return 0;
+}
+
 static const struct ethtool_ops ena_ethtool_ops = {
        .get_link_ksettings     = ena_get_link_ksettings,
        .get_drvinfo            = ena_get_drvinfo,
@@ -819,6 +871,7 @@ static const struct ethtool_ops ena_ethtool_ops = {
        .get_channels           = ena_get_channels,
        .get_tunable            = ena_get_tunable,
        .set_tunable            = ena_set_tunable,
+       .get_priv_flags         = ena_get_priv_flags,
 };
 
 void ena_set_ethtool_ops(struct net_device *netdev)
index d2b82f917d3f5562d1f4ec61a171fa186021807b..33fab4f41d7c5ae5efb07ee592516f20425c074f 100644 (file)
@@ -2369,6 +2369,14 @@ err:
        ena_com_delete_debug_area(adapter->ena_dev);
 }
 
+static void ena_extra_properties_strings_destroy(struct net_device *netdev)
+{
+       struct ena_adapter *adapter = netdev_priv(netdev);
+
+       ena_com_delete_extra_properties_strings(adapter->ena_dev);
+       adapter->ena_extra_properties_count = 0;
+}
+
 static void ena_get_stats64(struct net_device *netdev,
                            struct rtnl_link_stats64 *stats)
 {
@@ -3424,6 +3432,9 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        ena_config_debug_area(adapter);
 
+       adapter->ena_extra_properties_count =
+               ena_com_extra_properties_strings_init(ena_dev);
+
        memcpy(adapter->netdev->perm_addr, adapter->mac_addr, netdev->addr_len);
 
        netif_carrier_off(netdev);
@@ -3463,6 +3474,7 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        return 0;
 
 err_rss:
+       ena_extra_properties_strings_destroy(netdev);
        ena_com_delete_debug_area(ena_dev);
        ena_com_rss_destroy(ena_dev);
 err_free_msix:
@@ -3529,6 +3541,8 @@ static void ena_remove(struct pci_dev *pdev)
 
        ena_com_delete_host_info(ena_dev);
 
+       ena_extra_properties_strings_destroy(netdev);
+
        ena_release_bars(ena_dev, pdev);
 
        pci_disable_device(pdev);
index 63870072cbbd47ed3ec2c4426ba1210236d9ccab..0681e18b0019f3fc06dcbc43a6f129931056269b 100644 (file)
@@ -364,6 +364,8 @@ struct ena_adapter {
        u32 last_monitored_tx_qid;
 
        enum ena_regs_reset_reason_types reset_reason;
+
+       u8 ena_extra_properties_count;
 };
 
 void ena_set_ethtool_ops(struct net_device *netdev);