From: Sudheer Mogilappagari <sudheer.mogilappag...@intel.com>

During driver initialization VF determines QOS capability is allowed
by PF and receives QOS parameters. After which quanta size for queues
is configured which is not configurable and is set to 1KB currently.

Signed-off-by: Sudheer Mogilappagari <sudheer.mogilappag...@intel.com>
---
v5 -> v6:
 - error out on bad rate
---
 drivers/net/ethernet/intel/iavf/iavf.h        | 10 ++
 drivers/net/ethernet/intel/iavf/iavf_main.c   | 51 +++++++++-
 .../net/ethernet/intel/iavf/iavf_virtchnl.c   | 92 ++++++++++++++++++-
 3 files changed, 150 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/intel/iavf/iavf.h 
b/drivers/net/ethernet/intel/iavf/iavf.h
index a84bdbfbb0f7..75ac69670789 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -251,6 +251,9 @@ struct iavf_cloud_filter {
 #define IAVF_RESET_WAIT_DETECTED_COUNT 500
 #define IAVF_RESET_WAIT_COMPLETE_COUNT 2000
 
+#define IAVF_MAX_QOS_TC_NUM            8
+#define IAVF_DEFAULT_QUANTA_SIZE       1024
+
 /* board specific private data structure */
 struct iavf_adapter {
        struct workqueue_struct *wq;
@@ -338,6 +341,8 @@ struct iavf_adapter {
 #define IAVF_FLAG_AQ_ENABLE_STAG_VLAN_INSERTION                BIT_ULL(37)
 #define IAVF_FLAG_AQ_DISABLE_STAG_VLAN_INSERTION       BIT_ULL(38)
 #define IAVF_FLAG_AQ_CONFIGURE_QUEUES_BW               BIT_ULL(39)
+#define IAVF_FLAG_AQ_CFG_QUEUES_QUANTA_SIZE            BIT_ULL(40)
+#define IAVF_FLAG_AQ_GET_QOS_CAPS                      BIT_ULL(41)
 
        /* flags for processing extended capability messages during
         * __IAVF_INIT_EXTENDED_CAPS. Each capability exchange requires
@@ -410,6 +415,8 @@ struct iavf_adapter {
                               VIRTCHNL_VF_OFFLOAD_FDIR_PF)
 #define ADV_RSS_SUPPORT(_a) ((_a)->vf_res->vf_cap_flags & \
                             VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF)
+#define QOS_ALLOWED(_a) ((_a)->vf_res->vf_cap_flags & \
+                        VIRTCHNL_VF_OFFLOAD_QOS)
        struct virtchnl_vf_resource *vf_res; /* incl. all VSIs */
        struct virtchnl_vsi_resource *vsi_res; /* our LAN VSI */
        struct virtchnl_version_info pf_version;
@@ -418,6 +425,7 @@ struct iavf_adapter {
        struct virtchnl_vlan_caps vlan_v2_caps;
        u16 msg_enable;
        struct iavf_eth_stats current_stats;
+       struct virtchnl_qos_cap_list *qos_caps;
        struct iavf_vsi vsi;
        u32 aq_wait_count;
        /* RSS stuff */
@@ -584,6 +592,8 @@ int iavf_config_rss(struct iavf_adapter *adapter);
 int iavf_lan_add_device(struct iavf_adapter *adapter);
 int iavf_lan_del_device(struct iavf_adapter *adapter);
 void iavf_cfg_queues_bw(struct iavf_adapter *adapter);
+void iavf_cfg_queues_quanta_size(struct iavf_adapter *adapter);
+void iavf_get_qos_caps(struct iavf_adapter *adapter);
 void iavf_enable_channels(struct iavf_adapter *adapter);
 void iavf_disable_channels(struct iavf_adapter *adapter);
 void iavf_add_cloud_filter(struct iavf_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c 
b/drivers/net/ethernet/intel/iavf/iavf_main.c
index 7764d8ce7f4e..12ef160425aa 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -2094,6 +2094,16 @@ static int iavf_process_aq_command(struct iavf_adapter 
*adapter)
                return 0;
        }
 
+       if (adapter->aq_required & IAVF_FLAG_AQ_GET_QOS_CAPS) {
+               iavf_get_qos_caps(adapter);
+               return 0;
+       }
+
+       if (adapter->aq_required & IAVF_FLAG_AQ_CFG_QUEUES_QUANTA_SIZE) {
+               iavf_cfg_queues_quanta_size(adapter);
+               return 0;
+       }
+
        if (adapter->aq_required & IAVF_FLAG_AQ_CONFIGURE_QUEUES) {
                iavf_configure_queues(adapter);
                return 0;
@@ -2679,6 +2689,9 @@ static void iavf_init_config_adapter(struct iavf_adapter 
*adapter)
                /* request initial VLAN offload settings */
                iavf_set_vlan_offload_features(adapter, 0, netdev->features);
 
+       if (QOS_ALLOWED(adapter))
+               adapter->aq_required |= IAVF_FLAG_AQ_GET_QOS_CAPS;
+
        iavf_schedule_finish_config(adapter);
        return;
 
@@ -4935,6 +4948,26 @@ static netdev_features_t iavf_fix_features(struct 
net_device *netdev,
        return iavf_fix_strip_features(adapter, features);
 }
 
+static int
+iavf_verify_shaper(struct net_shaper_binding *binding,
+                  const struct net_shaper *shaper,
+                  struct netlink_ext_ack *extack)
+{
+       struct iavf_adapter *adapter = netdev_priv(binding->netdev);
+       u64 vf_max;
+
+       if (shaper->handle.scope == NET_SHAPER_SCOPE_QUEUE) {
+               vf_max = adapter->qos_caps->cap[0].shaper.peak;
+               if (vf_max && shaper->bw_max > vf_max) {
+                       NL_SET_ERR_MSG_FMT(extack, "Max rate (%llu) of queue %d 
can't exceed max TX rate of VF (%llu kbps)",
+                                          shaper->bw_max, shaper->handle.id,
+                                          vf_max);
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
 static int
 iavf_shaper_set(struct net_shaper_binding *binding,
                const struct net_shaper *shaper,
@@ -4943,11 +4976,16 @@ iavf_shaper_set(struct net_shaper_binding *binding,
        struct iavf_adapter *adapter = netdev_priv(binding->netdev);
        const struct net_shaper_handle *handle = &shaper->handle;
        struct iavf_ring *tx_ring;
+       int ret = 0;
 
        mutex_lock(&adapter->crit_lock);
        if (handle->id >= adapter->num_active_queues)
                goto unlock;
 
+       ret = iavf_verify_shaper(binding, shaper, extack);
+       if (ret)
+               goto unlock;
+
        tx_ring = &adapter->tx_rings[handle->id];
 
        tx_ring->q_shaper.bw_min = div_u64(shaper->bw_min, 1000);
@@ -4958,7 +4996,7 @@ iavf_shaper_set(struct net_shaper_binding *binding,
 
 unlock:
        mutex_unlock(&adapter->crit_lock);
-       return 0;
+       return ret;
 }
 
 static int iavf_shaper_del(struct net_shaper_binding *binding,
@@ -5164,7 +5202,7 @@ static int iavf_probe(struct pci_dev *pdev, const struct 
pci_device_id *ent)
        struct net_device *netdev;
        struct iavf_adapter *adapter = NULL;
        struct iavf_hw *hw = NULL;
-       int err;
+       int err, len;
 
        err = pci_enable_device(pdev);
        if (err)
@@ -5232,6 +5270,13 @@ static int iavf_probe(struct pci_dev *pdev, const struct 
pci_device_id *ent)
        hw->bus.func = PCI_FUNC(pdev->devfn);
        hw->bus.bus_id = pdev->bus->number;
 
+       len = struct_size(adapter->qos_caps, cap, IAVF_MAX_QOS_TC_NUM);
+       adapter->qos_caps = kzalloc(len, GFP_KERNEL);
+       if (!adapter->qos_caps) {
+               err = -ENOMEM;
+               goto err_alloc_qos_cap;
+       }
+
        /* set up the locks for the AQ, do this only once in probe
         * and destroy them only once in remove
         */
@@ -5270,6 +5315,8 @@ static int iavf_probe(struct pci_dev *pdev, const struct 
pci_device_id *ent)
        /* Initialization goes on in the work. Do not add more of it below. */
        return 0;
 
+err_alloc_qos_cap:
+       iounmap(hw->hw_addr);
 err_ioremap:
        destroy_workqueue(adapter->wq);
 err_alloc_wq:
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c 
b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index 64ddd0e66c0d..15d388b431c5 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -151,7 +151,8 @@ int iavf_send_vf_config_msg(struct iavf_adapter *adapter)
               VIRTCHNL_VF_OFFLOAD_USO |
               VIRTCHNL_VF_OFFLOAD_FDIR_PF |
               VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF |
-              VIRTCHNL_VF_CAP_ADV_LINK_SPEED;
+              VIRTCHNL_VF_CAP_ADV_LINK_SPEED |
+              VIRTCHNL_VF_OFFLOAD_QOS;
 
        adapter->current_op = VIRTCHNL_OP_GET_VF_RESOURCES;
        adapter->aq_required &= ~IAVF_FLAG_AQ_GET_CONFIG;
@@ -1507,6 +1508,76 @@ iavf_set_adapter_link_speed_from_vpe(struct iavf_adapter 
*adapter,
                adapter->link_speed = vpe->event_data.link_event.link_speed;
 }
 
+/**
+ * iavf_get_qos_caps - get qos caps support
+ * @adapter: iavf adapter struct instance
+ *
+ * This function requests PF for Supported QoS Caps.
+ */
+void iavf_get_qos_caps(struct iavf_adapter *adapter)
+{
+       if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
+               /* bail because we already have a command pending */
+               dev_err(&adapter->pdev->dev,
+                       "Cannot get qos caps, command %d pending\n",
+                       adapter->current_op);
+               return;
+       }
+
+       adapter->current_op = VIRTCHNL_OP_GET_QOS_CAPS;
+       adapter->aq_required &= ~IAVF_FLAG_AQ_GET_QOS_CAPS;
+       iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_QOS_CAPS, NULL, 0);
+}
+
+/**
+ * iavf_set_quanta_size - set quanta size of queue chunk
+ * @adapter: iavf adapter struct instance
+ * @quanta_size: quanta size in bytes
+ * @queue_index: starting index of queue chunk
+ * @num_queues: number of queues in the queue chunk
+ *
+ * This function requests PF to set quanta size of queue chunk
+ * starting at queue_index.
+ */
+static void
+iavf_set_quanta_size(struct iavf_adapter *adapter, u16 quanta_size,
+                    u16 queue_index, u16 num_queues)
+{
+       struct virtchnl_quanta_cfg quanta_cfg;
+
+       if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
+               /* bail because we already have a command pending */
+               dev_err(&adapter->pdev->dev,
+                       "Cannot set queue quanta size, command %d pending\n",
+                       adapter->current_op);
+               return;
+       }
+
+       adapter->current_op = VIRTCHNL_OP_CONFIG_QUANTA;
+       quanta_cfg.quanta_size = quanta_size;
+       quanta_cfg.queue_select.type = VIRTCHNL_QUEUE_TYPE_TX;
+       quanta_cfg.queue_select.start_queue_id = queue_index;
+       quanta_cfg.queue_select.num_queues = num_queues;
+       adapter->aq_required &= ~IAVF_FLAG_AQ_CFG_QUEUES_QUANTA_SIZE;
+       iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_QUANTA,
+                        (u8 *)&quanta_cfg, sizeof(quanta_cfg));
+}
+
+/**
+ * iavf_cfg_queues_quanta_size - configure quanta size of queues
+ * @adapter: adapter structure
+ *
+ * Request that the PF configure quanta size of allocated queues.
+ **/
+void iavf_cfg_queues_quanta_size(struct iavf_adapter *adapter)
+{
+       int quanta_size = IAVF_DEFAULT_QUANTA_SIZE;
+
+       /* Set Queue Quanta Size to default */
+       iavf_set_quanta_size(adapter, quanta_size, 0,
+                            adapter->num_active_queues);
+}
+
 /**
  * iavf_cfg_queues_bw - configure bandwidth of allocated queues
  * @adapter: iavf adapter structure instance
@@ -2281,6 +2352,14 @@ void iavf_virtchnl_completion(struct iavf_adapter 
*adapter,
                                        VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC;
 
                        break;
+               case VIRTCHNL_OP_GET_QOS_CAPS:
+                       dev_warn(&adapter->pdev->dev, "Failed to Get Qos CAPs, 
error %s\n",
+                                iavf_stat_str(&adapter->hw, v_retval));
+                       break;
+               case VIRTCHNL_OP_CONFIG_QUANTA:
+                       dev_warn(&adapter->pdev->dev, "Failed to Config Quanta, 
error %s\n",
+                                iavf_stat_str(&adapter->hw, v_retval));
+                       break;
                case VIRTCHNL_OP_CONFIG_QUEUE_BW:
                        dev_warn(&adapter->pdev->dev, "Failed to Config Queue 
BW, error %s\n",
                                 iavf_stat_str(&adapter->hw, v_retval));
@@ -2627,6 +2706,17 @@ void iavf_virtchnl_completion(struct iavf_adapter 
*adapter,
                if (!v_retval)
                        iavf_netdev_features_vlan_strip_set(netdev, false);
                break;
+       case VIRTCHNL_OP_GET_QOS_CAPS: {
+               u16 len = struct_size(adapter->qos_caps, cap,
+                                     IAVF_MAX_QOS_TC_NUM);
+
+               memcpy(adapter->qos_caps, msg, min(msglen, len));
+
+               adapter->aq_required |= IAVF_FLAG_AQ_CFG_QUEUES_QUANTA_SIZE;
+               }
+               break;
+       case VIRTCHNL_OP_CONFIG_QUANTA:
+               break;
        case VIRTCHNL_OP_CONFIG_QUEUE_BW: {
                int i;
                /* shaper configuration is successful for all queues */
-- 
2.45.2

Reply via email to