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
next prev parent reply other threads:[~2022-01-28 0:10 UTC|newest]
Thread overview: 83+ 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 12:39 ` Alexander Lobakin
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 17:44 ` Alexander Lobakin
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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox