All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alan Brady <alan.brady@intel.com>
To: intel-wired-lan@osuosl.org
Subject: [Intel-wired-lan] [PATCH net-next 12/19] iecm: finish netdev_ops
Date: Thu, 27 Jan 2022 16:10:02 -0800	[thread overview]
Message-ID: <20220128001009.721392-13-alan.brady@intel.com> (raw)
In-Reply-To: <20220128001009.721392-1-alan.brady@intel.com>

This fills out the remaining NDO callbacks. Once netdev_ops are there, the
rest of the patches will fill out the data path and advanced features.

Signed-off-by: Phani Burra <phani.r.burra@intel.com>
Signed-off-by: Joshua Hay <joshua.a.hay@intel.com>
Signed-off-by: Madhu Chittim <madhu.chittim@intel.com>
Signed-off-by: Pavan Kumar Linga <pavan.kumar.linga@intel.com>
Signed-off-by: Alan Brady <alan.brady@intel.com>
---
 drivers/net/ethernet/intel/iecm/iecm_lib.c    | 742 +++++++++++++++++-
 drivers/net/ethernet/intel/iecm/iecm_txrx.c   |  15 +
 .../net/ethernet/intel/iecm/iecm_virtchnl.c   |  63 ++
 drivers/net/ethernet/intel/include/iecm.h     |  14 +
 .../net/ethernet/intel/include/iecm_txrx.h    |   2 +
 5 files changed, 822 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ethernet/intel/iecm/iecm_lib.c b/drivers/net/ethernet/intel/iecm/iecm_lib.c
index 003057f48f0c..cc82e665dfaf 100644
--- a/drivers/net/ethernet/intel/iecm/iecm_lib.c
+++ b/drivers/net/ethernet/intel/iecm/iecm_lib.c
@@ -568,6 +568,147 @@ static void iecm_set_all_filters(struct iecm_vport *vport)
 	iecm_add_del_ether_addrs(vport, true, false);
 }
 
+/**
+ * iecm_find_vlan - Search filter list for specific vlan filter
+ * @vport: vport structure
+ * @vlan: vlan tag
+ *
+ * Returns ptr to the filter object or NULL. Must be called while holding the
+ * vlan_list_lock.
+ */
+static struct
+iecm_vlan_filter *iecm_find_vlan(struct iecm_vport *vport,
+				 struct iecm_vlan *vlan)
+{
+	struct iecm_vlan_filter *f;
+
+	list_for_each_entry(f, &vport->adapter->config_data.vlan_filter_list,
+			    list) {
+		if (vlan->vid == f->vlan.vid && vlan->tpid == f->vlan.tpid)
+			return f;
+	}
+	return NULL;
+}
+
+/**
+ * iecm_add_vlan - Add a vlan filter to the list
+ * @vport: vport structure
+ * @vlan: VLAN tag
+ *
+ * Returns ptr to the filter object or NULL when no memory available.
+ */
+static struct
+iecm_vlan_filter *iecm_add_vlan(struct iecm_vport *vport,
+				struct iecm_vlan *vlan)
+{
+	struct iecm_adapter *adapter = vport->adapter;
+	struct iecm_vlan_filter *f = NULL;
+
+	spin_lock_bh(&adapter->vlan_list_lock);
+
+	f = iecm_find_vlan(vport, vlan);
+	if (!f) {
+		f = kzalloc(sizeof(*f), GFP_ATOMIC);
+		if (!f)
+			goto error;
+
+		f->vlan.vid = vlan->vid;
+		f->vlan.tpid = vlan->tpid;
+
+		list_add_tail(&f->list, &adapter->config_data.vlan_filter_list);
+		f->add = true;
+	}
+
+error:
+	spin_unlock_bh(&adapter->vlan_list_lock);
+	return f;
+}
+
+/**
+ * iecm_del_vlan - Remove a vlan filter from the list
+ * @vport: vport structure
+ * @vlan: VLAN tag
+ */
+static void iecm_del_vlan(struct iecm_vport *vport, struct iecm_vlan *vlan)
+{
+	struct iecm_adapter *adapter = vport->adapter;
+	struct iecm_vlan_filter *f;
+
+	spin_lock_bh(&adapter->vlan_list_lock);
+
+	f = iecm_find_vlan(vport, vlan);
+	if (f)
+		f->remove = true;
+
+	spin_unlock_bh(&adapter->vlan_list_lock);
+}
+
+/**
+ * iecm_vlan_rx_add_vid - Add a VLAN filter to the device
+ * @netdev: network device struct
+ * @proto: unused protocol data
+ * @vid: VLAN tag
+ *
+ * Returns 0 on success
+ */
+static int iecm_vlan_rx_add_vid(struct net_device *netdev,
+				__always_unused __be16 proto, u16 vid)
+{
+	struct iecm_vport *vport = iecm_netdev_to_vport(netdev);
+	struct iecm_adapter *adapter = vport->adapter;
+	struct iecm_vlan vlan;
+
+	vlan = IECM_VLAN(vid, be16_to_cpu(proto));
+	if (!iecm_is_feature_ena(vport, NETIF_F_HW_VLAN_CTAG_FILTER))
+		return -EINVAL;
+
+	iecm_add_vlan(vport, &vlan);
+
+	if (adapter->state == __IECM_UP)
+		adapter->dev_ops.vc_ops.add_del_vlans(vport, true);
+
+	return 0;
+}
+
+/**
+ * iecm_vlan_rx_kill_vid - Remove a VLAN filter from the device
+ * @netdev: network device struct
+ * @proto: unused protocol data
+ * @vid: VLAN tag
+ *
+ * Returns 0 on success
+ */
+static int iecm_vlan_rx_kill_vid(struct net_device *netdev,
+				 __always_unused __be16 proto, u16 vid)
+{
+	struct iecm_vport *vport = iecm_netdev_to_vport(netdev);
+	struct iecm_adapter *adapter = vport->adapter;
+	struct iecm_vlan_filter *f, *ftmp;
+	struct iecm_vlan vlan;
+
+	vlan = IECM_VLAN(vid, be16_to_cpu(proto));
+	if (!iecm_is_feature_ena(vport, NETIF_F_HW_VLAN_CTAG_FILTER))
+		return -EINVAL;
+
+	if (vport->adapter->state == __IECM_UP) {
+		iecm_del_vlan(vport, &vlan);
+		adapter->dev_ops.vc_ops.add_del_vlans(vport, false);
+	}
+	/* It is safe to delete entry from the list now */
+	spin_lock_bh(&adapter->vlan_list_lock);
+	list_for_each_entry_safe(f, ftmp,
+				 &adapter->config_data.vlan_filter_list,
+				 list) {
+		if (f->vlan.vid == vlan.vid && f->vlan.tpid == vlan.tpid) {
+			list_del(&f->list);
+			kfree(f);
+		}
+	}
+	spin_unlock_bh(&adapter->vlan_list_lock);
+
+	return 0;
+}
+
 /**
  * iecm_set_all_vlans - Re-add all VLANs in list
  * @vport: main vport struct
@@ -804,6 +945,27 @@ static int iecm_get_free_slot(void *array, int size, int curr)
 	return next;
 }
 
+/**
+ * iecm_remove_vlan_filters - Remove all vlan filters
+ * @vport: vport structure
+ */
+static void iecm_remove_vlan_filters(struct iecm_vport *vport)
+{
+	struct iecm_adapter *adapter = vport->adapter;
+	struct iecm_user_config_data *config_data;
+
+	config_data = &adapter->config_data;
+	if (!list_empty(&config_data->vlan_filter_list)) {
+		struct iecm_vlan_filter *f;
+
+		spin_lock_bh(&adapter->vlan_list_lock);
+		list_for_each_entry(f, &config_data->vlan_filter_list, list)
+			f->remove = true;
+		spin_unlock_bh(&adapter->vlan_list_lock);
+		adapter->dev_ops.vc_ops.add_del_vlans(vport, false);
+	}
+}
+
 /**
  * iecm_vport_stop - Disable a vport
  * @vport: vport to disable
@@ -831,6 +993,8 @@ static void iecm_vport_stop(struct iecm_vport *vport)
 	if (test_and_clear_bit(__IECM_DEL_QUEUES,
 			       vport->adapter->flags))
 		iecm_send_delete_queues_msg(vport);
+	if (!test_bit(__IECM_REL_RES_IN_PROG, adapter->flags))
+		iecm_remove_vlan_filters(vport);
 
 	adapter->link_up = false;
 	iecm_vport_intr_deinit(vport);
@@ -1581,6 +1745,147 @@ static void iecm_vc_event_task(struct work_struct *work)
 	}
 }
 
+/**
+ * iecm_initiate_soft_reset - Initiate a software reset
+ * @vport: virtual port data struct
+ * @reset_cause: reason for the soft reset
+ *
+ * Soft reset only reallocs vport queue resources. Returns 0 on success,
+ * negative on failure.
+ */
+int iecm_initiate_soft_reset(struct iecm_vport *vport,
+			     enum iecm_flags reset_cause)
+{
+	enum iecm_state current_state = vport->adapter->state;
+	struct iecm_adapter *adapter = vport->adapter;
+	struct iecm_vport *new_vport;
+	int err = 0, i;
+
+	/* make sure we do not end up in initiating multiple resets */
+	mutex_lock(&adapter->reset_lock);
+
+	/* If the system is low on memory, we can end up in bad state if we
+	 * free all the memory for queue resources and try to allocate them
+	 * again. Instead, we can pre-allocate the new resources before doing
+	 * anything and bailing if the alloc fails.
+	 *
+	 * Make a clone of the existing vport to mimic its current configuration,
+	 * then modify the new structure with any requested changes. Once the
+	 * allocation of the new resources is done, stop the existing vport and
+	 * copy the configuration to the main vport. If an error occurred, the
+	 * existing vport will be untouched.
+	 *
+	 */
+	new_vport = kzalloc(sizeof(*vport), GFP_KERNEL);
+	if (!new_vport) {
+		mutex_unlock(&adapter->reset_lock);
+		return -ENOMEM;
+	}
+	memcpy(new_vport, vport, sizeof(*vport));
+
+	/* Adjust resource parameters prior to reallocating resources */
+	switch (reset_cause) {
+	case __IECM_SR_Q_CHANGE:
+		adapter->dev_ops.vc_ops.adjust_qs(new_vport);
+		break;
+	case __IECM_SR_Q_DESC_CHANGE:
+		/* Update queue parameters before allocating resources */
+		iecm_vport_calc_num_q_desc(new_vport);
+		break;
+	case __IECM_SR_Q_SCH_CHANGE:
+	case __IECM_SR_MTU_CHANGE:
+	case __IECM_SR_RSC_CHANGE:
+	case __IECM_SR_HSPLIT_CHANGE:
+		break;
+	default:
+		dev_err(&adapter->pdev->dev, "Unhandled soft reset cause\n");
+		err = -EINVAL;
+		goto err_default;
+	}
+
+	err = iecm_vport_queues_alloc(new_vport);
+	if (err)
+		goto err_default;
+
+	if (adapter->virt_ver_maj == VIRTCHNL_VERSION_MAJOR_2) {
+		if (current_state <= __IECM_DOWN) {
+			adapter->dev_ops.vc_ops.delete_queues(vport);
+		} else {
+			set_bit(__IECM_DEL_QUEUES, adapter->flags);
+			iecm_vport_stop(vport);
+		}
+
+		iecm_deinit_rss(vport);
+		err = adapter->dev_ops.vc_ops.add_queues(new_vport, new_vport->num_txq,
+							 new_vport->num_complq,
+							 new_vport->num_rxq,
+							 new_vport->num_bufq);
+		if (err)
+			goto err_reset;
+	} else {
+		iecm_vport_stop(vport);
+	}
+
+	memcpy(vport, new_vport, sizeof(*vport));
+	/* Since iecm_vport_queues_alloc was called with new_port, the queue
+	 * back pointers are currently pointing to the local new_vport. Reset
+	 * the backpointers to the original vport here
+	 */
+	for (i = 0; i < vport->num_txq_grp; i++) {
+		struct iecm_txq_group *tx_qgrp = &vport->txq_grps[i];
+		int j;
+
+		tx_qgrp->vport = vport;
+		for (j = 0; j < tx_qgrp->num_txq; j++)
+			tx_qgrp->txqs[j]->vport = vport;
+
+		if (iecm_is_queue_model_split(vport->txq_model))
+			tx_qgrp->complq->vport = vport;
+	}
+
+	for (i = 0; i < vport->num_rxq_grp; i++) {
+		struct iecm_rxq_group *rx_qgrp = &vport->rxq_grps[i];
+		struct iecm_queue *q;
+		int j, num_rxq;
+
+		rx_qgrp->vport = vport;
+		for (j = 0; j < vport->num_bufqs_per_qgrp; j++)
+			rx_qgrp->splitq.bufq_sets[j].bufq.vport = vport;
+
+		if (iecm_is_queue_model_split(vport->rxq_model))
+			num_rxq = rx_qgrp->splitq.num_rxq_sets;
+		else
+			num_rxq = rx_qgrp->singleq.num_rxq;
+
+		for (j = 0; j < num_rxq; j++) {
+			if (iecm_is_queue_model_split(vport->rxq_model))
+				q = &rx_qgrp->splitq.rxq_sets[j]->rxq;
+			else
+				q = rx_qgrp->singleq.rxqs[j];
+			q->vport = vport;
+		}
+	}
+
+	/* Post resource allocation reset */
+	if (reset_cause == __IECM_SR_Q_CHANGE) {
+		iecm_intr_rel(adapter);
+		iecm_intr_req(adapter);
+	}
+
+	kfree(new_vport);
+
+	if (current_state == __IECM_UP)
+		err = iecm_vport_open(vport, false);
+	mutex_unlock(&adapter->reset_lock);
+	return err;
+err_reset:
+	iecm_vport_queues_rel(vport);
+err_default:
+	kfree(new_vport);
+	mutex_unlock(&adapter->reset_lock);
+	return err;
+}
+
 /**
  * iecm_probe - Device initialization routine
  * @pdev: PCI device information struct
@@ -1905,6 +2210,47 @@ static void iecm_set_rx_mode(struct net_device *netdev)
 	}
 }
 
+/**
+ * iecm_set_features - set the netdev feature flags
+ * @netdev: ptr to the netdev being adjusted
+ * @features: the feature set that the stack is suggesting
+ */
+static int iecm_set_features(struct net_device *netdev,
+			     netdev_features_t features)
+{
+	struct iecm_vport *vport = iecm_netdev_to_vport(netdev);
+	struct iecm_adapter *adapter = vport->adapter;
+	int err = 0;
+
+	if (iecm_is_cap_ena(adapter, IECM_OTHER_CAPS, VIRTCHNL2_CAP_VLAN) ||
+	    iecm_is_cap_ena(adapter, IECM_BASE_CAPS, VIRTCHNL2_CAP_VLAN)) {
+		err = iecm_set_vlan_offload_features(netdev, netdev->features,
+						     features);
+		if (err)
+			return err;
+	}
+
+	if ((netdev->features ^ features) & NETIF_F_GRO_HW) {
+		netdev->features ^= NETIF_F_GRO_HW;
+		err = iecm_initiate_soft_reset(vport, __IECM_SR_RSC_CHANGE);
+	}
+
+	return err;
+}
+
+/**
+ * iecm_fix_features - fix up the netdev feature bits
+ * @netdev: our net device
+ * @features: desired feature bits
+ *
+ * Returns fixed-up features bits
+ */
+static netdev_features_t iecm_fix_features(struct net_device *netdev,
+					   netdev_features_t features)
+{
+	return features;
+}
+
 /**
  * iecm_open - Called when a network interface becomes active
  * @netdev: network interface device structure
@@ -1924,6 +2270,374 @@ static int iecm_open(struct net_device *netdev)
 	return iecm_vport_open(np->vport, true);
 }
 
+/**
+ * iecm_change_mtu - NDO callback to change the MTU
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int iecm_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	struct iecm_vport *vport =  iecm_netdev_to_vport(netdev);
+
+	netdev->mtu = new_mtu;
+
+	return iecm_initiate_soft_reset(vport, __IECM_SR_MTU_CHANGE);
+}
+
+static int iecm_offload_txtime(struct iecm_vport *vport,
+			       struct tc_etf_qopt_offload *qopt)
+{
+	return -EOPNOTSUPP;
+}
+
+/**
+ * iecm_validate_tx_bandwidth - validate the max Tx bandwidth
+ * @vport: vport structure
+ * @max_tx_rate: max Tx bandwidth for a tc
+ **/
+static int iecm_validate_tx_bandwidth(struct iecm_vport *vport,
+				      u64 max_tx_rate)
+{
+	struct iecm_adapter *adapter = vport->adapter;
+	int speed = 0, ret = 0;
+
+	if (adapter->link_speed_mbps) {
+		if (adapter->link_speed_mbps < U32_MAX) {
+			speed = adapter->link_speed_mbps;
+			goto validate_bw;
+		} else {
+			dev_err(&adapter->pdev->dev, "Unknown link speed\n");
+			return -EINVAL;
+		}
+	}
+
+	switch (adapter->link_speed) {
+	case VIRTCHNL_LINK_SPEED_40GB:
+		speed = SPEED_40000;
+		break;
+	case VIRTCHNL_LINK_SPEED_25GB:
+		speed = SPEED_25000;
+		break;
+	case VIRTCHNL_LINK_SPEED_20GB:
+		speed = SPEED_20000;
+		break;
+	case VIRTCHNL_LINK_SPEED_10GB:
+		speed = SPEED_10000;
+		break;
+	case VIRTCHNL_LINK_SPEED_5GB:
+		speed = SPEED_5000;
+		break;
+	case VIRTCHNL_LINK_SPEED_2_5GB:
+		speed = SPEED_2500;
+		break;
+	case VIRTCHNL_LINK_SPEED_1GB:
+		speed = SPEED_1000;
+		break;
+	case VIRTCHNL_LINK_SPEED_100MB:
+		speed = SPEED_100;
+		break;
+	default:
+		break;
+	}
+
+validate_bw:
+	if (max_tx_rate > speed) {
+		dev_err(&adapter->pdev->dev, "Invalid tx rate specified\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/**
+ * iecm_validate_ch_config - validate queue mapping info
+ * @vport: vport structure
+ * @mqprio_qopt: queue parameters
+ * @max_tc_allowed: MAX TC allowed, it could be 4 or 16 depends.
+ *
+ * This function validates if the configuration provided by the user to
+ * configure queue channels is valid or not.
+ *
+ * Returns 0 on a valid config and negative on invalid config.
+ **/
+static int iecm_validate_ch_config(struct iecm_vport *vport,
+				   struct tc_mqprio_qopt_offload *mqprio_qopt,
+				   u8 max_tc_allowed)
+{
+	struct iecm_adapter *adapter = vport->adapter;
+	u32 tc, qcount, non_power_2_qcount = 0;
+	u64 total_max_rate = 0;
+	int i, num_qs = 0;
+
+	if (mqprio_qopt->qopt.num_tc > max_tc_allowed ||
+	    mqprio_qopt->qopt.num_tc < 1)
+		return -EINVAL;
+
+	/* For ADQ there are few rules on queue allocation for each TC
+	 *     1. Number of queues for TC0 should always be a power of 2
+	 *     2. Number of queues for rest of TCs can be non-power of 2
+	 *     3. If the previous TC has non-power of 2 queues, then all the
+	 *        following TCs should be either
+	 *        a. same number of queues as that of the previous non-power
+	 *           of 2 or
+	 *        b. less than previous non-power of 2 and power of 2
+	 *        ex: 1 at 0 2 at 1 3 at 3 4 at 6 - Invalid
+	 *            1 at 0 2 at 1 3 at 3 3 at 6 - Valid
+	 *            1 at 0 2 at 1 3 at 3 2 at 6 - Valid
+	 *            1 at 0 2 at 1 3 at 3 1@6 - Valid
+	 */
+	for (tc = 0; tc < mqprio_qopt->qopt.num_tc; tc++) {
+		qcount = mqprio_qopt->qopt.count[tc];
+
+		/* case 1. check for first TC to be always power of 2 in ADQ */
+		if (!tc && !is_power_of_2(qcount)) {
+			dev_err(&adapter->pdev->dev,
+				"TC0:qcount[%d] must be a power of 2\n",
+				qcount);
+			return -EINVAL;
+		}
+		/* case 2 & 3, check for non-power of 2 number of queues */
+		if (tc && non_power_2_qcount) {
+			if (qcount > non_power_2_qcount) {
+				dev_err(&adapter->pdev->dev,
+					"TC%d has %d qcount cannot be > non_power_of_2 qcount [%d]\n",
+					tc, qcount, non_power_2_qcount);
+				return -EINVAL;
+			} else if (qcount < non_power_2_qcount) {
+				/* it must be power of 2, otherwise fail */
+				if (!is_power_of_2(qcount)) {
+					dev_err(&adapter->pdev->dev,
+						"TC%d has %d qcount must be a power of 2 < non_power_of_2 qcount [%d]\n",
+						tc, qcount, non_power_2_qcount);
+					return -EINVAL;
+				}
+			}
+		} else if (tc && !is_power_of_2(qcount)) {
+			/* this is the first TC to have a non-power of 2 queue
+			 * count and the code is going to enter this section
+			 * only once. The qcount for this TC will serve as
+			 * our reference/guide to allocate number of queues
+			 * for all the further TCs as per section a. and b. in
+			 * case 3 mentioned above.
+			 */
+			non_power_2_qcount = qcount;
+			dev_dbg(&adapter->pdev->dev,
+				"TC%d:count[%d] non power of 2\n", tc,
+				qcount);
+			}
+	}
+
+	for (i = 0; i <= mqprio_qopt->qopt.num_tc - 1; i++) {
+		u64 tx_rate = 0;
+
+		if (!mqprio_qopt->qopt.count[i] ||
+		    mqprio_qopt->qopt.offset[i] != num_qs)
+			return -EINVAL;
+		if (mqprio_qopt->min_rate[i]) {
+			dev_err(&adapter->pdev->dev,
+				"Invalid min tx rate (greater than 0) specified\n");
+			return -EINVAL;
+		}
+		/*convert to Mbps */
+		tx_rate = div_u64(mqprio_qopt->max_rate[i], IECM_MBPS_DIVISOR);
+		total_max_rate += tx_rate;
+		num_qs += mqprio_qopt->qopt.count[i];
+	}
+	/* Comparing with num_txq as num_txq and num_rxq are equal for single
+	 * queue model
+	 */
+	if (num_qs > vport->num_txq) {
+		dev_err(&adapter->pdev->dev,
+			"Cannot support requested number of queues\n");
+		return -EINVAL;
+	}
+	/* no point in validating TX bandwidth rate limit if the user hasn't
+	 * specified any rate limit for any TCs, so validate only if it's set.
+	 */
+	if (total_max_rate)
+		return iecm_validate_tx_bandwidth(vport, total_max_rate);
+	else
+		return 0;
+}
+
+/**
+ * __iecm_setup_tc - configure multiple traffic classes
+ * @vport: vport structure
+ * @type_data: tc offload data
+ *
+ * This function processes the config information provided by the
+ * user to configure traffic classes/queue channels and packages the
+ * information to request the PF to setup traffic classes.
+ *
+ * Returns 0 on success.
+ **/
+static int __iecm_setup_tc(struct iecm_vport *vport, void *type_data)
+{
+	struct iecm_adapter *adapter = vport->adapter;
+	struct tc_mqprio_qopt_offload *mqprio_qopt;
+	struct net_device *netdev = vport->netdev;
+	struct iecm_channel_config *ch_config;
+	u8 num_tc = 0, total_qs = 0;
+	int ret = 0;
+	u8 max_tc_allowed;
+	u64 max_tx_rate;
+	u16 mode;
+
+	mqprio_qopt = (struct tc_mqprio_qopt_offload *)type_data;
+	ch_config = &adapter->config_data.ch_config;
+	num_tc = mqprio_qopt->qopt.num_tc;
+	mode = mqprio_qopt->mode;
+
+	/* delete queue_channel */
+	if (!mqprio_qopt->qopt.hw) {
+		if (ch_config->tc_running) {
+			/* reset the tc configuration */
+			netdev_reset_tc(netdev);
+			ch_config->num_tc = 0;
+			netif_tx_stop_all_queues(netdev);
+			netif_tx_disable(netdev);
+			ret = iecm_send_disable_channels_msg(vport);
+			netif_tx_start_all_queues(netdev);
+			if (!test_bit(__IECM_REL_RES_IN_PROG, adapter->flags) &&
+			    !ret) {
+				ch_config->tc_running = false;
+				set_bit(__IECM_HR_FUNC_RESET, adapter->flags);
+				queue_delayed_work(adapter->vc_event_wq,
+						   &adapter->vc_event_task,
+						   msecs_to_jiffies(10));
+			}
+			return ret;
+		} else {
+			return -EINVAL;
+		}
+	}
+
+	if (mode == TC_MQPRIO_MODE_CHANNEL) {
+		int i, netdev_tc = 0;
+
+		if (!iecm_is_cap_ena(adapter, IECM_BASE_CAPS,
+				     VIRTCHNL2_CAP_ADQ) &&
+		    !iecm_is_cap_ena(adapter, IECM_OTHER_CAPS,
+					     VIRTCHNL2_CAP_ADQ)) {
+			dev_info(&adapter->pdev->dev, "ADQ not supported\n");
+			return -EOPNOTSUPP;
+		}
+
+		if (ch_config->tc_running) {
+			dev_info(&adapter->pdev->dev, "TC configuration already exists\n");
+			return -EINVAL;
+		}
+
+		/* If negotiated capability between VF and PF indicated that
+		 * ADQ_V2 is enabled, means it's OK to allow max_tc
+		 * to be 16. This is needed to handle the case where iAVF
+		 * is newer but PF is older or different generation
+		 */
+		if (iecm_is_cap_ena(adapter, IECM_OTHER_CAPS, VIRTCHNL2_CAP_ADQ))
+			max_tc_allowed = VIRTCHNL_MAX_ADQ_V2_CHANNELS;
+		else
+			max_tc_allowed = VIRTCHNL_MAX_ADQ_CHANNELS;
+
+		ret = iecm_validate_ch_config(vport, mqprio_qopt,
+					      max_tc_allowed);
+		if (ret)
+			return ret;
+		/* Return if same TC config is requested */
+		if (ch_config->num_tc == num_tc)
+			return 0;
+		ch_config->num_tc = num_tc;
+
+		for (i = 0; i < max_tc_allowed; i++) {
+			if (i < num_tc) {
+				ch_config->ch_info[i].count =
+					mqprio_qopt->qopt.count[i];
+				ch_config->ch_info[i].offset =
+					mqprio_qopt->qopt.offset[i];
+				total_qs += mqprio_qopt->qopt.count[i];
+				max_tx_rate = mqprio_qopt->max_rate[i];
+				/* convert to Mbps */
+				max_tx_rate = div_u64(max_tx_rate,
+						      IECM_MBPS_DIVISOR);
+				ch_config->ch_info[i].max_tx_rate =
+								max_tx_rate;
+			} else {
+				ch_config->ch_info[i].count = 1;
+				ch_config->ch_info[i].offset = 0;
+			}
+		}
+
+		/* Store queue info based on TC so that, VF gets configured
+		 * with correct number of queues when VF completes ADQ config
+		 * flow
+		 */
+		ch_config->total_qs = total_qs;
+
+		netif_tx_stop_all_queues(netdev);
+		netif_tx_disable(netdev);
+		ret = iecm_send_enable_channels_msg(vport);
+		if (ret)
+			return ret;
+		netdev_reset_tc(netdev);
+		/* Report the tc mapping up the stack */
+		netdev_set_num_tc(netdev, num_tc);
+		for (i = 0; i < max_tc_allowed; i++) {
+			u16 qcount = mqprio_qopt->qopt.count[i];
+			u16 qoffset = mqprio_qopt->qopt.offset[i];
+
+			if (i < num_tc)
+				netdev_set_tc_queue(netdev, netdev_tc++, qcount,
+						    qoffset);
+		}
+		/* Start all queues */
+		netif_tx_start_all_queues(netdev);
+		ch_config->tc_running = true;
+		set_bit(__IECM_HR_FUNC_RESET, adapter->flags);
+		queue_delayed_work(adapter->vc_event_wq,
+				   &adapter->vc_event_task,
+				   msecs_to_jiffies(10));
+	}
+	return ret;
+}
+
+/**
+ * iecm_setup_tc - ndo callback to setup up TC schedulers
+ * @netdev: pointer to net_device struct
+ * @type: TC type
+ * @type_data: TC type specific data
+ */
+static int iecm_setup_tc(struct net_device *netdev, enum tc_setup_type type,
+			 void *type_data)
+{
+	struct iecm_vport *vport = iecm_netdev_to_vport(netdev);
+	struct iecm_adapter *adapter = vport->adapter;
+	int err = 0;
+
+	switch (type) {
+	case TC_SETUP_QDISC_ETF:
+		if (iecm_is_queue_model_split(vport->txq_model))
+			err =
+			iecm_offload_txtime(vport,
+					    (struct tc_etf_qopt_offload *)
+					     type_data);
+		break;
+	case TC_SETUP_BLOCK:
+		break;
+	case TC_SETUP_QDISC_MQPRIO:
+		if (iecm_is_cap_ena(adapter, IECM_BASE_CAPS,
+				    VIRTCHNL2_CAP_ADQ) ||
+		    iecm_is_cap_ena(adapter, IECM_OTHER_CAPS, VIRTCHNL2_CAP_ADQ))
+			__iecm_setup_tc(vport, type_data);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	return err;
+}
+
 /**
  * iecm_set_mac - NDO callback to set port mac address
  * @netdev: network interface device structure
@@ -1997,13 +2711,13 @@ static const struct net_device_ops iecm_netdev_ops_splitq = {
 	.ndo_set_rx_mode = iecm_set_rx_mode,
 	.ndo_validate_addr = eth_validate_addr,
 	.ndo_set_mac_address = iecm_set_mac,
-	.ndo_change_mtu = NULL,
-	.ndo_get_stats64 = NULL,
-	.ndo_fix_features = NULL,
-	.ndo_set_features = NULL,
-	.ndo_vlan_rx_add_vid = NULL,
-	.ndo_vlan_rx_kill_vid = NULL,
-	.ndo_setup_tc = NULL,
+	.ndo_change_mtu = iecm_change_mtu,
+	.ndo_get_stats64 = iecm_get_stats64,
+	.ndo_fix_features = iecm_fix_features,
+	.ndo_set_features = iecm_set_features,
+	.ndo_vlan_rx_add_vid = iecm_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid = iecm_vlan_rx_kill_vid,
+	.ndo_setup_tc = iecm_setup_tc,
 };
 
 static const struct net_device_ops iecm_netdev_ops_singleq = {
@@ -2013,11 +2727,11 @@ static const struct net_device_ops iecm_netdev_ops_singleq = {
 	.ndo_set_rx_mode = iecm_set_rx_mode,
 	.ndo_validate_addr = eth_validate_addr,
 	.ndo_set_mac_address = iecm_set_mac,
-	.ndo_change_mtu = NULL,
-	.ndo_get_stats64 = NULL,
-	.ndo_fix_features = NULL,
-	.ndo_set_features = NULL,
-	.ndo_vlan_rx_add_vid = NULL,
-	.ndo_vlan_rx_kill_vid = NULL,
-	.ndo_setup_tc           = NULL,
+	.ndo_change_mtu = iecm_change_mtu,
+	.ndo_get_stats64 = iecm_get_stats64,
+	.ndo_fix_features = iecm_fix_features,
+	.ndo_set_features = iecm_set_features,
+	.ndo_vlan_rx_add_vid = iecm_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid = iecm_vlan_rx_kill_vid,
+	.ndo_setup_tc = iecm_setup_tc,
 };
diff --git a/drivers/net/ethernet/intel/iecm/iecm_txrx.c b/drivers/net/ethernet/intel/iecm/iecm_txrx.c
index ef5fe659389b..4b9288e1c254 100644
--- a/drivers/net/ethernet/intel/iecm/iecm_txrx.c
+++ b/drivers/net/ethernet/intel/iecm/iecm_txrx.c
@@ -218,6 +218,21 @@ const struct iecm_rx_ptype_decoded iecm_ptype_lookup[IECM_RX_MAX_PTYPE] = {
 };
 EXPORT_SYMBOL(iecm_ptype_lookup);
 
+/**
+ * iecm_get_stats64 - get statistics for network device structure
+ * @netdev: network interface device structure
+ * @stats: main device statistics structure
+ */
+void iecm_get_stats64(struct net_device *netdev,
+		      struct rtnl_link_stats64 *stats)
+{
+	struct iecm_vport *vport = iecm_netdev_to_vport(netdev);
+
+	set_bit(__IECM_MB_STATS_PENDING, vport->adapter->flags);
+
+	*stats = vport->netstats;
+}
+
 /**
  * iecm_tx_buf_rel - Release a Tx buffer
  * @tx_q: the queue that owns the buffer
diff --git a/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c b/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
index 919fb3958cf8..f2516343c199 100644
--- a/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
+++ b/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
@@ -2731,6 +2731,69 @@ static int iecm_send_insert_vlan_msg(struct iecm_vport *vport, bool ena)
 	return err;
 }
 
+/**
+ * iecm_send_enable_channels_msg - Send enable channels message
+ * @vport: vport structure
+ *
+ * Request the PF/CP to enable channels as specified by the user via tc tool.
+ * Returns 0 on success, negative on failure.
+ **/
+int iecm_send_enable_channels_msg(struct iecm_vport *vport)
+{
+	struct iecm_adapter *adapter = vport->adapter;
+	struct iecm_channel_config *ch_config;
+	struct virtchnl_tc_info *vti = NULL;
+	int i, err;
+	u16 len;
+
+	ch_config = &adapter->config_data.ch_config;
+	len = ((ch_config->num_tc - 1) * sizeof(struct virtchnl_channel_info)) +
+		sizeof(struct virtchnl_tc_info);
+
+	vti = kzalloc(len, GFP_KERNEL);
+	if (!vti)
+		return -ENOMEM;
+	vti->num_tc = ch_config->num_tc;
+	for (i = 0; i < vti->num_tc; i++) {
+		vti->list[i].count = ch_config->ch_info[i].count;
+		vti->list[i].offset = ch_config->ch_info[i].offset;
+		vti->list[i].pad = 0;
+		vti->list[i].max_tx_rate = ch_config->ch_info[i].max_tx_rate;
+	}
+
+	err = iecm_send_mb_msg(adapter, VIRTCHNL_OP_ENABLE_CHANNELS, len,
+			       (u8 *)vti);
+	if (err)
+		goto error;
+
+	err = iecm_wait_for_event(adapter, IECM_VC_ENA_CHANNELS,
+				  IECM_VC_ENA_CHANNELS_ERR);
+error:
+	kfree(vti);
+	return err;
+}
+
+/**
+ * iecm_send_disable_channels_msg - Send disable channels message
+ * @vport: vport structure to disable channels on
+ *
+ * Returns 0 on success, negative on failure.
+ */
+int iecm_send_disable_channels_msg(struct iecm_vport *vport)
+{
+	struct iecm_adapter *adapter = vport->adapter;
+	int err;
+
+	err = iecm_send_mb_msg(adapter, VIRTCHNL_OP_DISABLE_CHANNELS,
+			       0, NULL);
+	if (err)
+		return err;
+
+	err = iecm_min_wait_for_event(adapter, IECM_VC_DIS_CHANNELS,
+				      IECM_VC_DIS_CHANNELS_ERR);
+	return err;
+}
+
 /**
  * iecm_send_vlan_v2_caps_msg - send virtchnl get offload VLAN V2 caps message
  * @adapter: adapter info struct
diff --git a/drivers/net/ethernet/intel/include/iecm.h b/drivers/net/ethernet/intel/include/iecm.h
index f6f9884c10c2..a655e797f457 100644
--- a/drivers/net/ethernet/intel/include/iecm.h
+++ b/drivers/net/ethernet/intel/include/iecm.h
@@ -4,6 +4,8 @@
 #ifndef _IECM_H_
 #define _IECM_H_
 
+#include <net/pkt_sched.h>
+#include <net/pkt_cls.h>
 #include <linux/aer.h>
 #include <linux/pci.h>
 #include <linux/netdevice.h>
@@ -44,6 +46,8 @@
 /* available message levels */
 #define IECM_AVAIL_NETIF_M (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
 
+#define IECM_MBPS_DIVISOR		125000 /* divisor to convert to Mbps */
+
 #define IECM_VIRTCHNL_VERSION_MAJOR VIRTCHNL_VERSION_MAJOR_2
 #define IECM_VIRTCHNL_VERSION_MINOR VIRTCHNL_VERSION_MINOR_0
 
@@ -393,6 +397,13 @@ enum iecm_user_flags {
 	__IECM_USER_FLAGS_NBITS,
 };
 
+struct iecm_channel_config {
+	struct virtchnl_channel_info ch_info[VIRTCHNL_MAX_ADQ_V2_CHANNELS];
+	bool tc_running;
+	u8 total_qs;
+	u8 num_tc;
+};
+
 #define IECM_GET_PTYPE_SIZE(p) \
 	(sizeof(struct virtchnl2_ptype) + \
 	(((p)->proto_id_count ? ((p)->proto_id_count - 1) : 0) * sizeof(u16)))
@@ -430,6 +441,7 @@ struct iecm_user_config_data {
 	struct list_head mac_filter_list;
 	struct list_head vlan_filter_list;
 	struct list_head adv_rss_list;
+	struct iecm_channel_config ch_config;
 };
 
 struct iecm_rss_data {
@@ -703,6 +715,8 @@ int iecm_send_delete_queues_msg(struct iecm_vport *vport);
 int iecm_send_add_queues_msg(struct iecm_vport *vport, u16 num_tx_q,
 			     u16 num_complq, u16 num_rx_q, u16 num_rx_bufq);
 int iecm_send_vlan_v2_caps_msg(struct iecm_adapter *adapter);
+int iecm_initiate_soft_reset(struct iecm_vport *vport,
+			     enum iecm_flags reset_cause);
 int iecm_send_config_tx_queues_msg(struct iecm_vport *vport);
 int iecm_send_config_rx_queues_msg(struct iecm_vport *vport);
 int iecm_send_enable_vport_msg(struct iecm_vport *vport);
diff --git a/drivers/net/ethernet/intel/include/iecm_txrx.h b/drivers/net/ethernet/intel/include/iecm_txrx.h
index 26e480343876..7ec742fd4c6b 100644
--- a/drivers/net/ethernet/intel/include/iecm_txrx.h
+++ b/drivers/net/ethernet/intel/include/iecm_txrx.h
@@ -672,6 +672,8 @@ netdev_tx_t iecm_tx_singleq_start(struct sk_buff *skb,
 				  struct net_device *netdev);
 bool iecm_rx_singleq_buf_hw_alloc_all(struct iecm_queue *rxq,
 				      u16 cleaned_count);
+void iecm_get_stats64(struct net_device *netdev,
+		      struct rtnl_link_stats64 *stats);
 int iecm_tso(struct iecm_tx_buf *first, struct iecm_tx_offload_params *off);
 void iecm_tx_prepare_vlan_flags(struct iecm_queue *tx_q,
 				struct iecm_tx_buf *first,
-- 
2.33.0


  parent reply	other threads:[~2022-01-28  0:10 UTC|newest]

Thread overview: 89+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-28  0:09 [Intel-wired-lan] [PATCH net-next 00/19] Add iecm and idpf Alan Brady
2022-01-28  0:09 ` [Intel-wired-lan] [PATCH net-next 01/19] virtchnl: Add new virtchnl2 ops Alan Brady
2022-02-02 22:13   ` Brady, Alan
2022-01-28  0:09 ` [Intel-wired-lan] [PATCH net-next 02/19] iecm: add basic module init and documentation Alan Brady
2022-01-28 11:56   ` Alexander Lobakin
2022-02-02 22:15     ` Brady, Alan
2022-02-01 19:44   ` Shannon Nelson
2022-02-03  3:08     ` Brady, Alan
2022-01-28  0:09 ` [Intel-wired-lan] [PATCH net-next 03/19] iecm: add probe and remove Alan Brady
2022-02-01 20:02   ` Shannon Nelson
2022-02-03  3:13     ` Brady, Alan
2022-01-28  0:09 ` [Intel-wired-lan] [PATCH net-next 04/19] iecm: add api_init and controlq init Alan Brady
2022-01-28 12:09   ` Alexander Lobakin
2022-02-02 22:16     ` Brady, Alan
2022-02-01 21:26   ` Shannon Nelson
2022-02-03  3:24     ` Brady, Alan
2022-02-03  3:40       ` Brady, Alan
2022-02-03  5:26         ` Shannon Nelson
2022-02-03 13:13       ` Alexander Lobakin
2022-01-28  0:09 ` [Intel-wired-lan] [PATCH net-next 05/19] iecm: add vport alloc and virtchnl messages Alan Brady
2022-01-28  4:19   ` kernel test robot
2022-01-28  4:19     ` kernel test robot
2022-01-28 12:39     ` Alexander Lobakin
2022-01-28 12:39       ` Alexander Lobakin
2022-02-02 22:23       ` Brady, Alan
2022-02-02 22:23         ` Brady, Alan
2022-01-28 12:32   ` Alexander Lobakin
2022-02-02 22:21     ` Brady, Alan
2022-02-03 13:23       ` Alexander Lobakin
2022-01-28  0:09 ` [Intel-wired-lan] [PATCH net-next 06/19] iecm: add virtchnl messages for queues Alan Brady
2022-01-28 13:03   ` Alexander Lobakin
2022-02-02 22:48     ` Brady, Alan
2022-02-03 10:08       ` Maciej Fijalkowski
2022-02-03 14:09       ` Alexander Lobakin
2022-01-28  0:09 ` [Intel-wired-lan] [PATCH net-next 07/19] iecm: finish virtchnl messages Alan Brady
2022-01-28 13:19   ` Alexander Lobakin
2022-02-02 23:06     ` Brady, Alan
2022-02-03 15:05       ` Alexander Lobakin
2022-02-03 15:16         ` Maciej Fijalkowski
2022-01-28  0:09 ` [Intel-wired-lan] [PATCH net-next 08/19] iecm: add interrupts and configure netdev Alan Brady
2022-01-28 13:34   ` Alexander Lobakin
2022-02-02 23:17     ` Brady, Alan
2022-02-03 15:55       ` Alexander Lobakin
2022-01-28  0:09 ` [Intel-wired-lan] [PATCH net-next 09/19] iecm: alloc vport TX resources Alan Brady
2022-02-02 23:45   ` Brady, Alan
2022-02-03 17:56     ` Alexander Lobakin
2022-01-28  0:10 ` [Intel-wired-lan] [PATCH net-next 10/19] iecm: alloc vport RX resources Alan Brady
2022-01-28 14:16   ` Alexander Lobakin
2022-02-03  0:13     ` Brady, Alan
2022-02-03 18:29       ` Alexander Lobakin
2022-01-28  0:10 ` [Intel-wired-lan] [PATCH net-next 11/19] iecm: add start_xmit and set_rx_mode Alan Brady
2022-01-28 16:35   ` Alexander Lobakin
2022-01-28  0:10 ` Alan Brady [this message]
2022-01-28 17:06   ` [Intel-wired-lan] [PATCH net-next 12/19] iecm: finish netdev_ops Alexander Lobakin
2022-01-28  0:10 ` [Intel-wired-lan] [PATCH net-next 13/19] iecm: implement splitq napi_poll Alan Brady
2022-01-28  5:21   ` kernel test robot
2022-01-28  5:21     ` kernel test robot
2022-01-28 17:44     ` Alexander Lobakin
2022-01-28 17:44       ` Alexander Lobakin
2022-02-03  1:15       ` Brady, Alan
2022-02-03  1:15         ` Brady, Alan
2022-01-28 17:38   ` Alexander Lobakin
2022-02-03  1:07     ` Brady, Alan
2022-02-04 11:50       ` Alexander Lobakin
2022-01-28  0:10 ` [Intel-wired-lan] [PATCH net-next 14/19] iecm: implement singleq napi_poll Alan Brady
2022-01-28 17:57   ` Alexander Lobakin
2022-02-03  1:45     ` Brady, Alan
2022-02-03 19:05       ` Alexander Lobakin
2022-01-28  0:10 ` [Intel-wired-lan] [PATCH net-next 15/19] iecm: implement ethtool callbacks Alan Brady
2022-01-28 18:13   ` Alexander Lobakin
2022-02-03  2:13     ` Brady, Alan
2022-02-03 19:54       ` Alexander Lobakin
2022-01-28  0:10 ` [Intel-wired-lan] [PATCH net-next 16/19] iecm: implement flow director Alan Brady
2022-01-28 19:04   ` Alexander Lobakin
2022-02-03  2:41     ` Brady, Alan
2022-02-04 10:08       ` Alexander Lobakin
2022-01-28  0:10 ` [Intel-wired-lan] [PATCH net-next 17/19] iecm: implement cloud filters Alan Brady
2022-01-28 19:38   ` Alexander Lobakin
2022-02-03  2:53     ` Brady, Alan
2022-01-28  0:10 ` [Intel-wired-lan] [PATCH net-next 18/19] iecm: add advanced rss Alan Brady
2022-01-28 19:53   ` Alexander Lobakin
2022-02-03  2:55     ` Brady, Alan
2022-02-03 10:46       ` Maciej Fijalkowski
2022-02-04 10:22       ` Alexander Lobakin
2022-01-28  0:10 ` [Intel-wired-lan] [PATCH net-next 19/19] idpf: introduce idpf driver Alan Brady
2022-01-28 20:08   ` Alexander Lobakin
2022-02-03  3:07     ` Brady, Alan
2022-02-04 10:35       ` Alexander Lobakin
2022-02-04 12:05 ` [Intel-wired-lan] [PATCH net-next 00/19] Add iecm and idpf Alexander Lobakin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220128001009.721392-13-alan.brady@intel.com \
    --to=alan.brady@intel.com \
    --cc=intel-wired-lan@osuosl.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.