* [net-next 10/15] iecm: Deinit vport
From: Jeff Kirsher @ 2020-06-18 5:13 UTC (permalink / raw)
To: davem
Cc: Alice Michael, netdev, nhorman, sassmann, Alan Brady, Phani Burra,
Joshua Hay, Madhu Chittim, Pavan Kumar Linga, Donald Skidmore,
Jesse Brandeburg, Sridhar Samudrala, Jeff Kirsher
In-Reply-To: <20200618051344.516587-1-jeffrey.t.kirsher@intel.com>
From: Alice Michael <alice.michael@intel.com>
Implement vport take down and release its queue
resources.
Signed-off-by: Alice Michael <alice.michael@intel.com>
Signed-off-by: Alan Brady <alan.brady@intel.com>
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>
Reviewed-by: Donald Skidmore <donald.c.skidmore@intel.com>
Reviewed-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Reviewed-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/iecm/iecm_lib.c | 29 ++-
drivers/net/ethernet/intel/iecm/iecm_txrx.c | 218 ++++++++++++++++--
.../net/ethernet/intel/iecm/iecm_virtchnl.c | 15 +-
3 files changed, 246 insertions(+), 16 deletions(-)
diff --git a/drivers/net/ethernet/intel/iecm/iecm_lib.c b/drivers/net/ethernet/intel/iecm/iecm_lib.c
index d855d6238740..707520553912 100644
--- a/drivers/net/ethernet/intel/iecm/iecm_lib.c
+++ b/drivers/net/ethernet/intel/iecm/iecm_lib.c
@@ -366,7 +366,27 @@ struct iecm_adapter *iecm_netdev_to_adapter(struct net_device *netdev)
*/
static void iecm_vport_stop(struct iecm_vport *vport)
{
- /* stub */
+ struct iecm_adapter *adapter = vport->adapter;
+
+ if (adapter->state <= __IECM_DOWN)
+ return;
+ adapter->dev_ops.vc_ops.irq_map_unmap(vport, false);
+ adapter->dev_ops.vc_ops.disable_queues(vport);
+ /* Normally we ask for queues in create_vport, but if we're changing
+ * number of requested queues we do a delete then add instead of
+ * deleting and reallocating the vport.
+ */
+ if (test_and_clear_bit(__IECM_DEL_QUEUES,
+ vport->adapter->flags))
+ iecm_send_delete_queues_msg(vport);
+ netif_carrier_off(vport->netdev);
+ netif_tx_disable(vport->netdev);
+ adapter->link_up = false;
+ iecm_vport_intr_deinit(vport);
+ iecm_vport_queues_rel(vport);
+ if (adapter->dev_ops.vc_ops.disable_vport)
+ adapter->dev_ops.vc_ops.disable_vport(vport);
+ adapter->state = __IECM_DOWN;
}
/**
@@ -381,7 +401,11 @@ static void iecm_vport_stop(struct iecm_vport *vport)
*/
static int iecm_stop(struct net_device *netdev)
{
- /* stub */
+ struct iecm_netdev_priv *np = netdev_priv(netdev);
+
+ iecm_vport_stop(np->vport);
+
+ return 0;
}
/**
@@ -488,6 +512,7 @@ iecm_vport_alloc(struct iecm_adapter *adapter, int vport_id)
/* fill vport slot in the adapter struct */
adapter->vports[adapter->next_vport] = vport;
+
if (iecm_cfg_netdev(vport))
goto cfg_netdev_fail;
diff --git a/drivers/net/ethernet/intel/iecm/iecm_txrx.c b/drivers/net/ethernet/intel/iecm/iecm_txrx.c
index 16fea9ad6545..92dc25c10a6c 100644
--- a/drivers/net/ethernet/intel/iecm/iecm_txrx.c
+++ b/drivers/net/ethernet/intel/iecm/iecm_txrx.c
@@ -41,7 +41,23 @@ void iecm_get_stats64(struct net_device *netdev,
*/
void iecm_tx_buf_rel(struct iecm_queue *tx_q, struct iecm_tx_buf *tx_buf)
{
- /* stub */
+ if (tx_buf->skb) {
+ dev_kfree_skb_any(tx_buf->skb);
+ if (dma_unmap_len(tx_buf, len))
+ dma_unmap_single(tx_q->dev,
+ dma_unmap_addr(tx_buf, dma),
+ dma_unmap_len(tx_buf, len),
+ DMA_TO_DEVICE);
+ } else if (dma_unmap_len(tx_buf, len)) {
+ dma_unmap_page(tx_q->dev,
+ dma_unmap_addr(tx_buf, dma),
+ dma_unmap_len(tx_buf, len),
+ DMA_TO_DEVICE);
+ }
+
+ tx_buf->next_to_watch = NULL;
+ tx_buf->skb = NULL;
+ dma_unmap_len_set(tx_buf, len, 0);
}
/**
@@ -50,7 +66,26 @@ void iecm_tx_buf_rel(struct iecm_queue *tx_q, struct iecm_tx_buf *tx_buf)
*/
void iecm_tx_buf_rel_all(struct iecm_queue *txq)
{
- /* stub */
+ u16 i;
+
+ /* Buffers already cleared, nothing to do */
+ if (!txq->tx_buf)
+ return;
+
+ /* Free all the Tx buffer sk_buffs */
+ for (i = 0; i < txq->desc_count; i++)
+ iecm_tx_buf_rel(txq, &txq->tx_buf[i]);
+
+ kfree(txq->tx_buf);
+ txq->tx_buf = NULL;
+
+ if (txq->buf_stack.bufs) {
+ for (i = 0; i < txq->buf_stack.size; i++) {
+ iecm_tx_buf_rel(txq, txq->buf_stack.bufs[i]);
+ kfree(txq->buf_stack.bufs[i]);
+ }
+ kfree(txq->buf_stack.bufs);
+ }
}
/**
@@ -62,7 +97,17 @@ void iecm_tx_buf_rel_all(struct iecm_queue *txq)
*/
void iecm_tx_desc_rel(struct iecm_queue *txq, bool bufq)
{
- /* stub */
+ if (bufq)
+ iecm_tx_buf_rel_all(txq);
+
+ if (txq->desc_ring) {
+ dmam_free_coherent(txq->dev, txq->size,
+ txq->desc_ring, txq->dma);
+ txq->desc_ring = NULL;
+ txq->next_to_alloc = 0;
+ txq->next_to_use = 0;
+ txq->next_to_clean = 0;
+ }
}
/**
@@ -73,7 +118,24 @@ void iecm_tx_desc_rel(struct iecm_queue *txq, bool bufq)
*/
void iecm_tx_desc_rel_all(struct iecm_vport *vport)
{
- /* stub */
+ struct iecm_queue *txq;
+ int i, j;
+
+ if (!vport->txq_grps)
+ return;
+
+ for (i = 0; i < vport->num_txq_grp; i++) {
+ for (j = 0; j < vport->txq_grps[i].num_txq; j++) {
+ if (vport->txq_grps[i].txqs) {
+ txq = &vport->txq_grps[i].txqs[j];
+ iecm_tx_desc_rel(txq, true);
+ }
+ }
+ if (iecm_is_queue_model_split(vport->txq_model)) {
+ txq = vport->txq_grps[i].complq;
+ iecm_tx_desc_rel(txq, false);
+ }
+ }
}
/**
@@ -209,7 +271,21 @@ static enum iecm_status iecm_tx_desc_alloc_all(struct iecm_vport *vport)
static void iecm_rx_buf_rel(struct iecm_queue *rxq,
struct iecm_rx_buf *rx_buf)
{
- /* stub */
+ struct device *dev = rxq->dev;
+
+ if (!rx_buf->page)
+ return;
+
+ if (rx_buf->skb) {
+ dev_kfree_skb_any(rx_buf->skb);
+ rx_buf->skb = NULL;
+ }
+
+ dma_unmap_page(dev, rx_buf->dma, PAGE_SIZE, DMA_FROM_DEVICE);
+ __free_pages(rx_buf->page, 0);
+
+ rx_buf->page = NULL;
+ rx_buf->page_offset = 0;
}
/**
@@ -218,7 +294,23 @@ static void iecm_rx_buf_rel(struct iecm_queue *rxq,
*/
void iecm_rx_buf_rel_all(struct iecm_queue *rxq)
{
- /* stub */
+ u16 i;
+
+ /* queue already cleared, nothing to do */
+ if (!rxq->rx_buf.buf)
+ return;
+
+ /* Free all the bufs allocated and given to HW on Rx queue */
+ for (i = 0; i < rxq->desc_count; i++) {
+ iecm_rx_buf_rel(rxq, &rxq->rx_buf.buf[i]);
+ if (rxq->rx_hsplit_en)
+ iecm_rx_buf_rel(rxq, &rxq->rx_buf.hdr_buf[i]);
+ }
+
+ kfree(rxq->rx_buf.buf);
+ rxq->rx_buf.buf = NULL;
+ kfree(rxq->rx_buf.hdr_buf);
+ rxq->rx_buf.hdr_buf = NULL;
}
/**
@@ -232,7 +324,25 @@ void iecm_rx_buf_rel_all(struct iecm_queue *rxq)
void iecm_rx_desc_rel(struct iecm_queue *rxq, bool bufq,
enum virtchnl_queue_model q_model)
{
- /* stub */
+ if (!rxq)
+ return;
+
+ if (!bufq && iecm_is_queue_model_split(q_model) && rxq->skb) {
+ dev_kfree_skb_any(rxq->skb);
+ rxq->skb = NULL;
+ }
+
+ if (bufq || !iecm_is_queue_model_split(q_model))
+ iecm_rx_buf_rel_all(rxq);
+
+ if (rxq->desc_ring) {
+ dmam_free_coherent(rxq->dev, rxq->size,
+ rxq->desc_ring, rxq->dma);
+ rxq->desc_ring = NULL;
+ rxq->next_to_alloc = 0;
+ rxq->next_to_clean = 0;
+ rxq->next_to_use = 0;
+ }
}
/**
@@ -243,7 +353,49 @@ void iecm_rx_desc_rel(struct iecm_queue *rxq, bool bufq,
*/
void iecm_rx_desc_rel_all(struct iecm_vport *vport)
{
- /* stub */
+ struct iecm_rxq_group *rx_qgrp;
+ struct iecm_queue *q;
+ int i, j, num_rxq;
+
+ if (!vport->rxq_grps)
+ return;
+
+ for (i = 0; i < vport->num_rxq_grp; i++) {
+ rx_qgrp = &vport->rxq_grps[i];
+
+ if (iecm_is_queue_model_split(vport->rxq_model)) {
+ if (rx_qgrp->splitq.rxq_sets) {
+ num_rxq = rx_qgrp->splitq.num_rxq_sets;
+ for (j = 0; j < num_rxq; j++) {
+ q = &rx_qgrp->splitq.rxq_sets[j].rxq;
+ iecm_rx_desc_rel(q, false,
+ vport->rxq_model);
+ }
+ }
+
+ if (!rx_qgrp->splitq.bufq_sets)
+ continue;
+ for (j = 0; j < IECM_BUFQS_PER_RXQ_SET; j++) {
+ struct iecm_bufq_set *bufq_set =
+ &rx_qgrp->splitq.bufq_sets[j];
+
+ q = &bufq_set->bufq;
+ iecm_rx_desc_rel(q, true, vport->rxq_model);
+ if (!bufq_set->refillqs)
+ continue;
+ kfree(bufq_set->refillqs);
+ bufq_set->refillqs = NULL;
+ }
+ } else {
+ if (rx_qgrp->singleq.rxqs) {
+ for (j = 0; j < rx_qgrp->singleq.num_rxq; j++) {
+ q = &rx_qgrp->singleq.rxqs[j];
+ iecm_rx_desc_rel(q, false,
+ vport->rxq_model);
+ }
+ }
+ }
+ }
}
/**
@@ -570,7 +722,18 @@ static enum iecm_status iecm_rx_desc_alloc_all(struct iecm_vport *vport)
*/
static void iecm_txq_group_rel(struct iecm_vport *vport)
{
- /* stub */
+ if (vport->txq_grps) {
+ int i;
+
+ for (i = 0; i < vport->num_txq_grp; i++) {
+ kfree(vport->txq_grps[i].txqs);
+ vport->txq_grps[i].txqs = NULL;
+ kfree(vport->txq_grps[i].complq);
+ vport->txq_grps[i].complq = NULL;
+ }
+ kfree(vport->txq_grps);
+ vport->txq_grps = NULL;
+ }
}
/**
@@ -579,7 +742,25 @@ static void iecm_txq_group_rel(struct iecm_vport *vport)
*/
static void iecm_rxq_group_rel(struct iecm_vport *vport)
{
- /* stub */
+ if (vport->rxq_grps) {
+ int i;
+
+ for (i = 0; i < vport->num_rxq_grp; i++) {
+ struct iecm_rxq_group *rx_qgrp = &vport->rxq_grps[i];
+
+ if (iecm_is_queue_model_split(vport->rxq_model)) {
+ kfree(rx_qgrp->splitq.rxq_sets);
+ rx_qgrp->splitq.rxq_sets = NULL;
+ kfree(rx_qgrp->splitq.bufq_sets);
+ rx_qgrp->splitq.bufq_sets = NULL;
+ } else {
+ kfree(rx_qgrp->singleq.rxqs);
+ vport->rxq_grps[i].singleq.rxqs = NULL;
+ }
+ }
+ kfree(vport->rxq_grps);
+ vport->rxq_grps = NULL;
+ }
}
/**
@@ -588,7 +769,8 @@ static void iecm_rxq_group_rel(struct iecm_vport *vport)
*/
static void iecm_vport_queue_grp_rel_all(struct iecm_vport *vport)
{
- /* stub */
+ iecm_txq_group_rel(vport);
+ iecm_rxq_group_rel(vport);
}
/**
@@ -599,7 +781,12 @@ static void iecm_vport_queue_grp_rel_all(struct iecm_vport *vport)
*/
void iecm_vport_queues_rel(struct iecm_vport *vport)
{
- /* stub */
+ iecm_tx_desc_rel_all(vport);
+ iecm_rx_desc_rel_all(vport);
+ iecm_vport_queue_grp_rel_all(vport);
+
+ kfree(vport->txqs);
+ vport->txqs = NULL;
}
/**
@@ -2577,5 +2764,10 @@ int iecm_init_rss(struct iecm_vport *vport)
*/
void iecm_deinit_rss(struct iecm_vport *vport)
{
- /* stub */
+ struct iecm_adapter *adapter = vport->adapter;
+
+ kfree(adapter->rss_data.rss_key);
+ adapter->rss_data.rss_key = NULL;
+ kfree(adapter->rss_data.rss_lut);
+ adapter->rss_data.rss_lut = NULL;
}
diff --git a/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c b/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
index d56f8126521a..2aeeb8ca10af 100644
--- a/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
+++ b/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
@@ -689,7 +689,20 @@ iecm_send_enable_vport_msg(struct iecm_vport *vport)
enum iecm_status
iecm_send_disable_vport_msg(struct iecm_vport *vport)
{
- /* stub */
+ struct iecm_adapter *adapter = vport->adapter;
+ struct virtchnl_vport v_id;
+ enum iecm_status err;
+
+ v_id.vport_id = vport->vport_id;
+
+ err = iecm_send_mb_msg(adapter, VIRTCHNL_OP_DISABLE_VPORT,
+ sizeof(v_id), (u8 *)&v_id);
+
+ if (!err)
+ err = iecm_wait_for_event(adapter, IECM_VC_DIS_VPORT,
+ IECM_VC_DIS_VPORT_ERR);
+
+ return err;
}
/**
--
2.26.2
^ permalink raw reply related
* [net-next 04/15] iecm: Common module introduction and function stubs
From: Jeff Kirsher @ 2020-06-18 5:13 UTC (permalink / raw)
To: davem
Cc: Alice Michael, netdev, nhorman, sassmann, Alan Brady, Phani Burra,
Joshua Hay, Madhu Chittim, Pavan Kumar Linga, Donald Skidmore,
Jesse Brandeburg, Sridhar Samudrala, Jeff Kirsher
In-Reply-To: <20200618051344.516587-1-jeffrey.t.kirsher@intel.com>
From: Alice Michael <alice.michael@intel.com>
This introduces function stubs for the framework of the common
module.
Signed-off-by: Alice Michael <alice.michael@intel.com>
Signed-off-by: Alan Brady <alan.brady@intel.com>
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>
Reviewed-by: Donald Skidmore <donald.c.skidmore@intel.com>
Reviewed-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Reviewed-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
.../net/ethernet/intel/iecm/iecm_controlq.c | 200 +++
.../ethernet/intel/iecm/iecm_controlq_setup.c | 84 ++
.../net/ethernet/intel/iecm/iecm_ethtool.c | 16 +
drivers/net/ethernet/intel/iecm/iecm_lib.c | 406 ++++++
drivers/net/ethernet/intel/iecm/iecm_main.c | 47 +
drivers/net/ethernet/intel/iecm/iecm_osdep.c | 15 +
.../ethernet/intel/iecm/iecm_singleq_txrx.c | 255 ++++
drivers/net/ethernet/intel/iecm/iecm_txrx.c | 1256 +++++++++++++++++
.../net/ethernet/intel/iecm/iecm_virtchnl.c | 570 ++++++++
9 files changed, 2849 insertions(+)
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_controlq.c
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_controlq_setup.c
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_ethtool.c
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_lib.c
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_main.c
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_osdep.c
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_singleq_txrx.c
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_txrx.c
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
diff --git a/drivers/net/ethernet/intel/iecm/iecm_controlq.c b/drivers/net/ethernet/intel/iecm/iecm_controlq.c
new file mode 100644
index 000000000000..390c499d9eb5
--- /dev/null
+++ b/drivers/net/ethernet/intel/iecm/iecm_controlq.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2020, Intel Corporation. */
+
+#include <linux/net/intel/iecm_osdep.h>
+#include <linux/net/intel/iecm_controlq.h>
+#include <linux/net/intel/iecm_type.h>
+
+/**
+ * iecm_ctlq_setup_regs - initialize control queue registers
+ * @cq: pointer to the specific control queue
+ * @q_create_info: structs containing info for each queue to be initialized
+ */
+static void
+iecm_ctlq_setup_regs(struct iecm_ctlq_info *cq,
+ struct iecm_ctlq_create_info *q_create_info)
+{
+ /* stub */
+}
+
+/**
+ * iecm_ctlq_init_regs - Initialize control queue registers
+ * @hw: pointer to hw struct
+ * @cq: pointer to the specific Control queue
+ * @is_rxq: true if receive control queue, false otherwise
+ *
+ * Initialize registers. The caller is expected to have already initialized the
+ * descriptor ring memory and buffer memory
+ */
+static enum iecm_status iecm_ctlq_init_regs(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq,
+ bool is_rxq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_ctlq_init_rxq_bufs - populate receive queue descriptors with buf
+ * @cq: pointer to the specific Control queue
+ *
+ * Record the address of the receive queue DMA buffers in the descriptors.
+ * The buffers must have been previously allocated.
+ */
+static void iecm_ctlq_init_rxq_bufs(struct iecm_ctlq_info *cq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_ctlq_shutdown - shutdown the CQ
+ * @hw: pointer to hw struct
+ * @cq: pointer to the specific Control queue
+ *
+ * The main shutdown routine for any controq queue
+ */
+static void iecm_ctlq_shutdown(struct iecm_hw *hw, struct iecm_ctlq_info *cq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_ctlq_add - add one control queue
+ * @hw: pointer to hardware struct
+ * @q_info: info for queue to be created
+ * @cq: (output) double pointer to control queue to be created
+ *
+ * Allocate and initialize a control queue and add it to the control queue list.
+ * The cq parameter will be allocated/initialized and passed back to the caller
+ * if no errors occur.
+ *
+ * Note: iecm_ctlq_init must be called prior to any calls to iecm_ctlq_add
+ */
+enum iecm_status iecm_ctlq_add(struct iecm_hw *hw,
+ struct iecm_ctlq_create_info *qinfo,
+ struct iecm_ctlq_info **cq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_ctlq_remove - deallocate and remove specified control queue
+ * @hw: pointer to hardware struct
+ * @cq: pointer to control queue to be removed
+ */
+void iecm_ctlq_remove(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_ctlq_init - main initialization routine for all control queues
+ * @hw: pointer to hardware struct
+ * @num_q: number of queues to initialize
+ * @q_info: array of structs containing info for each queue to be initialized
+ *
+ * This initializes any number and any type of control queues. This is an all
+ * or nothing routine; if one fails, all previously allocated queues will be
+ * destroyed. This must be called prior to using the individual add/remove
+ * APIs.
+ */
+enum iecm_status iecm_ctlq_init(struct iecm_hw *hw, u8 num_q,
+ struct iecm_ctlq_create_info *q_info)
+{
+ /* stub */
+}
+
+/**
+ * iecm_ctlq_deinit - destroy all control queues
+ * @hw: pointer to hw struct
+ */
+enum iecm_status iecm_ctlq_deinit(struct iecm_hw *hw)
+{
+ /* stub */
+}
+
+/**
+ * iecm_ctlq_send - send command to Control Queue (CTQ)
+ * @hw: pointer to hw struct
+ * @cq: handle to control queue struct to send on
+ * @num_q_msg: number of messages to send on control queue
+ * @q_msg: pointer to array of queue messages to be sent
+ *
+ * The caller is expected to allocate DMAable buffers and pass them to the
+ * send routine via the q_msg struct / control queue specific data struct.
+ * The control queue will hold a reference to each send message until
+ * the completion for that message has been cleaned.
+ */
+enum iecm_status iecm_ctlq_send(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq,
+ u16 num_q_msg,
+ struct iecm_ctlq_msg q_msg[])
+{
+ /* stub */
+}
+
+/**
+ * iecm_ctlq_clean_sq - reclaim send descriptors on HW write back for the
+ * requested queue
+ * @hw: pointer to hw struct
+ * @cq: pointer to the specific Control queue
+ * @clean_count: (input|output) number of descriptors to clean as input, and
+ * number of descriptors actually cleaned as output
+ * @msg_status: (output) pointer to msg pointer array to be populated; needs
+ * to be allocated by caller
+ *
+ * Returns an an array of message pointers associated with the cleaned
+ * descriptors. The pointers are to the original ctlq_msgs sent on the cleaned
+ * descriptors. The status will be returned for each; any messages that failed
+ * to send will have a non-zero status. The caller is expected to free original
+ * ctlq_msgs and free or reuse the DMA buffers.
+ */
+enum iecm_status iecm_ctlq_clean_sq(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq,
+ u16 *clean_count,
+ struct iecm_ctlq_msg *msg_status[])
+{
+ /* stub */
+}
+
+/**
+ * iecm_ctlq_post_rx_buffs - post buffers to descriptor ring
+ * @hw: pointer to hw struct
+ * @cq: pointer to control queue handle
+ * @buff_count: (input|output) input is number of buffers caller is trying to
+ * return; output is number of buffers that were not posted
+ * @buffs: array of pointers to DMA mem structs to be given to hardware
+ *
+ * Caller uses this function to return DMA buffers to the descriptor ring after
+ * consuming them; buff_count will be the number of buffers.
+ *
+ * Note: this function needs to be called after a receive call even
+ * if there are no DMA buffers to be returned, i.e. buff_count = 0,
+ * buffs = NULL to support direct commands
+ */
+enum iecm_status iecm_ctlq_post_rx_buffs(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq,
+ u16 *buff_count,
+ struct iecm_dma_mem **buffs)
+{
+ /* stub */
+}
+
+/**
+ * iecm_ctlq_recv - receive control queue message call back
+ * @hw: pointer to hw struct
+ * @cq: pointer to control queue handle to receive on
+ * @num_q_msg: (input|output) input number of messages that should be received;
+ * output number of messages actually received
+ * @q_msg: (output) array of received control queue messages on this q;
+ * needs to be pre-allocated by caller for as many messages as requested
+ *
+ * Called by interrupt handler or polling mechanism. Caller is expected
+ * to free buffers
+ */
+enum iecm_status iecm_ctlq_recv(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq,
+ u16 *num_q_msg, struct iecm_ctlq_msg *q_msg)
+{
+ /* stub */
+}
diff --git a/drivers/net/ethernet/intel/iecm/iecm_controlq_setup.c b/drivers/net/ethernet/intel/iecm/iecm_controlq_setup.c
new file mode 100644
index 000000000000..2fd6e3d15a1a
--- /dev/null
+++ b/drivers/net/ethernet/intel/iecm/iecm_controlq_setup.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2020, Intel Corporation. */
+
+#include <linux/net/intel/iecm_osdep.h>
+#include <linux/net/intel/iecm_type.h>
+
+/**
+ * iecm_ctlq_alloc_desc_ring - Allocate Control Queue (CQ) rings
+ * @hw: pointer to hw struct
+ * @cq: pointer to the specific Control queue
+ */
+static enum iecm_status
+iecm_ctlq_alloc_desc_ring(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_ctlq_alloc_bufs - Allocate Control Queue (CQ) buffers
+ * @hw: pointer to hw struct
+ * @cq: pointer to the specific Control queue
+ *
+ * Allocate the buffer head for all control queues, and if it's a receive
+ * queue, allocate DMA buffers
+ */
+static enum iecm_status iecm_ctlq_alloc_bufs(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_ctlq_free_desc_ring - Free Control Queue (CQ) rings
+ * @hw: pointer to hw struct
+ * @cq: pointer to the specific Control queue
+ *
+ * This assumes the posted send buffers have already been cleaned
+ * and de-allocated
+ */
+static void iecm_ctlq_free_desc_ring(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_ctlq_free_bufs - Free CQ buffer info elements
+ * @hw: pointer to hw struct
+ * @cq: pointer to the specific Control queue
+ *
+ * Free the DMA buffers for RX queues, and DMA buffer header for both RX and TX
+ * queues. The upper layers are expected to manage freeing of TX DMA buffers
+ */
+static void iecm_ctlq_free_bufs(struct iecm_hw *hw, struct iecm_ctlq_info *cq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_ctlq_dealloc_ring_res - Free memory allocated for control queue
+ * @hw: pointer to hw struct
+ * @cq: pointer to the specific Control queue
+ *
+ * Free the memory used by the ring, buffers and other related structures
+ */
+void iecm_ctlq_dealloc_ring_res(struct iecm_hw *hw, struct iecm_ctlq_info *cq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_ctlq_alloc_ring_res - allocate memory for descriptor ring and bufs
+ * @hw: pointer to hw struct
+ * @cq: pointer to control queue struct
+ *
+ * Do *NOT* hold the lock when calling this as the memory allocation routines
+ * called are not going to be atomic context safe
+ */
+enum iecm_status iecm_ctlq_alloc_ring_res(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq)
+{
+ /* stub */
+}
diff --git a/drivers/net/ethernet/intel/iecm/iecm_ethtool.c b/drivers/net/ethernet/intel/iecm/iecm_ethtool.c
new file mode 100644
index 000000000000..a6532592f2f4
--- /dev/null
+++ b/drivers/net/ethernet/intel/iecm/iecm_ethtool.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2020 Intel Corporation */
+
+#include <linux/net/intel/iecm.h>
+
+/**
+ * iecm_set_ethtool_ops - Initialize ethtool ops struct
+ * @netdev: network interface device structure
+ *
+ * Sets ethtool ops struct in our netdev so that ethtool can call
+ * our functions.
+ */
+void iecm_set_ethtool_ops(struct net_device *netdev)
+{
+ /* stub */
+}
diff --git a/drivers/net/ethernet/intel/iecm/iecm_lib.c b/drivers/net/ethernet/intel/iecm/iecm_lib.c
new file mode 100644
index 000000000000..57a20204a7c8
--- /dev/null
+++ b/drivers/net/ethernet/intel/iecm/iecm_lib.c
@@ -0,0 +1,406 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2020 Intel Corporation */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/net/intel/iecm.h>
+
+static const struct net_device_ops iecm_netdev_ops_splitq;
+static const struct net_device_ops iecm_netdev_ops_singleq;
+extern int debug;
+
+/**
+ * iecm_mb_intr_rel_irq - Free the IRQ association with the OS
+ * @adapter: adapter structure
+ */
+static void iecm_mb_intr_rel_irq(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_intr_rel - Release interrupt capabilities and free memory
+ * @adapter: adapter to disable interrupts on
+ */
+static void iecm_intr_rel(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_mb_intr_clean - Interrupt handler for the mailbox
+ * @irq: interrupt number
+ * @data: pointer to the adapter structure
+ */
+irqreturn_t iecm_mb_intr_clean(int __always_unused irq, void *data)
+{
+ /* stub */
+}
+
+/**
+ * iecm_mb_irq_enable - Enable MSIX interrupt for the mailbox
+ * @adapter: adapter to get the hardware address for register write
+ */
+void iecm_mb_irq_enable(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_mb_intr_req_irq - Request IRQ for the mailbox interrupt
+ * @adapter: adapter structure to pass to the mailbox IRQ handler
+ */
+int iecm_mb_intr_req_irq(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_get_mb_vec_id - Get vector index for mailbox
+ * @adapter: adapter structure to access the vector chunks
+ *
+ * The first vector id in the requested vector chunks from the CP is for
+ * the mailbox
+ */
+void iecm_get_mb_vec_id(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_mb_intr_init - Initialize the mailbox interrupt
+ * @adapter: adapter structure to store the mailbox vector
+ */
+int iecm_mb_intr_init(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_intr_distribute - Distribute MSIX vectors
+ * @adapter: adapter structure to get the vports
+ *
+ * Distribute the MSIX vectors acquired from the OS to the vports based on the
+ * num of vectors requested by each vport
+ */
+void iecm_intr_distribute(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_intr_req - Request interrupt capabilities
+ * @adapter: adapter to enable interrupts on
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int iecm_intr_req(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_cfg_netdev - Allocate, configure and register a netdev
+ * @vport: main vport structure
+ *
+ * Returns 0 on success, negative value on failure
+ */
+static int iecm_cfg_netdev(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_cfg_hw - Initialize HW struct
+ * @adapter: adapter to setup hw struct for
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int iecm_cfg_hw(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_get_free_slot - get the next non-NULL location index in array
+ * @array: array to search
+ * @size: size of the array
+ * @curr: last known occupied index to be used as a search hint
+ *
+ * void * is being used to keep the functionality generic. This lets us use this
+ * function on any array of pointers.
+ */
+static int iecm_get_free_slot(void *array, int size, int curr)
+{
+ /* stub */
+}
+
+/**
+ * iecm_netdev_to_vport - get a vport handle from a netdev
+ * @netdev: network interface device structure
+ */
+struct iecm_vport *iecm_netdev_to_vport(struct net_device *netdev)
+{
+ /* stub */
+}
+
+/**
+ * iecm_netdev_to_adapter - get an adapter handle from a netdev
+ * @netdev: network interface device structure
+ */
+struct iecm_adapter *iecm_netdev_to_adapter(struct net_device *netdev)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_stop - Disable a vport
+ * @vport: vport to disable
+ */
+static void iecm_vport_stop(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_stop - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * The stop entry point is called when an interface is de-activated by the OS,
+ * and the netdevice enters the DOWN state. The hardware is still under the
+ * driver's control, but the netdev interface is disabled.
+ *
+ * Returns success only - not allowed to fail
+ */
+static int iecm_stop(struct net_device *netdev)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_rel - Delete a vport and free its resources
+ * @vport: the vport being removed
+ *
+ * Returns 0 on success or < 0 on error
+ */
+int iecm_vport_rel(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_rel_all - Delete all vports
+ * @adapter: adapter from which all vports are being removed
+ */
+static void iecm_vport_rel_all(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_set_hsplit - enable or disable header split on a given vport
+ * @vport: virtual port
+ * @prog: bpf_program attached to an interface or NULL
+ */
+void iecm_vport_set_hsplit(struct iecm_vport *vport, struct bpf_prog *prog)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_alloc - Allocates the next available struct vport in the adapter
+ * @adapter: board private structure
+ * @vport_type: type of vport
+ *
+ * returns a pointer to a vport on success, NULL on failure.
+ */
+static struct iecm_vport *
+iecm_vport_alloc(struct iecm_adapter *adapter, int vport_id)
+{
+ /* stub */
+}
+
+/**
+ * iecm_service_task - Delayed task for handling mailbox responses
+ * @work: work_struct handle to our data
+ *
+ */
+static void iecm_service_task(struct work_struct *work)
+{
+ /* stub */
+}
+
+/**
+ * iecm_up_complete - Complete interface up sequence
+ * @vport: virtual port structure
+ *
+ */
+static void iecm_up_complete(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_open - Bring up a vport
+ * @vport: vport to bring up
+ */
+static int iecm_vport_open(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_init_task - Delayed initialization task
+ * @work: work_struct handle to our data
+ *
+ * Init task finishes up pending work started in probe. Due to the asynchronous
+ * nature in which the device communicates with hardware, we may have to wait
+ * several milliseconds to get a response. Instead of busy polling in probe,
+ * pulling it out into a delayed work task prevents us from bogging down the
+ * whole system waiting for a response from hardware.
+ */
+static void iecm_init_task(struct work_struct *work)
+{
+ /* stub */
+}
+
+/**
+ * iecm_api_init - Initialize and verify device API
+ * @adapter: driver specific private structure
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int iecm_api_init(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_deinit_task - Device deinit routine
+ * @adapter: Driver specific private structure
+ *
+ * Extended remove logic which will be used for
+ * hard reset as well
+ */
+void iecm_deinit_task(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_init_hard_reset - Initiate a hardware reset
+ * @adapter: Driver specific private structure
+ *
+ * Deallocate the vports and all the resources associated with them and
+ * reallocate. Also reinitialize the mailbox
+ */
+static enum iecm_status
+iecm_init_hard_reset(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vc_event_task - Handle virtchannel event logic
+ * @work: work queue struct
+ */
+static void iecm_vc_event_task(struct work_struct *work)
+{
+ /* stub */
+}
+
+/**
+ * iecm_initiate_soft_reset - Initiate a software reset
+ * @vport: virtual port data struct
+ * @reset_cause: reason for the soft reset
+ *
+ * Soft reset does not involve bringing down the mailbox queue and also we do
+ * not destroy vport. Only queue resources are touched
+ */
+int iecm_initiate_soft_reset(struct iecm_vport *vport,
+ enum iecm_flags reset_cause)
+{
+ /* stub */
+}
+
+/**
+ * iecm_probe - Device initialization routine
+ * @pdev: PCI device information struct
+ * @ent: entry in iecm_pci_tbl
+ * @adapter: driver specific private structure
+ *
+ * Returns 0 on success, negative on failure
+ */
+int iecm_probe(struct pci_dev *pdev,
+ const struct pci_device_id __always_unused *ent,
+ struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+EXPORT_SYMBOL(iecm_probe);
+
+/**
+ * iecm_remove - Device removal routine
+ * @pdev: PCI device information struct
+ */
+void iecm_remove(struct pci_dev *pdev)
+{
+ /* stub */
+}
+EXPORT_SYMBOL(iecm_remove);
+
+/**
+ * iecm_shutdown - PCI callback for shutting down device
+ * @pdev: PCI device information struct
+ */
+void iecm_shutdown(struct pci_dev *pdev)
+{
+ /* stub */
+}
+EXPORT_SYMBOL(iecm_shutdown);
+
+/**
+ * iecm_open - Called when a network interface becomes active
+ * @netdev: network interface device structure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP). At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the netdev watchdog is enabled,
+ * and the stack is notified that the interface is ready.
+ *
+ * Returns 0 on success, negative value on failure
+ */
+static int iecm_open(struct net_device *netdev)
+{
+ /* stub */
+}
+
+/**
+ * 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)
+{
+ /* stub */
+}
+
+static const struct net_device_ops iecm_netdev_ops_splitq = {
+ .ndo_open = iecm_open,
+ .ndo_stop = iecm_stop,
+ .ndo_start_xmit = iecm_tx_splitq_start,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_get_stats64 = iecm_get_stats64,
+};
+
+static const struct net_device_ops iecm_netdev_ops_singleq = {
+ .ndo_open = iecm_open,
+ .ndo_stop = iecm_stop,
+ .ndo_start_xmit = iecm_tx_singleq_start,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = iecm_change_mtu,
+ .ndo_get_stats64 = iecm_get_stats64,
+};
diff --git a/drivers/net/ethernet/intel/iecm/iecm_main.c b/drivers/net/ethernet/intel/iecm/iecm_main.c
new file mode 100644
index 000000000000..0644581fc746
--- /dev/null
+++ b/drivers/net/ethernet/intel/iecm/iecm_main.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2020 Intel Corporation */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/net/intel/iecm.h>
+
+char iecm_drv_name[] = "iecm";
+#define DRV_SUMMARY "Intel(R) Data Plane Function Linux Driver"
+static const char iecm_driver_string[] = DRV_SUMMARY;
+static const char iecm_copyright[] = "Copyright (c) 2020, Intel Corporation.";
+
+MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
+MODULE_DESCRIPTION(DRV_SUMMARY);
+MODULE_LICENSE("GPL v2");
+
+int debug = -1;
+module_param(debug, int, 0644);
+#ifndef CONFIG_DYNAMIC_DEBUG
+MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all), hw debug_mask (0x8XXXXXXX)");
+#else
+MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
+#endif /* !CONFIG_DYNAMIC_DEBUG */
+
+/**
+ * iecm_module_init - Driver registration routine
+ *
+ * iecm_module_init is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ */
+static int __init iecm_module_init(void)
+{
+ /* stub */
+}
+module_init(iecm_module_init);
+
+/**
+ * iecm_module_exit - Driver exit cleanup routine
+ *
+ * iecm_module_exit is called just before the driver is removed
+ * from memory.
+ */
+static void __exit iecm_module_exit(void)
+{
+ /* stub */
+}
+module_exit(iecm_module_exit);
diff --git a/drivers/net/ethernet/intel/iecm/iecm_osdep.c b/drivers/net/ethernet/intel/iecm/iecm_osdep.c
new file mode 100644
index 000000000000..d0534df357d0
--- /dev/null
+++ b/drivers/net/ethernet/intel/iecm/iecm_osdep.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2020 Intel Corporation. */
+
+#include <linux/net/intel/iecm_osdep.h>
+#include <linux/net/intel/iecm.h>
+
+void *iecm_alloc_dma_mem(struct iecm_hw *hw, struct iecm_dma_mem *mem, u64 size)
+{
+ /* stub */
+}
+
+void iecm_free_dma_mem(struct iecm_hw *hw, struct iecm_dma_mem *mem)
+{
+ /* stub */
+}
diff --git a/drivers/net/ethernet/intel/iecm/iecm_singleq_txrx.c b/drivers/net/ethernet/intel/iecm/iecm_singleq_txrx.c
new file mode 100644
index 000000000000..a85471e72d66
--- /dev/null
+++ b/drivers/net/ethernet/intel/iecm/iecm_singleq_txrx.c
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2020 Intel Corporation */
+
+#include <linux/prefetch.h>
+#include <linux/net/intel/iecm.h>
+
+/**
+ * iecm_tx_singleq_build_ctob - populate command tag offset and size
+ * @td_cmd: Command to be filled in desc
+ * @td_offset: Offset to be filled in desc
+ * @size: Size of the buffer
+ * @td_tag: VLAN tag to be filled
+ *
+ * Returns the 64 bit value populated with the input parameters
+ */
+static __le64
+iecm_tx_singleq_build_ctob(u64 td_cmd, u64 td_offset, unsigned int size,
+ u64 td_tag)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_singleq_csum - Enable Tx checksum offloads
+ * @first: pointer to first descriptor
+ * @off: pointer to struct that holds offload parameters
+ *
+ * Returns 0 or error (negative) if checksum offload
+ */
+static
+int iecm_tx_singleq_csum(struct iecm_tx_buf *first,
+ struct iecm_tx_offload_params *off)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_singleq_map - Build the Tx base descriptor
+ * @tx_q: queue to send buffer on
+ * @first: first buffer info buffer to use
+ * @offloads: pointer to struct that holds offload parameters
+ *
+ * This function loops over the skb data pointed to by *first
+ * and gets a physical address for each memory location and programs
+ * it and the length into the transmit base mode descriptor.
+ */
+static void
+iecm_tx_singleq_map(struct iecm_queue *tx_q, struct iecm_tx_buf *first,
+ struct iecm_tx_offload_params *offloads)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_singleq_frame - Sends buffer on Tx ring using base descriptors
+ * @skb: send buffer
+ * @tx_q: queue to send buffer on
+ *
+ * Returns NETDEV_TX_OK if sent, else an error code
+ */
+static netdev_tx_t
+iecm_tx_singleq_frame(struct sk_buff *skb, struct iecm_queue *tx_q)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_singleq_start - Selects the right Tx queue to send buffer
+ * @skb: send buffer
+ * @netdev: network interface device structure
+ *
+ * Returns NETDEV_TX_OK if sent, else an error code
+ */
+netdev_tx_t iecm_tx_singleq_start(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_singleq_clean - Reclaim resources from queue
+ * @tx_q: Tx queue to clean
+ * @napi_budget: Used to determine if we are in netpoll
+ *
+ */
+static bool iecm_tx_singleq_clean(struct iecm_queue *tx_q, int napi_budget)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_singleq_clean_all - Clean all Tx queues
+ * @q_vec: queue vector
+ * @budget: Used to determine if we are in netpoll
+ *
+ * Returns false if clean is not complete else returns true
+ */
+static inline bool
+iecm_tx_singleq_clean_all(struct iecm_q_vector *q_vec, int budget)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_singleq_test_staterr - tests bits in Rx descriptor
+ * status and error fields
+ * @rx_desc: pointer to receive descriptor (in le64 format)
+ * @stat_err_bits: value to mask
+ *
+ * This function does some fast chicanery in order to return the
+ * value of the mask which is really only used for boolean tests.
+ * The status_error_ptype_len doesn't need to be shifted because it begins
+ * at offset zero.
+ */
+static bool
+iecm_rx_singleq_test_staterr(struct iecm_singleq_base_rx_desc *rx_desc,
+ const u64 stat_err_bits)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_singleq_is_non_eop - process handling of non-EOP buffers
+ * @rxq: Rx ring being processed
+ * @rx_desc: Rx descriptor for current buffer
+ * @skb: Current socket buffer containing buffer in progress
+ */
+static bool iecm_rx_singleq_is_non_eop(struct iecm_queue *rxq,
+ struct iecm_singleq_base_rx_desc
+ *rx_desc, struct sk_buff *skb)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_singleq_csum - Indicate in skb if checksum is good
+ * @rxq: Rx descriptor ring packet is being transacted on
+ * @skb: skb currently being received and modified
+ * @rx_desc: the receive descriptor
+ * @ptype: the packet type decoded by hardware
+ *
+ * skb->protocol must be set before this function is called
+ */
+static void iecm_rx_singleq_csum(struct iecm_queue *rxq, struct sk_buff *skb,
+ struct iecm_singleq_base_rx_desc *rx_desc,
+ u8 ptype)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_singleq_process_skb_fields - Populate skb header fields from Rx
+ * descriptor
+ * @rxq: Rx descriptor ring packet is being transacted on
+ * @skb: pointer to current skb being populated
+ *
+ * This function checks the ring, descriptor, and packet information in
+ * order to populate the hash, checksum, VLAN, protocol, and
+ * other fields within the skb.
+ */
+static void
+iecm_rx_singleq_process_skb_fields(struct iecm_queue *rxq, struct sk_buff *skb,
+ struct iecm_singleq_base_rx_desc *rx_desc,
+ u8 ptype)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_singleq_buf_hw_alloc_all - Replace used receive buffers
+ * @rx_q: queue for which the hw buffers are allocated
+ * @cleaned_count: number of buffers to replace
+ *
+ * Returns false if all allocations were successful, true if any fail
+ */
+bool iecm_rx_singleq_buf_hw_alloc_all(struct iecm_queue *rx_q,
+ u16 cleaned_count)
+{
+ /* stub */
+}
+
+/**
+ * iecm_singleq_rx_put_buf - wrapper function to clean and recycle buffers
+ * @rx_bufq: Rx descriptor queue to transact packets on
+ * @rx_buf: Rx buffer to pull data from
+
+ * This function will update the next_to_use/next_to_alloc if the current
+ * buffer is recycled.
+ */
+static void iecm_singleq_rx_put_buf(struct iecm_queue *rx_bufq,
+ struct iecm_rx_buf *rx_buf)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_bump_ntc - Bump and wrap q->next_to_clean value
+ * @q: queue to bump
+ */
+static void iecm_singleq_rx_bump_ntc(struct iecm_queue *q)
+{
+ /* stub */
+}
+
+/**
+ * iecm_singleq_rx_get_buf_page - Fetch Rx buffer page and synchronize data
+ * @rx_buf: Rx buf to fetch page for
+ * @size: size of buffer to add to skb
+ *
+ * This function will pull an Rx buffer page from the ring and synchronize it
+ * for use by the CPU.
+ */
+static struct sk_buff *
+iecm_singleq_rx_get_buf_page(struct device *dev, struct iecm_rx_buf *rx_buf,
+ const unsigned int size)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_singleq_clean - Reclaim resources after receive completes
+ * @rx_q: Rx queue to clean
+ * @budget: Total limit on number of packets to process
+ *
+ * Returns true if there's any budget left (e.g. the clean is finished)
+ */
+static int iecm_rx_singleq_clean(struct iecm_queue *rx_q, int budget)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_singleq_clean_all - Clean all Rx queues
+ * @q_vec: queue vector
+ * @budget: Used to determine if we are in netpoll
+ * @cleaned: returns number of packets cleaned
+ *
+ * Returns false if clean is not complete else returns true
+ */
+static inline bool
+iecm_rx_singleq_clean_all(struct iecm_q_vector *q_vec, int budget,
+ int *cleaned)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_singleq_napi_poll - NAPI handler
+ * @napi: struct from which you get q_vector
+ * @budget: budget provided by stack
+ */
+int iecm_vport_singleq_napi_poll(struct napi_struct *napi, int budget)
+{
+ /* stub */
+}
diff --git a/drivers/net/ethernet/intel/iecm/iecm_txrx.c b/drivers/net/ethernet/intel/iecm/iecm_txrx.c
new file mode 100644
index 000000000000..b4688daa744d
--- /dev/null
+++ b/drivers/net/ethernet/intel/iecm/iecm_txrx.c
@@ -0,0 +1,1256 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2020 Intel Corporation */
+
+#include <linux/net/intel/iecm.h>
+
+/**
+ * iecm_buf_lifo_push - push a buffer pointer onto stack
+ * @stack: pointer to stack struct
+ * @buf: pointer to buf to push
+ **/
+static enum iecm_status iecm_buf_lifo_push(struct iecm_buf_lifo *stack,
+ struct iecm_tx_buf *buf)
+{
+ /* stub */
+}
+
+/**
+ * iecm_buf_lifo_pop - pop a buffer pointer from stack
+ * @stack: pointer to stack struct
+ **/
+static struct iecm_tx_buf *iecm_buf_lifo_pop(struct iecm_buf_lifo *stack)
+{
+ /* stub */
+}
+
+/**
+ * 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)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_buf_rel - Release a Tx buffer
+ * @tx_q: the queue that owns the buffer
+ * @tx_buf: the buffer to free
+ */
+void iecm_tx_buf_rel(struct iecm_queue *tx_q, struct iecm_tx_buf *tx_buf)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_buf_rel all - Free any empty Tx buffers
+ * @txq: queue to be cleaned
+ */
+void iecm_tx_buf_rel_all(struct iecm_queue *txq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_desc_rel - Free Tx resources per queue
+ * @txq: Tx descriptor ring for a specific queue
+ * @bufq: buffer q or completion q
+ *
+ * Free all transmit software resources
+ */
+void iecm_tx_desc_rel(struct iecm_queue *txq, bool bufq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_desc_rel_all - Free Tx Resources for All Queues
+ * @vport: virtual port structure
+ *
+ * Free all transmit software resources
+ */
+void iecm_tx_desc_rel_all(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_buf_alloc_all - Allocate memory for all buffer resources
+ * @tx_q: queue for which the buffers are allocated
+ */
+static enum iecm_status iecm_tx_buf_alloc_all(struct iecm_queue *tx_q)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_desc_alloc - Allocate the Tx descriptors
+ * @tx_q: the Tx ring to set up
+ * @bufq: buffer or completion queue
+ */
+static enum iecm_status iecm_tx_desc_alloc(struct iecm_queue *tx_q, bool bufq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_desc_alloc_all - allocate all queues Tx resources
+ * @vport: virtual port private structure
+ */
+static enum iecm_status iecm_tx_desc_alloc_all(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_buf_rel - Release a Rx buffer
+ * @rxq: the queue that owns the buffer
+ * @rx_buf: the buffer to free
+ */
+static void iecm_rx_buf_rel(struct iecm_queue *rxq,
+ struct iecm_rx_buf *rx_buf)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_buf_rel_all - Free all Rx buffer resources for a queue
+ * @rxq: queue to be cleaned
+ */
+void iecm_rx_buf_rel_all(struct iecm_queue *rxq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_desc_rel - Free a specific Rx q resources
+ * @rxq: queue to clean the resources from
+ * @bufq: buffer q or completion q
+ * @q_model: single or split q model
+ *
+ * Free a specific Rx queue resources
+ */
+void iecm_rx_desc_rel(struct iecm_queue *rxq, bool bufq,
+ enum virtchnl_queue_model q_model)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_desc_rel_all - Free Rx Resources for All Queues
+ * @vport: virtual port structure
+ *
+ * Free all Rx queues resources
+ */
+void iecm_rx_desc_rel_all(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_buf_hw_update - Store the new tail and head values
+ * @rxq: queue to bump
+ * @val: new head index
+ */
+void iecm_rx_buf_hw_update(struct iecm_queue *rxq, u32 val)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_buf_hw_alloc - recycle or make a new page
+ * @rxq: ring to use
+ * @buf: rx_buffer struct to modify
+ *
+ * Returns true if the page was successfully allocated or
+ * reused.
+ */
+bool iecm_rx_buf_hw_alloc(struct iecm_queue *rxq, struct iecm_rx_buf *buf)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_hdr_buf_hw_alloc - recycle or make a new page for header buffer
+ * @rxq: ring to use
+ * @hdr_buf: rx_buffer struct to modify
+ *
+ * Returns true if the page was successfully allocated or
+ * reused.
+ */
+bool iecm_rx_hdr_buf_hw_alloc(struct iecm_queue *rxq,
+ struct iecm_rx_buf *hdr_buf)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_buf_hw_alloc_all - Replace used receive buffers
+ * @rxq: queue for which the hw buffers are allocated
+ * @cleaned_count: number of buffers to replace
+ *
+ * Returns false if all allocations were successful, true if any fail
+ */
+static bool
+iecm_rx_buf_hw_alloc_all(struct iecm_queue *rxq,
+ u16 cleaned_count)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_buf_alloc_all - Allocate memory for all buffer resources
+ * @rxq: queue for which the buffers are allocated
+ */
+static enum iecm_status iecm_rx_buf_alloc_all(struct iecm_queue *rxq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_desc_alloc - Allocate queue Rx resources
+ * @rxq: Rx queue for which the resources are setup
+ * @bufq: buffer or completion queue
+ * @q_model: single or split queue model
+ */
+static enum iecm_status iecm_rx_desc_alloc(struct iecm_queue *rxq, bool bufq,
+ enum virtchnl_queue_model q_model)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_desc_alloc_all - allocate all RX queues resources
+ * @vport: virtual port structure
+ */
+static enum iecm_status iecm_rx_desc_alloc_all(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_txq_group_rel - Release all resources for txq groups
+ * @vport: vport to release txq groups on
+ */
+static void iecm_txq_group_rel(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rxq_group_rel - Release all resources for rxq groups
+ * @vport: vport to release rxq groups on
+ */
+static void iecm_rxq_group_rel(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_queue_grp_rel_all - Release all queue groups
+ * @vport: vport to release queue groups for
+ */
+static void iecm_vport_queue_grp_rel_all(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_queues_rel - Free memory for all queues
+ * @vport: virtual port
+ *
+ * Free the memory allocated for queues associated to a vport
+ */
+void iecm_vport_queues_rel(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_init_fast_path_txqs - Initialize fast path txq array
+ * @vport: vport to init txqs on
+ *
+ * We get a queue index from skb->queue_mapping and we need a fast way to
+ * dereference the queue from queue groups. This allows us to quickly pull a
+ * txq based on a queue index.
+ */
+static enum iecm_status
+iecm_vport_init_fast_path_txqs(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_init_num_qs - Initialize number of queues
+ * @vport: vport to initialize qs
+ * @vport_msg: data to be filled into vport
+ */
+void iecm_vport_init_num_qs(struct iecm_vport *vport,
+ struct virtchnl_create_vport *vport_msg)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_calc_num_q_desc - Calculate number of queue groups
+ * @vport: vport to calculate q groups for
+ */
+void iecm_vport_calc_num_q_desc(struct iecm_vport *vport)
+{
+ /* stub */
+}
+EXPORT_SYMBOL(iecm_vport_calc_num_q_desc);
+
+/**
+ * iecm_vport_calc_total_qs - Calculate total number of queues
+ * @vport_msg: message to fill with data
+ * @num_req_qs: user requested queues
+ */
+void iecm_vport_calc_total_qs(struct virtchnl_create_vport *vport_msg,
+ int num_req_qs)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_calc_num_q_groups - Calculate number of queue groups
+ * @vport: vport to calculate q groups for
+ */
+void iecm_vport_calc_num_q_groups(struct iecm_vport *vport)
+{
+ /* stub */
+}
+EXPORT_SYMBOL(iecm_vport_calc_num_q_groups);
+
+/**
+ * iecm_vport_calc_numq_per_grp - Calculate number of queues per group
+ * @vport: vport to calculate queues for
+ * @num_txq: int return parameter
+ * @num_rxq: int return parameter
+ */
+static void iecm_vport_calc_numq_per_grp(struct iecm_vport *vport,
+ int *num_txq, int *num_rxq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_calc_num_q_vec - Calculate total number of vectors required for
+ * this vport
+ * @vport: virtual port
+ *
+ */
+void iecm_vport_calc_num_q_vec(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_txq_group_alloc - Allocate all txq group resources
+ * @vport: vport to allocate txq groups for
+ * @num_txq: number of txqs to allocate for each group
+ */
+static enum iecm_status iecm_txq_group_alloc(struct iecm_vport *vport,
+ int num_txq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rxq_group_alloc - Allocate all rxq group resources
+ * @vport: vport to allocate rxq groups for
+ * @num_rxq: number of rxqs to allocate for each group
+ */
+static enum iecm_status iecm_rxq_group_alloc(struct iecm_vport *vport,
+ int num_rxq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_queue_grp_alloc_all - Allocate all queue groups/resources
+ * @vport: vport with qgrps to allocate
+ */
+static enum iecm_status
+iecm_vport_queue_grp_alloc_all(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_queues_alloc - Allocate memory for all queues
+ * @vport: virtual port
+ *
+ * Allocate memory for queues associated with a vport
+ */
+enum iecm_status iecm_vport_queues_alloc(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_find_q - Find the Tx q based on q id
+ * @vport: the vport we care about
+ * @q_id: Id of the queue
+ *
+ * Returns queue ptr if found else returns NULL
+ */
+static struct iecm_queue *
+iecm_tx_find_q(struct iecm_vport *vport, int q_id)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_handle_sw_marker - Handle queue marker packet
+ * @tx_q: Tx queue to handle software marker
+ */
+static void iecm_tx_handle_sw_marker(struct iecm_queue *tx_q)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_splitq_clean_buf - Clean TX buffer resources
+ * @tx_q: Tx queue to clean buffer from
+ * @tx_buf: buffer to be cleaned
+ * @napi_budget: Used to determine if we are in netpoll
+ *
+ * Returns the stats (bytes/packets) cleaned from this buffer
+ */
+static struct iecm_tx_queue_stats
+iecm_tx_splitq_clean_buf(struct iecm_queue *tx_q, struct iecm_tx_buf *tx_buf,
+ int napi_budget)
+{
+ /* stub */
+}
+
+/**
+ * iecm_stash_flow_sch_buffers - store buffere parameter info to be freed at a
+ * later time (only relevant for flow scheduling mode)
+ * @txq: Tx queue to clean
+ * @tx_buf: buffer to store
+ */
+static int
+iecm_stash_flow_sch_buffers(struct iecm_queue *txq, struct iecm_tx_buf *tx_buf)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_splitq_clean - Reclaim resources from buffer queue
+ * @tx_q: Tx queue to clean
+ * @end: queue index until which it should be cleaned
+ * @napi_budget: Used to determine if we are in netpoll
+ * @descs_only: true if queue is using flow-based scheduling and should
+ * not clean buffers at this time
+ *
+ * Cleans the queue descriptor ring. If the queue is using queue-based
+ * scheduling, the buffers will be cleaned as well and this function will
+ * return the number of bytes/packets cleaned. If the queue is using flow-based
+ * scheduling, only the descriptors are cleaned at this time. Separate packet
+ * completion events will be reported on the completion queue, and the
+ * buffers will be cleaned separately. The stats returned from this function
+ * when using flow-based scheduling are irrelevant.
+ */
+static struct iecm_tx_queue_stats
+iecm_tx_splitq_clean(struct iecm_queue *tx_q, u16 end, int napi_budget,
+ bool descs_only)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_hw_tstamp - report hw timestamp from completion desc to stack
+ * @skb: original skb
+ * @desc_ts: pointer to 3 byte timestamp from descriptor
+ */
+static inline void iecm_tx_hw_tstamp(struct sk_buff *skb, u8 *desc_ts)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_clean_flow_sch_bufs - clean bufs that were stored for
+ * out of order completions
+ * @txq: queue to clean
+ * @compl_tag: completion tag of packet to clean (from completion descriptor)
+ * @desc_ts: pointer to 3 byte timestamp from descriptor
+ * @budget: Used to determine if we are in netpoll
+ */
+static struct iecm_tx_queue_stats
+iecm_tx_clean_flow_sch_bufs(struct iecm_queue *txq, u16 compl_tag,
+ u8 *desc_ts, int budget)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_clean_complq - Reclaim resources on completion queue
+ * @complq: Tx ring to clean
+ * @budget: Used to determine if we are in netpoll
+ *
+ * Returns true if there's any budget left (e.g. the clean is finished)
+ */
+static bool
+iecm_tx_clean_complq(struct iecm_queue *complq, int budget)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_splitq_build_ctb - populate command tag and size for queue
+ * based scheduling descriptors
+ * @desc: descriptor to populate
+ * @parms: pointer to Tx params struct
+ * @td_cmd: command to be filled in desc
+ * @size: size of buffer
+ */
+static inline void
+iecm_tx_splitq_build_ctb(union iecm_tx_flex_desc *desc,
+ struct iecm_tx_splitq_params *parms,
+ u16 td_cmd, u16 size)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_splitq_build_flow_desc - populate command tag and size for flow
+ * scheduling descriptors
+ * @desc: descriptor to populate
+ * @parms: pointer to Tx params struct
+ * @td_cmd: command to be filled in desc
+ * @size: size of buffer
+ */
+static inline void
+iecm_tx_splitq_build_flow_desc(union iecm_tx_flex_desc *desc,
+ struct iecm_tx_splitq_params *parms,
+ u16 td_cmd, u16 size)
+{
+ /* stub */
+}
+
+/**
+ * __iecm_tx_maybe_stop - 2nd level check for Tx stop conditions
+ * @tx_q: the queue to be checked
+ * @size: the size buffer we want to assure is available
+ *
+ * Returns -EBUSY if a stop is needed, else 0
+ */
+static int
+__iecm_tx_maybe_stop(struct iecm_queue *tx_q, unsigned int size)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_maybe_stop - 1st level check for Tx stop conditions
+ * @tx_q: the queue to be checked
+ * @size: number of descriptors we want to assure is available
+ *
+ * Returns 0 if stop is not needed
+ */
+int iecm_tx_maybe_stop(struct iecm_queue *tx_q, unsigned int size)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_buf_hw_update - Store the new tail and head values
+ * @tx_q: queue to bump
+ * @val: new head index
+ * @skb: skb for which the descriptors are updated
+ */
+void iecm_tx_buf_hw_update(struct iecm_queue *tx_q, u32 val,
+ struct sk_buff *skb)
+{
+ /* stub */
+}
+
+/**
+ * __iecm_tx_desc_count required - Get the number of descriptors needed for Tx
+ * @size: transmit request size in bytes
+ *
+ * Due to hardware alignment restrictions (4K alignment), we need to
+ * assume that we can have no more than 12K of data per descriptor, even
+ * though each descriptor can take up to 16K - 1 bytes of aligned memory.
+ * Thus, we need to divide by 12K. But division is slow! Instead,
+ * we decompose the operation into shifts and one relatively cheap
+ * multiply operation.
+ *
+ * To divide by 12K, we first divide by 4K, then divide by 3:
+ * To divide by 4K, shift right by 12 bits
+ * To divide by 3, multiply by 85, then divide by 256
+ * (Divide by 256 is done by shifting right by 8 bits)
+ * Finally, we add one to round up. Because 256 isn't an exact multiple of
+ * 3, we'll underestimate near each multiple of 12K. This is actually more
+ * accurate as we have 4K - 1 of wiggle room that we can fit into the last
+ * segment. For our purposes this is accurate out to 1M which is orders of
+ * magnitude greater than our largest possible GSO size.
+ *
+ * This would then be implemented as:
+ * return (((size >> 12) * 85) >> 8) + IECM_TX_DESCS_FOR_SKB_DATA_PTR;
+ *
+ * Since multiplication and division are commutative, we can reorder
+ * operations into:
+ * return ((size * 85) >> 20) + IECM_TX_DESCS_FOR_SKB_DATA_PTR;
+ */
+static unsigned int __iecm_tx_desc_count_required(unsigned int size)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_desc_count_required - calculate number of Tx descriptors needed
+ * @skb: send buffer
+ *
+ * Returns number of data descriptors needed for this skb.
+ */
+unsigned int iecm_tx_desc_count_required(struct sk_buff *skb)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_splitq_map - Build the Tx flex descriptor
+ * @tx_q: queue to send buffer on
+ * @off: pointer to offload params struct
+ * @first: first buffer info buffer to use
+ *
+ * This function loops over the skb data pointed to by *first
+ * and gets a physical address for each memory location and programs
+ * it and the length into the transmit flex descriptor.
+ */
+static void
+iecm_tx_splitq_map(struct iecm_queue *tx_q,
+ struct iecm_tx_offload_params *off,
+ struct iecm_tx_buf *first)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tso - computes mss and TSO length to prepare for TSO
+ * @first: pointer to struct iecm_tx_buf
+ * @off: pointer to struct that holds offload parameters
+ *
+ * Returns error (negative) if TSO doesn't apply to the given skb,
+ * 0 otherwise.
+ *
+ * Note: this function can be used in the splitq and singleq paths
+ */
+static int iecm_tso(struct iecm_tx_buf *first,
+ struct iecm_tx_offload_params *off)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_splitq_frame - Sends buffer on Tx ring using flex descriptors
+ * @skb: send buffer
+ * @tx_q: queue to send buffer on
+ *
+ * Returns NETDEV_TX_OK if sent, else an error code
+ */
+static netdev_tx_t
+iecm_tx_splitq_frame(struct sk_buff *skb, struct iecm_queue *tx_q)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_splitq_start - Selects the right Tx queue to send buffer
+ * @skb: send buffer
+ * @netdev: network interface device structure
+ *
+ * Returns NETDEV_TX_OK if sent, else an error code
+ */
+netdev_tx_t iecm_tx_splitq_start(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ /* stub */
+}
+
+/**
+ * iecm_ptype_to_htype - get a hash type
+ * @vport: virtual port data
+ * @ptype: the ptype value from the descriptor
+ *
+ * Returns appropriate hash type (such as PKT_HASH_TYPE_L2/L3/L4) to be used by
+ * skb_set_hash based on PTYPE as parsed by HW Rx pipeline and is part of
+ * Rx desc.
+ */
+static enum pkt_hash_types iecm_ptype_to_htype(struct iecm_vport *vport,
+ u16 ptype)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_hash - set the hash value in the skb
+ * @rxq: Rx descriptor ring packet is being transacted on
+ * @skb: pointer to current skb being populated
+ * @rx_desc: Receive descriptor
+ * @ptype: the packet type decoded by hardware
+ */
+static void
+iecm_rx_hash(struct iecm_queue *rxq, struct sk_buff *skb,
+ struct iecm_flex_rx_desc *rx_desc, u16 ptype)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_csum - Indicate in skb if checksum is good
+ * @rxq: Rx descriptor ring packet is being transacted on
+ * @skb: pointer to current skb being populated
+ * @rx_desc: Receive descriptor
+ * @ptype: the packet type decoded by hardware
+ *
+ * skb->protocol must be set before this function is called
+ */
+static void
+iecm_rx_csum(struct iecm_queue *rxq, struct sk_buff *skb,
+ struct iecm_flex_rx_desc *rx_desc, u16 ptype)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_rsc - Set the RSC fields in the skb
+ * @rxq : Rx descriptor ring packet is being transacted on
+ * @skb : pointer to current skb being populated
+ * @rx_desc: Receive descriptor
+ * @ptype: the packet type decoded by hardware
+ *
+ * Populate the skb fields with the total number of RSC segments, RSC payload
+ * length and packet type.
+ */
+static bool iecm_rx_rsc(struct iecm_queue *rxq, struct sk_buff *skb,
+ struct iecm_flex_rx_desc *rx_desc, u16 ptype)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_hwtstamp - check for an RX timestamp and pass up
+ * the stack
+ * @rx_desc: pointer to Rx descriptor containing timestamp
+ * @skb: skb to put timestamp in
+ */
+static void iecm_rx_hwtstamp(struct iecm_flex_rx_desc *rx_desc,
+ struct sk_buff __maybe_unused *skb)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_process_skb_fields - Populate skb header fields from Rx descriptor
+ * @rxq: Rx descriptor ring packet is being transacted on
+ * @skb: pointer to current skb being populated
+ * @rx_desc: Receive descriptor
+ *
+ * This function checks the ring, descriptor, and packet information in
+ * order to populate the hash, checksum, VLAN, protocol, and
+ * other fields within the skb.
+ */
+static bool
+iecm_rx_process_skb_fields(struct iecm_queue *rxq, struct sk_buff *skb,
+ struct iecm_flex_rx_desc *rx_desc)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_skb - Send a completed packet up the stack
+ * @rxq: Rx ring in play
+ * @skb: packet to send up
+ *
+ * This function sends the completed packet (via. skb) up the stack using
+ * GRO receive functions
+ */
+void iecm_rx_skb(struct iecm_queue *rxq, struct sk_buff *skb)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_page_is_reserved - check if reuse is possible
+ * @page: page struct to check
+ */
+static bool iecm_rx_page_is_reserved(struct page *page)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_buf_adjust_pg_offset - Prepare Rx buffer for reuse
+ * @rx_buf: Rx buffer to adjust
+ * @size: Size of adjustment
+ *
+ * Update the offset within page so that Rx buf will be ready to be reused.
+ * For systems with PAGE_SIZE < 8192 this function will flip the page offset
+ * so the second half of page assigned to Rx buffer will be used, otherwise
+ * the offset is moved by the @size bytes
+ */
+static void
+iecm_rx_buf_adjust_pg_offset(struct iecm_rx_buf *rx_buf, unsigned int size)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_can_reuse_page - Determine if page can be reused for another Rx
+ * @rx_buf: buffer containing the page
+ *
+ * If page is reusable, we have a green light for calling iecm_reuse_rx_page,
+ * which will assign the current buffer to the buffer that next_to_alloc is
+ * pointing to; otherwise, the DMA mapping needs to be destroyed and
+ * page freed
+ */
+static bool iecm_rx_can_reuse_page(struct iecm_rx_buf *rx_buf)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_add_frag - Add contents of Rx buffer to sk_buff as a frag
+ * @rx_buf: buffer containing page to add
+ * @skb: sk_buff to place the data into
+ * @size: packet length from rx_desc
+ *
+ * This function will add the data contained in rx_buf->page to the skb.
+ * It will just attach the page as a frag to the skb.
+ * The function will then update the page offset.
+ */
+void iecm_rx_add_frag(struct iecm_rx_buf *rx_buf, struct sk_buff *skb,
+ unsigned int size)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_reuse_page - page flip buffer and store it back on the queue
+ * @rx_bufq: Rx descriptor ring to store buffers on
+ * @hsplit: true if header buffer, false otherwise
+ * @old_buf: donor buffer to have page reused
+ *
+ * Synchronizes page for reuse by the adapter
+ */
+void iecm_rx_reuse_page(struct iecm_queue *rx_bufq,
+ bool hsplit,
+ struct iecm_rx_buf *old_buf)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_get_buf_page - Fetch Rx buffer page and synchronize data for use
+ * @rx_buf: Rx buf to fetch page for
+ * @size: size of buffer to add to skb
+ *
+ * This function will pull an Rx buffer page from the ring and synchronize it
+ * for use by the CPU.
+ */
+static void
+iecm_rx_get_buf_page(struct device *dev, struct iecm_rx_buf *rx_buf,
+ const unsigned int size)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_construct_skb - Allocate skb and populate it
+ * @rxq: Rx descriptor queue
+ * @rx_buf: Rx buffer to pull data from
+ * @size: the length of the packet
+ *
+ * This function allocates an skb. It then populates it with the page
+ * data from the current receive descriptor, taking care to set up the
+ * skb correctly.
+ */
+struct sk_buff *
+iecm_rx_construct_skb(struct iecm_queue *rxq, struct iecm_rx_buf *rx_buf,
+ unsigned int size)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_cleanup_headers - Correct empty headers
+ * @skb: pointer to current skb being fixed
+ *
+ * Also address the case where we are pulling data in on pages only
+ * and as such no data is present in the skb header.
+ *
+ * In addition if skb is not at least 60 bytes we need to pad it so that
+ * it is large enough to qualify as a valid Ethernet frame.
+ *
+ * Returns true if an error was encountered and skb was freed.
+ */
+bool iecm_rx_cleanup_headers(struct sk_buff *skb)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_splitq_test_staterr - tests bits in Rx descriptor
+ * status and error fields
+ * @stat_err_field: field from descriptor to test bits in
+ * @stat_err_bits: value to mask
+ *
+ */
+static bool
+iecm_rx_splitq_test_staterr(u8 stat_err_field, const u8 stat_err_bits)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_splitq_is_non_eop - process handling of non-EOP buffers
+ * @rx_desc: Rx descriptor for current buffer
+ *
+ * If the buffer is an EOP buffer, this function exits returning false,
+ * otherwise return true indicating that this is in fact a non-EOP buffer.
+ */
+static bool
+iecm_rx_splitq_is_non_eop(struct iecm_flex_rx_desc *rx_desc)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_recycle_buf - Clean up used buffer and either recycle or free
+ * @rx_bufq: Rx descriptor queue to transact packets on
+ * @hsplit: true if buffer is a header buffer
+ * @rx_buf: Rx buffer to pull data from
+ *
+ * This function will clean up the contents of the rx_buf. It will either
+ * recycle the buffer or unmap it and free the associated resources.
+ *
+ * Returns true if the buffer is reused, false if the buffer is freed.
+ */
+bool iecm_rx_recycle_buf(struct iecm_queue *rx_bufq, bool hsplit,
+ struct iecm_rx_buf *rx_buf)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_splitq_put_bufs - wrapper function to clean and recycle buffers
+ * @rx_bufq: Rx descriptor queue to transact packets on
+ * @hdr_buf: Rx header buffer to pull data from
+ * @rx_buf: Rx buffer to pull data from
+ *
+ * This function will update the next_to_use/next_to_alloc if the current
+ * buffer is recycled.
+ */
+static void iecm_rx_splitq_put_bufs(struct iecm_queue *rx_bufq,
+ struct iecm_rx_buf *hdr_buf,
+ struct iecm_rx_buf *rx_buf)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_bump_ntc - Bump and wrap q->next_to_clean value
+ * @q: queue to bump
+ */
+static void iecm_rx_bump_ntc(struct iecm_queue *q)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_splitq_clean - Clean completed descriptors from Rx queue
+ * @rxq: Rx descriptor queue to retrieve receive buffer queue
+ * @budget: Total limit on number of packets to process
+ *
+ * This function provides a "bounce buffer" approach to Rx interrupt
+ * processing. The advantage to this is that on systems that have
+ * expensive overhead for IOMMU access this provides a means of avoiding
+ * it by maintaining the mapping of the page to the system.
+ *
+ * Returns amount of work completed
+ */
+static int iecm_rx_splitq_clean(struct iecm_queue *rxq, int budget)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_intr_clean_queues - MSIX mode Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a q_vector
+ *
+ */
+irqreturn_t
+iecm_vport_intr_clean_queues(int __always_unused irq, void *data)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_intr_napi_dis_all - Disable NAPI for all q_vectors in the vport
+ * @vport: main vport structure
+ */
+static void iecm_vport_intr_napi_dis_all(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_intr_rel - Free memory allocated for interrupt vectors
+ * @vport: virtual port
+ *
+ * Free the memory allocated for interrupt vectors associated to a vport
+ */
+static void iecm_vport_intr_rel(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_intr_rel_irq - Free the IRQ association with the OS
+ * @vport: main vport structure
+ */
+static void iecm_vport_intr_rel_irq(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_intr_dis_irq_all - Disable each interrupt
+ * @vport: main vport structure
+ */
+void iecm_vport_intr_dis_irq_all(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_intr_buildreg_itr - Enable default interrupt generation settings
+ * @q_vector: pointer to q_vector
+ * @type: ITR index
+ * @itr: ITR value
+ */
+static u32 iecm_vport_intr_buildreg_itr(struct iecm_q_vector *q_vector,
+ const int type, u16 itr)
+{
+ /* stub */
+}
+
+static inline unsigned int iecm_itr_divisor(struct iecm_q_vector *q_vector)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_intr_set_new_itr - update the ITR value based on statistics
+ * @q_vector: structure containing interrupt and ring information
+ * @itr: structure containing queue performance data
+ * @q_type: queue type
+ *
+ * Stores a new ITR value based on packets and byte
+ * counts during the last interrupt. The advantage of per interrupt
+ * computation is faster updates and more accurate ITR for the current
+ * traffic pattern. Constants in this function were computed
+ * based on theoretical maximum wire speed and thresholds were set based
+ * on testing data as well as attempting to minimize response time
+ * while increasing bulk throughput.
+ */
+static void iecm_vport_intr_set_new_itr(struct iecm_q_vector *q_vector,
+ struct iecm_itr *itr,
+ enum virtchnl_queue_type q_type)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_intr_update_itr_ena_irq - Update ITR and re-enable MSIX interrupt
+ * @q_vector: q_vector for which ITR is being updated and interrupt enabled
+ */
+void iecm_vport_intr_update_itr_ena_irq(struct iecm_q_vector *q_vector)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_intr_req_irq - get MSI-X vectors from the OS for the vport
+ * @vport: main vport structure
+ * @basename: name for the vector
+ */
+static int
+iecm_vport_intr_req_irq(struct iecm_vport *vport, char *basename)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_intr_ena_irq_all - Enable IRQ for the given vport
+ * @vport: main vport structure
+ */
+void iecm_vport_intr_ena_irq_all(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_intr_deinit - Release all vector associations for the vport
+ * @vport: main vport structure
+ */
+void iecm_vport_intr_deinit(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_intr_napi_ena_all - Enable NAPI for all q_vectors in the vport
+ * @vport: main vport structure
+ */
+static void
+iecm_vport_intr_napi_ena_all(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_tx_splitq_clean_all- Clean completion queues
+ * @q_vec: queue vector
+ * @budget: Used to determine if we are in netpoll
+ *
+ * Returns false if clean is not complete else returns true
+ */
+static inline bool
+iecm_tx_splitq_clean_all(struct iecm_q_vector *q_vec, int budget)
+{
+ /* stub */
+}
+
+/**
+ * iecm_rx_splitq_clean_all- Clean completion queues
+ * @q_vec: queue vector
+ * @budget: Used to determine if we are in netpoll
+ * @cleaned: returns number of packets cleaned
+ *
+ * Returns false if clean is not complete else returns true
+ */
+static inline bool
+iecm_rx_splitq_clean_all(struct iecm_q_vector *q_vec, int budget,
+ int *cleaned)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_splitq_napi_poll - NAPI handler
+ * @napi: struct from which you get q_vector
+ * @budget: budget provided by stack
+ */
+int iecm_vport_splitq_napi_poll(struct napi_struct *napi, int budget)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_intr_map_vector_to_qs - Map vectors to queues
+ * @vport: virtual port
+ *
+ * Mapping for vectors to queues
+ */
+void iecm_vport_intr_map_vector_to_qs(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_intr_init_vec_idx - Initialize the vector indexes
+ * @vport: virtual port
+ *
+ * Initialize vector indexes with values returned over mailbox
+ */
+static int iecm_vport_intr_init_vec_idx(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_intr_alloc - Allocate memory for interrupt vectors
+ * @vport: virtual port
+ *
+ * We allocate one q_vector per queue interrupt. If allocation fails we
+ * return -ENOMEM.
+ */
+int iecm_vport_intr_alloc(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_intr_init - Setup all vectors for the given vport
+ * @vport: virtual port
+ *
+ * Returns 0 on success or negative on failure
+ */
+int iecm_vport_intr_init(struct iecm_vport *vport)
+{
+ /* stub */
+}
+EXPORT_SYMBOL(iecm_vport_calc_num_q_vec);
+
+/**
+ * iecm_config_rss - Prepare for RSS
+ * @vport: virtual port
+ *
+ * Return 0 on success, negative on failure
+ */
+int iecm_config_rss(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_get_rx_qid_list - Create a list of RX QIDs
+ * @vport: virtual port
+ *
+ * qid_list is created and freed by the caller
+ */
+void iecm_get_rx_qid_list(struct iecm_vport *vport, u16 *qid_list)
+{
+ /* stub */
+}
+
+/**
+ * iecm_fill_dflt_rss_lut - Fill the indirection table with the default values
+ * @vport: virtual port structure
+ * @qid_list: List of the RX qid's
+ *
+ * qid_list is created and freed by the caller
+ */
+void iecm_fill_dflt_rss_lut(struct iecm_vport *vport, u16 *qid_list)
+{
+ /* stub */
+}
+
+/**
+ * iecm_init_rss - Prepare for RSS
+ * @vport: virtual port
+ *
+ * Return 0 on success, negative on failure
+ */
+int iecm_init_rss(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_deinit_rss - Prepare for RSS
+ * @vport: virtual port
+ *
+ */
+void iecm_deinit_rss(struct iecm_vport *vport)
+{
+ /* stub */
+}
diff --git a/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c b/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
new file mode 100644
index 000000000000..271009350503
--- /dev/null
+++ b/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
@@ -0,0 +1,570 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2020 Intel Corporation */
+
+#include <linux/net/intel/iecm.h>
+
+/**
+ * iecm_recv_event_msg - Receive virtchnl event message
+ * @vport: virtual port structure
+ *
+ * Receive virtchnl event message
+ */
+void iecm_recv_event_msg(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_mb_clean - Reclaim the send mailbox queue entries
+ * @adapter: Driver specific private structure
+ *
+ * Reclaim the send mailbox queue entries to be used to send further messages
+ *
+ * Returns success or failure
+ */
+enum iecm_status
+iecm_mb_clean(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_mb_msg - Send message over mailbox
+ * @adapter: Driver specific private structure
+ * @op: virtchnl opcode
+ * @msg_size: size of the payload
+ * @msg: pointer to buffer holding the payload
+ *
+ * Will prepare the control queue message and initiates the send API
+ *
+ * Returns success or failure
+ */
+enum iecm_status
+iecm_send_mb_msg(struct iecm_adapter *adapter, enum virtchnl_ops op,
+ u16 msg_size, u8 *msg)
+{
+ /* stub */
+}
+EXPORT_SYMBOL(iecm_send_mb_msg);
+
+/**
+ * iecm_recv_mb_msg - Receive message over mailbox
+ * @adapter: Driver specific private structure
+ * @op: virtchnl operation code
+ * @msg: Received message holding buffer
+ * @msg_size: message size
+ *
+ * Will receive control queue message and posts the receive buffer
+ */
+enum iecm_status
+iecm_recv_mb_msg(struct iecm_adapter *adapter, enum virtchnl_ops op,
+ void *msg, int msg_size)
+{
+ /* stub */
+}
+EXPORT_SYMBOL(iecm_recv_mb_msg);
+
+/**
+ * iecm_send_ver_msg - send virtchnl version message
+ * @adapter: Driver specific private structure
+ *
+ * Send virtchnl version message
+ */
+static enum iecm_status
+iecm_send_ver_msg(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_recv_ver_msg - Receive virtchnl version message
+ * @adapter: Driver specific private structure
+ *
+ * Receive virtchnl version message
+ */
+static enum iecm_status
+iecm_recv_ver_msg(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_get_caps_msg - Send virtchnl get capabilities message
+ * @adapter: Driver specific private structure
+ *
+ * send virtchnl get capabilities message
+ */
+enum iecm_status
+iecm_send_get_caps_msg(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+EXPORT_SYMBOL(iecm_send_get_caps_msg);
+
+/**
+ * iecm_recv_get_caps_msg - Receive virtchnl get capabilities message
+ * @adapter: Driver specific private structure
+ *
+ * Receive virtchnl get capabilities message
+ */
+static enum iecm_status
+iecm_recv_get_caps_msg(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_create_vport_msg - Send virtchnl create vport message
+ * @adapter: Driver specific private structure
+ *
+ * send virtchnl create vport message
+ *
+ * Returns success or failure
+ */
+static enum iecm_status
+iecm_send_create_vport_msg(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_recv_create_vport_msg - Receive virtchnl create vport message
+ * @adapter: Driver specific private structure
+ * @vport_id: Virtual port identifier
+ *
+ * Receive virtchnl create vport message
+ *
+ * Returns success or failure
+ */
+static enum iecm_status
+iecm_recv_create_vport_msg(struct iecm_adapter *adapter,
+ int *vport_id)
+{
+ /* stub */
+}
+
+/**
+ * iecm_wait_for_event - wait for virtchnl response
+ * @adapter: Driver private data structure
+ * @state: check on state upon timeout after 500ms
+ * @err_check: check if this specific error bit is set
+ *
+ * checks if state is set upon expiry of timeout
+ *
+ * Returns success or failure
+ */
+enum iecm_status
+iecm_wait_for_event(struct iecm_adapter *adapter,
+ enum iecm_vport_vc_state state,
+ enum iecm_vport_vc_state err_check)
+{
+ /* stub */
+}
+EXPORT_SYMBOL(iecm_wait_for_event);
+
+/**
+ * iecm_send_destroy_vport_msg - Send virtchnl destroy vport message
+ * @vport: virtual port data structure
+ *
+ * send virtchnl destroy vport message
+ */
+enum iecm_status
+iecm_send_destroy_vport_msg(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_enable_vport_msg - Send virtchnl enable vport message
+ * @vport: virtual port data structure
+ *
+ * send enable vport virtchnl message
+ */
+enum iecm_status
+iecm_send_enable_vport_msg(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_disable_vport_msg - Send virtchnl disable vport message
+ * @vport: virtual port data structure
+ *
+ * send disable vport virtchnl message
+ */
+enum iecm_status
+iecm_send_disable_vport_msg(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_config_tx_queues_msg - Send virtchnl config Tx queues message
+ * @vport: virtual port data structure
+ *
+ * send config Tx queues virtchnl message
+ *
+ * Returns success or failure
+ */
+enum iecm_status
+iecm_send_config_tx_queues_msg(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_config_rx_queues_msg - Send virtchnl config Rx queues message
+ * @vport: virtual port data structure
+ *
+ * send config Rx queues virtchnl message
+ *
+ * Returns success or failure
+ */
+enum iecm_status
+iecm_send_config_rx_queues_msg(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_ena_dis_queues_msg - Send virtchnl enable or disable
+ * queues message
+ * @vport: virtual port data structure
+ * @vc_op: virtchnl op code to send
+ *
+ * send enable or disable queues virtchnl message
+ *
+ * Returns success or failure
+ */
+static enum iecm_status
+iecm_send_ena_dis_queues_msg(struct iecm_vport *vport,
+ enum virtchnl_ops vc_op)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_map_unmap_queue_vector_msg - Send virtchnl map or unmap queue
+ * vector message
+ * @vport: virtual port data structure
+ * @map: true for map and false for unmap
+ *
+ * send map or unmap queue vector virtchnl message
+ *
+ * Returns success or failure
+ */
+static enum iecm_status
+iecm_send_map_unmap_queue_vector_msg(struct iecm_vport *vport,
+ bool map)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_enable_queues_msg - send enable queues virtchnl message
+ * @vport: Virtual port private data structure
+ *
+ * Will send enable queues virtchnl message
+ */
+static enum iecm_status
+iecm_send_enable_queues_msg(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_disable_queues_msg - send disable queues virtchnl message
+ * @vport: Virtual port private data structure
+ *
+ * Will send disable queues virtchnl message
+ */
+static enum iecm_status
+iecm_send_disable_queues_msg(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_delete_queues_msg - send delete queues virtchnl message
+ * @vport: Virtual port private data structure
+ *
+ * Will send delete queues virtchnl message
+ */
+enum iecm_status
+iecm_send_delete_queues_msg(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_config_queues_msg - Send config queues virtchnl message
+ * @vport: Virtual port private data structure
+ *
+ * Will send config queues virtchnl message
+ */
+static enum iecm_status
+iecm_send_config_queues_msg(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_add_queues_msg - Send virtchnl add queues message
+ * @vport: Virtual port private data structure
+ * @num_tx_q: number of transmit queues
+ * @num_complq: number of transmit completion queues
+ * @num_rx_q: number of receive queues
+ * @num_rx_bufq: number of receive buffer queues
+ *
+ * Returns success or failure
+ */
+enum iecm_status
+iecm_send_add_queues_msg(struct iecm_vport *vport, u16 num_tx_q,
+ u16 num_complq, u16 num_rx_q, u16 num_rx_bufq)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_get_stats_msg - Send virtchnl get statistics message
+ * @adapter: Driver specific private structure
+ *
+ * Returns success or failure
+ */
+enum iecm_status
+iecm_send_get_stats_msg(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_get_set_rss_hash_msg - Send set or get RSS hash message
+ * @vport: virtual port data structure
+ * @get: flag to get or set RSS hash
+ *
+ * Returns success or failure
+ */
+enum iecm_status
+iecm_send_get_set_rss_hash_msg(struct iecm_vport *vport, bool get)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_get_set_rss_lut_msg - Send virtchnl get or set RSS lut message
+ * @vport: virtual port data structure
+ * @get: flag to set or get RSS look up table
+ *
+ * Returns success or failure
+ */
+enum iecm_status
+iecm_send_get_set_rss_lut_msg(struct iecm_vport *vport, bool get)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_get_set_rss_key_msg - Send virtchnl get or set RSS key message
+ * @vport: virtual port data structure
+ * @get: flag to set or get RSS look up table
+ *
+ * Returns success or failure
+ */
+enum iecm_status
+iecm_send_get_set_rss_key_msg(struct iecm_vport *vport, bool get)
+{
+ /* stub */
+}
+
+/**
+ * iecm_send_get_rx_ptype_msg - Send virtchnl get or set RSS key message
+ * @vport: virtual port data structure
+ *
+ * Returns success or failure
+ */
+enum iecm_status iecm_send_get_rx_ptype_msg(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_find_ctlq - Given a type and id, find ctlq info
+ * @adapter: adapter info struct
+ * @type: type of ctrlq to find
+ * @id: ctlq id to find
+ *
+ * Returns pointer to found ctlq info struct, NULL otherwise.
+ */
+static struct iecm_ctlq_info *iecm_find_ctlq(struct iecm_hw *hw,
+ enum iecm_ctlq_type type, int id)
+{
+ /* stub */
+}
+
+/**
+ * iecm_deinit_dflt_mbx - De initialize mailbox
+ * @adapter: adapter info struct
+ */
+void iecm_deinit_dflt_mbx(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_init_dflt_mbx - Setup default mailbox parameters and make request
+ * @adapter: adapter info struct
+ *
+ * Returns 0 on success, negative otherwise
+ */
+enum iecm_status iecm_init_dflt_mbx(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_params_buf_alloc - Allocate memory for mailbox resources
+ * @adapter: Driver specific private data structure
+ *
+ * Will alloc memory to hold the vport parameters received on mailbox
+ */
+int iecm_vport_params_buf_alloc(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_params_buf_rel - Release memory for mailbox resources
+ * @adapter: Driver specific private data structure
+ *
+ * Will release memory to hold the vport parameters received on mailbox
+ */
+void iecm_vport_params_buf_rel(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vc_core_init - Initialize mailbox and get resources
+ * @adapter: Driver specific private structure
+ * @vport_id: Virtual port identifier
+ *
+ * Will check if HW is ready with reset complete. Initializes the mailbox and
+ * communicate with master to get all the default vport parameters.
+ */
+int iecm_vc_core_init(struct iecm_adapter *adapter, int *vport_id)
+{
+ /* stub */
+}
+EXPORT_SYMBOL(iecm_vc_core_init);
+
+/**
+ * iecm_vport_init - Initialize virtual port
+ * @vport: virtual port to be initialized
+ * @vport_id: Unique identification number of vport
+ *
+ * Will initialize vport with the info received through MB earlier
+ */
+static void iecm_vport_init(struct iecm_vport *vport, int vport_id)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_get_vec_ids - Initialize vector id from Mailbox parameters
+ * @vecids: Array of vector ids
+ * @num_vecids: number of vector ids
+ * @chunks: vector ids received over mailbox
+ *
+ * Will initialize all vector ids with ids received as mailbox parameters
+ * Returns number of ids filled
+ */
+int
+iecm_vport_get_vec_ids(u16 *vecids, int num_vecids,
+ struct virtchnl_vector_chunks *chunks)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_get_queue_ids - Initialize queue id from Mailbox parameters
+ * @qids: Array of queue ids
+ * @num_qids: number of queue ids
+ * @q_type: queue model
+ * @chunks: queue ids received over mailbox
+ *
+ * Will initialize all queue ids with ids received as mailbox parameters
+ * Returns number of ids filled
+ */
+static int
+iecm_vport_get_queue_ids(u16 *qids, int num_qids,
+ enum virtchnl_queue_type q_type,
+ struct virtchnl_queue_chunks *chunks)
+{
+ /* stub */
+}
+
+/**
+ * __iecm_vport_queue_ids_init - Initialize queue ids from Mailbox parameters
+ * @vport: virtual port for which the queues ids are initialized
+ * @qids: queue ids
+ * @num_qids: number of queue ids
+ * @q_type: type of queue
+ *
+ * Will initialize all queue ids with ids received as mailbox
+ * parameters. Returns number of queue ids initialized.
+ */
+static int
+__iecm_vport_queue_ids_init(struct iecm_vport *vport, u16 *qids,
+ int num_qids, enum virtchnl_queue_type q_type)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_queue_ids_init - Initialize queue ids from Mailbox parameters
+ * @vport: virtual port for which the queues ids are initialized
+ *
+ * Will initialize all queue ids with ids received as mailbox
+ * parameters. Returns error if all the queues are not initialized
+ */
+static
+enum iecm_status iecm_vport_queue_ids_init(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vport_adjust_qs - Adjust to new requested queues
+ * @vport: virtual port data struct
+ *
+ * Renegotiate queues
+ */
+enum iecm_status iecm_vport_adjust_qs(struct iecm_vport *vport)
+{
+ /* stub */
+}
+
+/**
+ * iecm_is_capability_ena - Default implementation of capability checking
+ * @adapter: Private data struct
+ * @flag: flag to check
+ *
+ * Return true if capability is supported, false otherwise
+ */
+static bool iecm_is_capability_ena(struct iecm_adapter *adapter, u64 flag)
+{
+ /* stub */
+}
+
+/**
+ * iecm_vc_ops_init - Initialize virtchnl common API
+ * @adapter: Driver specific private structure
+ *
+ * Initialize the function pointers with the extended feature set functions
+ * as APF will deal only with new set of opcodes.
+ */
+void iecm_vc_ops_init(struct iecm_adapter *adapter)
+{
+ /* stub */
+}
+EXPORT_SYMBOL(iecm_vc_ops_init);
--
2.26.2
^ permalink raw reply related
* [net-next 06/15] iecm: Implement mailbox functionality
From: Jeff Kirsher @ 2020-06-18 5:13 UTC (permalink / raw)
To: davem
Cc: Alice Michael, netdev, nhorman, sassmann, Alan Brady, Phani Burra,
Joshua Hay, Madhu Chittim, Pavan Kumar Linga, Donald Skidmore,
Jesse Brandeburg, Sridhar Samudrala, Jeff Kirsher
In-Reply-To: <20200618051344.516587-1-jeffrey.t.kirsher@intel.com>
From: Alice Michael <alice.michael@intel.com>
Implement mailbox setup, take down, and commands.
Signed-off-by: Alice Michael <alice.michael@intel.com>
Signed-off-by: Alan Brady <alan.brady@intel.com>
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>
Reviewed-by: Donald Skidmore <donald.c.skidmore@intel.com>
Reviewed-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Reviewed-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
.../net/ethernet/intel/iecm/iecm_controlq.c | 497 +++++++++++++++++-
.../ethernet/intel/iecm/iecm_controlq_setup.c | 105 +++-
drivers/net/ethernet/intel/iecm/iecm_lib.c | 71 ++-
drivers/net/ethernet/intel/iecm/iecm_osdep.c | 17 +-
.../net/ethernet/intel/iecm/iecm_virtchnl.c | 427 ++++++++++++++-
5 files changed, 1088 insertions(+), 29 deletions(-)
diff --git a/drivers/net/ethernet/intel/iecm/iecm_controlq.c b/drivers/net/ethernet/intel/iecm/iecm_controlq.c
index 390c499d9eb5..1232a9374046 100644
--- a/drivers/net/ethernet/intel/iecm/iecm_controlq.c
+++ b/drivers/net/ethernet/intel/iecm/iecm_controlq.c
@@ -14,7 +14,15 @@ static void
iecm_ctlq_setup_regs(struct iecm_ctlq_info *cq,
struct iecm_ctlq_create_info *q_create_info)
{
- /* stub */
+ /* set head and tail registers in our local struct */
+ cq->reg.head = q_create_info->reg.head;
+ cq->reg.tail = q_create_info->reg.tail;
+ cq->reg.len = q_create_info->reg.len;
+ cq->reg.bah = q_create_info->reg.bah;
+ cq->reg.bal = q_create_info->reg.bal;
+ cq->reg.len_mask = q_create_info->reg.len_mask;
+ cq->reg.len_ena_mask = q_create_info->reg.len_ena_mask;
+ cq->reg.head_mask = q_create_info->reg.head_mask;
}
/**
@@ -30,7 +38,32 @@ static enum iecm_status iecm_ctlq_init_regs(struct iecm_hw *hw,
struct iecm_ctlq_info *cq,
bool is_rxq)
{
- /* stub */
+ u32 reg = 0;
+
+ if (is_rxq)
+ /* Update tail to post pre-allocated buffers for Rx queues */
+ wr32(hw, cq->reg.tail, (u32)(cq->ring_size - 1));
+ else
+ wr32(hw, cq->reg.tail, 0);
+
+ /* For non-Mailbox control queues only TAIL need to be set */
+ if (cq->q_id != -1)
+ return 0;
+
+ /* Clear Head for both send or receive */
+ wr32(hw, cq->reg.head, 0);
+
+ /* set starting point */
+ wr32(hw, cq->reg.bal, IECM_LO_DWORD(cq->desc_ring.pa));
+ wr32(hw, cq->reg.bah, IECM_HI_DWORD(cq->desc_ring.pa));
+ wr32(hw, cq->reg.len, (cq->ring_size | cq->reg.len_ena_mask));
+
+ /* Check one register to verify that config was applied */
+ reg = rd32(hw, cq->reg.bah);
+ if (reg != IECM_HI_DWORD(cq->desc_ring.pa))
+ return IECM_ERR_CTLQ_ERROR;
+
+ return 0;
}
/**
@@ -42,7 +75,30 @@ static enum iecm_status iecm_ctlq_init_regs(struct iecm_hw *hw,
*/
static void iecm_ctlq_init_rxq_bufs(struct iecm_ctlq_info *cq)
{
- /* stub */
+ int i = 0;
+
+ for (i = 0; i < cq->ring_size; i++) {
+ struct iecm_ctlq_desc *desc = IECM_CTLQ_DESC(cq, i);
+ struct iecm_dma_mem *bi = cq->bi.rx_buff[i];
+
+ /* No buffer to post to descriptor, continue */
+ if (!bi)
+ continue;
+
+ desc->flags =
+ cpu_to_le16(IECM_CTLQ_FLAG_BUF | IECM_CTLQ_FLAG_RD);
+ desc->opcode = 0;
+ desc->datalen = (__le16)cpu_to_le16(bi->size);
+ desc->ret_val = 0;
+ desc->cookie_high = 0;
+ desc->cookie_low = 0;
+ desc->params.indirect.addr_high =
+ cpu_to_le32(IECM_HI_DWORD(bi->pa));
+ desc->params.indirect.addr_low =
+ cpu_to_le32(IECM_LO_DWORD(bi->pa));
+ desc->params.indirect.param0 = 0;
+ desc->params.indirect.param1 = 0;
+ }
}
/**
@@ -54,7 +110,20 @@ static void iecm_ctlq_init_rxq_bufs(struct iecm_ctlq_info *cq)
*/
static void iecm_ctlq_shutdown(struct iecm_hw *hw, struct iecm_ctlq_info *cq)
{
- /* stub */
+ mutex_lock(&cq->cq_lock);
+
+ if (!cq->ring_size)
+ goto shutdown_sq_out;
+
+ /* free ring buffers and the ring itself */
+ iecm_ctlq_dealloc_ring_res(hw, cq);
+
+ /* Set ring_size to 0 to indicate uninitialized queue */
+ cq->ring_size = 0;
+
+shutdown_sq_out:
+ mutex_unlock(&cq->cq_lock);
+ mutex_destroy(&cq->cq_lock);
}
/**
@@ -73,7 +142,74 @@ enum iecm_status iecm_ctlq_add(struct iecm_hw *hw,
struct iecm_ctlq_create_info *qinfo,
struct iecm_ctlq_info **cq)
{
- /* stub */
+ enum iecm_status status = 0;
+ bool is_rxq = false;
+
+ if (!qinfo->len || !qinfo->buf_size ||
+ qinfo->len > IECM_CTLQ_MAX_RING_SIZE ||
+ qinfo->buf_size > IECM_CTLQ_MAX_BUF_LEN)
+ return IECM_ERR_CFG;
+
+ *cq = kcalloc(1, sizeof(struct iecm_ctlq_info), GFP_KERNEL);
+ if (!(*cq))
+ return IECM_ERR_NO_MEMORY;
+
+ (*cq)->cq_type = qinfo->type;
+ (*cq)->q_id = qinfo->id;
+ (*cq)->buf_size = qinfo->buf_size;
+ (*cq)->ring_size = qinfo->len;
+
+ (*cq)->next_to_use = 0;
+ (*cq)->next_to_clean = 0;
+ (*cq)->next_to_post = (*cq)->ring_size - 1;
+
+ switch (qinfo->type) {
+ case IECM_CTLQ_TYPE_MAILBOX_RX:
+ is_rxq = true;
+ fallthrough;
+ case IECM_CTLQ_TYPE_MAILBOX_TX:
+ status = iecm_ctlq_alloc_ring_res(hw, *cq);
+ break;
+ default:
+ status = IECM_ERR_PARAM;
+ break;
+ }
+
+ if (status)
+ goto init_free_q;
+
+ if (is_rxq) {
+ iecm_ctlq_init_rxq_bufs(*cq);
+ } else {
+ /* Allocate the array of msg pointers for TX queues */
+ (*cq)->bi.tx_msg = kcalloc(qinfo->len,
+ sizeof(struct iecm_ctlq_msg *),
+ GFP_KERNEL);
+ if (!(*cq)->bi.tx_msg) {
+ status = IECM_ERR_NO_MEMORY;
+ goto init_dealloc_q_mem;
+ }
+ }
+
+ iecm_ctlq_setup_regs(*cq, qinfo);
+
+ status = iecm_ctlq_init_regs(hw, *cq, is_rxq);
+ if (status)
+ goto init_dealloc_q_mem;
+
+ mutex_init(&(*cq)->cq_lock);
+
+ list_add(&(*cq)->cq_list, &hw->cq_list_head);
+
+ return status;
+
+init_dealloc_q_mem:
+ /* free ring buffers and the ring itself */
+ iecm_ctlq_dealloc_ring_res(hw, *cq);
+init_free_q:
+ kfree(*cq);
+
+ return status;
}
/**
@@ -84,7 +220,9 @@ enum iecm_status iecm_ctlq_add(struct iecm_hw *hw,
void iecm_ctlq_remove(struct iecm_hw *hw,
struct iecm_ctlq_info *cq)
{
- /* stub */
+ list_del(&cq->cq_list);
+ iecm_ctlq_shutdown(hw, cq);
+ kfree(cq);
}
/**
@@ -101,7 +239,27 @@ void iecm_ctlq_remove(struct iecm_hw *hw,
enum iecm_status iecm_ctlq_init(struct iecm_hw *hw, u8 num_q,
struct iecm_ctlq_create_info *q_info)
{
- /* stub */
+ struct iecm_ctlq_info *cq = NULL, *tmp = NULL;
+ enum iecm_status ret_code = 0;
+ int i = 0;
+
+ INIT_LIST_HEAD(&hw->cq_list_head);
+
+ for (i = 0; i < num_q; i++) {
+ struct iecm_ctlq_create_info *qinfo = q_info + i;
+
+ ret_code = iecm_ctlq_add(hw, qinfo, &cq);
+ if (ret_code)
+ goto init_destroy_qs;
+ }
+
+ return ret_code;
+
+init_destroy_qs:
+ list_for_each_entry_safe(cq, tmp, &hw->cq_list_head, cq_list)
+ iecm_ctlq_remove(hw, cq);
+
+ return ret_code;
}
/**
@@ -110,7 +268,13 @@ enum iecm_status iecm_ctlq_init(struct iecm_hw *hw, u8 num_q,
*/
enum iecm_status iecm_ctlq_deinit(struct iecm_hw *hw)
{
- /* stub */
+ struct iecm_ctlq_info *cq = NULL, *tmp = NULL;
+ enum iecm_status ret_code = 0;
+
+ list_for_each_entry_safe(cq, tmp, &hw->cq_list_head, cq_list)
+ iecm_ctlq_remove(hw, cq);
+
+ return ret_code;
}
/**
@@ -130,7 +294,79 @@ enum iecm_status iecm_ctlq_send(struct iecm_hw *hw,
u16 num_q_msg,
struct iecm_ctlq_msg q_msg[])
{
- /* stub */
+ enum iecm_status status = 0;
+ struct iecm_ctlq_desc *desc;
+ int num_desc_avail = 0;
+ int i = 0;
+
+ if (!cq || !cq->ring_size)
+ return IECM_ERR_CTLQ_EMPTY;
+
+ mutex_lock(&cq->cq_lock);
+
+ /* Ensure there are enough descriptors to send all messages */
+ num_desc_avail = IECM_CTLQ_DESC_UNUSED(cq);
+ if (num_desc_avail == 0 || num_desc_avail < num_q_msg) {
+ status = IECM_ERR_CTLQ_FULL;
+ goto sq_send_command_out;
+ }
+
+ for (i = 0; i < num_q_msg; i++) {
+ struct iecm_ctlq_msg *msg = &q_msg[i];
+ u64 msg_cookie;
+
+ desc = IECM_CTLQ_DESC(cq, cq->next_to_use);
+
+ desc->opcode = cpu_to_le16(msg->opcode);
+ desc->pfid_vfid = msg->func_id;
+
+ msg_cookie = *(u64 *)&msg->cookie;
+ desc->cookie_high =
+ cpu_to_le32(IECM_HI_DWORD(msg_cookie));
+ desc->cookie_low =
+ cpu_to_le32(IECM_LO_DWORD(msg_cookie));
+
+ if (msg->data_len) {
+ struct iecm_dma_mem *buff = msg->ctx.indirect.payload;
+
+ desc->datalen = cpu_to_le16(msg->data_len);
+ desc->flags |= cpu_to_le16(IECM_CTLQ_FLAG_BUF);
+ desc->flags |= cpu_to_le16(IECM_CTLQ_FLAG_RD);
+
+ /* Update the address values in the desc with the pa
+ * value for respective buffer
+ */
+ desc->params.indirect.addr_high =
+ cpu_to_le32(IECM_HI_DWORD(buff->pa));
+ desc->params.indirect.addr_low =
+ cpu_to_le32(IECM_LO_DWORD(buff->pa));
+
+ memcpy(&desc->params, msg->ctx.indirect.context,
+ IECM_INDIRECT_CTX_SIZE);
+ } else {
+ memcpy(&desc->params, msg->ctx.direct,
+ IECM_DIRECT_CTX_SIZE);
+ }
+
+ /* Store buffer info */
+ cq->bi.tx_msg[cq->next_to_use] = msg;
+
+ (cq->next_to_use)++;
+ if (cq->next_to_use == cq->ring_size)
+ cq->next_to_use = 0;
+ }
+
+ /* Force memory write to complete before letting hardware
+ * know that there are new descriptors to fetch.
+ */
+ iecm_wmb();
+
+ wr32(hw, cq->reg.tail, cq->next_to_use);
+
+sq_send_command_out:
+ mutex_unlock(&cq->cq_lock);
+
+ return status;
}
/**
@@ -154,7 +390,58 @@ enum iecm_status iecm_ctlq_clean_sq(struct iecm_hw *hw,
u16 *clean_count,
struct iecm_ctlq_msg *msg_status[])
{
- /* stub */
+ enum iecm_status ret = 0;
+ struct iecm_ctlq_desc *desc;
+ u16 i = 0, num_to_clean;
+ u16 ntc, desc_err;
+
+ if (!cq || !cq->ring_size)
+ return IECM_ERR_CTLQ_EMPTY;
+
+ if (*clean_count == 0)
+ return 0;
+ else if (*clean_count > cq->ring_size)
+ return IECM_ERR_PARAM;
+
+ mutex_lock(&cq->cq_lock);
+
+ ntc = cq->next_to_clean;
+
+ num_to_clean = *clean_count;
+
+ for (i = 0; i < num_to_clean; i++) {
+ /* Fetch next descriptor and check if marked as done */
+ desc = IECM_CTLQ_DESC(cq, ntc);
+ if (!(le16_to_cpu(desc->flags) & IECM_CTLQ_FLAG_DD))
+ break;
+
+ desc_err = le16_to_cpu(desc->ret_val);
+ if (desc_err) {
+ /* strip off FW internal code */
+ desc_err &= 0xff;
+ }
+
+ msg_status[i] = cq->bi.tx_msg[ntc];
+ msg_status[i]->status = desc_err;
+
+ cq->bi.tx_msg[ntc] = NULL;
+
+ /* Zero out any stale data */
+ memset(desc, 0, sizeof(*desc));
+
+ ntc++;
+ if (ntc == cq->ring_size)
+ ntc = 0;
+ }
+
+ cq->next_to_clean = ntc;
+
+ mutex_unlock(&cq->cq_lock);
+
+ /* Return number of descriptors actually cleaned */
+ *clean_count = i;
+
+ return ret;
}
/**
@@ -177,7 +464,111 @@ enum iecm_status iecm_ctlq_post_rx_buffs(struct iecm_hw *hw,
u16 *buff_count,
struct iecm_dma_mem **buffs)
{
- /* stub */
+ enum iecm_status status = 0;
+ struct iecm_ctlq_desc *desc;
+ u16 ntp = cq->next_to_post;
+ bool buffs_avail = false;
+ u16 tbp = ntp + 1;
+ int i = 0;
+
+ if (*buff_count > cq->ring_size)
+ return IECM_ERR_PARAM;
+
+ if (*buff_count > 0)
+ buffs_avail = true;
+
+ mutex_lock(&cq->cq_lock);
+
+ if (tbp >= cq->ring_size)
+ tbp = 0;
+
+ if (tbp == cq->next_to_clean)
+ /* Nothing to do */
+ goto post_buffs_out;
+
+ /* Post buffers for as many as provided or up until the last one used */
+ while (ntp != cq->next_to_clean) {
+ desc = IECM_CTLQ_DESC(cq, ntp);
+
+ if (!cq->bi.rx_buff[ntp]) {
+ if (!buffs_avail) {
+ /* If the caller hasn't given us any buffers or
+ * there are none left, search the ring itself
+ * for an available buffer to move to this
+ * entry starting at the next entry in the ring
+ */
+ tbp = ntp + 1;
+
+ /* Wrap ring if necessary */
+ if (tbp >= cq->ring_size)
+ tbp = 0;
+
+ while (tbp != cq->next_to_clean) {
+ if (cq->bi.rx_buff[tbp]) {
+ cq->bi.rx_buff[ntp] =
+ cq->bi.rx_buff[tbp];
+ cq->bi.rx_buff[tbp] = NULL;
+
+ /* Found a buffer, no need to
+ * search anymore
+ */
+ break;
+ }
+
+ /* Wrap ring if necessary */
+ tbp++;
+ if (tbp >= cq->ring_size)
+ tbp = 0;
+ }
+
+ if (tbp == cq->next_to_clean)
+ goto post_buffs_out;
+ } else {
+ /* Give back pointer to DMA buffer */
+ cq->bi.rx_buff[ntp] = buffs[i];
+ i++;
+
+ if (i >= *buff_count)
+ buffs_avail = false;
+ }
+ }
+
+ desc->flags =
+ cpu_to_le16(IECM_CTLQ_FLAG_BUF | IECM_CTLQ_FLAG_RD);
+
+ /* Post buffers to descriptor */
+ desc->datalen = cpu_to_le16(cq->bi.rx_buff[ntp]->size);
+ desc->params.indirect.addr_high =
+ cpu_to_le32(IECM_HI_DWORD(cq->bi.rx_buff[ntp]->pa));
+ desc->params.indirect.addr_low =
+ cpu_to_le32(IECM_LO_DWORD(cq->bi.rx_buff[ntp]->pa));
+
+ ntp++;
+ if (ntp == cq->ring_size)
+ ntp = 0;
+ }
+
+post_buffs_out:
+ /* Only update tail if buffers were actually posted */
+ if (cq->next_to_post != ntp) {
+ if (ntp)
+ /* Update next_to_post to ntp - 1 since current ntp
+ * will not have a buffer
+ */
+ cq->next_to_post = ntp - 1;
+ else
+ /* Wrap to end of end ring since current ntp is 0 */
+ cq->next_to_post = cq->ring_size - 1;
+
+ wr32(hw, cq->reg.tail, cq->next_to_post);
+ }
+
+ mutex_unlock(&cq->cq_lock);
+
+ /* return the number of buffers that were not posted */
+ *buff_count = *buff_count - i;
+
+ return status;
}
/**
@@ -196,5 +587,87 @@ enum iecm_status iecm_ctlq_recv(struct iecm_hw *hw,
struct iecm_ctlq_info *cq,
u16 *num_q_msg, struct iecm_ctlq_msg *q_msg)
{
- /* stub */
+ u16 num_to_clean, ntc, ret_val, flags;
+ enum iecm_status ret_code = 0;
+ struct iecm_ctlq_desc *desc;
+ u16 i = 0;
+
+ if (!cq || !cq->ring_size)
+ return IECM_ERR_CTLQ_EMPTY;
+
+ if (*num_q_msg == 0)
+ return 0;
+ else if (*num_q_msg > cq->ring_size)
+ return IECM_ERR_PARAM;
+
+ /* take the lock before we start messing with the ring */
+ mutex_lock(&cq->cq_lock);
+
+ ntc = cq->next_to_clean;
+
+ num_to_clean = *num_q_msg;
+
+ for (i = 0; i < num_to_clean; i++) {
+ u64 msg_cookie;
+
+ /* Fetch next descriptor and check if marked as done */
+ desc = IECM_CTLQ_DESC(cq, ntc);
+ flags = le16_to_cpu(desc->flags);
+
+ if (!(flags & IECM_CTLQ_FLAG_DD))
+ break;
+
+ ret_val = le16_to_cpu(desc->ret_val);
+
+ q_msg[i].vmvf_type = (flags &
+ (IECM_CTLQ_FLAG_FTYPE_VM |
+ IECM_CTLQ_FLAG_FTYPE_PF)) >>
+ IECM_CTLQ_FLAG_FTYPE_S;
+
+ if (flags & IECM_CTLQ_FLAG_ERR)
+ ret_code = IECM_ERR_CTLQ_ERROR;
+
+ msg_cookie = (u64)le32_to_cpu(desc->cookie_high) << 32;
+ msg_cookie |= (u64)le32_to_cpu(desc->cookie_low);
+ memcpy(&q_msg[i].cookie, &msg_cookie, sizeof(u64));
+
+ q_msg[i].opcode = le16_to_cpu(desc->opcode);
+ q_msg[i].data_len = le16_to_cpu(desc->datalen);
+ q_msg[i].status = ret_val;
+
+ if (desc->datalen) {
+ memcpy(q_msg[i].ctx.indirect.context,
+ &desc->params.indirect, IECM_INDIRECT_CTX_SIZE);
+
+ /* Assign pointer to DMA buffer to ctlq_msg array
+ * to be given to upper layer
+ */
+ q_msg[i].ctx.indirect.payload = cq->bi.rx_buff[ntc];
+
+ /* Zero out pointer to DMA buffer info;
+ * will be repopulated by post buffers API
+ */
+ cq->bi.rx_buff[ntc] = NULL;
+ } else {
+ memcpy(q_msg[i].ctx.direct, desc->params.raw,
+ IECM_DIRECT_CTX_SIZE);
+ }
+
+ /* Zero out stale data in descriptor */
+ memset(desc, 0, sizeof(struct iecm_ctlq_desc));
+
+ ntc++;
+ if (ntc == cq->ring_size)
+ ntc = 0;
+ };
+
+ cq->next_to_clean = ntc;
+
+ mutex_unlock(&cq->cq_lock);
+
+ *num_q_msg = i;
+ if (*num_q_msg == 0)
+ ret_code = IECM_ERR_CTLQ_NO_WORK;
+
+ return ret_code;
}
diff --git a/drivers/net/ethernet/intel/iecm/iecm_controlq_setup.c b/drivers/net/ethernet/intel/iecm/iecm_controlq_setup.c
index 2fd6e3d15a1a..f230f2044a48 100644
--- a/drivers/net/ethernet/intel/iecm/iecm_controlq_setup.c
+++ b/drivers/net/ethernet/intel/iecm/iecm_controlq_setup.c
@@ -13,7 +13,13 @@ static enum iecm_status
iecm_ctlq_alloc_desc_ring(struct iecm_hw *hw,
struct iecm_ctlq_info *cq)
{
- /* stub */
+ size_t size = cq->ring_size * sizeof(struct iecm_ctlq_desc);
+
+ cq->desc_ring.va = iecm_alloc_dma_mem(hw, &cq->desc_ring, size);
+ if (!cq->desc_ring.va)
+ return IECM_ERR_NO_MEMORY;
+
+ return 0;
}
/**
@@ -27,7 +33,52 @@ iecm_ctlq_alloc_desc_ring(struct iecm_hw *hw,
static enum iecm_status iecm_ctlq_alloc_bufs(struct iecm_hw *hw,
struct iecm_ctlq_info *cq)
{
- /* stub */
+ int i = 0;
+
+ /* Do not allocate DMA buffers for transmit queues */
+ if (cq->cq_type == IECM_CTLQ_TYPE_MAILBOX_TX)
+ return 0;
+
+ /* We'll be allocating the buffer info memory first, then we can
+ * allocate the mapped buffers for the event processing
+ */
+ cq->bi.rx_buff = kcalloc(cq->ring_size, sizeof(struct iecm_dma_mem *),
+ GFP_KERNEL);
+ if (!cq->bi.rx_buff)
+ return IECM_ERR_NO_MEMORY;
+
+ /* allocate the mapped buffers (except for the last one) */
+ for (i = 0; i < cq->ring_size - 1; i++) {
+ struct iecm_dma_mem *bi;
+ int num = 1; /* number of iecm_dma_mem to be allocated */
+
+ cq->bi.rx_buff[i] = kcalloc(num, sizeof(struct iecm_dma_mem),
+ GFP_KERNEL);
+ if (!cq->bi.rx_buff[i])
+ goto unwind_alloc_cq_bufs;
+
+ bi = cq->bi.rx_buff[i];
+
+ bi->va = iecm_alloc_dma_mem(hw, bi, cq->buf_size);
+ if (!bi->va) {
+ /* unwind will not free the failed entry */
+ kfree(cq->bi.rx_buff[i]);
+ goto unwind_alloc_cq_bufs;
+ }
+ }
+
+ return 0;
+
+unwind_alloc_cq_bufs:
+ /* don't try to free the one that failed... */
+ i--;
+ for (; i >= 0; i--) {
+ iecm_free_dma_mem(hw, cq->bi.rx_buff[i]);
+ kfree(cq->bi.rx_buff[i]);
+ }
+ kfree(cq->bi.rx_buff);
+
+ return IECM_ERR_NO_MEMORY;
}
/**
@@ -41,7 +92,7 @@ static enum iecm_status iecm_ctlq_alloc_bufs(struct iecm_hw *hw,
static void iecm_ctlq_free_desc_ring(struct iecm_hw *hw,
struct iecm_ctlq_info *cq)
{
- /* stub */
+ iecm_free_dma_mem(hw, &cq->desc_ring);
}
/**
@@ -54,7 +105,26 @@ static void iecm_ctlq_free_desc_ring(struct iecm_hw *hw,
*/
static void iecm_ctlq_free_bufs(struct iecm_hw *hw, struct iecm_ctlq_info *cq)
{
- /* stub */
+ void *bi;
+
+ if (cq->cq_type == IECM_CTLQ_TYPE_MAILBOX_RX) {
+ int i;
+
+ /* free DMA buffers for Rx queues*/
+ for (i = 0; i < cq->ring_size; i++) {
+ if (cq->bi.rx_buff[i]) {
+ iecm_free_dma_mem(hw, cq->bi.rx_buff[i]);
+ kfree(cq->bi.rx_buff[i]);
+ }
+ }
+
+ bi = (void *)cq->bi.rx_buff;
+ } else {
+ bi = (void *)cq->bi.tx_msg;
+ }
+
+ /* free the buffer header */
+ kfree(bi);
}
/**
@@ -66,7 +136,9 @@ static void iecm_ctlq_free_bufs(struct iecm_hw *hw, struct iecm_ctlq_info *cq)
*/
void iecm_ctlq_dealloc_ring_res(struct iecm_hw *hw, struct iecm_ctlq_info *cq)
{
- /* stub */
+ /* free ring buffers and the ring itself */
+ iecm_ctlq_free_bufs(hw, cq);
+ iecm_ctlq_free_desc_ring(hw, cq);
}
/**
@@ -80,5 +152,26 @@ void iecm_ctlq_dealloc_ring_res(struct iecm_hw *hw, struct iecm_ctlq_info *cq)
enum iecm_status iecm_ctlq_alloc_ring_res(struct iecm_hw *hw,
struct iecm_ctlq_info *cq)
{
- /* stub */
+ enum iecm_status ret_code;
+
+ /* verify input for valid configuration */
+ if (!cq->ring_size || !cq->buf_size)
+ return IECM_ERR_CFG;
+
+ /* allocate the ring memory */
+ ret_code = iecm_ctlq_alloc_desc_ring(hw, cq);
+ if (ret_code)
+ return ret_code;
+
+ /* allocate buffers in the rings */
+ ret_code = iecm_ctlq_alloc_bufs(hw, cq);
+ if (ret_code)
+ goto iecm_init_cq_free_ring;
+
+ /* success! */
+ return 0;
+
+iecm_init_cq_free_ring:
+ iecm_free_dma_mem(hw, &cq->desc_ring);
+ return ret_code;
}
diff --git a/drivers/net/ethernet/intel/iecm/iecm_lib.c b/drivers/net/ethernet/intel/iecm/iecm_lib.c
index 6023d0c727fb..3f6878704b3e 100644
--- a/drivers/net/ethernet/intel/iecm/iecm_lib.c
+++ b/drivers/net/ethernet/intel/iecm/iecm_lib.c
@@ -163,7 +163,76 @@ static int iecm_intr_req(struct iecm_adapter *adapter)
*/
static int iecm_cfg_netdev(struct iecm_vport *vport)
{
- /* stub */
+ struct iecm_adapter *adapter = vport->adapter;
+ netdev_features_t dflt_features;
+ netdev_features_t offloads = 0;
+ struct iecm_netdev_priv *np;
+ struct net_device *netdev;
+ int err;
+
+ netdev = alloc_etherdev_mqs(sizeof(struct iecm_netdev_priv),
+ IECM_MAX_Q, IECM_MAX_Q);
+ if (!netdev)
+ return -ENOMEM;
+ vport->netdev = netdev;
+ np = netdev_priv(netdev);
+ np->vport = vport;
+
+ if (!is_valid_ether_addr(vport->default_mac_addr)) {
+ eth_hw_addr_random(netdev);
+ ether_addr_copy(vport->default_mac_addr, netdev->dev_addr);
+ } else {
+ ether_addr_copy(netdev->dev_addr, vport->default_mac_addr);
+ ether_addr_copy(netdev->perm_addr, vport->default_mac_addr);
+ }
+
+ /* assign netdev_ops */
+ if (iecm_is_queue_model_split(vport->txq_model))
+ netdev->netdev_ops = &iecm_netdev_ops_splitq;
+ else
+ netdev->netdev_ops = &iecm_netdev_ops_singleq;
+
+ /* setup watchdog timeout value to be 5 second */
+ netdev->watchdog_timeo = 5 * HZ;
+
+ /* configure default MTU size */
+ netdev->min_mtu = ETH_MIN_MTU;
+ netdev->max_mtu = vport->max_mtu;
+
+ dflt_features = NETIF_F_SG |
+ NETIF_F_HIGHDMA |
+ NETIF_F_RXHASH;
+
+ if (iecm_is_cap_ena(adapter, VIRTCHNL_CAP_STATELESS_OFFLOADS)) {
+ dflt_features |=
+ NETIF_F_RXCSUM |
+ NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM |
+ 0;
+ offloads |= NETIF_F_TSO |
+ NETIF_F_TSO6;
+ }
+ if (iecm_is_cap_ena(adapter, VIRTCHNL_CAP_UDP_SEG_OFFLOAD))
+ offloads |= NETIF_F_GSO_UDP_L4;
+
+ netdev->features |= dflt_features;
+ netdev->hw_features |= dflt_features | offloads;
+ netdev->hw_enc_features |= dflt_features | offloads;
+
+ iecm_set_ethtool_ops(netdev);
+ SET_NETDEV_DEV(netdev, &adapter->pdev->dev);
+
+ err = register_netdev(netdev);
+ if (err)
+ return err;
+
+ /* carrier off on init to avoid Tx hangs */
+ netif_carrier_off(netdev);
+
+ /* make sure transmit queues start off as stopped */
+ netif_tx_stop_all_queues(netdev);
+
+ return 0;
}
/**
diff --git a/drivers/net/ethernet/intel/iecm/iecm_osdep.c b/drivers/net/ethernet/intel/iecm/iecm_osdep.c
index d0534df357d0..be5dbe1d23b2 100644
--- a/drivers/net/ethernet/intel/iecm/iecm_osdep.c
+++ b/drivers/net/ethernet/intel/iecm/iecm_osdep.c
@@ -6,10 +6,23 @@
void *iecm_alloc_dma_mem(struct iecm_hw *hw, struct iecm_dma_mem *mem, u64 size)
{
- /* stub */
+ size_t sz = ALIGN(size, 4096);
+ struct iecm_adapter *pf = hw->back;
+
+ mem->va = dma_alloc_coherent(&pf->pdev->dev, sz,
+ &mem->pa, GFP_KERNEL | __GFP_ZERO);
+ mem->size = size;
+
+ return mem->va;
}
void iecm_free_dma_mem(struct iecm_hw *hw, struct iecm_dma_mem *mem)
{
- /* stub */
+ struct iecm_adapter *pf = hw->back;
+
+ dma_free_coherent(&pf->pdev->dev, mem->size,
+ mem->va, mem->pa);
+ mem->size = 0;
+ mem->va = NULL;
+ mem->pa = 0;
}
diff --git a/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c b/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
index 7bf7c02f2d6f..0fdf87d6e98f 100644
--- a/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
+++ b/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
@@ -11,7 +11,42 @@
*/
void iecm_recv_event_msg(struct iecm_vport *vport)
{
- /* stub */
+ struct iecm_adapter *adapter = vport->adapter;
+ enum virtchnl_link_speed link_speed;
+ struct virtchnl_pf_event *vpe;
+
+ vpe = (struct virtchnl_pf_event *)vport->adapter->vc_msg;
+
+ switch (vpe->event) {
+ case VIRTCHNL_EVENT_LINK_CHANGE:
+ link_speed = vpe->event_data.link_event.link_speed;
+ adapter->link_speed = link_speed;
+ if (adapter->link_up !=
+ vpe->event_data.link_event.link_status) {
+ adapter->link_up =
+ vpe->event_data.link_event.link_status;
+ if (adapter->link_up) {
+ netif_tx_start_all_queues(vport->netdev);
+ netif_carrier_on(vport->netdev);
+ } else {
+ netif_tx_stop_all_queues(vport->netdev);
+ netif_carrier_off(vport->netdev);
+ }
+ }
+ break;
+ case VIRTCHNL_EVENT_RESET_IMPENDING:
+ mutex_lock(&adapter->reset_lock);
+ set_bit(__IECM_HR_CORE_RESET, adapter->flags);
+ queue_delayed_work(adapter->vc_event_wq,
+ &adapter->vc_event_task,
+ msecs_to_jiffies(10));
+ break;
+ default:
+ dev_err(&vport->adapter->pdev->dev,
+ "Unknown event %d from PF\n", vpe->event);
+ break;
+ }
+ mutex_unlock(&vport->adapter->vc_msg_lock);
}
/**
@@ -25,7 +60,34 @@ void iecm_recv_event_msg(struct iecm_vport *vport)
enum iecm_status
iecm_mb_clean(struct iecm_adapter *adapter)
{
- /* stub */
+ enum iecm_status err = 0;
+ u16 num_q_msg = IECM_DFLT_MBX_Q_LEN;
+ struct iecm_ctlq_msg **q_msg;
+ struct iecm_dma_mem *dma_mem;
+ u16 i;
+
+ q_msg = kcalloc(num_q_msg, sizeof(struct iecm_ctlq_msg *), GFP_KERNEL);
+ if (!q_msg) {
+ err = IECM_ERR_NO_MEMORY;
+ goto error;
+ }
+
+ err = iecm_ctlq_clean_sq(&adapter->hw, adapter->hw.asq, &num_q_msg,
+ q_msg);
+ if (err)
+ goto error;
+
+ for (i = 0; i < num_q_msg; i++) {
+ dma_mem = q_msg[i]->ctx.indirect.payload;
+ if (dma_mem)
+ dmam_free_coherent(&adapter->pdev->dev, dma_mem->size,
+ dma_mem->va, dma_mem->pa);
+ kfree(q_msg[i]);
+ }
+ kfree(q_msg);
+
+error:
+ return err;
}
/**
@@ -43,7 +105,56 @@ enum iecm_status
iecm_send_mb_msg(struct iecm_adapter *adapter, enum virtchnl_ops op,
u16 msg_size, u8 *msg)
{
- /* stub */
+ enum iecm_status err = 0;
+ struct iecm_ctlq_msg *ctlq_msg;
+ struct iecm_dma_mem *dma_mem;
+
+ err = iecm_mb_clean(adapter);
+ if (err)
+ goto err;
+
+ ctlq_msg = kzalloc(sizeof(struct iecm_ctlq_msg), GFP_KERNEL);
+ if (!ctlq_msg) {
+ err = IECM_ERR_NO_MEMORY;
+ goto err;
+ }
+
+ dma_mem = kzalloc(sizeof(struct iecm_dma_mem), GFP_KERNEL);
+ if (!dma_mem) {
+ err = IECM_ERR_NO_MEMORY;
+ goto dma_mem_error;
+ }
+
+ memset(ctlq_msg, 0, sizeof(struct iecm_ctlq_msg));
+ ctlq_msg->opcode = iecm_mbq_opc_send_msg_to_cp;
+ ctlq_msg->func_id = 0;
+ ctlq_msg->data_len = msg_size;
+ ctlq_msg->cookie.mbx.chnl_opcode = op;
+ ctlq_msg->cookie.mbx.chnl_retval = VIRTCHNL_STATUS_SUCCESS;
+ dma_mem->size = IECM_DFLT_MBX_BUF_SIZE;
+ dma_mem->va = dmam_alloc_coherent(&adapter->pdev->dev, dma_mem->size,
+ &dma_mem->pa, GFP_KERNEL);
+ if (!dma_mem->va) {
+ err = IECM_ERR_NO_MEMORY;
+ goto dma_alloc_error;
+ }
+ memcpy(dma_mem->va, msg, msg_size);
+ ctlq_msg->ctx.indirect.payload = dma_mem;
+
+ err = iecm_ctlq_send(&adapter->hw, adapter->hw.asq, 1, ctlq_msg);
+ if (err)
+ goto send_error;
+
+ return err;
+send_error:
+ dmam_free_coherent(&adapter->pdev->dev, dma_mem->size, dma_mem->va,
+ dma_mem->pa);
+dma_alloc_error:
+ kfree(dma_mem);
+dma_mem_error:
+ kfree(ctlq_msg);
+err:
+ return err;
}
EXPORT_SYMBOL(iecm_send_mb_msg);
@@ -60,7 +171,265 @@ enum iecm_status
iecm_recv_mb_msg(struct iecm_adapter *adapter, enum virtchnl_ops op,
void *msg, int msg_size)
{
- /* stub */
+ enum iecm_status status = 0;
+ struct iecm_ctlq_msg ctlq_msg;
+ struct iecm_dma_mem *dma_mem;
+ struct iecm_vport *vport;
+ bool work_done = false;
+ int payload_size = 0;
+ int num_retry = 10;
+ u16 num_q_msg;
+
+ vport = adapter->vports[0];
+ while (1) {
+ /* Try to get one message */
+ num_q_msg = 1;
+ dma_mem = NULL;
+ status = iecm_ctlq_recv(&adapter->hw, adapter->hw.arq,
+ &num_q_msg, &ctlq_msg);
+ /* If no message then decide if we have to retry based on
+ * opcode
+ */
+ if (status || !num_q_msg) {
+ if (op && num_retry--) {
+ msleep(20);
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ /* If we are here a message is received. Check if we are looking
+ * for a specific message based on opcode. If it is different
+ * ignore and post buffers
+ */
+ if (op && ctlq_msg.cookie.mbx.chnl_opcode != op)
+ goto post_buffs;
+
+ if (ctlq_msg.data_len)
+ payload_size = ctlq_msg.ctx.indirect.payload->size;
+
+ /* All conditions are met. Either a message requested is
+ * received or we received a message to be processed
+ */
+ switch (ctlq_msg.cookie.mbx.chnl_opcode) {
+ case VIRTCHNL_OP_VERSION:
+ case VIRTCHNL_OP_GET_CAPS:
+ case VIRTCHNL_OP_CREATE_VPORT:
+ if (msg)
+ memcpy(msg, ctlq_msg.ctx.indirect.payload->va,
+ min_t(int,
+ payload_size, msg_size));
+ work_done = true;
+ break;
+ case VIRTCHNL_OP_ENABLE_VPORT:
+ if (ctlq_msg.cookie.mbx.chnl_retval)
+ set_bit(IECM_VC_ENA_VPORT_ERR,
+ adapter->vc_state);
+ set_bit(IECM_VC_ENA_VPORT, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_DISABLE_VPORT:
+ if (ctlq_msg.cookie.mbx.chnl_retval)
+ set_bit(IECM_VC_DIS_VPORT_ERR,
+ adapter->vc_state);
+ set_bit(IECM_VC_DIS_VPORT, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_DESTROY_VPORT:
+ if (ctlq_msg.cookie.mbx.chnl_retval)
+ set_bit(IECM_VC_DESTROY_VPORT_ERR,
+ adapter->vc_state);
+ set_bit(IECM_VC_DESTROY_VPORT, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_CONFIG_TX_QUEUES:
+ if (ctlq_msg.cookie.mbx.chnl_retval)
+ set_bit(IECM_VC_CONFIG_TXQ_ERR,
+ adapter->vc_state);
+ set_bit(IECM_VC_CONFIG_TXQ, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_CONFIG_RX_QUEUES:
+ if (ctlq_msg.cookie.mbx.chnl_retval)
+ set_bit(IECM_VC_CONFIG_RXQ_ERR,
+ adapter->vc_state);
+ set_bit(IECM_VC_CONFIG_RXQ, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_ENABLE_QUEUES_V2:
+ if (ctlq_msg.cookie.mbx.chnl_retval)
+ set_bit(IECM_VC_ENA_QUEUES_ERR,
+ adapter->vc_state);
+ set_bit(IECM_VC_ENA_QUEUES, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_DISABLE_QUEUES_V2:
+ if (ctlq_msg.cookie.mbx.chnl_retval)
+ set_bit(IECM_VC_DIS_QUEUES_ERR,
+ adapter->vc_state);
+ set_bit(IECM_VC_DIS_QUEUES, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_ADD_QUEUES:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ set_bit(IECM_VC_ADD_QUEUES_ERR,
+ adapter->vc_state);
+ } else {
+ mutex_lock(&adapter->vc_msg_lock);
+ memcpy(adapter->vc_msg,
+ ctlq_msg.ctx.indirect.payload->va,
+ min((int)
+ ctlq_msg.ctx.indirect.payload->size,
+ IECM_DFLT_MBX_BUF_SIZE));
+ }
+ set_bit(IECM_VC_ADD_QUEUES, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_DEL_QUEUES:
+ if (ctlq_msg.cookie.mbx.chnl_retval)
+ set_bit(IECM_VC_DEL_QUEUES_ERR,
+ adapter->vc_state);
+ set_bit(IECM_VC_DEL_QUEUES, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_MAP_QUEUE_VECTOR:
+ if (ctlq_msg.cookie.mbx.chnl_retval)
+ set_bit(IECM_VC_MAP_IRQ_ERR,
+ adapter->vc_state);
+ set_bit(IECM_VC_MAP_IRQ, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_UNMAP_QUEUE_VECTOR:
+ if (ctlq_msg.cookie.mbx.chnl_retval)
+ set_bit(IECM_VC_UNMAP_IRQ_ERR,
+ adapter->vc_state);
+ set_bit(IECM_VC_UNMAP_IRQ, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_GET_STATS:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ set_bit(IECM_VC_GET_STATS_ERR,
+ adapter->vc_state);
+ } else {
+ mutex_lock(&adapter->vc_msg_lock);
+ memcpy(adapter->vc_msg,
+ ctlq_msg.ctx.indirect.payload->va,
+ min_t(int,
+ payload_size,
+ IECM_DFLT_MBX_BUF_SIZE));
+ }
+ set_bit(IECM_VC_GET_STATS, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_GET_RSS_HASH:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ set_bit(IECM_VC_GET_RSS_HASH_ERR,
+ adapter->vc_state);
+ } else {
+ mutex_lock(&adapter->vc_msg_lock);
+ memcpy(adapter->vc_msg,
+ ctlq_msg.ctx.indirect.payload->va,
+ min_t(int,
+ payload_size,
+ IECM_DFLT_MBX_BUF_SIZE));
+ }
+ set_bit(IECM_VC_GET_RSS_HASH, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_SET_RSS_HASH:
+ if (ctlq_msg.cookie.mbx.chnl_retval)
+ set_bit(IECM_VC_SET_RSS_HASH_ERR,
+ adapter->vc_state);
+ set_bit(IECM_VC_SET_RSS_HASH, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_GET_RSS_LUT:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ set_bit(IECM_VC_GET_RSS_LUT_ERR,
+ adapter->vc_state);
+ } else {
+ mutex_lock(&adapter->vc_msg_lock);
+ memcpy(adapter->vc_msg,
+ ctlq_msg.ctx.indirect.payload->va,
+ min_t(int,
+ payload_size,
+ IECM_DFLT_MBX_BUF_SIZE));
+ }
+ set_bit(IECM_VC_GET_RSS_LUT, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_SET_RSS_LUT:
+ if (ctlq_msg.cookie.mbx.chnl_retval)
+ set_bit(IECM_VC_SET_RSS_LUT_ERR,
+ adapter->vc_state);
+ set_bit(IECM_VC_SET_RSS_LUT, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_GET_RSS_KEY:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ set_bit(IECM_VC_GET_RSS_KEY_ERR,
+ adapter->vc_state);
+ } else {
+ mutex_lock(&adapter->vc_msg_lock);
+ memcpy(adapter->vc_msg,
+ ctlq_msg.ctx.indirect.payload->va,
+ min_t(int,
+ payload_size,
+ IECM_DFLT_MBX_BUF_SIZE));
+ }
+ set_bit(IECM_VC_GET_RSS_KEY, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_CONFIG_RSS_KEY:
+ if (ctlq_msg.cookie.mbx.chnl_retval)
+ set_bit(IECM_VC_CONFIG_RSS_KEY_ERR,
+ adapter->vc_state);
+ set_bit(IECM_VC_CONFIG_RSS_KEY, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_EVENT:
+ mutex_lock(&adapter->vc_msg_lock);
+ memcpy(adapter->vc_msg,
+ ctlq_msg.ctx.indirect.payload->va,
+ min_t(int,
+ payload_size,
+ IECM_DFLT_MBX_BUF_SIZE));
+ iecm_recv_event_msg(vport);
+ break;
+ default:
+ if (adapter->dev_ops.vc_ops.recv_mbx_msg)
+ status =
+ adapter->dev_ops.vc_ops.recv_mbx_msg(adapter,
+ msg,
+ msg_size,
+ &ctlq_msg,
+ &work_done);
+ else
+ dev_warn(&adapter->pdev->dev,
+ "Unhandled virtchnl response %d\n",
+ ctlq_msg.cookie.mbx.chnl_opcode);
+ break;
+ } /* switch v_opcode */
+post_buffs:
+ if (ctlq_msg.data_len)
+ dma_mem = ctlq_msg.ctx.indirect.payload;
+ else
+ num_q_msg = 0;
+
+ status = iecm_ctlq_post_rx_buffs(&adapter->hw, adapter->hw.arq,
+ &num_q_msg,
+ &dma_mem);
+ /* If post failed clear the only buffer we supplied */
+ if (status && dma_mem)
+ dmam_free_coherent(&adapter->pdev->dev, dma_mem->size,
+ dma_mem->va, dma_mem->pa);
+ /* Applies only if we are looking for a specific opcode */
+ if (work_done)
+ break;
+ }
+
+ return status;
}
EXPORT_SYMBOL(iecm_recv_mb_msg);
@@ -158,7 +527,27 @@ iecm_wait_for_event(struct iecm_adapter *adapter,
enum iecm_vport_vc_state state,
enum iecm_vport_vc_state err_check)
{
- /* stub */
+ enum iecm_status status;
+ int event;
+
+ event = wait_event_timeout(adapter->vchnl_wq,
+ test_and_clear_bit(state, adapter->vc_state),
+ msecs_to_jiffies(500));
+ if (event) {
+ if (test_and_clear_bit(err_check, adapter->vc_state)) {
+ dev_err(&adapter->pdev->dev,
+ "VC response error %d", err_check);
+ status = IECM_ERR_CFG;
+ } else {
+ status = 0;
+ }
+ } else {
+ /* Timeout occurred */
+ status = IECM_ERR_NOT_READY;
+ dev_err(&adapter->pdev->dev, "VC timeout, state = %u", state);
+ }
+
+ return status;
}
EXPORT_SYMBOL(iecm_wait_for_event);
@@ -398,7 +787,14 @@ enum iecm_status iecm_send_get_rx_ptype_msg(struct iecm_vport *vport)
static struct iecm_ctlq_info *iecm_find_ctlq(struct iecm_hw *hw,
enum iecm_ctlq_type type, int id)
{
- /* stub */
+ struct iecm_ctlq_info *cq, *tmp;
+
+ list_for_each_entry_safe(cq, tmp, &hw->cq_list_head, cq_list) {
+ if (cq->q_id == id && cq->cq_type == type)
+ return cq;
+ }
+
+ return NULL;
}
/**
@@ -407,7 +803,8 @@ static struct iecm_ctlq_info *iecm_find_ctlq(struct iecm_hw *hw,
*/
void iecm_deinit_dflt_mbx(struct iecm_adapter *adapter)
{
- /* stub */
+ cancel_delayed_work_sync(&adapter->init_task);
+ iecm_ctlq_deinit(&adapter->hw);
}
/**
@@ -469,7 +866,21 @@ enum iecm_status iecm_init_dflt_mbx(struct iecm_adapter *adapter)
*/
int iecm_vport_params_buf_alloc(struct iecm_adapter *adapter)
{
- /* stub */
+ adapter->vport_params_reqd = kcalloc(IECM_MAX_NUM_VPORTS,
+ sizeof(*adapter->vport_params_reqd),
+ GFP_KERNEL);
+ if (!adapter->vport_params_reqd)
+ return -ENOMEM;
+
+ adapter->vport_params_recvd = kcalloc(IECM_MAX_NUM_VPORTS,
+ sizeof(*adapter->vport_params_recvd),
+ GFP_KERNEL);
+ if (!adapter->vport_params_recvd) {
+ kfree(adapter->vport_params_reqd);
+ return -ENOMEM;
+ }
+
+ return 0;
}
/**
--
2.26.2
^ permalink raw reply related
* [net-next 07/15] iecm: Implement virtchnl commands
From: Jeff Kirsher @ 2020-06-18 5:13 UTC (permalink / raw)
To: davem
Cc: Alice Michael, netdev, nhorman, sassmann, Alan Brady, Phani Burra,
Joshua Hay, Madhu Chittim, Pavan Kumar Linga, Donald Skidmore,
Jesse Brandeburg, Sridhar Samudrala, Jeff Kirsher
In-Reply-To: <20200618051344.516587-1-jeffrey.t.kirsher@intel.com>
From: Alice Michael <alice.michael@intel.com>
Implement various virtchnl commands that enable
communication with hardware.
Signed-off-by: Alice Michael <alice.michael@intel.com>
Signed-off-by: Alan Brady <alan.brady@intel.com>
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>
Reviewed-by: Donald Skidmore <donald.c.skidmore@intel.com>
Reviewed-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Reviewed-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
.../net/ethernet/intel/iecm/iecm_virtchnl.c | 1171 ++++++++++++++++-
1 file changed, 1144 insertions(+), 27 deletions(-)
diff --git a/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c b/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
index 0fdf87d6e98f..57862fbfdb9b 100644
--- a/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
+++ b/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
@@ -442,7 +442,13 @@ EXPORT_SYMBOL(iecm_recv_mb_msg);
static enum iecm_status
iecm_send_ver_msg(struct iecm_adapter *adapter)
{
- /* stub */
+ struct virtchnl_version_info vvi;
+
+ vvi.major = VIRTCHNL_VERSION_MAJOR;
+ vvi.minor = VIRTCHNL_VERSION_MINOR;
+
+ return iecm_send_mb_msg(adapter, VIRTCHNL_OP_VERSION, sizeof(vvi),
+ (u8 *)&vvi);
}
/**
@@ -454,7 +460,19 @@ iecm_send_ver_msg(struct iecm_adapter *adapter)
static enum iecm_status
iecm_recv_ver_msg(struct iecm_adapter *adapter)
{
- /* stub */
+ enum iecm_status err = 0;
+ struct virtchnl_version_info vvi;
+
+ err = iecm_recv_mb_msg(adapter, VIRTCHNL_OP_VERSION, &vvi, sizeof(vvi));
+ if (err)
+ goto error;
+
+ if (vvi.major > VIRTCHNL_VERSION_MAJOR ||
+ (vvi.major == VIRTCHNL_VERSION_MAJOR &&
+ vvi.minor > VIRTCHNL_VERSION_MINOR))
+ dev_warn(&adapter->pdev->dev, "Virtchnl version not matched\n");
+error:
+ return err;
}
/**
@@ -466,7 +484,25 @@ iecm_recv_ver_msg(struct iecm_adapter *adapter)
enum iecm_status
iecm_send_get_caps_msg(struct iecm_adapter *adapter)
{
- /* stub */
+ struct virtchnl_get_capabilities caps = {0};
+ int buf_size;
+
+ buf_size = sizeof(struct virtchnl_get_capabilities);
+ adapter->caps = kzalloc(buf_size, GFP_KERNEL);
+ if (!adapter->caps)
+ return IECM_ERR_NO_MEMORY;
+
+ caps.cap_flags = VIRTCHNL_CAP_STATELESS_OFFLOADS |
+ VIRTCHNL_CAP_UDP_SEG_OFFLOAD |
+ VIRTCHNL_CAP_RSS |
+ VIRTCHNL_CAP_TCP_RSC |
+ VIRTCHNL_CAP_HEADER_SPLIT |
+ VIRTCHNL_CAP_RDMA |
+ VIRTCHNL_CAP_SRIOV |
+ VIRTCHNL_CAP_EDT;
+
+ return iecm_send_mb_msg(adapter, VIRTCHNL_OP_GET_CAPS, sizeof(caps),
+ (u8 *)&caps);
}
EXPORT_SYMBOL(iecm_send_get_caps_msg);
@@ -479,7 +515,8 @@ EXPORT_SYMBOL(iecm_send_get_caps_msg);
static enum iecm_status
iecm_recv_get_caps_msg(struct iecm_adapter *adapter)
{
- /* stub */
+ return iecm_recv_mb_msg(adapter, VIRTCHNL_OP_GET_CAPS, adapter->caps,
+ sizeof(struct virtchnl_get_capabilities));
}
/**
@@ -493,7 +530,30 @@ iecm_recv_get_caps_msg(struct iecm_adapter *adapter)
static enum iecm_status
iecm_send_create_vport_msg(struct iecm_adapter *adapter)
{
- /* stub */
+ struct virtchnl_create_vport *vport_msg;
+ enum iecm_status err = 0;
+ int buf_size;
+
+ buf_size = sizeof(struct virtchnl_create_vport);
+ if (!adapter->vport_params_reqd[0]) {
+ adapter->vport_params_reqd[0] = kzalloc(buf_size, GFP_KERNEL);
+ if (!adapter->vport_params_reqd[0]) {
+ err = IECM_ERR_NO_MEMORY;
+ goto error;
+ }
+ }
+
+ vport_msg = (struct virtchnl_create_vport *)
+ adapter->vport_params_reqd[0];
+ vport_msg->vport_type = VIRTCHNL_VPORT_TYPE_DEFAULT;
+ vport_msg->txq_model = VIRTCHNL_QUEUE_MODEL_SPLIT;
+ vport_msg->rxq_model = VIRTCHNL_QUEUE_MODEL_SPLIT;
+ iecm_vport_calc_total_qs(vport_msg, 0);
+
+ err = iecm_send_mb_msg(adapter, VIRTCHNL_OP_CREATE_VPORT, buf_size,
+ (u8 *)vport_msg);
+error:
+ return err;
}
/**
@@ -509,7 +569,26 @@ static enum iecm_status
iecm_recv_create_vport_msg(struct iecm_adapter *adapter,
int *vport_id)
{
- /* stub */
+ struct virtchnl_create_vport *vport_msg;
+ enum iecm_status err = 0;
+
+ if (!adapter->vport_params_recvd[0]) {
+ adapter->vport_params_recvd[0] = kzalloc(IECM_DFLT_MBX_BUF_SIZE,
+ GFP_KERNEL);
+ if (!adapter->vport_params_recvd[0]) {
+ err = IECM_ERR_NO_MEMORY;
+ goto error;
+ }
+ }
+
+ vport_msg = (struct virtchnl_create_vport *)
+ adapter->vport_params_recvd[0];
+
+ err = iecm_recv_mb_msg(adapter, VIRTCHNL_OP_CREATE_VPORT, vport_msg,
+ IECM_DFLT_MBX_BUF_SIZE);
+ *vport_id = vport_msg->vport_id;
+error:
+ return err;
}
/**
@@ -560,7 +639,20 @@ EXPORT_SYMBOL(iecm_wait_for_event);
enum iecm_status
iecm_send_destroy_vport_msg(struct iecm_vport *vport)
{
- /* stub */
+ struct iecm_adapter *adapter = vport->adapter;
+ struct virtchnl_vport v_id;
+ enum iecm_status err;
+
+ v_id.vport_id = vport->vport_id;
+
+ err = iecm_send_mb_msg(adapter, VIRTCHNL_OP_DESTROY_VPORT,
+ sizeof(v_id), (u8 *)&v_id);
+
+ if (!err)
+ err = iecm_wait_for_event(adapter, IECM_VC_DESTROY_VPORT,
+ IECM_VC_DESTROY_VPORT_ERR);
+
+ return err;
}
/**
@@ -598,7 +690,121 @@ iecm_send_disable_vport_msg(struct iecm_vport *vport)
enum iecm_status
iecm_send_config_tx_queues_msg(struct iecm_vport *vport)
{
- /* stub */
+ struct virtchnl_config_tx_queues *ctq = NULL;
+ struct virtchnl_txq_info_v2 *qi;
+ enum iecm_status err = 0;
+ int totqs, num_msgs;
+ int i, k = 0;
+ int num_qs;
+
+ totqs = vport->num_txq + vport->num_complq;
+ qi = kcalloc(totqs, sizeof(struct virtchnl_txq_info_v2), GFP_KERNEL);
+ if (!qi) {
+ err = IECM_ERR_NO_MEMORY;
+ goto error;
+ }
+
+ /* Populate the queue info buffer with all queue context info */
+ for (i = 0; i < vport->num_txq_grp; i++) {
+ struct iecm_txq_group *tx_qgrp = &vport->txq_grps[i];
+ int j;
+
+ for (j = 0; j < tx_qgrp->num_txq; j++, k++) {
+ qi[k].queue_id = tx_qgrp->txqs[j].q_id;
+ qi[k].model = vport->txq_model;
+ qi[k].type = tx_qgrp->txqs[j].q_type;
+ qi[k].ring_len = tx_qgrp->txqs[j].desc_count;
+ qi[k].dma_ring_addr = tx_qgrp->txqs[j].dma;
+ if (iecm_is_queue_model_split(vport->txq_model)) {
+ struct iecm_queue *q = &tx_qgrp->txqs[j];
+
+ qi[k].tx_compl_queue_id = tx_qgrp->complq->q_id;
+ qi[k].desc_profile =
+ VIRTCHNL_TXQ_DESC_PROFILE_NATIVE;
+
+ if (test_bit(__IECM_Q_FLOW_SCH_EN, q->flags))
+ qi[k].sched_mode =
+ VIRTCHNL_TXQ_SCHED_MODE_FLOW;
+ else
+ qi[k].sched_mode =
+ VIRTCHNL_TXQ_SCHED_MODE_QUEUE;
+ } else {
+ qi[k].sched_mode =
+ VIRTCHNL_TXQ_SCHED_MODE_QUEUE;
+ qi[k].desc_profile =
+ VIRTCHNL_TXQ_DESC_PROFILE_BASE;
+ }
+ }
+
+ if (iecm_is_queue_model_split(vport->txq_model)) {
+ qi[k].queue_id = tx_qgrp->complq->q_id;
+ qi[k].model = vport->txq_model;
+ qi[k].type = tx_qgrp->complq->q_type;
+ qi[k].desc_profile = VIRTCHNL_TXQ_DESC_PROFILE_NATIVE;
+ qi[k].ring_len = tx_qgrp->complq->desc_count;
+ qi[k].dma_ring_addr = tx_qgrp->complq->dma;
+ k++;
+ }
+ }
+
+ if (k != totqs) {
+ err = IECM_ERR_CFG;
+ goto error;
+ }
+
+ /* Chunk up the queue contexts into multiple messages to avoid
+ * sending a control queue message buffer that is too large
+ */
+ if (totqs < IECM_NUM_QCTX_PER_MSG)
+ num_qs = totqs;
+ else
+ num_qs = IECM_NUM_QCTX_PER_MSG;
+
+ num_msgs = totqs / IECM_NUM_QCTX_PER_MSG;
+ if (totqs % IECM_NUM_QCTX_PER_MSG)
+ num_msgs++;
+
+ for (i = 0, k = 0; i < num_msgs || num_qs; i++) {
+ int buf_size = sizeof(struct virtchnl_config_tx_queues) +
+ (sizeof(struct virtchnl_txq_info_v2) * (num_qs - 1));
+ if (!ctq || num_qs != IECM_NUM_QCTX_PER_MSG) {
+ kfree(ctq);
+ ctq = kzalloc(buf_size, GFP_KERNEL);
+ if (!ctq) {
+ err = IECM_ERR_NO_MEMORY;
+ goto error;
+ }
+ } else {
+ memset(ctq, 0, buf_size);
+ }
+
+ ctq->vport_id = vport->vport_id;
+ ctq->num_qinfo = num_qs;
+ memcpy(ctq->qinfo, &qi[k],
+ sizeof(struct virtchnl_txq_info_v2) * num_qs);
+
+ err = iecm_send_mb_msg(vport->adapter,
+ VIRTCHNL_OP_CONFIG_TX_QUEUES,
+ buf_size, (u8 *)ctq);
+
+ if (!err)
+ err = iecm_wait_for_event(vport->adapter,
+ IECM_VC_CONFIG_TXQ,
+ IECM_VC_CONFIG_TXQ_ERR);
+ if (err)
+ goto mbx_error;
+
+ k += num_qs;
+ totqs -= num_qs;
+ if (totqs < IECM_NUM_QCTX_PER_MSG)
+ num_qs = totqs;
+ }
+
+mbx_error:
+ kfree(ctq);
+error:
+ kfree(qi);
+ return err;
}
/**
@@ -612,7 +818,148 @@ iecm_send_config_tx_queues_msg(struct iecm_vport *vport)
enum iecm_status
iecm_send_config_rx_queues_msg(struct iecm_vport *vport)
{
- /* stub */
+ struct virtchnl_config_rx_queues *crq = NULL;
+ struct virtchnl_rxq_info_v2 *qi;
+ enum iecm_status err = 0;
+ int totqs, num_msgs;
+ int i, k = 0;
+ int num_qs;
+
+ totqs = vport->num_rxq + vport->num_bufq;
+ qi = kcalloc(totqs, sizeof(struct virtchnl_rxq_info_v2), GFP_KERNEL);
+ if (!qi) {
+ err = IECM_ERR_NO_MEMORY;
+ goto error;
+ }
+
+ /* Populate the queue info buffer with all queue context info */
+ for (i = 0; i < vport->num_rxq_grp; i++) {
+ struct iecm_rxq_group *rx_qgrp = &vport->rxq_grps[i];
+ int num_rxq;
+ int j;
+
+ 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++, k++) {
+ struct iecm_queue *rxq;
+
+ if (iecm_is_queue_model_split(vport->rxq_model)) {
+ rxq = &rx_qgrp->splitq.rxq_sets[j].rxq;
+ qi[k].rx_bufq1_id =
+ rxq->rxq_grp->splitq.bufq_sets[0].bufq.q_id;
+ qi[k].rx_bufq2_id =
+ rxq->rxq_grp->splitq.bufq_sets[1].bufq.q_id;
+ qi[k].hdr_buffer_size = rxq->rx_hbuf_size;
+ qi[k].rsc_low_watermark =
+ rxq->rsc_low_watermark;
+
+ if (rxq->rx_hsplit_en) {
+ qi[k].queue_flags =
+ VIRTCHNL_RXQ_HDR_SPLIT;
+ qi[k].hdr_buffer_size =
+ rxq->rx_hbuf_size;
+ }
+ if (iecm_is_feature_ena(vport, NETIF_F_GRO_HW))
+ qi[k].queue_flags |= VIRTCHNL_RXQ_RSC;
+ } else {
+ rxq = &rx_qgrp->singleq.rxqs[j];
+ }
+
+ qi[k].queue_id = rxq->q_id;
+ qi[k].model = vport->rxq_model;
+ qi[k].type = rxq->q_type;
+ qi[k].desc_profile = VIRTCHNL_TXQ_DESC_PROFILE_BASE;
+ qi[k].desc_size = VIRTCHNL_RXQ_DESC_SIZE_32BYTE;
+ qi[k].ring_len = rxq->desc_count;
+ qi[k].dma_ring_addr = rxq->dma;
+ qi[k].max_pkt_size = rxq->rx_max_pkt_size;
+ qi[k].data_buffer_size = rxq->rx_buf_size;
+ }
+
+ if (iecm_is_queue_model_split(vport->rxq_model)) {
+ for (j = 0; j < IECM_BUFQS_PER_RXQ_SET; j++, k++) {
+ struct iecm_queue *bufq =
+ &rx_qgrp->splitq.bufq_sets[j].bufq;
+
+ qi[k].queue_id = bufq->q_id;
+ qi[k].model = vport->rxq_model;
+ qi[k].type = bufq->q_type;
+ qi[k].desc_profile =
+ VIRTCHNL_TXQ_DESC_PROFILE_NATIVE;
+ qi[k].desc_size =
+ VIRTCHNL_RXQ_DESC_SIZE_32BYTE;
+ qi[k].ring_len = bufq->desc_count;
+ qi[k].dma_ring_addr = bufq->dma;
+ qi[k].data_buffer_size = bufq->rx_buf_size;
+ qi[k].buffer_notif_stride =
+ bufq->rx_buf_stride;
+ qi[k].rsc_low_watermark =
+ bufq->rsc_low_watermark;
+ }
+ }
+ }
+
+ if (k != totqs) {
+ err = IECM_ERR_CFG;
+ goto error;
+ }
+
+ /* Chunk up the queue contexts into multiple messages to avoid
+ * sending a control queue message buffer that is too large
+ */
+ if (totqs < IECM_NUM_QCTX_PER_MSG)
+ num_qs = totqs;
+ else
+ num_qs = IECM_NUM_QCTX_PER_MSG;
+
+ num_msgs = totqs / IECM_NUM_QCTX_PER_MSG;
+ if (totqs % IECM_NUM_QCTX_PER_MSG)
+ num_msgs++;
+
+ for (i = 0, k = 0; i < num_msgs || num_qs; i++) {
+ int buf_size = sizeof(struct virtchnl_config_rx_queues) +
+ (sizeof(struct virtchnl_rxq_info_v2) * (num_qs - 1));
+ if (!crq || num_qs != IECM_NUM_QCTX_PER_MSG) {
+ kfree(crq);
+ crq = kzalloc(buf_size, GFP_KERNEL);
+ if (!crq) {
+ err = IECM_ERR_NO_MEMORY;
+ goto error;
+ }
+ } else {
+ memset(crq, 0, buf_size);
+ }
+
+ crq->vport_id = vport->vport_id;
+ crq->num_qinfo = num_qs;
+ memcpy(crq->qinfo, &qi[k],
+ sizeof(struct virtchnl_rxq_info_v2) * num_qs);
+
+ err = iecm_send_mb_msg(vport->adapter,
+ VIRTCHNL_OP_CONFIG_RX_QUEUES,
+ buf_size, (u8 *)crq);
+
+ if (!err)
+ err = iecm_wait_for_event(vport->adapter,
+ IECM_VC_CONFIG_RXQ,
+ IECM_VC_CONFIG_RXQ_ERR);
+ if (err)
+ goto mbx_error;
+
+ k += num_qs;
+ totqs -= num_qs;
+ if (totqs < IECM_NUM_QCTX_PER_MSG)
+ num_qs = totqs;
+ }
+
+mbx_error:
+ kfree(crq);
+error:
+ kfree(qi);
+ return err;
}
/**
@@ -629,7 +976,118 @@ static enum iecm_status
iecm_send_ena_dis_queues_msg(struct iecm_vport *vport,
enum virtchnl_ops vc_op)
{
- /* stub */
+ struct virtchnl_del_ena_dis_queues *eq;
+ struct virtchnl_queue_chunk *qc;
+ int num_txq, num_rxq, num_q;
+ int i, j, k = 0, buf_size;
+ enum iecm_status err = 0;
+
+ /* validate virtchnl op */
+ switch (vc_op) {
+ case VIRTCHNL_OP_ENABLE_QUEUES_V2:
+ case VIRTCHNL_OP_DISABLE_QUEUES_V2:
+ break;
+ default:
+ err = IECM_ERR_CFG;
+ goto error;
+ }
+
+ num_txq = vport->num_txq + vport->num_complq;
+ num_rxq = vport->num_rxq + vport->num_bufq;
+ num_q = num_txq + num_rxq;
+ buf_size = sizeof(struct virtchnl_del_ena_dis_queues) +
+ (sizeof(struct virtchnl_queue_chunk) * (num_q - 1));
+ eq = kzalloc(buf_size, GFP_KERNEL);
+ if (!eq) {
+ err = IECM_ERR_NO_MEMORY;
+ goto error;
+ }
+
+ eq->vport_id = vport->vport_id;
+ eq->chunks.num_chunks = num_q;
+ qc = eq->chunks.chunks;
+
+ for (i = 0; i < vport->num_txq_grp; i++) {
+ struct iecm_txq_group *tx_qgrp = &vport->txq_grps[i];
+
+ for (j = 0; j < tx_qgrp->num_txq; j++, k++) {
+ qc[k].type = tx_qgrp->txqs[j].q_type;
+ qc[k].start_queue_id = tx_qgrp->txqs[j].q_id;
+ qc[k].num_queues = 1;
+ }
+ }
+ if (vport->num_txq != k) {
+ err = IECM_ERR_CFG;
+ goto err_cfg;
+ }
+
+ if (iecm_is_queue_model_split(vport->txq_model)) {
+ for (i = 0; i < vport->num_txq_grp; i++, k++) {
+ struct iecm_txq_group *tx_qgrp = &vport->txq_grps[i];
+
+ qc[k].type = tx_qgrp->complq->q_type;
+ qc[k].start_queue_id = tx_qgrp->complq->q_id;
+ qc[k].num_queues = 1;
+ }
+ if (vport->num_complq != (k - vport->num_txq)) {
+ err = IECM_ERR_CFG;
+ goto err_cfg;
+ }
+ }
+
+ for (i = 0; i < vport->num_rxq_grp; i++) {
+ struct iecm_rxq_group *rx_qgrp = &vport->rxq_grps[i];
+
+ 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++, k++) {
+ if (iecm_is_queue_model_split(vport->rxq_model)) {
+ qc[k].start_queue_id =
+ rx_qgrp->splitq.rxq_sets[j].rxq.q_id;
+ qc[k].type =
+ rx_qgrp->splitq.rxq_sets[j].rxq.q_type;
+ } else {
+ qc[k].start_queue_id =
+ rx_qgrp->singleq.rxqs[j].q_id;
+ qc[k].type =
+ rx_qgrp->singleq.rxqs[j].q_type;
+ }
+ qc[k].num_queues = 1;
+ }
+ }
+ if (vport->num_rxq != k - (vport->num_txq + vport->num_complq)) {
+ err = IECM_ERR_CFG;
+ goto err_cfg;
+ }
+
+ if (iecm_is_queue_model_split(vport->rxq_model)) {
+ for (i = 0; i < vport->num_rxq_grp; i++) {
+ struct iecm_rxq_group *rx_qgrp = &vport->rxq_grps[i];
+ struct iecm_queue *q;
+
+ for (j = 0; j < IECM_BUFQS_PER_RXQ_SET; j++, k++) {
+ q = &rx_qgrp->splitq.bufq_sets[j].bufq;
+ qc[k].type = q->q_type;
+ qc[k].start_queue_id = q->q_id;
+ qc[k].num_queues = 1;
+ }
+ }
+ if (vport->num_bufq != k - (vport->num_txq +
+ vport->num_complq +
+ vport->num_rxq)) {
+ err = IECM_ERR_CFG;
+ goto err_cfg;
+ }
+ }
+
+ err = iecm_send_mb_msg(vport->adapter, vc_op, buf_size, (u8 *)eq);
+err_cfg:
+ kfree(eq);
+error:
+ return err;
}
/**
@@ -646,7 +1104,107 @@ static enum iecm_status
iecm_send_map_unmap_queue_vector_msg(struct iecm_vport *vport,
bool map)
{
- /* stub */
+ struct iecm_adapter *adapter = vport->adapter;
+ struct virtchnl_queue_vector_maps *vqvm;
+ struct virtchnl_queue_vector *vqv;
+ int buf_size, num_q, i, j, k = 0;
+ enum iecm_status err = 0;
+
+ num_q = vport->num_txq + vport->num_rxq;
+
+ buf_size = sizeof(struct virtchnl_queue_vector_maps) +
+ (sizeof(struct virtchnl_queue_vector) * (num_q - 1));
+ vqvm = kzalloc(buf_size, GFP_KERNEL);
+ if (!vqvm) {
+ err = IECM_ERR_NO_MEMORY;
+ goto error;
+ }
+
+ vqvm->vport_id = vport->vport_id;
+ vqvm->num_maps = num_q;
+ vqv = vqvm->qv_maps;
+
+ for (i = 0; i < vport->num_txq_grp; i++) {
+ struct iecm_txq_group *tx_qgrp = &vport->txq_grps[i];
+
+ for (j = 0; j < tx_qgrp->num_txq; j++, k++) {
+ vqv[k].queue_type = tx_qgrp->txqs[j].q_type;
+ vqv[k].queue_id = tx_qgrp->txqs[j].q_id;
+
+ if (iecm_is_queue_model_split(vport->txq_model)) {
+ vqv[k].vector_id =
+ tx_qgrp->complq->q_vector->v_idx;
+ vqv[k].itr_idx =
+ tx_qgrp->complq->itr.itr_idx;
+ } else {
+ vqv[k].vector_id =
+ tx_qgrp->txqs[j].q_vector->v_idx;
+ vqv[k].itr_idx =
+ tx_qgrp->txqs[j].itr.itr_idx;
+ }
+ }
+ }
+
+ if (vport->num_txq != k) {
+ err = IECM_ERR_CFG;
+ goto err_cfg;
+ }
+
+ for (i = 0; i < vport->num_rxq_grp; i++) {
+ struct iecm_rxq_group *rx_qgrp = &vport->rxq_grps[i];
+ int num_rxq;
+
+ 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++, k++) {
+ struct iecm_queue *rxq;
+
+ if (iecm_is_queue_model_split(vport->rxq_model))
+ rxq = &rx_qgrp->splitq.rxq_sets[j].rxq;
+ else
+ rxq = &rx_qgrp->singleq.rxqs[j];
+
+ vqv[k].queue_type = rxq->q_type;
+ vqv[k].queue_id = rxq->q_id;
+ vqv[k].vector_id = rxq->q_vector->v_idx;
+ vqv[k].itr_idx = rxq->itr.itr_idx;
+ }
+ }
+
+ if (iecm_is_queue_model_split(vport->txq_model)) {
+ if (vport->num_rxq != k - vport->num_complq) {
+ err = IECM_ERR_CFG;
+ goto err_cfg;
+ }
+ } else {
+ if (vport->num_rxq != k - vport->num_txq) {
+ err = IECM_ERR_CFG;
+ goto err_cfg;
+ }
+ }
+
+ if (map) {
+ err = iecm_send_mb_msg(adapter,
+ VIRTCHNL_OP_MAP_QUEUE_VECTOR,
+ buf_size, (u8 *)vqvm);
+ if (!err)
+ err = iecm_wait_for_event(adapter, IECM_VC_MAP_IRQ,
+ IECM_VC_MAP_IRQ_ERR);
+ } else {
+ err = iecm_send_mb_msg(adapter,
+ VIRTCHNL_OP_UNMAP_QUEUE_VECTOR,
+ buf_size, (u8 *)vqvm);
+ if (!err)
+ err = iecm_wait_for_event(adapter, IECM_VC_UNMAP_IRQ,
+ IECM_VC_UNMAP_IRQ_ERR);
+ }
+err_cfg:
+ kfree(vqvm);
+error:
+ return err;
}
/**
@@ -658,7 +1216,16 @@ iecm_send_map_unmap_queue_vector_msg(struct iecm_vport *vport,
static enum iecm_status
iecm_send_enable_queues_msg(struct iecm_vport *vport)
{
- /* stub */
+ struct iecm_adapter *adapter = vport->adapter;
+ enum iecm_status err;
+
+ err = iecm_send_ena_dis_queues_msg(vport,
+ VIRTCHNL_OP_ENABLE_QUEUES_V2);
+ if (!err)
+ err = iecm_wait_for_event(adapter, IECM_VC_ENA_QUEUES,
+ IECM_VC_ENA_QUEUES_ERR);
+
+ return err;
}
/**
@@ -670,7 +1237,15 @@ iecm_send_enable_queues_msg(struct iecm_vport *vport)
static enum iecm_status
iecm_send_disable_queues_msg(struct iecm_vport *vport)
{
- /* stub */
+ struct iecm_adapter *adapter = vport->adapter;
+ enum iecm_status err;
+
+ err = iecm_send_ena_dis_queues_msg(vport,
+ VIRTCHNL_OP_DISABLE_QUEUES_V2);
+ if (!err)
+ err = iecm_wait_for_event(adapter, IECM_VC_DIS_QUEUES,
+ IECM_VC_DIS_QUEUES_ERR);
+ return err;
}
/**
@@ -682,7 +1257,48 @@ iecm_send_disable_queues_msg(struct iecm_vport *vport)
enum iecm_status
iecm_send_delete_queues_msg(struct iecm_vport *vport)
{
- /* stub */
+ struct iecm_adapter *adapter = vport->adapter;
+ struct virtchnl_create_vport *vport_params;
+ struct virtchnl_del_ena_dis_queues *eq;
+ struct virtchnl_queue_chunks *chunks;
+ int buf_size, num_chunks;
+ enum iecm_status err;
+
+ if (vport->adapter->config_data.req_qs_chunks) {
+ struct virtchnl_add_queues *vc_aq =
+ (struct virtchnl_add_queues *)
+ vport->adapter->config_data.req_qs_chunks;
+ chunks = &vc_aq->chunks;
+ } else {
+ vport_params = (struct virtchnl_create_vport *)
+ vport->adapter->vport_params_recvd[0];
+ chunks = &vport_params->chunks;
+ }
+
+ num_chunks = chunks->num_chunks;
+ buf_size = sizeof(struct virtchnl_del_ena_dis_queues) +
+ (sizeof(struct virtchnl_queue_chunk) *
+ (num_chunks - 1));
+
+ eq = kzalloc(buf_size, GFP_KERNEL);
+ if (!eq) {
+ err = IECM_ERR_NO_MEMORY;
+ return err;
+ }
+ eq->vport_id = vport->vport_id;
+ eq->chunks.num_chunks = num_chunks;
+
+ memcpy(eq->chunks.chunks, chunks->chunks, num_chunks *
+ sizeof(struct virtchnl_queue_chunk));
+
+ err = iecm_send_mb_msg(vport->adapter, VIRTCHNL_OP_DEL_QUEUES,
+ buf_size, (u8 *)eq);
+ if (!err)
+ err = iecm_wait_for_event(adapter, IECM_VC_DEL_QUEUES,
+ IECM_VC_DEL_QUEUES_ERR);
+
+ kfree(eq);
+ return err;
}
/**
@@ -694,7 +1310,14 @@ iecm_send_delete_queues_msg(struct iecm_vport *vport)
static enum iecm_status
iecm_send_config_queues_msg(struct iecm_vport *vport)
{
- /* stub */
+ enum iecm_status err;
+
+ err = iecm_send_config_tx_queues_msg(vport);
+
+ if (!err)
+ err = iecm_send_config_rx_queues_msg(vport);
+
+ return err;
}
/**
@@ -711,7 +1334,55 @@ enum iecm_status
iecm_send_add_queues_msg(struct iecm_vport *vport, u16 num_tx_q,
u16 num_complq, u16 num_rx_q, u16 num_rx_bufq)
{
- /* stub */
+ struct iecm_adapter *adapter = vport->adapter;
+ struct virtchnl_add_queues aq = {0};
+ enum iecm_status err;
+ int size;
+
+ aq.vport_id = vport->vport_id;
+ aq.num_tx_q = num_tx_q;
+ aq.num_tx_complq = num_complq;
+ aq.num_rx_q = num_rx_q;
+ aq.num_rx_bufq = num_rx_bufq;
+
+ err = iecm_send_mb_msg(adapter,
+ VIRTCHNL_OP_ADD_QUEUES,
+ sizeof(struct virtchnl_add_queues), (u8 *)&aq);
+
+ if (!err)
+ err = iecm_wait_for_event(adapter, IECM_VC_ADD_QUEUES,
+ IECM_VC_ADD_QUEUES_ERR);
+
+ if (!err) {
+ struct virtchnl_add_queues *vc_msg =
+ (struct virtchnl_add_queues *)adapter->vc_msg;
+
+ kfree(adapter->config_data.req_qs_chunks);
+ adapter->config_data.req_qs_chunks = NULL;
+
+ /* compare vc_msg num queues with vport num queues */
+ if (vc_msg->num_tx_q != num_tx_q ||
+ vc_msg->num_rx_q != num_rx_q ||
+ vc_msg->num_tx_complq != num_complq ||
+ vc_msg->num_rx_bufq != num_rx_bufq)
+ return IECM_ERR_CFG;
+
+ size = sizeof(struct virtchnl_add_queues) +
+ ((vc_msg->chunks.num_chunks - 1) *
+ sizeof(struct virtchnl_queue_chunk));
+ adapter->config_data.req_qs_chunks =
+ kzalloc(size, GFP_KERNEL);
+ if (!adapter->config_data.req_qs_chunks) {
+ err = IECM_ERR_NO_MEMORY;
+ mutex_unlock(&adapter->vc_msg_lock);
+ goto mem_err;
+ }
+ memcpy(adapter->config_data.req_qs_chunks,
+ adapter->vc_msg, size);
+ mutex_unlock(&adapter->vc_msg_lock);
+ }
+mem_err:
+ return err;
}
/**
@@ -723,7 +1394,44 @@ iecm_send_add_queues_msg(struct iecm_vport *vport, u16 num_tx_q,
enum iecm_status
iecm_send_get_stats_msg(struct iecm_vport *vport)
{
- /* stub */
+ struct iecm_adapter *adapter = vport->adapter;
+ struct virtchnl_queue_select vqs;
+ enum iecm_status err;
+
+ /* Don't send get_stats message if one is pending or the
+ * link is down
+ */
+ if (test_bit(IECM_VC_GET_STATS, adapter->vc_state) ||
+ adapter->state <= __IECM_DOWN)
+ return 0;
+
+ vqs.vsi_id = vport->vport_id;
+
+ err = iecm_send_mb_msg(adapter, VIRTCHNL_OP_GET_STATS,
+ sizeof(vqs), (u8 *)&vqs);
+
+ if (!err)
+ err = iecm_wait_for_event(adapter, IECM_VC_GET_STATS,
+ IECM_VC_GET_STATS_ERR);
+
+ if (!err) {
+ struct virtchnl_eth_stats *stats =
+ (struct virtchnl_eth_stats *)adapter->vc_msg;
+ vport->netstats.rx_packets = stats->rx_unicast +
+ stats->rx_multicast +
+ stats->rx_broadcast;
+ vport->netstats.tx_packets = stats->tx_unicast +
+ stats->tx_multicast +
+ stats->tx_broadcast;
+ vport->netstats.rx_bytes = stats->rx_bytes;
+ vport->netstats.tx_bytes = stats->tx_bytes;
+ vport->netstats.tx_errors = stats->tx_errors;
+ vport->netstats.rx_dropped = stats->rx_discards;
+ vport->netstats.tx_dropped = stats->tx_discards;
+ mutex_unlock(&adapter->vc_msg_lock);
+ }
+
+ return err;
}
/**
@@ -736,7 +1444,36 @@ iecm_send_get_stats_msg(struct iecm_vport *vport)
enum iecm_status
iecm_send_get_set_rss_hash_msg(struct iecm_vport *vport, bool get)
{
- /* stub */
+ struct iecm_adapter *adapter = vport->adapter;
+ struct virtchnl_rss_hash rh = {0};
+ enum iecm_status err;
+
+ rh.vport_id = vport->vport_id;
+ rh.hash = adapter->rss_data.rss_hash;
+
+ if (get) {
+ err = iecm_send_mb_msg(adapter, VIRTCHNL_OP_GET_RSS_HASH,
+ sizeof(rh), (u8 *)&rh);
+ if (!err) {
+ err = iecm_wait_for_event(adapter, IECM_VC_GET_RSS_HASH,
+ IECM_VC_GET_RSS_HASH_ERR);
+ if (!err) {
+ memcpy(&rh, adapter->vc_msg, sizeof(rh));
+ adapter->rss_data.rss_hash = rh.hash;
+ /* Leave the buffer clean for next message */
+ memset(adapter->vc_msg, 0,
+ IECM_DFLT_MBX_BUF_SIZE);
+ mutex_unlock(&adapter->vc_msg_lock);
+ }
+ }
+ } else {
+ err = iecm_send_mb_msg(adapter, VIRTCHNL_OP_SET_RSS_HASH,
+ sizeof(rh), (u8 *)&rh);
+ if (!err)
+ err = iecm_wait_for_event(adapter, IECM_VC_SET_RSS_HASH,
+ IECM_VC_SET_RSS_HASH_ERR);
+ }
+ return err;
}
/**
@@ -749,7 +1486,72 @@ iecm_send_get_set_rss_hash_msg(struct iecm_vport *vport, bool get)
enum iecm_status
iecm_send_get_set_rss_lut_msg(struct iecm_vport *vport, bool get)
{
- /* stub */
+ struct iecm_adapter *adapter = vport->adapter;
+ struct virtchnl_rss_lut_v2 *recv_rl;
+ struct virtchnl_rss_lut_v2 *rl;
+ enum iecm_status err;
+ int i, buf_size;
+
+ buf_size = sizeof(struct virtchnl_rss_lut_v2) +
+ (sizeof(u16) * (adapter->rss_data.rss_lut_size - 1));
+ rl = kzalloc(buf_size, GFP_KERNEL);
+ if (!rl) {
+ err = IECM_ERR_NO_MEMORY;
+ goto error;
+ }
+
+ if (!get) {
+ rl->lut_entries = adapter->rss_data.rss_lut_size;
+ for (i = 0; i < adapter->rss_data.rss_lut_size; i++)
+ rl->lut[i] = adapter->rss_data.rss_lut[i];
+ }
+ rl->vport_id = vport->vport_id;
+
+ if (get) {
+ err = iecm_send_mb_msg(vport->adapter, VIRTCHNL_OP_GET_RSS_LUT,
+ buf_size, (u8 *)rl);
+ if (!err) {
+ err = iecm_wait_for_event(adapter, IECM_VC_GET_RSS_LUT,
+ IECM_VC_GET_RSS_LUT_ERR);
+ if (err)
+ goto get_lut_err;
+ recv_rl = (struct virtchnl_rss_lut_v2 *)adapter->vc_msg;
+ if (adapter->rss_data.rss_lut_size !=
+ recv_rl->lut_entries) {
+ adapter->rss_data.rss_lut_size =
+ recv_rl->lut_entries;
+ kfree(adapter->rss_data.rss_lut);
+ adapter->rss_data.rss_lut =
+ kzalloc(adapter->rss_data.rss_lut_size,
+ GFP_KERNEL);
+ if (!adapter->rss_data.rss_lut) {
+ adapter->rss_data.rss_lut_size = 0;
+ err = IECM_ERR_NO_MEMORY;
+ /* Leave the buffer clean */
+ memset(adapter->vc_msg, 0,
+ IECM_DFLT_MBX_BUF_SIZE);
+ mutex_unlock(&adapter->vc_msg_lock);
+ goto mem_alloc_err;
+ }
+ }
+ memcpy(adapter->rss_data.rss_lut, adapter->vc_msg,
+ adapter->rss_data.rss_lut_size);
+ /* Leave the buffer clean for next message */
+ memset(adapter->vc_msg, 0, IECM_DFLT_MBX_BUF_SIZE);
+ mutex_unlock(&adapter->vc_msg_lock);
+ }
+ } else {
+ err = iecm_send_mb_msg(adapter, VIRTCHNL_OP_SET_RSS_LUT,
+ buf_size, (u8 *)rl);
+ if (!err)
+ err = iecm_wait_for_event(adapter, IECM_VC_SET_RSS_LUT,
+ IECM_VC_SET_RSS_LUT_ERR);
+ }
+mem_alloc_err:
+get_lut_err:
+ kfree(rl);
+error:
+ return err;
}
/**
@@ -762,7 +1564,74 @@ iecm_send_get_set_rss_lut_msg(struct iecm_vport *vport, bool get)
enum iecm_status
iecm_send_get_set_rss_key_msg(struct iecm_vport *vport, bool get)
{
- /* stub */
+ struct iecm_adapter *adapter = vport->adapter;
+ struct virtchnl_rss_key *recv_rk;
+ struct virtchnl_rss_key *rk;
+ enum iecm_status err;
+ int i, buf_size;
+
+ buf_size = sizeof(struct virtchnl_rss_key) +
+ (sizeof(u8) * (adapter->rss_data.rss_key_size - 1));
+ rk = kzalloc(buf_size, GFP_KERNEL);
+ if (!rk) {
+ err = IECM_ERR_NO_MEMORY;
+ goto error;
+ }
+
+ if (!get) {
+ rk->key_len = adapter->rss_data.rss_key_size;
+ for (i = 0; i < adapter->rss_data.rss_key_size; i++)
+ rk->key[i] = adapter->rss_data.rss_key[i];
+ }
+ rk->vsi_id = vport->vport_id;
+
+ if (get) {
+ err = iecm_send_mb_msg(adapter, VIRTCHNL_OP_GET_RSS_KEY,
+ buf_size, (u8 *)rk);
+ if (!err) {
+ err = iecm_wait_for_event(adapter, IECM_VC_GET_RSS_KEY,
+ IECM_VC_GET_RSS_KEY_ERR);
+ if (err)
+ goto get_key_err;
+ recv_rk = (struct virtchnl_rss_key *)adapter->vc_msg;
+ if (adapter->rss_data.rss_key_size !=
+ recv_rk->key_len) {
+ adapter->rss_data.rss_key_size =
+ min_t(u16, NETDEV_RSS_KEY_LEN,
+ recv_rk->key_len);
+ kfree(adapter->rss_data.rss_key);
+ adapter->rss_data.rss_key =
+ kzalloc(adapter->rss_data.rss_key_size,
+ GFP_KERNEL);
+ if (!adapter->rss_data.rss_key) {
+ adapter->rss_data.rss_key_size = 0;
+ err = IECM_ERR_NO_MEMORY;
+ /* Leave the buffer clean */
+ memset(adapter->vc_msg, 0,
+ IECM_DFLT_MBX_BUF_SIZE);
+ mutex_unlock(&adapter->vc_msg_lock);
+ goto mem_alloc_err;
+ }
+ }
+ memcpy(adapter->rss_data.rss_key, adapter->vc_msg,
+ adapter->rss_data.rss_key_size);
+ /* Leave the buffer clean for next message */
+ memset(adapter->vc_msg, 0, IECM_DFLT_MBX_BUF_SIZE);
+ mutex_unlock(&adapter->vc_msg_lock);
+ }
+ } else {
+ err = iecm_send_mb_msg(adapter, VIRTCHNL_OP_CONFIG_RSS_KEY,
+ buf_size, (u8 *)rk);
+ if (!err)
+ err = iecm_wait_for_event(adapter,
+ IECM_VC_CONFIG_RSS_KEY,
+ IECM_VC_CONFIG_RSS_KEY_ERR);
+ }
+mem_alloc_err:
+get_key_err:
+ kfree(rk);
+error:
+ return err;
}
/**
@@ -773,7 +1642,24 @@ iecm_send_get_set_rss_key_msg(struct iecm_vport *vport, bool get)
*/
enum iecm_status iecm_send_get_rx_ptype_msg(struct iecm_vport *vport)
{
- /* stub */
+ struct iecm_rx_ptype_decoded *rx_ptype_lkup = vport->rx_ptype_lkup;
+ int ptype_list[IECM_RX_SUPP_PTYPE] = { 0, 1, 11, 12, 22, 23, 24, 25, 26,
+ 27, 28, 88, 89, 90, 91, 92, 93,
+ 94 };
+ enum iecm_status err = 0;
+ int i;
+
+ for (i = 0; i < IECM_RX_MAX_PTYPE; i++)
+ rx_ptype_lkup[i] = iecm_rx_ptype_lkup[0];
+
+ for (i = 0; i < IECM_RX_SUPP_PTYPE; i++) {
+ int j = ptype_list[i];
+
+ rx_ptype_lkup[j] = iecm_rx_ptype_lkup[i];
+ rx_ptype_lkup[j].ptype = ptype_list[i];
+ };
+
+ return err;
}
/**
@@ -912,7 +1798,54 @@ void iecm_vport_params_buf_rel(struct iecm_adapter *adapter)
*/
int iecm_vc_core_init(struct iecm_adapter *adapter, int *vport_id)
{
- /* stub */
+ switch (adapter->state) {
+ case __IECM_STARTUP:
+ if (iecm_send_ver_msg(adapter))
+ goto init_failed;
+ adapter->state = __IECM_VER_CHECK;
+ goto restart;
+ case __IECM_VER_CHECK:
+ if (iecm_recv_ver_msg(adapter))
+ goto init_failed;
+ adapter->state = __IECM_GET_CAPS;
+ if (adapter->dev_ops.vc_ops.get_caps(adapter))
+ goto init_failed;
+ goto restart;
+ case __IECM_GET_CAPS:
+ if (iecm_recv_get_caps_msg(adapter))
+ goto init_failed;
+ if (iecm_send_create_vport_msg(adapter))
+ goto init_failed;
+ adapter->state = __IECM_GET_DFLT_VPORT_PARAMS;
+ goto restart;
+ case __IECM_GET_DFLT_VPORT_PARAMS:
+ if (iecm_recv_create_vport_msg(adapter, vport_id))
+ goto init_failed;
+ adapter->state = __IECM_INIT_SW;
+ break;
+ case __IECM_INIT_SW:
+ break;
+ default:
+ dev_err(&adapter->pdev->dev, "Device is in bad state: %d\n",
+ adapter->state);
+ goto init_failed;
+ }
+
+ return 0;
+
+restart:
+ queue_delayed_work(adapter->init_wq, &adapter->init_task,
+ msecs_to_jiffies(30));
+ /* Not an error. Using try again to continue with state machine */
+ return -EAGAIN;
+init_failed:
+ if (++adapter->mb_wait_count > IECM_MB_MAX_ERR) {
+ dev_err(&adapter->pdev->dev, "Failed to establish mailbox communications with hardware\n");
+ return -EFAULT;
+ }
+ adapter->state = __IECM_STARTUP;
+ queue_delayed_work(adapter->init_wq, &adapter->init_task, HZ);
+ return -EAGAIN;
}
EXPORT_SYMBOL(iecm_vc_core_init);
@@ -959,7 +1892,32 @@ iecm_vport_get_queue_ids(u16 *qids, int num_qids,
enum virtchnl_queue_type q_type,
struct virtchnl_queue_chunks *chunks)
{
- /* stub */
+ int num_chunks = chunks->num_chunks;
+ struct virtchnl_queue_chunk *chunk;
+ int num_q_id_filled = 0;
+ int start_q_id;
+ int num_q;
+ int i;
+
+ while (num_chunks) {
+ chunk = &chunks->chunks[num_chunks - 1];
+ if (chunk->type == q_type) {
+ num_q = chunk->num_queues;
+ start_q_id = chunk->start_queue_id;
+ for (i = 0; i < num_q; i++) {
+ if ((num_q_id_filled + i) < num_qids) {
+ qids[num_q_id_filled + i] = start_q_id;
+ start_q_id++;
+ } else {
+ break;
+ }
+ }
+ num_q_id_filled = num_q_id_filled + i;
+ }
+ num_chunks--;
+ }
+
+ return num_q_id_filled;
}
/**
@@ -976,7 +1934,80 @@ static int
__iecm_vport_queue_ids_init(struct iecm_vport *vport, u16 *qids,
int num_qids, enum virtchnl_queue_type q_type)
{
- /* stub */
+ struct iecm_queue *q;
+ int i, j, k = 0;
+
+ switch (q_type) {
+ case VIRTCHNL_QUEUE_TYPE_TX:
+ for (i = 0; i < vport->num_txq_grp; i++) {
+ struct iecm_txq_group *tx_qgrp = &vport->txq_grps[i];
+
+ for (j = 0; j < tx_qgrp->num_txq; j++) {
+ if (k < num_qids) {
+ tx_qgrp->txqs[j].q_id = qids[k];
+ tx_qgrp->txqs[j].q_type =
+ VIRTCHNL_QUEUE_TYPE_TX;
+ k++;
+ } else {
+ break;
+ }
+ }
+ }
+ break;
+ case VIRTCHNL_QUEUE_TYPE_RX:
+ for (i = 0; i < vport->num_rxq_grp; i++) {
+ struct iecm_rxq_group *rx_qgrp = &vport->rxq_grps[i];
+ int num_rxq;
+
+ 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 && k < num_qids; j++, k++) {
+ 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->q_id = qids[k];
+ q->q_type = VIRTCHNL_QUEUE_TYPE_RX;
+ }
+ }
+ break;
+ case VIRTCHNL_QUEUE_TYPE_TX_COMPLETION:
+ for (i = 0; i < vport->num_txq_grp; i++) {
+ struct iecm_txq_group *tx_qgrp = &vport->txq_grps[i];
+
+ if (k < num_qids) {
+ tx_qgrp->complq->q_id = qids[k];
+ tx_qgrp->complq->q_type =
+ VIRTCHNL_QUEUE_TYPE_TX_COMPLETION;
+ k++;
+ } else {
+ break;
+ }
+ }
+ break;
+ case VIRTCHNL_QUEUE_TYPE_RX_BUFFER:
+ for (i = 0; i < vport->num_rxq_grp; i++) {
+ struct iecm_rxq_group *rx_qgrp = &vport->rxq_grps[i];
+
+ for (j = 0; j < IECM_BUFQS_PER_RXQ_SET; j++) {
+ if (k < num_qids) {
+ q = &rx_qgrp->splitq.bufq_sets[j].bufq;
+ q->q_id = qids[k];
+ q->q_type =
+ VIRTCHNL_QUEUE_TYPE_RX_BUFFER;
+ k++;
+ } else {
+ break;
+ }
+ }
+ }
+ break;
+ }
+
+ return k;
}
/**
@@ -989,7 +2020,76 @@ __iecm_vport_queue_ids_init(struct iecm_vport *vport, u16 *qids,
static
enum iecm_status iecm_vport_queue_ids_init(struct iecm_vport *vport)
{
- /* stub */
+ struct virtchnl_create_vport *vport_params;
+ struct virtchnl_queue_chunks *chunks;
+ enum virtchnl_queue_type q_type;
+ /* We may never deal with more that 256 same type of queues */
+#define IECM_MAX_QIDS 256
+ u16 qids[IECM_MAX_QIDS];
+ int num_ids;
+
+ if (vport->adapter->config_data.num_req_qs) {
+ struct virtchnl_add_queues *vc_aq =
+ (struct virtchnl_add_queues *)
+ vport->adapter->config_data.req_qs_chunks;
+ chunks = &vc_aq->chunks;
+ } else {
+ vport_params = (struct virtchnl_create_vport *)
+ vport->adapter->vport_params_recvd[0];
+ chunks = &vport_params->chunks;
+ /* compare vport_params num queues with vport num queues */
+ if (vport_params->num_tx_q != vport->num_txq ||
+ vport_params->num_rx_q != vport->num_rxq ||
+ vport_params->num_tx_complq != vport->num_complq ||
+ vport_params->num_rx_bufq != vport->num_bufq)
+ return IECM_ERR_CFG;
+ }
+
+ num_ids = iecm_vport_get_queue_ids(qids, IECM_MAX_QIDS,
+ VIRTCHNL_QUEUE_TYPE_TX,
+ chunks);
+ if (num_ids != vport->num_txq)
+ return IECM_ERR_CFG;
+ num_ids = __iecm_vport_queue_ids_init(vport, qids, num_ids,
+ VIRTCHNL_QUEUE_TYPE_TX);
+ if (num_ids != vport->num_txq)
+ return IECM_ERR_CFG;
+ num_ids = iecm_vport_get_queue_ids(qids, IECM_MAX_QIDS,
+ VIRTCHNL_QUEUE_TYPE_RX,
+ chunks);
+ if (num_ids != vport->num_rxq)
+ return IECM_ERR_CFG;
+ num_ids = __iecm_vport_queue_ids_init(vport, qids, num_ids,
+ VIRTCHNL_QUEUE_TYPE_RX);
+ if (num_ids != vport->num_rxq)
+ return IECM_ERR_CFG;
+
+ if (iecm_is_queue_model_split(vport->txq_model)) {
+ q_type = VIRTCHNL_QUEUE_TYPE_TX_COMPLETION;
+ num_ids = iecm_vport_get_queue_ids(qids, IECM_MAX_QIDS, q_type,
+ chunks);
+ if (num_ids != vport->num_complq)
+ return IECM_ERR_CFG;
+ num_ids = __iecm_vport_queue_ids_init(vport, qids,
+ num_ids,
+ q_type);
+ if (num_ids != vport->num_complq)
+ return IECM_ERR_CFG;
+ }
+
+ if (iecm_is_queue_model_split(vport->rxq_model)) {
+ q_type = VIRTCHNL_QUEUE_TYPE_RX_BUFFER;
+ num_ids = iecm_vport_get_queue_ids(qids, IECM_MAX_QIDS, q_type,
+ chunks);
+ if (num_ids != vport->num_bufq)
+ return IECM_ERR_CFG;
+ num_ids = __iecm_vport_queue_ids_init(vport, qids, num_ids,
+ q_type);
+ if (num_ids != vport->num_bufq)
+ return IECM_ERR_CFG;
+ }
+
+ return 0;
}
/**
@@ -1000,7 +2100,23 @@ enum iecm_status iecm_vport_queue_ids_init(struct iecm_vport *vport)
*/
enum iecm_status iecm_vport_adjust_qs(struct iecm_vport *vport)
{
- /* stub */
+ struct virtchnl_create_vport vport_msg;
+ enum iecm_status err;
+
+ vport_msg.txq_model = vport->txq_model;
+ vport_msg.rxq_model = vport->rxq_model;
+ iecm_vport_calc_total_qs(&vport_msg,
+ vport->adapter->config_data.num_req_qs);
+ err = iecm_send_add_queues_msg(vport, vport_msg.num_tx_q,
+ vport_msg.num_tx_complq,
+ vport_msg.num_rx_q,
+ vport_msg.num_rx_bufq);
+ if (err)
+ goto failure;
+ iecm_vport_init_num_qs(vport, &vport_msg);
+ iecm_vport_calc_num_q_groups(vport);
+failure:
+ return err;
}
/**
@@ -1012,7 +2128,8 @@ enum iecm_status iecm_vport_adjust_qs(struct iecm_vport *vport)
*/
static bool iecm_is_capability_ena(struct iecm_adapter *adapter, u64 flag)
{
- /* stub */
+ return ((struct virtchnl_get_capabilities *)adapter->caps)->cap_flags &
+ flag;
}
/**
--
2.26.2
^ permalink raw reply related
* [net-next 02/15] iecm: Add framework set of header files
From: Jeff Kirsher @ 2020-06-18 5:13 UTC (permalink / raw)
To: davem
Cc: Alice Michael, netdev, nhorman, sassmann, Alan Brady, Phani Burra,
Joshua Hay, Madhu Chittim, Pavan Kumar Linga, Donald Skidmore,
Jesse Brandeburg, Sridhar Samudrala, Jeff Kirsher
In-Reply-To: <20200618051344.516587-1-jeffrey.t.kirsher@intel.com>
From: Alice Michael <alice.michael@intel.com>
Introduces the framework of data for the driver common
module.
Signed-off-by: Alice Michael <alice.michael@intel.com>
Signed-off-by: Alan Brady <alan.brady@intel.com>
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>
Reviewed-by: Donald Skidmore <donald.c.skidmore@intel.com>
Reviewed-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Reviewed-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
include/linux/net/intel/iecm.h | 432 ++++++++++++++++++++
include/linux/net/intel/iecm_alloc.h | 29 ++
include/linux/net/intel/iecm_controlq.h | 95 +++++
include/linux/net/intel/iecm_controlq_api.h | 221 ++++++++++
include/linux/net/intel/iecm_osdep.h | 24 ++
include/linux/net/intel/iecm_type.h | 47 +++
6 files changed, 848 insertions(+)
create mode 100644 include/linux/net/intel/iecm.h
create mode 100644 include/linux/net/intel/iecm_alloc.h
create mode 100644 include/linux/net/intel/iecm_controlq.h
create mode 100644 include/linux/net/intel/iecm_controlq_api.h
create mode 100644 include/linux/net/intel/iecm_osdep.h
create mode 100644 include/linux/net/intel/iecm_type.h
diff --git a/include/linux/net/intel/iecm.h b/include/linux/net/intel/iecm.h
new file mode 100644
index 000000000000..0a0c4b928622
--- /dev/null
+++ b/include/linux/net/intel/iecm.h
@@ -0,0 +1,432 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2020 Intel Corporation */
+
+#ifndef _IECM_H_
+#define _IECM_H_
+
+#include <linux/aer.h>
+#include <linux/bitmap.h>
+#include <linux/compiler.h>
+#include <linux/cpumask.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if_bridge.h>
+#include <linux/if_vlan.h>
+#include <linux/interrupt.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/pkt_sched.h>
+#include <linux/rtnetlink.h>
+#include <linux/sctp.h>
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <net/tcp.h>
+#include <net/ipv6.h>
+#include <net/ip6_checksum.h>
+#include <linux/prefetch.h>
+#include <net/pkt_sched.h>
+
+#include <net/gre.h>
+#include <net/udp_tunnel.h>
+#include <linux/avf/virtchnl.h>
+
+#include <linux/net/intel/iecm_osdep.h>
+#include <linux/net/intel/iecm_controlq_api.h>
+#include <linux/net/intel/iecm_lan_txrx.h>
+
+#include <linux/net/intel/iecm_txrx.h>
+#include <linux/net/intel/iecm_type.h>
+
+extern const char iecm_drv_ver[];
+extern char iecm_drv_name[];
+
+#define IECM_BAR0 0
+#define IECM_NO_FREE_SLOT 0xffff
+
+/* Default Mailbox settings */
+#define IECM_DFLT_MBX_BUF_SIZE (1 * 1024)
+#define IECM_NUM_QCTX_PER_MSG 3
+#define IECM_DFLT_MBX_Q_LEN 64
+#define IECM_DFLT_MBX_ID -1
+/* maximum number of times to try before resetting mailbox */
+#define IECM_MB_MAX_ERR 20
+
+#define IECM_MAX_NUM_VPORTS 1
+
+/* default message levels */
+#define IECM_DFLT_NETIF_M (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
+
+/* Forward declaration */
+struct iecm_adapter;
+
+enum iecm_state {
+ __IECM_STARTUP,
+ __IECM_VER_CHECK,
+ __IECM_GET_RES,
+ __IECM_GET_CAPS,
+ __IECM_GET_DFLT_VPORT_PARAMS,
+ __IECM_INIT_SW,
+ __IECM_DOWN,
+ __IECM_UP,
+ __IECM_REMOVE,
+ __IECM_STATE_LAST /* this member MUST be last */
+};
+
+enum iecm_flags {
+ /* Soft reset causes */
+ __IECM_SR_Q_CHANGE, /* Soft reset to do queue change */
+ __IECM_SR_Q_DESC_CHANGE,
+ __IECM_SR_Q_SCH_CHANGE, /* Scheduling mode change in queue context */
+ __IECM_SR_MTU_CHANGE,
+ __IECM_SR_TC_CHANGE,
+ /* Hard reset causes */
+ __IECM_HR_FUNC_RESET, /* Hard reset when txrx timeout */
+ __IECM_HR_CORE_RESET, /* when reset event is received on virtchannel */
+ __IECM_HR_DRV_LOAD, /* Set on driver load for a clean HW */
+ /* Generic bits to share a message */
+ __IECM_DEL_QUEUES,
+ __IECM_UP_REQUESTED, /* Set if open to be called explicitly by driver */
+ /* Mailbox interrupt event */
+ __IECM_MB_INTR_MODE,
+ __IECM_MB_INTR_TRIGGER,
+ /* must be last */
+ __IECM_FLAGS_NBITS,
+};
+
+struct iecm_netdev_priv {
+ struct iecm_vport *vport;
+};
+
+struct iecm_reset_reg {
+ u32 rstat;
+ u32 rstat_m;
+};
+
+/* product specific register API */
+struct iecm_reg_ops {
+ void (*ctlq_reg_init)(struct iecm_ctlq_create_info *cq);
+ void (*vportq_reg_init)(struct iecm_vport *vport);
+ void (*intr_reg_init)(struct iecm_vport *vport);
+ void (*mb_intr_reg_init)(struct iecm_adapter *adapter);
+ void (*reset_reg_init)(struct iecm_reset_reg *reset_reg);
+ void (*trigger_reset)(struct iecm_adapter *adapter,
+ enum iecm_flags trig_cause);
+};
+
+struct iecm_virtchnl_ops {
+ int (*core_init)(struct iecm_adapter *adapter, int *vport_id);
+ void (*vport_init)(struct iecm_vport *vport, int vport_id);
+ enum iecm_status (*vport_queue_ids_init)(struct iecm_vport *vport);
+ enum iecm_status (*get_caps)(struct iecm_adapter *adapter);
+ enum iecm_status (*config_queues)(struct iecm_vport *vport);
+ enum iecm_status (*enable_queues)(struct iecm_vport *vport);
+ enum iecm_status (*disable_queues)(struct iecm_vport *vport);
+ enum iecm_status (*irq_map_unmap)(struct iecm_vport *vport, bool map);
+ enum iecm_status (*enable_vport)(struct iecm_vport *vport);
+ enum iecm_status (*disable_vport)(struct iecm_vport *vport);
+ enum iecm_status (*destroy_vport)(struct iecm_vport *vport);
+ enum iecm_status (*get_ptype)(struct iecm_vport *vport);
+ enum iecm_status (*get_set_rss_lut)(struct iecm_vport *vport, bool get);
+ enum iecm_status (*get_set_rss_hash)(struct iecm_vport *vport,
+ bool get);
+ enum iecm_status (*adjust_qs)(struct iecm_vport *vport);
+ enum iecm_status (*recv_mbx_msg)(struct iecm_adapter *adapter,
+ void *msg, int msg_size,
+ struct iecm_ctlq_msg *ctlq_msg,
+ bool *work_done);
+ enum iecm_status (*alloc_vectors)(struct iecm_adapter *adapter,
+ u16 num_vectors);
+ enum iecm_status (*dealloc_vectors)(struct iecm_adapter *adapter);
+ bool (*is_cap_ena)(struct iecm_adapter *adapter, u64 flag);
+};
+
+struct iecm_dev_ops {
+ void (*reg_ops_init)(struct iecm_adapter *adapter);
+ void (*vc_ops_init)(struct iecm_adapter *adapter);
+ void (*crc_enable)(u64 *td_cmd);
+ struct iecm_reg_ops reg_ops;
+ struct iecm_virtchnl_ops vc_ops;
+};
+
+/* vport specific data structure */
+
+enum iecm_vport_vc_state {
+ IECM_VC_ENA_VPORT,
+ IECM_VC_ENA_VPORT_ERR,
+ IECM_VC_DIS_VPORT,
+ IECM_VC_DIS_VPORT_ERR,
+ IECM_VC_DESTROY_VPORT,
+ IECM_VC_DESTROY_VPORT_ERR,
+ IECM_VC_CONFIG_TXQ,
+ IECM_VC_CONFIG_TXQ_ERR,
+ IECM_VC_CONFIG_RXQ,
+ IECM_VC_CONFIG_RXQ_ERR,
+ IECM_VC_CONFIG_Q,
+ IECM_VC_CONFIG_Q_ERR,
+ IECM_VC_ENA_QUEUES,
+ IECM_VC_ENA_QUEUES_ERR,
+ IECM_VC_DIS_QUEUES,
+ IECM_VC_DIS_QUEUES_ERR,
+ IECM_VC_MAP_IRQ,
+ IECM_VC_MAP_IRQ_ERR,
+ IECM_VC_UNMAP_IRQ,
+ IECM_VC_UNMAP_IRQ_ERR,
+ IECM_VC_ADD_QUEUES,
+ IECM_VC_ADD_QUEUES_ERR,
+ IECM_VC_DEL_QUEUES,
+ IECM_VC_DEL_QUEUES_ERR,
+ IECM_VC_ALLOC_VECTORS,
+ IECM_VC_ALLOC_VECTORS_ERR,
+ IECM_VC_DEALLOC_VECTORS,
+ IECM_VC_DEALLOC_VECTORS_ERR,
+ IECM_VC_CREATE_VFS,
+ IECM_VC_CREATE_VFS_ERR,
+ IECM_VC_DESTROY_VFS,
+ IECM_VC_DESTROY_VFS_ERR,
+ IECM_VC_GET_RSS_HASH,
+ IECM_VC_GET_RSS_HASH_ERR,
+ IECM_VC_SET_RSS_HASH,
+ IECM_VC_SET_RSS_HASH_ERR,
+ IECM_VC_GET_RSS_LUT,
+ IECM_VC_GET_RSS_LUT_ERR,
+ IECM_VC_SET_RSS_LUT,
+ IECM_VC_SET_RSS_LUT_ERR,
+ IECM_VC_GET_RSS_KEY,
+ IECM_VC_GET_RSS_KEY_ERR,
+ IECM_VC_CONFIG_RSS_KEY,
+ IECM_VC_CONFIG_RSS_KEY_ERR,
+ IECM_VC_GET_STATS,
+ IECM_VC_GET_STATS_ERR,
+ IECM_VC_NBITS
+};
+
+enum iecm_vport_flags {
+ __IECM_VPORT_SW_MARKER,
+ __IECM_VPORT_FLAGS_NBITS,
+};
+
+struct iecm_vport {
+ /* TX */
+ unsigned int num_txq;
+ unsigned int num_complq;
+ /* It makes more sense for descriptor count to be part of only iecm
+ * queue structure. But when user changes the count via ethtool, driver
+ * has to store that value somewhere other than queue structure as the
+ * queues will be freed and allocated again.
+ */
+ unsigned int txq_desc_count;
+ unsigned int complq_desc_count;
+ unsigned int compln_clean_budget;
+ unsigned int num_txq_grp;
+ struct iecm_txq_group *txq_grps;
+ enum virtchnl_queue_model txq_model;
+ /* Used only in hotpath to get to the right queue very fast */
+ struct iecm_queue **txqs;
+ wait_queue_head_t sw_marker_wq;
+ DECLARE_BITMAP(flags, __IECM_VPORT_FLAGS_NBITS);
+
+ /* RX */
+ unsigned int num_rxq;
+ unsigned int num_bufq;
+ unsigned int rxq_desc_count;
+ unsigned int bufq_desc_count;
+ unsigned int num_rxq_grp;
+ struct iecm_rxq_group *rxq_grps;
+ enum virtchnl_queue_model rxq_model;
+ struct iecm_rx_ptype_decoded rx_ptype_lkup[IECM_RX_MAX_PTYPE];
+
+ struct iecm_adapter *adapter;
+ struct net_device *netdev;
+ u16 vport_type;
+ u16 vport_id;
+ u16 idx; /* software index in adapter vports struct */
+ struct rtnl_link_stats64 netstats;
+
+ /* handler for hard interrupt */
+ irqreturn_t (*irq_q_handler)(int irq, void *data);
+ struct iecm_q_vector *q_vectors; /* q vector array */
+ u16 num_q_vectors;
+ u16 q_vector_base;
+ u16 max_mtu;
+ u8 default_mac_addr[ETH_ALEN];
+ u16 qset_handle;
+ /* Duplicated in queue structure for performance reasons */
+ enum iecm_rx_hsplit rx_hsplit_en;
+};
+
+/* User defined configuration values */
+struct iecm_user_config_data {
+ u32 num_req_qs; /* user requested queues through ethtool */
+ u32 num_req_txq_desc;
+ u32 num_req_rxq_desc;
+ void *req_qs_chunks;
+};
+
+struct iecm_rss_data {
+ u64 rss_hash;
+ u16 rss_key_size;
+ u8 *rss_key;
+ u16 rss_lut_size;
+ u8 *rss_lut;
+};
+
+struct iecm_adapter {
+ struct pci_dev *pdev;
+
+ u32 tx_timeout_count;
+ u32 msg_enable;
+ enum iecm_state state;
+ DECLARE_BITMAP(flags, __IECM_FLAGS_NBITS);
+ struct mutex reset_lock; /* lock to protect reset flows */
+ struct iecm_reset_reg reset_reg;
+ struct iecm_hw hw;
+
+ u16 num_req_msix;
+ u16 num_msix_entries;
+ struct msix_entry *msix_entries;
+ struct virtchnl_alloc_vectors *req_vec_chunks;
+ struct iecm_q_vector mb_vector;
+ /* handler for hard interrupt for mailbox*/
+ irqreturn_t (*irq_mb_handler)(int irq, void *data);
+
+ /* vport structs */
+ struct iecm_vport **vports; /* vports created by the driver */
+ u16 num_alloc_vport;
+ u16 next_vport; /* Next free slot in pf->vport[] - 0-based! */
+ struct mutex sw_mutex; /* lock to protect vport alloc flow */
+
+ struct delayed_work init_task; /* delayed init task */
+ struct workqueue_struct *init_wq;
+ u32 mb_wait_count;
+ struct delayed_work serv_task; /* delayed service task */
+ struct workqueue_struct *serv_wq;
+ struct delayed_work stats_task; /* delayed statistics task */
+ struct workqueue_struct *stats_wq;
+ struct delayed_work vc_event_task; /* delayed virtchannel event task */
+ struct workqueue_struct *vc_event_wq;
+ /* Store the resources data received from control plane */
+ void **vport_params_reqd;
+ void **vport_params_recvd;
+ /* User set parameters */
+ struct iecm_user_config_data config_data;
+ void *caps;
+ wait_queue_head_t vchnl_wq;
+ DECLARE_BITMAP(vc_state, IECM_VC_NBITS);
+ struct mutex vc_msg_lock; /* lock to protect vc_msg flow */
+ char vc_msg[IECM_DFLT_MBX_BUF_SIZE];
+ struct iecm_rss_data rss_data;
+ struct iecm_dev_ops dev_ops;
+ enum virtchnl_link_speed link_speed;
+ bool link_up;
+};
+
+/**
+ * iecm_is_queue_model_split - check if queue model is split
+ * @q_model: queue model single or split
+ *
+ * Returns true if queue model is split else false
+ */
+static inline int iecm_is_queue_model_split(enum virtchnl_queue_model q_model)
+{
+ return (q_model == VIRTCHNL_QUEUE_MODEL_SPLIT);
+}
+
+/**
+ * iecm_is_cap_ena - Determine if HW capability is supported
+ * @adapter: private data struct
+ * @flag: Feature flag to check
+ */
+static inline bool iecm_is_cap_ena(struct iecm_adapter *adapter, u64 flag)
+{
+ return adapter->dev_ops.vc_ops.is_cap_ena(adapter, flag);
+}
+
+/**
+ * iecm_is_feature_ena - Determine if a particular feature is enabled
+ * @vport: vport to check
+ * @feature: netdev flag to check
+ *
+ * Returns true or false if a particular feature is enabled.
+ */
+static inline bool iecm_is_feature_ena(struct iecm_vport *vport,
+ netdev_features_t feature)
+{
+ return vport->netdev->features & feature;
+}
+
+/**
+ * iecm_rx_offset - Return expected offset into page to access data
+ * @rx_q: queue we are requesting offset of
+ *
+ * Returns the offset value for queue into the data buffer.
+ */
+static inline unsigned int
+iecm_rx_offset(struct iecm_queue __maybe_unused *rx_q)
+{
+ return 0;
+}
+
+int iecm_probe(struct pci_dev *pdev,
+ const struct pci_device_id __always_unused *ent,
+ struct iecm_adapter *adapter);
+void iecm_remove(struct pci_dev *pdev);
+void iecm_shutdown(struct pci_dev *pdev);
+enum iecm_status iecm_vport_adjust_qs(struct iecm_vport *vport);
+enum iecm_status
+iecm_ctlq_reg_init(struct iecm_ctlq_create_info *cq, int num_q);
+enum iecm_status iecm_init_dflt_mbx(struct iecm_adapter *adapter);
+void iecm_deinit_dflt_mbx(struct iecm_adapter *adapter);
+void iecm_vc_ops_init(struct iecm_adapter *adapter);
+int iecm_vc_core_init(struct iecm_adapter *adapter, int *vport_id);
+enum iecm_status
+iecm_wait_for_event(struct iecm_adapter *adapter,
+ enum iecm_vport_vc_state state,
+ enum iecm_vport_vc_state err_check);
+enum iecm_status iecm_send_get_caps_msg(struct iecm_adapter *adapter);
+enum iecm_status iecm_send_delete_queues_msg(struct iecm_vport *vport);
+enum iecm_status
+iecm_send_add_queues_msg(struct iecm_vport *vport, u16 num_tx_q,
+ u16 num_complq, u16 num_rx_q, u16 num_rx_bufq);
+enum iecm_status iecm_initiate_soft_reset(struct iecm_vport *vport,
+ enum iecm_flags reset_cause);
+enum iecm_status iecm_send_config_tx_queues_msg(struct iecm_vport *vport);
+enum iecm_status iecm_send_config_rx_queues_msg(struct iecm_vport *vport);
+enum iecm_status iecm_send_enable_vport_msg(struct iecm_vport *vport);
+enum iecm_status iecm_send_disable_vport_msg(struct iecm_vport *vport);
+enum iecm_status iecm_send_destroy_vport_msg(struct iecm_vport *vport);
+enum iecm_status iecm_send_get_rx_ptype_msg(struct iecm_vport *vport);
+enum iecm_status
+iecm_send_get_set_rss_key_msg(struct iecm_vport *vport, bool get);
+enum iecm_status
+iecm_send_get_set_rss_lut_msg(struct iecm_vport *vport, bool get);
+enum iecm_status
+iecm_send_get_set_rss_hash_msg(struct iecm_vport *vport, bool get);
+int iecm_vport_params_buf_alloc(struct iecm_adapter *adapter);
+void iecm_vport_params_buf_rel(struct iecm_adapter *adapter);
+struct iecm_vport *iecm_netdev_to_vport(struct net_device *netdev);
+struct iecm_adapter *iecm_netdev_to_adapter(struct net_device *netdev);
+enum iecm_status iecm_send_get_stats_msg(struct iecm_vport *vport);
+int iecm_vport_get_vec_ids(u16 *vecids, int num_vecids,
+ struct virtchnl_vector_chunks *chunks);
+enum iecm_status
+iecm_recv_mb_msg(struct iecm_adapter *adapter, enum virtchnl_ops op,
+ void *msg, int msg_size);
+enum iecm_status
+iecm_send_mb_msg(struct iecm_adapter *adapter, enum virtchnl_ops op,
+ u16 msg_size, u8 *msg);
+void iecm_set_ethtool_ops(struct net_device *netdev);
+void iecm_vport_set_hsplit(struct iecm_vport *vport, struct bpf_prog *prog);
+#endif /* !_IECM_H_ */
diff --git a/include/linux/net/intel/iecm_alloc.h b/include/linux/net/intel/iecm_alloc.h
new file mode 100644
index 000000000000..fd13bf085663
--- /dev/null
+++ b/include/linux/net/intel/iecm_alloc.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2020, Intel Corporation. */
+
+#ifndef _IECM_ALLOC_H_
+#define _IECM_ALLOC_H_
+
+/* Memory types */
+enum iecm_memset_type {
+ IECM_NONDMA_MEM = 0,
+ IECM_DMA_MEM
+};
+
+/* Memcpy types */
+enum iecm_memcpy_type {
+ IECM_NONDMA_TO_NONDMA = 0,
+ IECM_NONDMA_TO_DMA,
+ IECM_DMA_TO_DMA,
+ IECM_DMA_TO_NONDMA
+};
+
+struct iecm_hw;
+struct iecm_dma_mem;
+
+/* prototype for functions used for dynamic memory allocation */
+void *iecm_alloc_dma_mem(struct iecm_hw *hw, struct iecm_dma_mem *mem,
+ u64 size);
+void iecm_free_dma_mem(struct iecm_hw *hw, struct iecm_dma_mem *mem);
+
+#endif /* _IECM_ALLOC_H_ */
diff --git a/include/linux/net/intel/iecm_controlq.h b/include/linux/net/intel/iecm_controlq.h
new file mode 100644
index 000000000000..4cba637042cd
--- /dev/null
+++ b/include/linux/net/intel/iecm_controlq.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2020, Intel Corporation. */
+
+#ifndef _IECM_CONTROLQ_H_
+#define _IECM_CONTROLQ_H_
+
+#include <linux/net/intel/iecm_controlq_api.h>
+
+/* Maximum buffer lengths for all control queue types */
+#define IECM_CTLQ_MAX_RING_SIZE 1024
+#define IECM_CTLQ_MAX_BUF_LEN 4096
+
+#define IECM_CTLQ_DESC(R, i) \
+ (&(((struct iecm_ctlq_desc *)((R)->desc_ring.va))[i]))
+
+#define IECM_CTLQ_DESC_UNUSED(R) \
+ (u16)((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->ring_size) + \
+ (R)->next_to_clean - (R)->next_to_use - 1)
+
+/* Data type manipulation macros. */
+#define IECM_HI_DWORD(x) ((u32)((((x) >> 16) >> 16) & 0xFFFFFFFF))
+#define IECM_LO_DWORD(x) ((u32)((x) & 0xFFFFFFFF))
+#define IECM_HI_WORD(x) ((u16)(((x) >> 16) & 0xFFFF))
+#define IECM_LO_WORD(x) ((u16)((x) & 0xFFFF))
+
+/* Control Queue default settings */
+#define IECM_CTRL_SQ_CMD_TIMEOUT 250 /* msecs */
+
+struct iecm_ctlq_desc {
+ __le16 flags;
+ __le16 opcode;
+ __le16 datalen; /* 0 for direct commands */
+ union {
+ __le16 ret_val;
+ __le16 pfid_vfid;
+#define IECM_CTLQ_DESC_VF_ID_S 0
+#define IECM_CTLQ_DESC_VF_ID_M (0x3FF << IECM_CTLQ_DESC_VF_ID_S)
+#define IECM_CTLQ_DESC_PF_ID_S 10
+#define IECM_CTLQ_DESC_PF_ID_M (0x3F << IECM_CTLQ_DESC_PF_ID_S)
+ };
+ __le32 cookie_high;
+ __le32 cookie_low;
+ union {
+ struct {
+ __le32 param0;
+ __le32 param1;
+ __le32 param2;
+ __le32 param3;
+ } direct;
+ struct {
+ __le32 param0;
+ __le32 param1;
+ __le32 addr_high;
+ __le32 addr_low;
+ } indirect;
+ u8 raw[16];
+ } params;
+};
+
+/* Flags sub-structure
+ * |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10 |11 |12 |13 |14 |15 |
+ * |DD |CMP|ERR| * RSV * |FTYPE | *RSV* |RD |VFC|BUF| * RSV * |
+ */
+/* command flags and offsets */
+#define IECM_CTLQ_FLAG_DD_S 0
+#define IECM_CTLQ_FLAG_CMP_S 1
+#define IECM_CTLQ_FLAG_ERR_S 2
+#define IECM_CTLQ_FLAG_FTYPE_S 6
+#define IECM_CTLQ_FLAG_RD_S 10
+#define IECM_CTLQ_FLAG_VFC_S 11
+#define IECM_CTLQ_FLAG_BUF_S 12
+
+#define IECM_CTLQ_FLAG_DD BIT(IECM_CTLQ_FLAG_DD_S) /* 0x1 */
+#define IECM_CTLQ_FLAG_CMP BIT(IECM_CTLQ_FLAG_CMP_S) /* 0x2 */
+#define IECM_CTLQ_FLAG_ERR BIT(IECM_CTLQ_FLAG_ERR_S) /* 0x4 */
+#define IECM_CTLQ_FLAG_FTYPE_VM BIT(IECM_CTLQ_FLAG_FTYPE_S) /* 0x40 */
+#define IECM_CTLQ_FLAG_FTYPE_PF BIT(IECM_CTLQ_FLAG_FTYPE_S + 1) /* 0x80 */
+#define IECM_CTLQ_FLAG_RD BIT(IECM_CTLQ_FLAG_RD_S) /* 0x400 */
+#define IECM_CTLQ_FLAG_VFC BIT(IECM_CTLQ_FLAG_VFC_S) /* 0x800 */
+#define IECM_CTLQ_FLAG_BUF BIT(IECM_CTLQ_FLAG_BUF_S) /* 0x1000 */
+
+struct iecm_mbxq_desc {
+ u8 pad[8]; /* CTLQ flags/opcode/len/retval fields */
+ u32 chnl_opcode; /* avoid confusion with desc->opcode */
+ u32 chnl_retval; /* ditto for desc->retval */
+ u32 pf_vf_id; /* used by CP when sending to PF */
+};
+
+enum iecm_status
+iecm_ctlq_alloc_ring_res(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq);
+
+void iecm_ctlq_dealloc_ring_res(struct iecm_hw *hw, struct iecm_ctlq_info *cq);
+
+#endif /* _IECM_CONTROLQ_H_ */
diff --git a/include/linux/net/intel/iecm_controlq_api.h b/include/linux/net/intel/iecm_controlq_api.h
new file mode 100644
index 000000000000..3992abefb479
--- /dev/null
+++ b/include/linux/net/intel/iecm_controlq_api.h
@@ -0,0 +1,221 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2020, Intel Corporation. */
+
+#ifndef _IECM_CONTROLQ_API_H_
+#define _IECM_CONTROLQ_API_H_
+
+/* Error Codes */
+enum iecm_status {
+ IECM_SUCCESS = 0,
+
+ /* Reserve range -1..-49 for generic codes */
+ IECM_ERR_PARAM = -1,
+ IECM_ERR_NOT_IMPL = -2,
+ IECM_ERR_NOT_READY = -3,
+ IECM_ERR_BAD_PTR = -5,
+ IECM_ERR_INVAL_SIZE = -6,
+ IECM_ERR_DEVICE_NOT_SUPPORTED = -8,
+ IECM_ERR_FW_API_VER = -9,
+ IECM_ERR_NO_MEMORY = -10,
+ IECM_ERR_CFG = -11,
+ IECM_ERR_OUT_OF_RANGE = -12,
+ IECM_ERR_ALREADY_EXISTS = -13,
+ IECM_ERR_DOES_NOT_EXIST = -14,
+ IECM_ERR_IN_USE = -15,
+ IECM_ERR_MAX_LIMIT = -16,
+ IECM_ERR_RESET_ONGOING = -17,
+
+ /* Reserve range -100..-109 for CRQ/CSQ specific error codes */
+ IECM_ERR_CTLQ_ERROR = -100,
+ IECM_ERR_CTLQ_TIMEOUT = -101,
+ IECM_ERR_CTLQ_FULL = -102,
+ IECM_ERR_CTLQ_NO_WORK = -103,
+ IECM_ERR_CTLQ_EMPTY = -104,
+};
+
+enum iecm_ctlq_err {
+ IECM_CTLQ_RC_OK = 0, /* Success */
+ IECM_CTLQ_RC_EPERM = 1, /* Operation not permitted */
+ IECM_CTLQ_RC_ENOENT = 2, /* No such element */
+ IECM_CTLQ_RC_ESRCH = 3, /* Bad opcode */
+ IECM_CTLQ_RC_EINTR = 4, /* Operation interrupted */
+ IECM_CTLQ_RC_EIO = 5, /* I/O error */
+ IECM_CTLQ_RC_ENXIO = 6, /* No such resource */
+ IECM_CTLQ_RC_E2BIG = 7, /* Arg too long */
+ IECM_CTLQ_RC_EAGAIN = 8, /* Try again */
+ IECM_CTLQ_RC_ENOMEM = 9, /* Out of memory */
+ IECM_CTLQ_RC_EACCES = 10, /* Permission denied */
+ IECM_CTLQ_RC_EFAULT = 11, /* Bad address */
+ IECM_CTLQ_RC_EBUSY = 12, /* Device or resource busy */
+ IECM_CTLQ_RC_EEXIST = 13, /* object already exists */
+ IECM_CTLQ_RC_EINVAL = 14, /* Invalid argument */
+ IECM_CTLQ_RC_ENOTTY = 15, /* Not a typewriter */
+ IECM_CTLQ_RC_ENOSPC = 16, /* No space left or allocation failure */
+ IECM_CTLQ_RC_ENOSYS = 17, /* Function not implemented */
+ IECM_CTLQ_RC_ERANGE = 18, /* Parameter out of range */
+ IECM_CTLQ_RC_EFLUSHED = 19, /* Cmd flushed due to prev cmd error */
+ IECM_CTLQ_RC_BAD_ADDR = 20, /* Descriptor contains a bad pointer */
+ IECM_CTLQ_RC_EMODE = 21, /* Op not allowed in current dev mode */
+ IECM_CTLQ_RC_EFBIG = 22, /* File too big */
+ IECM_CTLQ_RC_ENOSEC = 24, /* Missing security manifest */
+ IECM_CTLQ_RC_EBADSIG = 25, /* Bad RSA signature */
+ IECM_CTLQ_RC_ESVN = 26, /* SVN number prohibits this package */
+ IECM_CTLQ_RC_EBADMAN = 27, /* Manifest hash mismatch */
+ IECM_CTLQ_RC_EBADBUF = 28, /* Buffer hash mismatches manifest */
+};
+
+/* Used for queue init, response and events */
+enum iecm_ctlq_type {
+ IECM_CTLQ_TYPE_MAILBOX_TX = 0,
+ IECM_CTLQ_TYPE_MAILBOX_RX = 1,
+ IECM_CTLQ_TYPE_CONFIG_TX = 2,
+ IECM_CTLQ_TYPE_CONFIG_RX = 3,
+ IECM_CTLQ_TYPE_EVENT_RX = 4,
+ IECM_CTLQ_TYPE_RDMA_TX = 5,
+ IECM_CTLQ_TYPE_RDMA_RX = 6,
+ IECM_CTLQ_TYPE_RDMA_COMPL = 7
+};
+
+/* Generic Control Queue Structures */
+
+struct iecm_ctlq_reg {
+ /* used for queue tracking */
+ u32 head;
+ u32 tail;
+ /* Below applies only to default mb (if present) */
+ u32 len;
+ u32 bah;
+ u32 bal;
+ u32 len_mask;
+ u32 len_ena_mask;
+ u32 head_mask;
+};
+
+/* Generic queue msg structure */
+struct iecm_ctlq_msg {
+ u16 vmvf_type; /* represents the source of the message on recv */
+#define IECM_VMVF_TYPE_VF 0
+#define IECM_VMVF_TYPE_VM 1
+#define IECM_VMVF_TYPE_PF 2
+ u16 opcode;
+ u16 data_len; /* data_len = 0 when no payload is attached */
+ union {
+ u16 func_id; /* when sending a message */
+ u16 status; /* when receiving a message */
+ };
+ union {
+ struct {
+ u32 chnl_retval;
+ u32 chnl_opcode;
+ } mbx;
+ } cookie;
+ union {
+#define IECM_DIRECT_CTX_SIZE 16
+#define IECM_INDIRECT_CTX_SIZE 8
+ /* 16 bytes of context can be provided or 8 bytes of context
+ * plus the address of a DMA buffer
+ */
+ u8 direct[IECM_DIRECT_CTX_SIZE];
+ struct {
+ u8 context[IECM_INDIRECT_CTX_SIZE];
+ struct iecm_dma_mem *payload;
+ } indirect;
+ } ctx;
+};
+
+/* Generic queue info structures */
+/* MB, CONFIG and EVENT q do not have extended info */
+struct iecm_ctlq_create_info {
+ enum iecm_ctlq_type type;
+ /* absolute queue offset passed as input
+ * -1 for default mailbox if present
+ */
+ int id;
+ u16 len; /* Queue length passed as input */
+ u16 buf_size; /* buffer size passed as input */
+ u64 base_address; /* output, HPA of the Queue start */
+ struct iecm_ctlq_reg reg; /* registers accessed by ctlqs */
+
+ int ext_info_size;
+ void *ext_info; /* Specific to q type */
+};
+
+/* Control Queue information */
+struct iecm_ctlq_info {
+ struct list_head cq_list;
+
+ enum iecm_ctlq_type cq_type;
+ int q_id;
+ struct mutex cq_lock; /* queue lock */
+
+ /* used for interrupt processing */
+ u16 next_to_use;
+ u16 next_to_clean;
+
+ /* starting descriptor to post buffers to after recev */
+ u16 next_to_post;
+ struct iecm_dma_mem desc_ring; /* descriptor ring memory */
+
+ union {
+ struct iecm_dma_mem **rx_buff;
+ struct iecm_ctlq_msg **tx_msg;
+ } bi;
+
+ u16 buf_size; /* queue buffer size */
+ u16 ring_size; /* Number of descriptors */
+ struct iecm_ctlq_reg reg; /* registers accessed by ctlqs */
+};
+
+/* PF/VF mailbox commands */
+enum iecm_mbx_opc {
+ iecm_mbq_opc_send_msg_to_cp = 0x0801,
+ iecm_mbq_opc_send_msg_to_vf = 0x0802,
+ iecm_mbq_opc_send_msg_to_pf = 0x0803,
+};
+
+/* API supported for control queue management */
+
+/* Will init all required q including default mb. "q_info" is an array of
+ * create_info structs equal to the number of control queues to be created.
+ */
+enum iecm_status iecm_ctlq_init(struct iecm_hw *hw, u8 num_q,
+ struct iecm_ctlq_create_info *q_info);
+
+/* Allocate and initialize a single control queue, which will be added to the
+ * control queue list; returns a handle to the created control queue
+ */
+enum iecm_status iecm_ctlq_add(struct iecm_hw *hw,
+ struct iecm_ctlq_create_info *qinfo,
+ struct iecm_ctlq_info **cq);
+/* Deinitialize and deallocate a single control queue */
+void iecm_ctlq_remove(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq);
+
+/* Sends messages to HW and will also free the buffer*/
+enum iecm_status iecm_ctlq_send(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq,
+ u16 num_q_msg,
+ struct iecm_ctlq_msg q_msg[]);
+
+/* Receives messages and called by interrupt handler/polling
+ * initiated by app/process. Also caller is supposed to free the buffers
+ */
+enum iecm_status iecm_ctlq_recv(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq,
+ u16 *num_q_msg, struct iecm_ctlq_msg *q_msg);
+/* Reclaims send descriptors on HW write back */
+enum iecm_status iecm_ctlq_clean_sq(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq,
+ u16 *clean_count,
+ struct iecm_ctlq_msg *msg_status[]);
+
+/* Indicate RX buffers are done being processed */
+enum iecm_status iecm_ctlq_post_rx_buffs(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq,
+ u16 *buff_count,
+ struct iecm_dma_mem **buffs);
+
+/* Will destroy all q including the default mb */
+enum iecm_status iecm_ctlq_deinit(struct iecm_hw *hw);
+
+#endif /* _IECM_CONTROLQ_API_H_ */
diff --git a/include/linux/net/intel/iecm_osdep.h b/include/linux/net/intel/iecm_osdep.h
new file mode 100644
index 000000000000..59f64f66b9f0
--- /dev/null
+++ b/include/linux/net/intel/iecm_osdep.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2020, Intel Corporation. */
+
+#ifndef _IECM_OSDEP_H_
+#define _IECM_OSDEP_H_
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/net/intel/iecm_alloc.h>
+
+#define wr32(a, reg, value) writel((value), (u8 *)((a)->hw_addr + (reg)))
+#define rd32(a, reg) readl((u8 *)(a)->hw_addr + (reg))
+#define wr64(a, reg, value) writeq((value), (u8 *)((a)->hw_addr + (reg)))
+#define rd64(a, reg) readq((u8 *)(a)->hw_addr + (reg))
+
+struct iecm_dma_mem {
+ void *va;
+ dma_addr_t pa;
+ size_t size;
+};
+
+#define iecm_wmb() wmb() /* memory barrier */
+#endif /* _IECM_OSDEP_H_ */
diff --git a/include/linux/net/intel/iecm_type.h b/include/linux/net/intel/iecm_type.h
new file mode 100644
index 000000000000..5a599285b548
--- /dev/null
+++ b/include/linux/net/intel/iecm_type.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2020, Intel Corporation. */
+
+#ifndef _IECM_TYPE_H_
+#define _IECM_TYPE_H_
+
+#include <linux/if_ether.h>
+#include <linux/net/intel/iecm_osdep.h>
+#include <linux/net/intel/iecm_alloc.h>
+#include <linux/net/intel/iecm_controlq.h>
+
+#define MAKEMASK(m, s) ((m) << (s))
+
+/* Bus parameters */
+struct iecm_bus_info {
+ u16 func;
+ u16 device;
+ u16 bus_id;
+};
+
+/* Define the APF hardware struct to replace other control structs as needed
+ * Align to ctlq_hw_info
+ */
+struct iecm_hw {
+ u8 *hw_addr;
+ u64 hw_addr_len;
+ void *back;
+
+ /* control queue - send and receive */
+ struct iecm_ctlq_info *asq;
+ struct iecm_ctlq_info *arq;
+
+ /* subsystem structs */
+ struct iecm_bus_info bus;
+
+ /* pci info */
+ u16 device_id;
+ u16 vendor_id;
+ u16 subsystem_device_id;
+ u16 subsystem_vendor_id;
+ u8 revision_id;
+ bool adapter_stopped;
+
+ struct list_head cq_list_head;
+};
+
+#endif /* _IECM_TYPE_H_ */
--
2.26.2
^ permalink raw reply related
* [net-next 00/15][pull request] Intel Wired LAN Driver Updates 2020-06-17
From: Jeff Kirsher @ 2020-06-18 5:13 UTC (permalink / raw)
To: davem; +Cc: Jeff Kirsher, netdev, nhorman, sassmann
This series introduces both the Intel Ethernet Common Module and the Intel
Data Plane Function. The patches also incorporate extended features and
functionality added in the virtchnl.h file.
The format of the series flow is to add the data set, then introduce
function stubs and finally introduce pieces in large cohesive subjects or
functionality. This is to allow for more in depth understanding and
review of the bigger picture as the series is reviewed.
Currently this is common layer (iecm) is initially only being used by only
the idpf driver (PF driver for SmartNIC). However, the plan is to
eventually switch our iavf driver along with future drivers to use this
common module. The hope is to better enable code sharing going forward as
well as support other developers writing drivers for our hardware
The following are changes since commit 69119673bd50b176ded34032fadd41530fb5af21:
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
and are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue 100GbE
Alan Brady (1):
idpf: Introduce idpf driver
Alice Michael (14):
virtchnl: Extend AVF ops
iecm: Add framework set of header files
iecm: Add TX/RX header files
iecm: Common module introduction and function stubs
iecm: Add basic netdevice functionality
iecm: Implement mailbox functionality
iecm: Implement virtchnl commands
iecm: Implement vector allocation
iecm: Init and allocate vport
iecm: Deinit vport
iecm: Add splitq TX/RX
iecm: Add singleq TX/RX
iecm: Add ethtool
iecm: Add iecm to the kernel build system
.../networking/device_drivers/intel/idpf.rst | 47 +
.../networking/device_drivers/intel/iecm.rst | 93 +
MAINTAINERS | 3 +
drivers/net/ethernet/intel/Kconfig | 15 +
drivers/net/ethernet/intel/Makefile | 2 +
drivers/net/ethernet/intel/idpf/Makefile | 12 +
drivers/net/ethernet/intel/idpf/idpf_dev.h | 17 +
drivers/net/ethernet/intel/idpf/idpf_devids.h | 10 +
drivers/net/ethernet/intel/idpf/idpf_main.c | 136 +
drivers/net/ethernet/intel/idpf/idpf_reg.c | 152 +
drivers/net/ethernet/intel/iecm/Makefile | 19 +
.../net/ethernet/intel/iecm/iecm_controlq.c | 673 +++
.../ethernet/intel/iecm/iecm_controlq_setup.c | 177 +
.../net/ethernet/intel/iecm/iecm_ethtool.c | 1121 +++++
drivers/net/ethernet/intel/iecm/iecm_lib.c | 1092 +++++
drivers/net/ethernet/intel/iecm/iecm_main.c | 50 +
drivers/net/ethernet/intel/iecm/iecm_osdep.c | 28 +
.../ethernet/intel/iecm/iecm_singleq_txrx.c | 889 ++++
drivers/net/ethernet/intel/iecm/iecm_txrx.c | 3960 +++++++++++++++++
.../net/ethernet/intel/iecm/iecm_virtchnl.c | 2233 ++++++++++
include/linux/avf/virtchnl.h | 592 +++
include/linux/net/intel/iecm.h | 432 ++
include/linux/net/intel/iecm_alloc.h | 29 +
include/linux/net/intel/iecm_controlq.h | 95 +
include/linux/net/intel/iecm_controlq_api.h | 221 +
include/linux/net/intel/iecm_lan_pf_regs.h | 120 +
include/linux/net/intel/iecm_lan_txrx.h | 636 +++
include/linux/net/intel/iecm_osdep.h | 24 +
include/linux/net/intel/iecm_txrx.h | 610 +++
include/linux/net/intel/iecm_type.h | 47 +
30 files changed, 13535 insertions(+)
create mode 100644 Documentation/networking/device_drivers/intel/idpf.rst
create mode 100644 Documentation/networking/device_drivers/intel/iecm.rst
create mode 100644 drivers/net/ethernet/intel/idpf/Makefile
create mode 100644 drivers/net/ethernet/intel/idpf/idpf_dev.h
create mode 100644 drivers/net/ethernet/intel/idpf/idpf_devids.h
create mode 100644 drivers/net/ethernet/intel/idpf/idpf_main.c
create mode 100644 drivers/net/ethernet/intel/idpf/idpf_reg.c
create mode 100644 drivers/net/ethernet/intel/iecm/Makefile
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_controlq.c
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_controlq_setup.c
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_ethtool.c
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_lib.c
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_main.c
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_osdep.c
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_singleq_txrx.c
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_txrx.c
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
create mode 100644 include/linux/net/intel/iecm.h
create mode 100644 include/linux/net/intel/iecm_alloc.h
create mode 100644 include/linux/net/intel/iecm_controlq.h
create mode 100644 include/linux/net/intel/iecm_controlq_api.h
create mode 100644 include/linux/net/intel/iecm_lan_pf_regs.h
create mode 100644 include/linux/net/intel/iecm_lan_txrx.h
create mode 100644 include/linux/net/intel/iecm_osdep.h
create mode 100644 include/linux/net/intel/iecm_txrx.h
create mode 100644 include/linux/net/intel/iecm_type.h
--
2.26.2
^ permalink raw reply
* Re: [PATCH net-next 3/5] cxgb4: add support to flash boot image
From: Vishal Kulkarni @ 2020-06-18 5:08 UTC (permalink / raw)
To: Jakub Kicinski
Cc: netdev@vger.kernel.org, davem@davemloft.net,
Nirranjan Kirubaharan, dt
In-Reply-To: <20200617092527.30333c1f@kicinski-fedora-PC1C0HJN>
On Wednesday, June 06/17/20, 2020 at 21:55:27 +0530, Jakub Kicinski wrote:
> On Wed, 17 Jun 2020 11:59:05 +0530 Vishal Kulkarni wrote:
> > Update set_flash to flash boot image to flash region
> >
> > Signed-off-by: Vishal Kulkarni <vishal@chelsio.com>
>
> This patch adds 4 new warnings to the plethora of warnings in
> drivers/net/ethernet/chelsio/cxgb4/t4_hw.c when built with W=1 C=1 flags.
>
> Please don't add new ones. And preferably address the existing
> hundreds of warnings in your driver.
Hi Jakub,
Thank you for feedback. I will fix those 4 new warnings and post v2.
As for old ones, We have already started on addressing them
and will post patches soon.
-Vishal
^ permalink raw reply
* RE: [PATCH bpf-next] bpf: sk_storage: Prefer to get a free cache_idx
From: John Fastabend @ 2020-06-18 5:01 UTC (permalink / raw)
To: Martin KaFai Lau, bpf
Cc: Alexei Starovoitov, Daniel Borkmann, kernel-team, netdev
In-Reply-To: <20200617174226.2301909-1-kafai@fb.com>
Martin KaFai Lau wrote:
> The cache_idx is currently picked by RR. There is chance that
> the same cache_idx will be picked by multiple sk_storage_maps while
> other cache_idx is still unused. e.g. It could happen when the
> sk_storage_map is recreated during the restart of the user
> space process.
>
> This patch tracks the usage count for each cache_idx. There is
> 16 of them now (defined in BPF_SK_STORAGE_CACHE_SIZE).
> It will try to pick the free cache_idx. If none was found,
> it would pick one with the minimal usage count.
>
> Signed-off-by: Martin KaFai Lau <kafai@fb.com>
> ---
> net/core/bpf_sk_storage.c | 41 +++++++++++++++++++++++++++++++++++----
> 1 file changed, 37 insertions(+), 4 deletions(-)
>
Acked-by: John Fastabend <john.fastabend@gmail.com>
^ permalink raw reply
* memory leak in macvlan_hash_add_source
From: syzbot @ 2020-06-18 4:04 UTC (permalink / raw)
To: davem, kuba, linux-kernel, netdev, syzkaller-bugs
Hello,
syzbot found the following crash on:
HEAD commit: 7ae77150 Merge tag 'powerpc-5.8-1' of git://git.kernel.org..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=11fbb456100000
kernel config: https://syzkaller.appspot.com/x/.config?x=9a1aa05456dfd557
dashboard link: https://syzkaller.appspot.com/bug?extid=62100d232f618b7da606
compiler: gcc (GCC) 9.0.0 20181231 (experimental)
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=163092a9100000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=12caed7a100000
IMPORTANT: if you fix the bug, please add the following tag to the commit:
Reported-by: syzbot+62100d232f618b7da606@syzkaller.appspotmail.com
BUG: memory leak
unreferenced object 0xffff888115ac4080 (size 64):
comm "syz-executor882", pid 6646, jiffies 4294954688 (age 14.840s)
hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 20 ee 41 15 81 88 ff ff ........ .A.....
00 09 92 15 81 88 ff ff aa aa aa aa aa 23 00 00 .............#..
backtrace:
[<00000000fe90004e>] kmalloc include/linux/slab.h:555 [inline]
[<00000000fe90004e>] macvlan_hash_add_source+0x52/0xe0 drivers/net/macvlan.c:161
[<000000005aee7a07>] macvlan_changelink_sources+0x8a/0x1f0 drivers/net/macvlan.c:1355
[<00000000e0e074d6>] macvlan_common_newlink+0x21a/0x570 drivers/net/macvlan.c:1463
[<00000000c89166a4>] __rtnl_newlink+0x843/0xb10 net/core/rtnetlink.c:3340
[<000000009677515c>] rtnl_newlink+0x49/0x70 net/core/rtnetlink.c:3398
[<00000000fab710c9>] rtnetlink_rcv_msg+0x173/0x4b0 net/core/rtnetlink.c:5461
[<00000000d3f45a45>] netlink_rcv_skb+0x5a/0x180 net/netlink/af_netlink.c:2469
[<00000000b9db6049>] netlink_unicast_kernel net/netlink/af_netlink.c:1303 [inline]
[<00000000b9db6049>] netlink_unicast+0x20a/0x2f0 net/netlink/af_netlink.c:1329
[<000000006a00463c>] netlink_sendmsg+0x2b5/0x560 net/netlink/af_netlink.c:1918
[<00000000a31e18a9>] sock_sendmsg_nosec net/socket.c:652 [inline]
[<00000000a31e18a9>] sock_sendmsg+0x4c/0x60 net/socket.c:672
[<000000000ca330a5>] ____sys_sendmsg+0x118/0x2f0 net/socket.c:2352
[<000000006a5fc310>] ___sys_sendmsg+0x8a/0xd0 net/socket.c:2406
[<000000004d3b2570>] __sys_sendmmsg+0xda/0x230 net/socket.c:2496
[<00000000a524412c>] __do_sys_sendmmsg net/socket.c:2525 [inline]
[<00000000a524412c>] __se_sys_sendmmsg net/socket.c:2522 [inline]
[<00000000a524412c>] __x64_sys_sendmmsg+0x24/0x30 net/socket.c:2522
[<00000000333adef2>] do_syscall_64+0x6e/0x220 arch/x86/entry/common.c:295
[<00000000df7893d8>] entry_SYSCALL_64_after_hwframe+0x44/0xa9
---
This bug is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
syzbot will keep track of this bug report. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
syzbot can test patches for this bug, for details see:
https://goo.gl/tpsmEJ#testing-patches
^ permalink raw reply
* [PATCH] [net/sched]: Remove redundant condition in qdisc_graft
From: Gaurav Singh @ 2020-06-18 4:00 UTC (permalink / raw)
To: gaurav1086, Jamal Hadi Salim, Cong Wang, Jiri Pirko,
David S. Miller, Jakub Kicinski, open list:TC subsystem,
open list
In-Reply-To: <20200618012308.28153-1-gaurav1086@gmail.com>
parent cannot be NULL here since its in the else part
of the if (parent == NULL) condition. Remove the extra
check on parent pointer.
Signed-off-by: Gaurav Singh <gaurav1086@gmail.com>
---
net/sched/sch_api.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 9a3449b56bd6..be93ebcdb18d 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1094,7 +1094,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
/* Only support running class lockless if parent is lockless */
if (new && (new->flags & TCQ_F_NOLOCK) &&
- parent && !(parent->flags & TCQ_F_NOLOCK))
+ !(parent->flags & TCQ_F_NOLOCK))
qdisc_clear_nolock(new);
if (!cops || !cops->graft)
--
2.17.1
^ permalink raw reply related
* [PATCH v2 net-next 5/6] net: tso: cache transport header length
From: Eric Dumazet @ 2020-06-18 3:53 UTC (permalink / raw)
To: David S . Miller
Cc: netdev, Eric Dumazet, Eric Dumazet, Jakub Kicinski,
Willem de Bruijn, Sunil Goutham, Antoine Tenart
In-Reply-To: <20200618035326.39686-1-edumazet@google.com>
Add tlen field into struct tso_t, and change tso_start()
to return skb_transport_offset(skb) + tso->tlen
This removes from callers the need to use tcp_hdrlen(skb) and
will ease UDP segmentation offload addition.
v2: calls tso_start() earlier in otx2_sq_append_tso() [Jakub]
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
drivers/net/ethernet/cavium/thunder/nicvf_queues.c | 5 +++--
drivers/net/ethernet/freescale/fec_main.c | 5 ++---
drivers/net/ethernet/marvell/mv643xx_eth.c | 5 ++---
drivers/net/ethernet/marvell/mvneta.c | 5 ++---
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 6 +++---
.../net/ethernet/marvell/octeontx2/nic/otx2_txrx.c | 6 +++---
include/net/tso.h | 3 ++-
net/core/tso.c | 11 +++++++----
8 files changed, 24 insertions(+), 22 deletions(-)
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
index 069e7413f1ef57ef401adfa6c7efdaad8005aba0..a45223f0cca5813324dd6543095f5375ffe5f27e 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
@@ -1489,9 +1489,10 @@ static int nicvf_sq_append_tso(struct nicvf *nic, struct snd_queue *sq,
int seg_subdescs = 0, desc_cnt = 0;
int seg_len, total_len, data_left;
int hdr_qentry = qentry;
- int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ int hdr_len;
+
+ hdr_len = tso_start(skb, &tso);
- tso_start(skb, &tso);
total_len = skb->len - hdr_len;
while (total_len > 0) {
char *hdr;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 2d0d313ee7c5a193a805f858b9fcd83f98a4ebea..9f80a33c5b16b07b30aa8ebfbc4dc8338a6ae056 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -710,8 +710,7 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
- int total_len, data_left;
+ int hdr_len, total_len, data_left;
struct bufdesc *bdp = txq->bd.cur;
struct tso_t tso;
unsigned int index = 0;
@@ -731,7 +730,7 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
}
/* Initialize the TSO handler, and prepare the first payload */
- tso_start(skb, &tso);
+ hdr_len = tso_start(skb, &tso);
total_len = skb->len - hdr_len;
while (total_len > 0) {
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 4d4b6243318a59ac01190446766d2864f016564e..90e6111ce534dba7f16de983549ade748890124c 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -816,10 +816,9 @@ static int txq_submit_tso(struct tx_queue *txq, struct sk_buff *skb,
struct net_device *dev)
{
struct mv643xx_eth_private *mp = txq_to_mp(txq);
- int total_len, data_left, ret;
+ int hdr_len, total_len, data_left, ret;
int desc_count = 0;
struct tso_t tso;
- int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
struct tx_desc *first_tx_desc;
u32 first_cmd_sts = 0;
@@ -832,7 +831,7 @@ static int txq_submit_tso(struct tx_queue *txq, struct sk_buff *skb,
first_tx_desc = &txq->tx_desc_area[txq->tx_curr_desc];
/* Initialize the TSO handler, and prepare the first payload */
- tso_start(skb, &tso);
+ hdr_len = tso_start(skb, &tso);
total_len = skb->len - hdr_len;
while (total_len > 0) {
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index 946925bbcb2de93629f45c3b9eecbfaf7338e8d1..95b447c14411479a026cf5a0375e79b345152d7c 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -2604,11 +2604,10 @@ mvneta_tso_put_data(struct net_device *dev, struct mvneta_tx_queue *txq,
static int mvneta_tx_tso(struct sk_buff *skb, struct net_device *dev,
struct mvneta_tx_queue *txq)
{
- int total_len, data_left;
+ int hdr_len, total_len, data_left;
int desc_count = 0;
struct mvneta_port *pp = netdev_priv(dev);
struct tso_t tso;
- int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
int i;
/* Count needed descriptors */
@@ -2621,7 +2620,7 @@ static int mvneta_tx_tso(struct sk_buff *skb, struct net_device *dev,
}
/* Initialize the TSO handler, and prepare the first payload */
- tso_start(skb, &tso);
+ hdr_len = tso_start(skb, &tso);
total_len = skb->len - hdr_len;
while (total_len > 0) {
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index 24f4d8e0da989daaca10333ec9c5a3a22ec66c48..e9f28756802628cc0a77dd80451a36ffe4b7f19c 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -3160,9 +3160,8 @@ static int mvpp2_tx_tso(struct sk_buff *skb, struct net_device *dev,
struct mvpp2_txq_pcpu *txq_pcpu)
{
struct mvpp2_port *port = netdev_priv(dev);
+ int hdr_sz, i, len, descs = 0;
struct tso_t tso;
- int hdr_sz = skb_transport_offset(skb) + tcp_hdrlen(skb);
- int i, len, descs = 0;
/* Check number of available descriptors */
if (mvpp2_aggr_desc_num_check(port, aggr_txq, tso_count_descs(skb)) ||
@@ -3170,7 +3169,8 @@ static int mvpp2_tx_tso(struct sk_buff *skb, struct net_device *dev,
tso_count_descs(skb)))
return 0;
- tso_start(skb, &tso);
+ hdr_sz = tso_start(skb, &tso);
+
len = skb->len - hdr_sz;
while (len > 0) {
int left = min_t(int, skb_shinfo(skb)->gso_size, len);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
index b04f5429d72d911da145ee13b99506d84a9d7925..3a5b34a2a7a653370f66272487cd7c2f69985142 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
@@ -619,13 +619,14 @@ static void otx2_sq_append_tso(struct otx2_nic *pfvf, struct otx2_snd_queue *sq,
struct sk_buff *skb, u16 qidx)
{
struct netdev_queue *txq = netdev_get_tx_queue(pfvf->netdev, qidx);
- int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
- int tcp_data, seg_len, pkt_len, offset;
+ int hdr_len, tcp_data, seg_len, pkt_len, offset;
struct nix_sqe_hdr_s *sqe_hdr;
int first_sqe = sq->head;
struct sg_list list;
struct tso_t tso;
+ hdr_len = tso_start(skb, &tso);
+
/* Map SKB's fragments to DMA.
* It's done here to avoid mapping for every TSO segment's packet.
*/
@@ -636,7 +637,6 @@ static void otx2_sq_append_tso(struct otx2_nic *pfvf, struct otx2_snd_queue *sq,
netdev_tx_sent_queue(txq, skb->len);
- tso_start(skb, &tso);
tcp_data = skb->len - hdr_len;
while (tcp_data > 0) {
char *hdr;
diff --git a/include/net/tso.h b/include/net/tso.h
index 32d9272ade6af0e3dd1272ecafa948f1535ea61f..62c98a9c60f15d7b4869f1ab523dfeb83fb18ba6 100644
--- a/include/net/tso.h
+++ b/include/net/tso.h
@@ -11,6 +11,7 @@ struct tso_t {
int size;
void *data;
u16 ip_id;
+ u8 tlen; /* transport header len */
bool ipv6;
u32 tcp_seq;
};
@@ -19,6 +20,6 @@ int tso_count_descs(const struct sk_buff *skb);
void tso_build_hdr(const struct sk_buff *skb, char *hdr, struct tso_t *tso,
int size, bool is_last);
void tso_build_data(const struct sk_buff *skb, struct tso_t *tso, int size);
-void tso_start(struct sk_buff *skb, struct tso_t *tso);
+int tso_start(struct sk_buff *skb, struct tso_t *tso);
#endif /* _TSO_H */
diff --git a/net/core/tso.c b/net/core/tso.c
index 56487e3bb26dc01b65f73f96fd0157bec73ea0d0..9f35518815bda275106d27bc5cc34b019429d254 100644
--- a/net/core/tso.c
+++ b/net/core/tso.c
@@ -17,7 +17,7 @@ void tso_build_hdr(const struct sk_buff *skb, char *hdr, struct tso_t *tso,
int size, bool is_last)
{
struct tcphdr *tcph;
- int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ int hdr_len = skb_transport_offset(skb) + tso->tlen;
int mac_hdr_len = skb_network_offset(skb);
memcpy(hdr, skb->data, hdr_len);
@@ -30,7 +30,7 @@ void tso_build_hdr(const struct sk_buff *skb, char *hdr, struct tso_t *tso,
} else {
struct ipv6hdr *iph = (void *)(hdr + mac_hdr_len);
- iph->payload_len = htons(size + tcp_hdrlen(skb));
+ iph->payload_len = htons(size + tso->tlen);
}
tcph = (struct tcphdr *)(hdr + skb_transport_offset(skb));
put_unaligned_be32(tso->tcp_seq, &tcph->seq);
@@ -62,10 +62,12 @@ void tso_build_data(const struct sk_buff *skb, struct tso_t *tso, int size)
}
EXPORT_SYMBOL(tso_build_data);
-void tso_start(struct sk_buff *skb, struct tso_t *tso)
+int tso_start(struct sk_buff *skb, struct tso_t *tso)
{
- int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ int tlen = tcp_hdrlen(skb);
+ int hdr_len = skb_transport_offset(skb) + tlen;
+ tso->tlen = tlen;
tso->ip_id = ntohs(ip_hdr(skb)->id);
tso->tcp_seq = ntohl(tcp_hdr(skb)->seq);
tso->next_frag_idx = 0;
@@ -83,5 +85,6 @@ void tso_start(struct sk_buff *skb, struct tso_t *tso)
tso->data = skb_frag_address(frag);
tso->next_frag_idx++;
}
+ return hdr_len;
}
EXPORT_SYMBOL(tso_start);
--
2.27.0.290.gba653c62da-goog
^ permalink raw reply related
* [PATCH v2 net-next 6/6] net: tso: add UDP segmentation support
From: Eric Dumazet @ 2020-06-18 3:53 UTC (permalink / raw)
To: David S . Miller
Cc: netdev, Eric Dumazet, Eric Dumazet, Jakub Kicinski,
Willem de Bruijn, Sunil Goutham, Antoine Tenart
In-Reply-To: <20200618035326.39686-1-edumazet@google.com>
Note that like TCP, we do not support additional encapsulations,
and that checksums must be offloaded to the NIC.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
net/core/tso.c | 29 ++++++++++++++++++-----------
1 file changed, 18 insertions(+), 11 deletions(-)
diff --git a/net/core/tso.c b/net/core/tso.c
index 9f35518815bda275106d27bc5cc34b019429d254..4148f6d48953e1e1ebd878c3953f3e41d47832d9 100644
--- a/net/core/tso.c
+++ b/net/core/tso.c
@@ -16,7 +16,6 @@ EXPORT_SYMBOL(tso_count_descs);
void tso_build_hdr(const struct sk_buff *skb, char *hdr, struct tso_t *tso,
int size, bool is_last)
{
- struct tcphdr *tcph;
int hdr_len = skb_transport_offset(skb) + tso->tlen;
int mac_hdr_len = skb_network_offset(skb);
@@ -32,21 +31,29 @@ void tso_build_hdr(const struct sk_buff *skb, char *hdr, struct tso_t *tso,
iph->payload_len = htons(size + tso->tlen);
}
- tcph = (struct tcphdr *)(hdr + skb_transport_offset(skb));
- put_unaligned_be32(tso->tcp_seq, &tcph->seq);
+ hdr += skb_transport_offset(skb);
+ if (tso->tlen != sizeof(struct udphdr)) {
+ struct tcphdr *tcph = (struct tcphdr *)hdr;
- if (!is_last) {
- /* Clear all special flags for not last packet */
- tcph->psh = 0;
- tcph->fin = 0;
- tcph->rst = 0;
+ put_unaligned_be32(tso->tcp_seq, &tcph->seq);
+
+ if (!is_last) {
+ /* Clear all special flags for not last packet */
+ tcph->psh = 0;
+ tcph->fin = 0;
+ tcph->rst = 0;
+ }
+ } else {
+ struct udphdr *uh = (struct udphdr *)hdr;
+
+ uh->len = htons(sizeof(*uh) + size);
}
}
EXPORT_SYMBOL(tso_build_hdr);
void tso_build_data(const struct sk_buff *skb, struct tso_t *tso, int size)
{
- tso->tcp_seq += size;
+ tso->tcp_seq += size; /* not worth avoiding this operation for UDP */
tso->size -= size;
tso->data += size;
@@ -64,12 +71,12 @@ EXPORT_SYMBOL(tso_build_data);
int tso_start(struct sk_buff *skb, struct tso_t *tso)
{
- int tlen = tcp_hdrlen(skb);
+ int tlen = skb_is_gso_tcp(skb) ? tcp_hdrlen(skb) : sizeof(struct udphdr);
int hdr_len = skb_transport_offset(skb) + tlen;
tso->tlen = tlen;
tso->ip_id = ntohs(ip_hdr(skb)->id);
- tso->tcp_seq = ntohl(tcp_hdr(skb)->seq);
+ tso->tcp_seq = (tlen != sizeof(struct udphdr)) ? ntohl(tcp_hdr(skb)->seq) : 0;
tso->next_frag_idx = 0;
tso->ipv6 = vlan_get_protocol(skb) == htons(ETH_P_IPV6);
--
2.27.0.290.gba653c62da-goog
^ permalink raw reply related
* [PATCH v2 net-next 4/6] net: tso: constify tso_count_descs() and friends
From: Eric Dumazet @ 2020-06-18 3:53 UTC (permalink / raw)
To: David S . Miller
Cc: netdev, Eric Dumazet, Eric Dumazet, Jakub Kicinski,
Willem de Bruijn, Sunil Goutham, Antoine Tenart
In-Reply-To: <20200618035326.39686-1-edumazet@google.com>
skb argument of tso_count_descs(), tso_build_hdr() and tso_build_data() can be const.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
include/net/tso.h | 6 +++---
net/core/tso.c | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/include/net/tso.h b/include/net/tso.h
index d9b0a14b2a57b388ae4518fc63497ffd600b8887..32d9272ade6af0e3dd1272ecafa948f1535ea61f 100644
--- a/include/net/tso.h
+++ b/include/net/tso.h
@@ -15,10 +15,10 @@ struct tso_t {
u32 tcp_seq;
};
-int tso_count_descs(struct sk_buff *skb);
-void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso,
+int tso_count_descs(const struct sk_buff *skb);
+void tso_build_hdr(const struct sk_buff *skb, char *hdr, struct tso_t *tso,
int size, bool is_last);
-void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size);
+void tso_build_data(const struct sk_buff *skb, struct tso_t *tso, int size);
void tso_start(struct sk_buff *skb, struct tso_t *tso);
#endif /* _TSO_H */
diff --git a/net/core/tso.c b/net/core/tso.c
index d4d5c077ad7293aa71c3a64f67629e1079060227..56487e3bb26dc01b65f73f96fd0157bec73ea0d0 100644
--- a/net/core/tso.c
+++ b/net/core/tso.c
@@ -6,14 +6,14 @@
#include <asm/unaligned.h>
/* Calculate expected number of TX descriptors */
-int tso_count_descs(struct sk_buff *skb)
+int tso_count_descs(const struct sk_buff *skb)
{
/* The Marvell Way */
return skb_shinfo(skb)->gso_segs * 2 + skb_shinfo(skb)->nr_frags;
}
EXPORT_SYMBOL(tso_count_descs);
-void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso,
+void tso_build_hdr(const struct sk_buff *skb, char *hdr, struct tso_t *tso,
int size, bool is_last)
{
struct tcphdr *tcph;
@@ -44,7 +44,7 @@ void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso,
}
EXPORT_SYMBOL(tso_build_hdr);
-void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size)
+void tso_build_data(const struct sk_buff *skb, struct tso_t *tso, int size)
{
tso->tcp_seq += size;
tso->size -= size;
--
2.27.0.290.gba653c62da-goog
^ permalink raw reply related
* [PATCH v2 net-next 2/6] net: tso: double TSO_HEADER_SIZE value
From: Eric Dumazet @ 2020-06-18 3:53 UTC (permalink / raw)
To: David S . Miller
Cc: netdev, Eric Dumazet, Eric Dumazet, Jakub Kicinski,
Willem de Bruijn, Sunil Goutham, Antoine Tenart
In-Reply-To: <20200618035326.39686-1-edumazet@google.com>
Transport header size could be 60 bytes, and network header
size can also be 60 bytes. Add the Ethernet header and we
are above 128 bytes.
Since drivers using net/core/tso.c usually allocates
one DMA coherent piece of memory per TX queue, this patch
might cause issues if a driver was using too many slots.
For 1024 slots, we would need 256 KB of physically
contiguous memory instead of 128 KB.
Alternative fix would be to add checks in the fast path,
but this involves more work in all drivers using net/core/tso.c.
Fixes: f9cbe9a556af ("net: define the TSO header size in net/tso.h")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Antoine Tenart <antoine.tenart@bootlin.com>
---
include/net/tso.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/net/tso.h b/include/net/tso.h
index 7e166a5703497fadf4662acc474f827b2754da78..c33dd00c161f7a6aa65f586b0ceede46af2e8730 100644
--- a/include/net/tso.h
+++ b/include/net/tso.h
@@ -4,7 +4,7 @@
#include <net/ip.h>
-#define TSO_HEADER_SIZE 128
+#define TSO_HEADER_SIZE 256
struct tso_t {
int next_frag_idx;
--
2.27.0.290.gba653c62da-goog
^ permalink raw reply related
* [PATCH v2 net-next 3/6] net: tso: shrink struct tso_t
From: Eric Dumazet @ 2020-06-18 3:53 UTC (permalink / raw)
To: David S . Miller
Cc: netdev, Eric Dumazet, Eric Dumazet, Jakub Kicinski,
Willem de Bruijn, Sunil Goutham, Antoine Tenart
In-Reply-To: <20200618035326.39686-1-edumazet@google.com>
size field can be an int, no need for size_t
Removes a 32bit hole on 64bit kernels.
And align fields for better readability.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
include/net/tso.h | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/include/net/tso.h b/include/net/tso.h
index c33dd00c161f7a6aa65f586b0ceede46af2e8730..d9b0a14b2a57b388ae4518fc63497ffd600b8887 100644
--- a/include/net/tso.h
+++ b/include/net/tso.h
@@ -7,12 +7,12 @@
#define TSO_HEADER_SIZE 256
struct tso_t {
- int next_frag_idx;
- void *data;
- size_t size;
- u16 ip_id;
- bool ipv6;
- u32 tcp_seq;
+ int next_frag_idx;
+ int size;
+ void *data;
+ u16 ip_id;
+ bool ipv6;
+ u32 tcp_seq;
};
int tso_count_descs(struct sk_buff *skb);
--
2.27.0.290.gba653c62da-goog
^ permalink raw reply related
* [PATCH v2 net-next 1/6] octeontx2-af: change (struct qmem)->entry_sz from u8 to u16
From: Eric Dumazet @ 2020-06-18 3:53 UTC (permalink / raw)
To: David S . Miller
Cc: netdev, Eric Dumazet, Eric Dumazet, Jakub Kicinski,
Willem de Bruijn, Sunil Goutham, Antoine Tenart
In-Reply-To: <20200618035326.39686-1-edumazet@google.com>
We need to increase TSO_HEADER_SIZE from 128 to 256.
Since otx2_sq_init() calls qmem_alloc() with TSO_HEADER_SIZE,
we need to change (struct qmem)->entry_sz to avoid truncation to 0.
Fixes: 7a37245ef23f ("octeontx2-af: NPA block admin queue init")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Sunil Goutham <sgoutham@marvell.com>
---
drivers/net/ethernet/marvell/octeontx2/af/common.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h
index cd33c2e6ca5fc25e16ec3b3f036df799471d88d5..f48eb66ed021b052b94d09684008cdb4e6356cd0 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/common.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h
@@ -43,7 +43,7 @@ struct qmem {
void *base;
dma_addr_t iova;
int alloc_sz;
- u8 entry_sz;
+ u16 entry_sz;
u8 align;
u32 qsize;
};
--
2.27.0.290.gba653c62da-goog
^ permalink raw reply related
* [PATCH v2 net-next 0/6] net: tso: expand to UDP support
From: Eric Dumazet @ 2020-06-18 3:53 UTC (permalink / raw)
To: David S . Miller
Cc: netdev, Eric Dumazet, Eric Dumazet, Jakub Kicinski,
Willem de Bruijn, Sunil Goutham, Antoine Tenart
With QUIC getting more attention these days, it is worth
implementing UDP direct segmentation, the same we did for TCP.
Drivers will need to advertize NETIF_F_GSO_UDP_L4 so that
GSO stack does not do the (more expensive) segmentation.
Note the two first patches are stable candidates, after
tests confirm they do not add regressions.
v2: addressed Jakub feedback :
1) Added a prep patch for octeontx2-af
2) calls tso_start() earlier in otx2_sq_append_tso()
Eric Dumazet (6):
octeontx2-af: change (struct qmem)->entry_sz from u8 to u16
net: tso: double TSO_HEADER_SIZE value
net: tso: shrink struct tso_t
net: tso: constify tso_count_descs() and friends
net: tso: cache transport header length
net: tso: add UDP segmentation support
.../ethernet/cavium/thunder/nicvf_queues.c | 5 ++-
drivers/net/ethernet/freescale/fec_main.c | 5 +--
drivers/net/ethernet/marvell/mv643xx_eth.c | 5 +--
drivers/net/ethernet/marvell/mvneta.c | 5 +--
.../net/ethernet/marvell/mvpp2/mvpp2_main.c | 6 +--
.../ethernet/marvell/octeontx2/af/common.h | 2 +-
.../marvell/octeontx2/nic/otx2_txrx.c | 6 +--
include/net/tso.h | 23 +++++-----
net/core/tso.c | 44 ++++++++++++-------
9 files changed, 55 insertions(+), 46 deletions(-)
--
2.27.0.290.gba653c62da-goog
^ permalink raw reply
* Re: [PATCH] [net/sched] Fix null pointer deref skb in tc_ctl_action
From: Eric Dumazet @ 2020-06-18 3:43 UTC (permalink / raw)
To: Gaurav Singh, Jamal Hadi Salim, Cong Wang, Jiri Pirko,
David S. Miller, Jakub Kicinski, open list:TC subsystem,
open list
In-Reply-To: <20200618014328.28668-1-gaurav1086@gmail.com>
On 6/17/20 6:43 PM, Gaurav Singh wrote:
> Add null check for skb
>
Bad choice really.
You have to really understand code intent before trying to fix it.
> Signed-off-by: Gaurav Singh <gaurav1086@gmail.com>
> ---
> net/sched/act_api.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/net/sched/act_api.c b/net/sched/act_api.c
> index 8ac7eb0a8309..fd584821d75a 100644
> --- a/net/sched/act_api.c
> +++ b/net/sched/act_api.c
> @@ -1473,9 +1473,12 @@ static const struct nla_policy tcaa_policy[TCA_ROOT_MAX + 1] = {
> static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n,
> struct netlink_ext_ack *extack)
> {
> + if (!skb)
> + return 0;
We do not allow this
warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
> +
> struct net *net = sock_net(skb->sk);
> struct nlattr *tca[TCA_ROOT_MAX + 1];
> - u32 portid = skb ? NETLINK_CB(skb).portid : 0;
> + u32 portid = NETLINK_CB(skb).portid;
> int ret = 0, ovr = 0;
>
> if ((n->nlmsg_type != RTM_GETACTION) &&
>
Please compile your patches, do not expect us from doing this.
^ permalink raw reply
* Re: [PATCH] [net/sched]: Remove redundant condition in qdisc_graft
From: Eric Dumazet @ 2020-06-18 3:43 UTC (permalink / raw)
To: Gaurav Singh, Jamal Hadi Salim, Cong Wang, Jiri Pirko,
David S. Miller, Jakub Kicinski, open list:TC subsystem,
open list
In-Reply-To: <20200618012308.28153-1-gaurav1086@gmail.com>
On 6/17/20 6:23 PM, Gaurav Singh wrote:
> Signed-off-by: Gaurav Singh <gaurav1086@gmail.com>
Two Signed-off-by ?
>
> Fix build errors
Your patch does not fix a build error.
>
> Signed-off-by: Gaurav Singh <gaurav1086@gmail.com>
> ---
> net/sched/sch_api.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
> index 9a3449b56bd6..be93ebcdb18d 100644
> --- a/net/sched/sch_api.c
> +++ b/net/sched/sch_api.c
> @@ -1094,7 +1094,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
>
> /* Only support running class lockless if parent is lockless */
> if (new && (new->flags & TCQ_F_NOLOCK) &&
> - parent && !(parent->flags & TCQ_F_NOLOCK))
> + !(parent->flags & TCQ_F_NOLOCK))
> qdisc_clear_nolock(new);
>
> if (!cops || !cops->graft)
>
^ permalink raw reply
* [PATCH net] net: dsa: bcm_sf2: Fix node reference count
From: Florian Fainelli @ 2020-06-18 3:42 UTC (permalink / raw)
To: netdev
Cc: Florian Fainelli, Andrew Lunn, Vivien Didelot, David S. Miller,
Jakub Kicinski, open list
of_find_node_by_name() will do an of_node_put() on the "from" argument.
With CONFIG_OF_DYNAMIC enabled which checks for device_node reference
counts, we would be getting a warning like this:
[ 6.347230] refcount_t: increment on 0; use-after-free.
[ 6.352498] WARNING: CPU: 3 PID: 77 at lib/refcount.c:156
refcount_inc_checked+0x38/0x44
[ 6.360601] Modules linked in:
[ 6.363661] CPU: 3 PID: 77 Comm: kworker/3:1 Tainted: G W
5.4.46-gb78b3e9956e6 #13
[ 6.372546] Hardware name: BCM97278SV (DT)
[ 6.376649] Workqueue: events deferred_probe_work_func
[ 6.381796] pstate: 60000005 (nZCv daif -PAN -UAO)
[ 6.386595] pc : refcount_inc_checked+0x38/0x44
[ 6.391133] lr : refcount_inc_checked+0x38/0x44
...
[ 6.478791] Call trace:
[ 6.481243] refcount_inc_checked+0x38/0x44
[ 6.485433] kobject_get+0x3c/0x4c
[ 6.488840] of_node_get+0x24/0x34
[ 6.492247] of_irq_find_parent+0x3c/0xe0
[ 6.496263] of_irq_parse_one+0xe4/0x1d0
[ 6.500191] irq_of_parse_and_map+0x44/0x84
[ 6.504381] bcm_sf2_sw_probe+0x22c/0x844
[ 6.508397] platform_drv_probe+0x58/0xa8
[ 6.512413] really_probe+0x238/0x3fc
[ 6.516081] driver_probe_device+0x11c/0x12c
[ 6.520358] __device_attach_driver+0xa8/0x100
[ 6.524808] bus_for_each_drv+0xb4/0xd0
[ 6.528650] __device_attach+0xd0/0x164
[ 6.532493] device_initial_probe+0x24/0x30
[ 6.536682] bus_probe_device+0x38/0x98
[ 6.540524] deferred_probe_work_func+0xa8/0xd4
[ 6.545061] process_one_work+0x178/0x288
[ 6.549078] process_scheduled_works+0x44/0x48
[ 6.553529] worker_thread+0x218/0x270
[ 6.557285] kthread+0xdc/0xe4
[ 6.560344] ret_from_fork+0x10/0x18
[ 6.563925] ---[ end trace 68f65caf69bb152a ]---
Fix this by adding a of_node_get() to increment the reference count
prior to the call.
Fixes: afa3b592953b ("net: dsa: bcm_sf2: Ensure correct sub-node is parsed")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/dsa/bcm_sf2.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index c1bd21e4b15c..9f62ba3e4345 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -1154,6 +1154,8 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev)
set_bit(0, priv->cfp.used);
set_bit(0, priv->cfp.unique);
+ /* Balance of_node_put() done by of_find_node_by_name() */
+ of_node_get(dn);
ports = of_find_node_by_name(dn, "ports");
if (ports) {
bcm_sf2_identify_ports(priv, ports);
--
2.17.1
^ permalink raw reply related
* Re: [net-next PATCH 4/5 v2] net: dsa: rtl8366: VLAN 0 as disable tagging
From: Florian Fainelli @ 2020-06-18 3:23 UTC (permalink / raw)
To: Linus Walleij, Andrew Lunn, Vivien Didelot
Cc: netdev, DENG Qingfang, Mauri Sandberg
In-Reply-To: <20200617083132.1847234-4-linus.walleij@linaro.org>
On 6/17/2020 1:31 AM, Linus Walleij wrote:
> The code in net/8021q/vlan.c, vlan_device_event() sets
> VLAN 0 for a VLAN-capable ethernet device when it
> comes up.
>
> Since the RTL8366 DSA switches must have a VLAN and
> PVID set up for any packets to come through we have
> already set up default VLAN for each port as part of
> bringing the switch online.
>
> Make sure that setting VLAN 0 has the same effect
> and does not try to actually tell the hardware to use
> VLAN 0 on the port because that will not work.
Why, you are not really describing what happens if VID = 0 is programmed?
It also sounds like you should be setting
configure_vlan_while_not_filtering if you need the switch to be
configured with VLAN awareness no matter whether there is a bridge
configured or not.
--
Florian
^ permalink raw reply
* Re: [net-next PATCH 1/5] net: dsa: tag_rtl4_a: Implement Realtek 4 byte A tag
From: DENG Qingfang @ 2020-06-18 3:17 UTC (permalink / raw)
To: Linus Walleij
Cc: Vladimir Oltean, Andrew Lunn, Vivien Didelot, Florian Fainelli,
netdev, Mauri Sandberg
In-Reply-To: <CACRpkda9kJUFwx-ASQfO-ThhgbV2fmT_tqT8zH0W_Jm23ZTVMg@mail.gmail.com>
Hi
On Wed, Jun 17, 2020 at 4:06 PM Linus Walleij <linus.walleij@linaro.org> wrote:
>
> On Thu, Jun 4, 2020 at 1:23 PM Vladimir Oltean <olteanv@gmail.com> wrote:
>
> > In the code you pointed to, there is a potentially relevant comment:
> >
> > 1532//CPU tag: Realtek Ethertype==0x8899(2 bytes)+protocol==0x9(4
> > MSB)+priority(2 bits)+reserved(4 bits)+portmask(6 LSB)
> >
> > https://svn.dd-wrt.com/browser/src/linux/universal/linux-3.2/drivers/net/ethernet/raeth/rb/rtl_multicast_snooping.c#L1527
> > https://svn.dd-wrt.com/browser/src/linux/universal/linux-3.2/drivers/net/ethernet/raeth/rb/rtl_multicast_snooping.c#L5224
> >
> > This strongly indicates to me that the insertion tag is the same as
> > the extraction tag.
>
> This code is a problem because it is Realtek-development style.
> This style seems to be that the hardware people write the drivers
> using copy/paste from the previous ASIC and ship is as soon as
> possible. Keep this in mind.
>
> The above tag is using protocol 9 and is actually even documented
> in a PDF I have for RTL8306. The problem is that the RTL8366RB
> (I suspect also RTL8366S) uses protocol "a" (as in hex 10).
> Which is of course necessarily different.
>
> I have *really* tried to figure out how the bits in protocol a works
> when transmissing from the CPU port to any switch port.
>
> When nothing else worked, I just tried all bit combinations with
> 0xannp where a is protocol and p is port. I looped through all
> values several times trying to get a response from ping.
Have you looped through the whole 32-bit field?
>
> So this is really how far I can get right now, even with brute
> force.
>
> > It is completely opaque to me why in patch "[net-next PATCH 2/5] net:
> > dsa: rtl8366rb: Support the CPU DSA tag" you are _disabling_ the
> > injection of these tags via RTL8368RB_CPU_INSTAG. I think it's natural
> > that the switch drops these packets when CPU tag insertion is
> > disabled.
>
> This is another Realtek-ism where they managed to invert the
> meaning of a bit.
>
> Bit 15 in register 0x0061 (RTL8368RB_CPU_CTRL_REG) can
> be set to 1 and then the special (custom) CPU tag 0x8899
> protocol a will be DISABLED. This value Realtek calls
> "RTL8368RB_CPU_INSTAG" which makes you think that
> the tag will be inserted, it is named "instag" right? But that
> is not how it works.
>
> That bit needs to be set to 0 to insert the tag and 1 to disable
> insertion of the tag.
>
> For this reason the patch also renames this bit to
> RTL8368RB_CPU_NO_TAG which is more to the point.
>
> Yours,
> Linus Walleij
^ permalink raw reply
* [PATCH AUTOSEL 5.7 077/388] scsi: vhost: Notify TCM about the maximum sg entries supported per command
From: Sasha Levin @ 2020-06-18 1:02 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Sudhakar Panneerselvam, Michael S . Tsirkin, Jason Wang,
Paolo Bonzini, Stefan Hajnoczi, Mike Christie,
Martin K . Petersen, Sasha Levin, virtualization, kvm, netdev
In-Reply-To: <20200618010805.600873-1-sashal@kernel.org>
From: Sudhakar Panneerselvam <sudhakar.panneerselvam@oracle.com>
[ Upstream commit 5ae6a6a915033bfee79e76e0c374d4f927909edc ]
vhost-scsi pre-allocates the maximum sg entries per command and if a
command requires more than VHOST_SCSI_PREALLOC_SGLS entries, then that
command is failed by it. This patch lets vhost communicate the max sg limit
when it registers vhost_scsi_ops with TCM. With this change, TCM would
report the max sg entries through "Block Limits" VPD page which will be
typically queried by the SCSI initiator during device discovery. By knowing
this limit, the initiator could ensure the maximum transfer length is less
than or equal to what is reported by vhost-scsi.
Link: https://lore.kernel.org/r/1590166317-953-1-git-send-email-sudhakar.panneerselvam@oracle.com
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Jason Wang <jasowang@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Mike Christie <mchristi@redhat.com>
Signed-off-by: Sudhakar Panneerselvam <sudhakar.panneerselvam@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/vhost/scsi.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index c39952243fd3..8b104f76f324 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -2280,6 +2280,7 @@ static struct configfs_attribute *vhost_scsi_wwn_attrs[] = {
static const struct target_core_fabric_ops vhost_scsi_ops = {
.module = THIS_MODULE,
.fabric_name = "vhost",
+ .max_data_sg_nents = VHOST_SCSI_PREALLOC_SGLS,
.tpg_get_wwn = vhost_scsi_get_fabric_wwn,
.tpg_get_tag = vhost_scsi_get_tpgt,
.tpg_check_demo_mode = vhost_scsi_check_true,
--
2.25.1
^ permalink raw reply related
* [PATCH AUTOSEL 5.7 092/388] yam: fix possible memory leak in yam_init_driver
From: Sasha Levin @ 2020-06-18 1:03 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Wang Hai, Hulk Robot, David S . Miller, Sasha Levin, linux-hams,
netdev
In-Reply-To: <20200618010805.600873-1-sashal@kernel.org>
From: Wang Hai <wanghai38@huawei.com>
[ Upstream commit 98749b7188affbf2900c2aab704a8853901d1139 ]
If register_netdev(dev) fails, free_netdev(dev) needs
to be called, otherwise a memory leak will occur.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: Hulk Robot <hulkci@huawei.com>
Signed-off-by: Wang Hai <wanghai38@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/hamradio/yam.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 71cdef9fb56b..5ab53e9942f3 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -1133,6 +1133,7 @@ static int __init yam_init_driver(void)
err = register_netdev(dev);
if (err) {
printk(KERN_WARNING "yam: cannot register net device %s\n", dev->name);
+ free_netdev(dev);
goto error;
}
yam_devs[i] = dev;
--
2.25.1
^ permalink raw reply related
* [PATCH AUTOSEL 5.7 093/388] net: mdiobus: Disable preemption upon u64_stats update
From: Sasha Levin @ 2020-06-18 1:03 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Ahmed S. Darwish, kernel test robot, Sebastian Andrzej Siewior,
David S . Miller, Sasha Levin, netdev
In-Reply-To: <20200618010805.600873-1-sashal@kernel.org>
From: "Ahmed S. Darwish" <a.darwish@linutronix.de>
[ Upstream commit c7e261d81783387a0502878cd229327e7c54322e ]
The u64_stats mechanism uses sequence counters to protect against 64-bit
values tearing on 32-bit architectures. Updating u64_stats is thus a
sequence counter write side critical section where preemption must be
disabled.
For mdiobus_stats_acct(), disable preemption upon the u64_stats update.
It is called from process context through mdiobus_read() and
mdiobus_write().
Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Ahmed S. Darwish <a.darwish@linutronix.de>
Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/phy/mdio_bus.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 7a4eb3f2cb74..a1a4dee2a033 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -757,6 +757,7 @@ EXPORT_SYMBOL(mdiobus_scan);
static void mdiobus_stats_acct(struct mdio_bus_stats *stats, bool op, int ret)
{
+ preempt_disable();
u64_stats_update_begin(&stats->syncp);
u64_stats_inc(&stats->transfers);
@@ -771,6 +772,7 @@ static void mdiobus_stats_acct(struct mdio_bus_stats *stats, bool op, int ret)
u64_stats_inc(&stats->writes);
out:
u64_stats_update_end(&stats->syncp);
+ preempt_enable();
}
/**
--
2.25.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox