From: Alan Brady <alan.brady@intel.com>
To: intel-wired-lan@osuosl.org
Subject: [Intel-wired-lan] [PATCH net-next 05/19] iecm: add vport alloc and virtchnl messages
Date: Thu, 27 Jan 2022 16:09:55 -0800 [thread overview]
Message-ID: <20220128001009.721392-6-alan.brady@intel.com> (raw)
In-Reply-To: <20220128001009.721392-1-alan.brady@intel.com>
After handling hard reset, we end up in init task. This starts by
allocating and setting up a vport. To do that we need implement virtchnl
messages.
The virtchnl messages are also offloaded into function pointers so that a
device driver may override them. Here a default implementation is provided
for devices using virtchnl 2.0 but there exists the flexibility add
virtchnl 1.1 support through function pointers.
Signed-off-by: Phani Burra <phani.r.burra@intel.com>
Signed-off-by: Joshua Hay <joshua.a.hay@intel.com>
Signed-off-by: Madhu Chittim <madhu.chittim@intel.com>
Signed-off-by: Pavan Kumar Linga <pavan.kumar.linga@intel.com>
Signed-off-by: Alan Brady <alan.brady@intel.com>
---
drivers/net/ethernet/intel/iecm/Makefile | 4 +-
drivers/net/ethernet/intel/iecm/iecm_lib.c | 167 ++-
drivers/net/ethernet/intel/iecm/iecm_txrx.c | 22 +
.../net/ethernet/intel/iecm/iecm_virtchnl.c | 1299 +++++++++++++++++
drivers/net/ethernet/intel/include/iecm.h | 316 +++-
.../net/ethernet/intel/include/iecm_txrx.h | 94 ++
6 files changed, 1898 insertions(+), 4 deletions(-)
create mode 100644 drivers/net/ethernet/intel/iecm/iecm_txrx.c
diff --git a/drivers/net/ethernet/intel/iecm/Makefile b/drivers/net/ethernet/intel/iecm/Makefile
index db8fecb075a6..fcb49402334f 100644
--- a/drivers/net/ethernet/intel/iecm/Makefile
+++ b/drivers/net/ethernet/intel/iecm/Makefile
@@ -7,11 +7,13 @@
obj-$(CONFIG_IECM) += iecm.o
-ccflags-y += -I$(srctree)/drivers/net/ethernet/intel/include
+ccflags-y += -I$(srctree)/drivers/net/ethernet/intel/include \
+ -I$(srctree)/include/linux/avf
iecm-y := \
iecm_lib.o \
iecm_virtchnl.o \
+ iecm_txrx.o \
iecm_controlq.o \
iecm_controlq_setup.o \
iecm_main.o
diff --git a/drivers/net/ethernet/intel/iecm/iecm_lib.c b/drivers/net/ethernet/intel/iecm/iecm_lib.c
index 64cdbce2c842..e2e523f0700e 100644
--- a/drivers/net/ethernet/intel/iecm/iecm_lib.c
+++ b/drivers/net/ethernet/intel/iecm/iecm_lib.c
@@ -5,6 +5,11 @@
#include "iecm.h"
+const char * const iecm_vport_vc_state_str[] = {
+ IECM_FOREACH_VPORT_VC_STATE(IECM_GEN_STRING)
+};
+EXPORT_SYMBOL(iecm_vport_vc_state_str);
+
/**
* iecm_cfg_hw - Initialize HW struct
* @adapter: adapter to setup hw struct for
@@ -24,6 +29,113 @@ static int iecm_cfg_hw(struct iecm_adapter *adapter)
return 0;
}
+/**
+ * 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)
+{
+ int **tmp_array = (int **)array;
+ int next;
+
+ if (curr < (size - 1) && !tmp_array[curr + 1]) {
+ next = curr + 1;
+ } else {
+ int i = 0;
+
+ while ((i < size) && (tmp_array[i]))
+ i++;
+ if (i == size)
+ next = IECM_NO_FREE_SLOT;
+ else
+ next = i;
+ }
+ return next;
+}
+
+/**
+ * iecm_vport_rel - Delete a vport and free its resources
+ * @vport: the vport being removed
+ */
+static void iecm_vport_rel(struct iecm_vport *vport)
+{
+ mutex_destroy(&vport->stop_mutex);
+ kfree(vport);
+}
+
+/**
+ * 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)
+{
+ int i;
+
+ if (!adapter->vports)
+ return;
+
+ for (i = 0; i < adapter->num_alloc_vport; i++) {
+ if (!adapter->vports[i])
+ continue;
+
+ iecm_vport_rel(adapter->vports[i]);
+ adapter->vports[i] = NULL;
+ adapter->next_vport = 0;
+ }
+ adapter->num_alloc_vport = 0;
+}
+
+/**
+ * iecm_vport_alloc - Allocates the next available struct vport in the adapter
+ * @adapter: board private structure
+ * @vport_id: vport identifier
+ *
+ * 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)
+{
+ struct iecm_vport *vport = NULL;
+
+ if (adapter->next_vport == IECM_NO_FREE_SLOT)
+ return vport;
+
+ /* Need to protect the allocation of the vports at the adapter level */
+ mutex_lock(&adapter->sw_mutex);
+
+ vport = kzalloc(sizeof(*vport), GFP_KERNEL);
+ if (!vport)
+ goto unlock_adapter;
+
+ vport->adapter = adapter;
+ vport->idx = adapter->next_vport;
+ vport->compln_clean_budget = IECM_TX_COMPLQ_CLEAN_BUDGET;
+ adapter->num_alloc_vport++;
+
+ /* Setup default MSIX irq handler for the vport */
+ vport->irq_q_handler = iecm_vport_intr_clean_queues;
+ vport->q_vector_base = IECM_NONQ_VEC;
+
+ mutex_init(&vport->stop_mutex);
+
+ /* fill vport slot in the adapter struct */
+ adapter->vports[adapter->next_vport] = vport;
+
+ /* prepare adapter->next_vport for next use */
+ adapter->next_vport = iecm_get_free_slot(adapter->vports,
+ adapter->num_alloc_vport,
+ adapter->next_vport);
+
+unlock_adapter:
+ mutex_unlock(&adapter->sw_mutex);
+ return vport;
+}
+
/**
* iecm_statistics_task - Delayed task to get statistics over mailbox
* @work: work_struct handle to our data
@@ -55,7 +167,25 @@ static void iecm_service_task(struct work_struct *work)
*/
static void iecm_init_task(struct work_struct *work)
{
- /* stub */
+ struct iecm_adapter *adapter = container_of(work,
+ struct iecm_adapter,
+ init_task.work);
+ struct iecm_vport *vport;
+ struct pci_dev *pdev;
+ int vport_id, err;
+
+ err = adapter->dev_ops.vc_ops.core_init(adapter, &vport_id);
+ if (err)
+ return;
+
+ pdev = adapter->pdev;
+ vport = iecm_vport_alloc(adapter, vport_id);
+ if (!vport) {
+ err = -EFAULT;
+ dev_err(&pdev->dev, "failed to allocate vport: %d\n",
+ err);
+ return;
+ }
}
/**
@@ -81,6 +211,31 @@ static int iecm_api_init(struct iecm_adapter *adapter)
return -EINVAL;
}
+ if (adapter->dev_ops.vc_ops_init) {
+ struct iecm_virtchnl_ops *vc_ops;
+
+ adapter->dev_ops.vc_ops_init(adapter);
+ vc_ops = &adapter->dev_ops.vc_ops;
+ if (!(vc_ops->core_init &&
+ vc_ops->vport_init &&
+ vc_ops->vport_queue_ids_init &&
+ vc_ops->get_caps &&
+ vc_ops->config_queues &&
+ vc_ops->enable_queues &&
+ vc_ops->disable_queues &&
+ vc_ops->irq_map_unmap &&
+ vc_ops->get_set_rss_lut &&
+ vc_ops->get_set_rss_hash &&
+ vc_ops->adjust_qs &&
+ vc_ops->get_ptype &&
+ vc_ops->init_max_queues)) {
+ dev_err(&pdev->dev, "Invalid device, missing one or more virtchnl functions\n");
+ return -EINVAL;
+ }
+ } else {
+ iecm_vc_ops_init(adapter);
+ }
+
return 0;
}
@@ -93,7 +248,15 @@ static int iecm_api_init(struct iecm_adapter *adapter)
*/
static void iecm_deinit_task(struct iecm_adapter *adapter)
{
- /* stub */
+ set_bit(__IECM_REL_RES_IN_PROG, adapter->flags);
+ /* Wait until the init_task is done else this thread might release
+ * the resources first and the other thread might end up in a bad state
+ */
+ cancel_delayed_work_sync(&adapter->init_task);
+ iecm_vport_rel_all(adapter);
+
+ cancel_delayed_work_sync(&adapter->serv_task);
+ cancel_delayed_work_sync(&adapter->stats_task);
}
/**
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..2f5c16a28266
--- /dev/null
+++ b/drivers/net/ethernet/intel/iecm/iecm_txrx.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2019 Intel Corporation */
+
+#include "iecm.h"
+
+/**
+ * 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)
+{
+ struct iecm_q_vector *q_vector = (struct iecm_q_vector *)data;
+
+ q_vector->total_events++;
+ napi_schedule(&q_vector->napi);
+
+ return IRQ_HANDLED;
+}
+
diff --git a/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c b/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
index b8f54b8c700a..aae06064d706 100644
--- a/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
+++ b/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
@@ -3,6 +3,74 @@
#include "iecm.h"
+/**
+ * iecm_recv_event_msg - Receive virtchnl event message
+ * @vport: virtual port structure
+ *
+ * Receive virtchnl event message
+ */
+static void iecm_recv_event_msg(struct iecm_vport *vport)
+{
+ struct iecm_adapter *adapter = vport->adapter;
+ struct virtchnl_pf_event *vpe;
+ struct virtchnl2_event *v2e;
+ bool link_status;
+ u32 event;
+
+ if (adapter->virt_ver_maj < VIRTCHNL_VERSION_MAJOR_2) {
+ vpe = (struct virtchnl_pf_event *)adapter->vc_msg;
+ event = vpe->event;
+ } else {
+ v2e = (struct virtchnl2_event *)adapter->vc_msg;
+ event = le32_to_cpu(v2e->event);
+ }
+
+ switch (event) {
+ case VIRTCHNL2_EVENT_LINK_CHANGE:
+ if (adapter->virt_ver_maj < VIRTCHNL_VERSION_MAJOR_2) {
+ if (iecm_is_cap_ena(adapter, IECM_OTHER_CAPS,
+ VIRTCHNL2_CAP_LINK_SPEED)) {
+ adapter->link_speed_mbps =
+ vpe->event_data.link_event_adv.link_speed;
+ link_status =
+ vpe->event_data.link_event_adv.link_status;
+ } else {
+ adapter->link_speed =
+ vpe->event_data.link_event.link_speed;
+ link_status =
+ vpe->event_data.link_event.link_status;
+ }
+ } else {
+ adapter->link_speed_mbps = le32_to_cpu(v2e->link_speed);
+ link_status = v2e->link_status;
+ }
+ if (adapter->link_up != link_status) {
+ adapter->link_up = link_status;
+ if (adapter->state == __IECM_UP) {
+ 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:
+ 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", event);
+ break;
+ }
+ clear_bit(__IECM_VC_MSG_PENDING, adapter->flags);
+}
+
/**
* iecm_mb_clean - Reclaim the send mailbox queue entries
* @adapter: Driver specific private structure
@@ -39,6 +107,865 @@ static int iecm_mb_clean(struct iecm_adapter *adapter)
return err;
}
+/**
+ * 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 0 on success, negative on failure
+ */
+int iecm_send_mb_msg(struct iecm_adapter *adapter, enum virtchnl_ops op,
+ u16 msg_size, u8 *msg)
+{
+ struct iecm_ctlq_msg *ctlq_msg;
+ struct iecm_dma_mem *dma_mem;
+ int err = 0;
+
+ if (iecm_is_reset_detected(adapter))
+ return -EBUSY;
+
+ err = iecm_mb_clean(adapter);
+ if (err)
+ return err;
+
+ ctlq_msg = kzalloc(sizeof(*ctlq_msg), GFP_KERNEL);
+ if (!ctlq_msg)
+ return -ENOMEM;
+
+ dma_mem = kzalloc(sizeof(*dma_mem), GFP_KERNEL);
+ if (!dma_mem) {
+ err = -ENOMEM;
+ goto dma_mem_error;
+ }
+
+ memset(ctlq_msg, 0, sizeof(struct iecm_ctlq_msg));
+ ctlq_msg->opcode = iecm_mbq_opc_send_msg_to_pf;
+ 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 = -ENOMEM;
+ 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 0;
+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);
+ return err;
+}
+EXPORT_SYMBOL(iecm_send_mb_msg);
+
+/**
+ * iecm_set_msg_pending_bit - Wait for clear and set msg pending
+ * @adapter: driver specific private structure
+ *
+ * If clear sets msg pending bit, otherwise waits for it to clear before
+ * setting it again. Returns 0 on success, negative on failure.
+ */
+static int iecm_set_msg_pending_bit(struct iecm_adapter *adapter)
+{
+ unsigned int retries = 100;
+
+ /* If msg pending bit already set, there's a message waiting to be
+ * parsed and we must wait for it to be cleared before copying a new
+ * message into the vc_msg buffer or else we'll stomp all over the
+ * previous message.
+ */
+ while (retries) {
+ if (!test_and_set_bit(__IECM_VC_MSG_PENDING,
+ adapter->flags))
+ break;
+ msleep(20);
+ retries--;
+ }
+ return retries ? 0 : -ETIMEDOUT;
+}
+
+/**
+ * iecm_set_msg_pending - Wait for msg pending bit and copy msg to buf
+ * @adapter: driver specific private structure
+ * @ctlq_msg: msg to copy from
+ * @err_enum: err bit to set on error
+ *
+ * Copies payload from ctlq_msg into vc_msg buf in adapter and sets msg pending
+ * bit. Returns 0 on success, negative on failure.
+ */
+int iecm_set_msg_pending(struct iecm_adapter *adapter,
+ struct iecm_ctlq_msg *ctlq_msg,
+ enum iecm_vport_vc_state err_enum)
+{
+ if (ctlq_msg->cookie.mbx.chnl_retval) {
+ set_bit(err_enum, adapter->vc_state);
+ return -EINVAL;
+ }
+
+ if (iecm_set_msg_pending_bit(adapter)) {
+ set_bit(err_enum, adapter->vc_state);
+ dev_info(&adapter->pdev->dev, "Timed out setting msg pending\n");
+ return -ETIMEDOUT;
+ }
+
+ memcpy(adapter->vc_msg, ctlq_msg->ctx.indirect.payload->va,
+ min_t(int, ctlq_msg->ctx.indirect.payload->size,
+ IECM_DFLT_MBX_BUF_SIZE));
+ return 0;
+}
+EXPORT_SYMBOL(iecm_set_msg_pending);
+
+/**
+ * iecm_recv_mb_msg - Receive message over mailbox
+ * @adapter: Driver specific private structure
+ * @op: virtchannel operation code
+ * @msg: Received message holding buffer
+ * @msg_size: message size
+ *
+ * Will receive control queue message and posts the receive buffer. Returns 0
+ * on success and negative on failure.
+ */
+int iecm_recv_mb_msg(struct iecm_adapter *adapter, enum virtchnl_ops op,
+ void *msg, int msg_size)
+{
+ struct iecm_ctlq_msg ctlq_msg;
+ struct iecm_dma_mem *dma_mem;
+ struct iecm_vport *vport;
+ bool work_done = false;
+ int num_retry = 2000;
+ int payload_size = 0;
+ u16 num_q_msg;
+ int err = 0;
+
+ vport = adapter->vports[0];
+ while (1) {
+ /* Try to get one message */
+ num_q_msg = 1;
+ dma_mem = NULL;
+ err = iecm_ctlq_recv(adapter->hw.arq, &num_q_msg, &ctlq_msg);
+ /* If no message then decide if we have to retry based on
+ * opcode
+ */
+ if (err || !num_q_msg) {
+ /* Increasing num_retry to consider the delayed
+ * responses because of large number of VF's mailbox
+ * messages. If the mailbox message is received from
+ * the other side, we come out of the sleep cycle
+ * immediately else we wait for more time.
+ */
+ if (op && num_retry-- &&
+ !test_bit(__IECM_REL_RES_IN_PROG, adapter->flags)) {
+ 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 VIRTCHNL2_OP_GET_CAPS:
+ case VIRTCHNL2_OP_CREATE_VPORT:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ dev_info(&adapter->pdev->dev, "Failure initializing, vc op: %u retval: %u\n",
+ ctlq_msg.cookie.mbx.chnl_opcode,
+ ctlq_msg.cookie.mbx.chnl_retval);
+ err = -EBADMSG;
+ } else if (msg) {
+ memcpy(msg, ctlq_msg.ctx.indirect.payload->va,
+ min_t(int,
+ payload_size, msg_size));
+ }
+ work_done = true;
+ break;
+ case VIRTCHNL2_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 VIRTCHNL2_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 VIRTCHNL2_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 VIRTCHNL2_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 VIRTCHNL2_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 VIRTCHNL2_OP_ENABLE_QUEUES:
+ 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 VIRTCHNL2_OP_DISABLE_QUEUES:
+ 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 VIRTCHNL2_OP_ADD_QUEUES:
+ iecm_set_msg_pending(adapter, &ctlq_msg,
+ IECM_VC_ADD_QUEUES_ERR);
+ set_bit(IECM_VC_ADD_QUEUES, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL2_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 VIRTCHNL2_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 VIRTCHNL2_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 VIRTCHNL2_OP_GET_STATS:
+ iecm_set_msg_pending(adapter, &ctlq_msg,
+ IECM_VC_GET_STATS_ERR);
+ set_bit(IECM_VC_GET_STATS, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL2_OP_GET_RSS_HASH:
+ iecm_set_msg_pending(adapter, &ctlq_msg,
+ IECM_VC_GET_RSS_HASH_ERR);
+ set_bit(IECM_VC_GET_RSS_HASH, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL2_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 VIRTCHNL2_OP_GET_RSS_LUT:
+ iecm_set_msg_pending(adapter, &ctlq_msg,
+ IECM_VC_GET_RSS_LUT_ERR);
+ set_bit(IECM_VC_GET_RSS_LUT, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL2_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 VIRTCHNL2_OP_GET_RSS_KEY:
+ iecm_set_msg_pending(adapter, &ctlq_msg,
+ IECM_VC_GET_RSS_KEY_ERR);
+ set_bit(IECM_VC_GET_RSS_KEY, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL2_OP_SET_RSS_KEY:
+ if (ctlq_msg.cookie.mbx.chnl_retval)
+ set_bit(IECM_VC_SET_RSS_KEY_ERR,
+ adapter->vc_state);
+ set_bit(IECM_VC_SET_RSS_KEY, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL2_OP_ALLOC_VECTORS:
+ iecm_set_msg_pending(adapter, &ctlq_msg,
+ IECM_VC_ALLOC_VECTORS_ERR);
+ set_bit(IECM_VC_ALLOC_VECTORS, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL2_OP_DEALLOC_VECTORS:
+ if (ctlq_msg.cookie.mbx.chnl_retval)
+ set_bit(IECM_VC_DEALLOC_VECTORS_ERR,
+ adapter->vc_state);
+ set_bit(IECM_VC_DEALLOC_VECTORS, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL2_OP_GET_PTYPE_INFO:
+ iecm_set_msg_pending(adapter, &ctlq_msg,
+ IECM_VC_GET_PTYPE_INFO_ERR);
+ set_bit(IECM_VC_GET_PTYPE_INFO, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL2_OP_EVENT:
+ case VIRTCHNL_OP_EVENT:
+ if (iecm_set_msg_pending_bit(adapter)) {
+ dev_info(&adapter->pdev->dev, "Timed out setting msg pending\n");
+ } else {
+ 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;
+ case VIRTCHNL_OP_ADD_ETH_ADDR:
+ if (test_and_clear_bit(__IECM_ADD_ETH_REQ, adapter->flags)) {
+ /* Message was sent asynchronously. We don't
+ * normally print errors here, instead
+ * preferring to handle errors in the function
+ * calling wait_for_event. However, we will
+ * have lost the context in which we sent the
+ * message if asynchronous. We can't really do
+ * anything about at it this point, but we
+ * should at a minimum indicate that it looks
+ * like something went wrong. Also don't bother
+ * setting ERR bit or waking vchnl_wq since no
+ * one will be waiting to read the async
+ * message.
+ */
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ dev_err(&adapter->pdev->dev, "Failed to add MAC address: %d\n",
+ ctlq_msg.cookie.mbx.chnl_retval);
+ }
+ break;
+ }
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ set_bit(IECM_VC_ADD_ETH_ADDR_ERR,
+ adapter->vc_state);
+ }
+ set_bit(IECM_VC_ADD_ETH_ADDR, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_DEL_ETH_ADDR:
+ if (test_and_clear_bit(__IECM_DEL_ETH_REQ, adapter->flags)) {
+ /* Message was sent asynchronously. We don't
+ * normally print errors here, instead
+ * preferring to handle errors in the function
+ * calling wait_for_event. However, we will
+ * have lost the context in which we sent the
+ * message if asynchronous. We can't really do
+ * anything about at it this point, but we
+ * should at a minimum indicate that it looks
+ * like something went wrong. Also don't bother
+ * setting ERR bit or waking vchnl_wq since no
+ * one will be waiting to read the async
+ * message.
+ */
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ dev_err(&adapter->pdev->dev, "Failed to delete MAC address: %d\n",
+ ctlq_msg.cookie.mbx.chnl_retval);
+ }
+ break;
+ }
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ set_bit(IECM_VC_DEL_ETH_ADDR_ERR,
+ adapter->vc_state);
+ }
+ set_bit(IECM_VC_DEL_ETH_ADDR, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ set_bit(IECM_VC_OFFLOAD_VLAN_V2_CAPS_ERR, adapter->vc_state);
+ } else {
+ memcpy(adapter->vc_msg,
+ ctlq_msg.ctx.indirect.payload->va,
+ min_t(int, payload_size,
+ IECM_DFLT_MBX_BUF_SIZE));
+ }
+ set_bit(IECM_VC_OFFLOAD_VLAN_V2_CAPS, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_ADD_VLAN_V2:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ dev_err(&adapter->pdev->dev, "Failed to add vlan filter: %d\n",
+ ctlq_msg.cookie.mbx.chnl_retval);
+ }
+ break;
+ case VIRTCHNL_OP_DEL_VLAN_V2:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ dev_err(&adapter->pdev->dev, "Failed to delete vlan filter: %d\n",
+ ctlq_msg.cookie.mbx.chnl_retval);
+ }
+ break;
+ case VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ set_bit(IECM_VC_INSERTION_ENA_VLAN_V2_ERR,
+ adapter->vc_state);
+ }
+ set_bit(IECM_VC_INSERTION_ENA_VLAN_V2,
+ adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ set_bit(IECM_VC_INSERTION_DIS_VLAN_V2_ERR,
+ adapter->vc_state);
+ }
+ set_bit(IECM_VC_INSERTION_DIS_VLAN_V2,
+ adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ set_bit(IECM_VC_STRIPPING_ENA_VLAN_V2_ERR,
+ adapter->vc_state);
+ }
+ set_bit(IECM_VC_STRIPPING_ENA_VLAN_V2,
+ adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ set_bit(IECM_VC_STRIPPING_DIS_VLAN_V2_ERR,
+ adapter->vc_state);
+ }
+ set_bit(IECM_VC_STRIPPING_DIS_VLAN_V2,
+ adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
+ /* This message can only be sent asynchronously. As
+ * such we'll have lost the context in which it was
+ * called and thus can only really report if it looks
+ * like an error occurred. Don't bother setting ERR bit
+ * or waking chnl_wq since no will be waiting to
+ * reading message.
+ */
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ dev_err(&adapter->pdev->dev, "Failed to set promiscuous mode: %d\n",
+ ctlq_msg.cookie.mbx.chnl_retval);
+ }
+ break;
+ case VIRTCHNL_OP_ADD_CLOUD_FILTER:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ dev_err(&adapter->pdev->dev, "Failed to add cloud filter: %d\n",
+ ctlq_msg.cookie.mbx.chnl_retval);
+ set_bit(IECM_VC_ADD_CLOUD_FILTER_ERR,
+ adapter->vc_state);
+ }
+ set_bit(IECM_VC_ADD_CLOUD_FILTER, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_DEL_CLOUD_FILTER:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ dev_err(&adapter->pdev->dev, "Failed to delete cloud filter: %d\n",
+ ctlq_msg.cookie.mbx.chnl_retval);
+ set_bit(IECM_VC_DEL_CLOUD_FILTER_ERR,
+ adapter->vc_state);
+ }
+ set_bit(IECM_VC_DEL_CLOUD_FILTER, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_ADD_RSS_CFG:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ dev_err(&adapter->pdev->dev, "Failed to add RSS configuration: %d\n",
+ ctlq_msg.cookie.mbx.chnl_retval);
+ set_bit(IECM_VC_ADD_RSS_CFG_ERR,
+ adapter->vc_state);
+ }
+ set_bit(IECM_VC_ADD_RSS_CFG, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_DEL_RSS_CFG:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ dev_err(&adapter->pdev->dev, "Failed to delete RSS configuration: %d\n",
+ ctlq_msg.cookie.mbx.chnl_retval);
+ set_bit(IECM_VC_DEL_RSS_CFG_ERR,
+ adapter->vc_state);
+ }
+ set_bit(IECM_VC_DEL_RSS_CFG, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_ADD_FDIR_FILTER:
+ iecm_set_msg_pending(adapter, &ctlq_msg,
+ IECM_VC_ADD_FDIR_FILTER_ERR);
+ set_bit(IECM_VC_ADD_FDIR_FILTER, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_DEL_FDIR_FILTER:
+ iecm_set_msg_pending(adapter, &ctlq_msg,
+ IECM_VC_DEL_FDIR_FILTER_ERR);
+ set_bit(IECM_VC_DEL_FDIR_FILTER, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_ENABLE_CHANNELS:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ dev_err(&adapter->pdev->dev, "Failed to enable channels: %d\n",
+ ctlq_msg.cookie.mbx.chnl_retval);
+ set_bit(IECM_VC_ENA_CHANNELS_ERR,
+ adapter->vc_state);
+ }
+ set_bit(IECM_VC_ENA_CHANNELS, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ case VIRTCHNL_OP_DISABLE_CHANNELS:
+ if (ctlq_msg.cookie.mbx.chnl_retval) {
+ dev_err(&adapter->pdev->dev, "Failed to disable channels: %d\n",
+ ctlq_msg.cookie.mbx.chnl_retval);
+ set_bit(IECM_VC_DIS_CHANNELS_ERR,
+ adapter->vc_state);
+ }
+ set_bit(IECM_VC_DIS_CHANNELS, adapter->vc_state);
+ wake_up(&adapter->vchnl_wq);
+ break;
+ default:
+ if (adapter->dev_ops.vc_ops.recv_mbx_msg)
+ err =
+ 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;
+
+ err = 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 (err && 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 err;
+}
+EXPORT_SYMBOL(iecm_recv_mb_msg);
+
+/**
+ * iecm_send_ver_msg - send virtchnl version message
+ * @adapter: Driver specific private structure
+ *
+ * Send virtchnl version message. Returns 0 on success, negative on failure.
+ */
+static int iecm_send_ver_msg(struct iecm_adapter *adapter)
+{
+ struct virtchnl_version_info vvi;
+
+ if (adapter->virt_ver_maj) {
+ vvi.major = adapter->virt_ver_maj;
+ vvi.minor = adapter->virt_ver_min;
+ } else {
+ vvi.major = IECM_VIRTCHNL_VERSION_MAJOR;
+ vvi.minor = IECM_VIRTCHNL_VERSION_MINOR;
+ }
+
+ return iecm_send_mb_msg(adapter, VIRTCHNL_OP_VERSION, sizeof(vvi),
+ (u8 *)&vvi);
+}
+
+/**
+ * iecm_recv_ver_msg - Receive virtchnl version message
+ * @adapter: Driver specific private structure
+ *
+ * Receive virtchnl version message. Returns 0 on success, -EAGAIN if we need
+ * to send version message again, otherwise negative on failure.
+ */
+static int iecm_recv_ver_msg(struct iecm_adapter *adapter)
+{
+ struct virtchnl_version_info vvi;
+ int err = 0;
+
+ err = iecm_recv_mb_msg(adapter, VIRTCHNL_OP_VERSION, &vvi, sizeof(vvi));
+ if (err)
+ return err;
+
+ if (vvi.major > IECM_VIRTCHNL_VERSION_MAJOR) {
+ dev_warn(&adapter->pdev->dev, "Virtchnl major version greater than supported\n");
+ return -EINVAL;
+ }
+ if (vvi.major == IECM_VIRTCHNL_VERSION_MAJOR &&
+ vvi.minor > IECM_VIRTCHNL_VERSION_MINOR)
+ dev_warn(&adapter->pdev->dev, "Virtchnl minor version not matched\n");
+
+ /* If we have a mismatch, resend version to update receiver on what
+ * version we will use.
+ */
+ if (!adapter->virt_ver_maj &&
+ vvi.major != IECM_VIRTCHNL_VERSION_MAJOR &&
+ vvi.minor != IECM_VIRTCHNL_VERSION_MINOR)
+ err = -EAGAIN;
+
+ adapter->virt_ver_maj = vvi.major;
+ adapter->virt_ver_min = vvi.minor;
+
+ return err;
+}
+
+/**
+ * iecm_send_get_caps_msg - Send virtchnl get capabilities message
+ * @adapter: Driver specific private structure
+ *
+ * Send virtchl get capabilities message. Returns 0 on success, negative on
+ * failure.
+ */
+int iecm_send_get_caps_msg(struct iecm_adapter *adapter)
+{
+ struct virtchnl2_get_capabilities caps = {0};
+ int buf_size;
+
+ buf_size = sizeof(struct virtchnl2_get_capabilities);
+ adapter->caps = kzalloc(buf_size, GFP_KERNEL);
+ if (!adapter->caps)
+ return -ENOMEM;
+
+ caps.csum_caps =
+ cpu_to_le32(VIRTCHNL2_CAP_TX_CSUM_L3_IPV4 |
+ VIRTCHNL2_CAP_TX_CSUM_L4_IPV4_TCP |
+ VIRTCHNL2_CAP_TX_CSUM_L4_IPV4_UDP |
+ VIRTCHNL2_CAP_TX_CSUM_L4_IPV4_SCTP |
+ VIRTCHNL2_CAP_TX_CSUM_L4_IPV6_TCP |
+ VIRTCHNL2_CAP_TX_CSUM_L4_IPV6_UDP |
+ VIRTCHNL2_CAP_TX_CSUM_L4_IPV6_SCTP |
+ VIRTCHNL2_CAP_TX_CSUM_GENERIC |
+ VIRTCHNL2_CAP_RX_CSUM_L3_IPV4 |
+ VIRTCHNL2_CAP_RX_CSUM_L4_IPV4_TCP |
+ VIRTCHNL2_CAP_RX_CSUM_L4_IPV4_UDP |
+ VIRTCHNL2_CAP_RX_CSUM_L4_IPV4_SCTP |
+ VIRTCHNL2_CAP_RX_CSUM_L4_IPV6_TCP |
+ VIRTCHNL2_CAP_RX_CSUM_L4_IPV6_UDP |
+ VIRTCHNL2_CAP_RX_CSUM_L4_IPV6_SCTP |
+ VIRTCHNL2_CAP_RX_CSUM_GENERIC);
+
+ caps.seg_caps =
+ cpu_to_le32(VIRTCHNL2_CAP_SEG_IPV4_TCP |
+ VIRTCHNL2_CAP_SEG_IPV4_UDP |
+ VIRTCHNL2_CAP_SEG_IPV4_SCTP |
+ VIRTCHNL2_CAP_SEG_IPV6_TCP |
+ VIRTCHNL2_CAP_SEG_IPV6_UDP |
+ VIRTCHNL2_CAP_SEG_IPV6_SCTP |
+ VIRTCHNL2_CAP_SEG_GENERIC);
+
+ caps.rss_caps =
+ cpu_to_le64(VIRTCHNL2_CAP_RSS_IPV4_TCP |
+ VIRTCHNL2_CAP_RSS_IPV4_UDP |
+ VIRTCHNL2_CAP_RSS_IPV4_SCTP |
+ VIRTCHNL2_CAP_RSS_IPV4_OTHER |
+ VIRTCHNL2_CAP_RSS_IPV6_TCP |
+ VIRTCHNL2_CAP_RSS_IPV6_UDP |
+ VIRTCHNL2_CAP_RSS_IPV6_SCTP |
+ VIRTCHNL2_CAP_RSS_IPV6_OTHER |
+ VIRTCHNL2_CAP_RSS_IPV4_AH |
+ VIRTCHNL2_CAP_RSS_IPV4_ESP |
+ VIRTCHNL2_CAP_RSS_IPV4_AH_ESP |
+ VIRTCHNL2_CAP_RSS_IPV6_AH |
+ VIRTCHNL2_CAP_RSS_IPV6_ESP |
+ VIRTCHNL2_CAP_RSS_IPV6_AH_ESP);
+
+ caps.hsplit_caps =
+ cpu_to_le32(VIRTCHNL2_CAP_RX_HSPLIT_AT_L2 |
+ VIRTCHNL2_CAP_RX_HSPLIT_AT_L3 |
+ VIRTCHNL2_CAP_RX_HSPLIT_AT_L4V4 |
+ VIRTCHNL2_CAP_RX_HSPLIT_AT_L4V6);
+
+ caps.rsc_caps =
+ cpu_to_le32(VIRTCHNL2_CAP_RSC_IPV4_TCP |
+ VIRTCHNL2_CAP_RSC_IPV4_SCTP |
+ VIRTCHNL2_CAP_RSC_IPV6_TCP |
+ VIRTCHNL2_CAP_RSC_IPV6_SCTP);
+
+ caps.other_caps =
+ cpu_to_le64(VIRTCHNL2_CAP_RDMA |
+ VIRTCHNL2_CAP_SRIOV |
+ VIRTCHNL2_CAP_MACFILTER |
+ VIRTCHNL2_CAP_FLOW_DIRECTOR |
+ VIRTCHNL2_CAP_SPLITQ_QSCHED |
+ VIRTCHNL2_CAP_CRC |
+ VIRTCHNL2_CAP_ADQ |
+ VIRTCHNL2_CAP_WB_ON_ITR |
+ VIRTCHNL2_CAP_PROMISC |
+ VIRTCHNL2_CAP_INLINE_IPSEC |
+ VIRTCHNL2_CAP_VLAN |
+ VIRTCHNL2_CAP_RX_FLEX_DESC);
+
+ return iecm_send_mb_msg(adapter, VIRTCHNL2_OP_GET_CAPS, sizeof(caps),
+ (u8 *)&caps);
+}
+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. Returns 0 on succes, negative on
+ * failure.
+ */
+static int iecm_recv_get_caps_msg(struct iecm_adapter *adapter)
+{
+ return iecm_recv_mb_msg(adapter, VIRTCHNL2_OP_GET_CAPS, adapter->caps,
+ sizeof(struct virtchnl2_get_capabilities));
+}
+
+/**
+ * iecm_send_create_vport_msg - Send virtchnl create vport message
+ * @adapter: Driver specific private structure
+ *
+ * send virtchnl creae vport message
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int iecm_send_create_vport_msg(struct iecm_adapter *adapter)
+{
+ /* stub */
+ return 0;
+}
+
+/**
+ * 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 0 on success, negative on
+ * failure.
+ */
+static int iecm_recv_create_vport_msg(struct iecm_adapter *adapter,
+ int *vport_id)
+{
+ /* stub */
+ return 0;
+}
+
+/**
+ * __iecm_wait_for_event - wrapper function for wait on virtchannel response
+ * @adapter: Driver private data structure
+ * @state: check on state upon timeout
+ * @err_check: check if this specific error bit is set
+ * @timeout: Max time to wait
+ *
+ * Checks if state is set upon expiry of timeout. Returns 0 on success,
+ * negative on failure.
+ */
+static int __iecm_wait_for_event(struct iecm_adapter *adapter,
+ enum iecm_vport_vc_state state,
+ enum iecm_vport_vc_state err_check,
+ int timeout)
+{
+ int event;
+
+ event = wait_event_timeout(adapter->vchnl_wq,
+ test_and_clear_bit(state, adapter->vc_state),
+ msecs_to_jiffies(timeout));
+ if (event) {
+ if (test_and_clear_bit(err_check, adapter->vc_state)) {
+ dev_err(&adapter->pdev->dev, "VC response error %s\n",
+ iecm_vport_vc_state_str[err_check]);
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ /* Timeout occurred */
+ dev_err(&adapter->pdev->dev, "VC timeout, state = %s\n",
+ iecm_vport_vc_state_str[state]);
+ return -ETIMEDOUT;
+}
+
+/**
+ * iecm_min_wait_for_event - wait for virtchannel response
+ * @adapter: Driver private data structure
+ * @state: check on state upon timeout
+ * @err_check: check if this specific error bit is set
+ *
+ * Returns 0 on success, negative on failure.
+ */
+int iecm_min_wait_for_event(struct iecm_adapter *adapter,
+ enum iecm_vport_vc_state state,
+ enum iecm_vport_vc_state err_check)
+{
+ int timeout = 2000;
+
+ return __iecm_wait_for_event(adapter, state, err_check, timeout);
+}
+EXPORT_SYMBOL(iecm_min_wait_for_event);
+
+/**
+ * iecm_wait_for_event - wait for virtchannel response
+ * @adapter: Driver private data structure
+ * @state: check on state upon timeout after 500ms
+ * @err_check: check if this specific error bit is set
+ *
+ * Returns 0 on success, negative on failure.
+ */
+int iecm_wait_for_event(struct iecm_adapter *adapter,
+ enum iecm_vport_vc_state state,
+ enum iecm_vport_vc_state err_check)
+{
+ /* Increasing the timeout in __IECM_INIT_SW flow to consider large
+ * number of VF's mailbox message responses. When a message is received
+ * on mailbox, this thread is wake up by the iecm_recv_mb_msg before the
+ * timeout expires. Only in the error case i.e. if no message is
+ * received on mailbox, we wait for the complete timeout which is
+ * less likely to happen.
+ */
+ int timeout = 60000;
+
+ return __iecm_wait_for_event(adapter, state, err_check, timeout);
+}
+EXPORT_SYMBOL(iecm_wait_for_event);
+
/**
* iecm_find_ctlq - Given a type and id, find ctlq info
* @hw: hardware struct
@@ -170,3 +1097,375 @@ void iecm_vport_params_buf_rel(struct iecm_adapter *adapter)
kfree(adapter->caps);
kfree(adapter->config_data.req_qs_chunks);
}
+
+/**
+ * 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. Returns 0
+ * on success, -EAGAIN function will get called again, otherwise negative on
+ * failure.
+ */
+int iecm_vc_core_init(struct iecm_adapter *adapter, int *vport_id)
+{
+ int err;
+
+ 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:
+ err = iecm_recv_ver_msg(adapter);
+ if (err == -EAGAIN) {
+ adapter->state = __IECM_STARTUP;
+ goto restart;
+ } else if (err) {
+ 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;
+ /* If it reaches here, it is possible that mailbox queue initialization
+ * register writes might not have taken effect. Retry to initialize
+ * the mailbox again
+ */
+ iecm_deinit_dflt_mbx(adapter);
+ set_bit(__IECM_HR_DRV_LOAD, adapter->flags);
+ queue_delayed_work(adapter->vc_event_wq, &adapter->vc_event_task,
+ msecs_to_jiffies(20));
+ return -EAGAIN;
+}
+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,
+ __always_unused int vport_id)
+{
+ struct virtchnl2_create_vport *vport_msg;
+ u16 rx_itr[] = {2, 8, 32, 96, 128};
+ u16 tx_itr[] = {2, 8, 64, 128, 256};
+
+ vport_msg = (struct virtchnl2_create_vport *)
+ vport->adapter->vport_params_recvd[0];
+ vport->txq_model = le16_to_cpu(vport_msg->txq_model);
+ vport->rxq_model = le16_to_cpu(vport_msg->rxq_model);
+ vport->vport_type = le16_to_cpu(vport_msg->vport_type);
+ vport->vport_id = le32_to_cpu(vport_msg->vport_id);
+ vport->adapter->rss_data.rss_key_size =
+ min_t(u16, NETDEV_RSS_KEY_LEN,
+ le16_to_cpu(vport_msg->rss_key_size));
+ vport->adapter->rss_data.rss_lut_size =
+ le16_to_cpu(vport_msg->rss_lut_size);
+ ether_addr_copy(vport->default_mac_addr, vport_msg->default_mac_addr);
+ vport->max_mtu = IECM_MAX_MTU;
+
+ if (iecm_is_queue_model_split(vport->rxq_model)) {
+ vport->num_bufqs_per_qgrp = IECM_MAX_BUFQS_PER_RXQ_GRP;
+ /* Bufq[0] default buffer size is 4K
+ * Bufq[1] default buffer size is 2K
+ */
+ vport->bufq_size[0] = IECM_RX_BUF_4096;
+ vport->bufq_size[1] = IECM_RX_BUF_2048;
+ } else {
+ vport->num_bufqs_per_qgrp = 0;
+ vport->bufq_size[0] = IECM_RX_BUF_2048;
+ }
+
+ /*Initialize Tx and Rx profiles for Dynamic Interrupt Moderation */
+ memcpy(vport->rx_itr_profile, rx_itr, IECM_DIM_PROFILE_SLOTS);
+ memcpy(vport->tx_itr_profile, tx_itr, IECM_DIM_PROFILE_SLOTS);
+}
+
+/**
+ * iecm_get_vec_ids - Initialize vector id from Mailbox parameters
+ * @adapter: adapter structure to get the mailbox vector id
+ * @vecids: Array of vector ids
+ * @num_vecids: number of vector ids
+ * @chunks: vector ids received over mailbox
+ *
+ * Will initialize the mailbox vector id which is received from the
+ * get capabilities and data queue vector ids with ids received as
+ * mailbox parameters.
+ * Returns number of ids filled
+ */
+int iecm_get_vec_ids(struct iecm_adapter *adapter,
+ u16 *vecids, int num_vecids,
+ struct virtchnl2_vector_chunks *chunks)
+{
+ u16 num_chunks = le16_to_cpu(chunks->num_vchunks);
+ u16 start_vecid, num_vec;
+ int num_vecid_filled = 0;
+ int i, j;
+
+ vecids[num_vecid_filled] = adapter->mb_vector.v_idx;
+ num_vecid_filled++;
+
+ for (j = 0; j < num_chunks; j++) {
+ struct virtchnl2_vector_chunk *chunk = &chunks->vchunks[j];
+
+ num_vec = le16_to_cpu(chunk->num_vectors);
+ start_vecid = le16_to_cpu(chunk->start_vector_id);
+ for (i = 0; i < num_vec; i++) {
+ if ((num_vecid_filled + i) < num_vecids) {
+ vecids[num_vecid_filled + i] = start_vecid;
+ start_vecid++;
+ } else {
+ break;
+ }
+ }
+ num_vecid_filled = num_vecid_filled + i;
+ }
+
+ return num_vecid_filled;
+}
+
+/**
+ * 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(u32 *qids, int num_qids, u16 q_type,
+ struct virtchnl2_queue_reg_chunks *chunks)
+{
+ u16 num_chunks = le16_to_cpu(chunks->num_chunks);
+ u32 num_q_id_filled = 0, i;
+ u32 start_q_id, num_q;
+
+ while (num_chunks) {
+ struct virtchnl2_queue_reg_chunk *chunk = &chunks->chunks[num_chunks - 1];
+
+ if (le32_to_cpu(chunk->type) == q_type) {
+ num_q = le32_to_cpu(chunk->num_queues);
+ start_q_id = le32_to_cpu(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;
+}
+
+/**
+ * __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, u32 *qids,
+ int num_qids, u32 q_type)
+{
+ /* stub */
+ return 0;
+}
+
+/**
+ * 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 0 on success, negative if all the queues are not initialized.
+ */
+static int iecm_vport_queue_ids_init(struct iecm_vport *vport)
+{
+ struct virtchnl2_create_vport *vport_params;
+ struct virtchnl2_queue_reg_chunks *chunks;
+ /* We may never deal with more than 256 same type of queues */
+#define IECM_MAX_QIDS 256
+ u32 qids[IECM_MAX_QIDS];
+ int num_ids;
+ u16 q_type;
+
+ if (vport->adapter->config_data.req_qs_chunks) {
+ struct virtchnl2_add_queues *vc_aq =
+ (struct virtchnl2_add_queues *)
+ vport->adapter->config_data.req_qs_chunks;
+ chunks = &vc_aq->chunks;
+ } else {
+ vport_params = (struct virtchnl2_create_vport *)
+ vport->adapter->vport_params_recvd[0];
+ chunks = &vport_params->chunks;
+ }
+
+ num_ids = iecm_vport_get_queue_ids(qids, IECM_MAX_QIDS,
+ VIRTCHNL2_QUEUE_TYPE_TX,
+ chunks);
+ if (num_ids != vport->num_txq)
+ return -EINVAL;
+ num_ids = __iecm_vport_queue_ids_init(vport, qids, num_ids,
+ VIRTCHNL2_QUEUE_TYPE_TX);
+ if (num_ids != vport->num_txq)
+ return -EINVAL;
+ num_ids = iecm_vport_get_queue_ids(qids, IECM_MAX_QIDS,
+ VIRTCHNL2_QUEUE_TYPE_RX,
+ chunks);
+ if (num_ids != vport->num_rxq)
+ return -EINVAL;
+ num_ids = __iecm_vport_queue_ids_init(vport, qids, num_ids,
+ VIRTCHNL2_QUEUE_TYPE_RX);
+ if (num_ids != vport->num_rxq)
+ return -EINVAL;
+
+ if (iecm_is_queue_model_split(vport->txq_model)) {
+ q_type = VIRTCHNL2_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 -EINVAL;
+ num_ids = __iecm_vport_queue_ids_init(vport, qids,
+ num_ids,
+ q_type);
+ if (num_ids != vport->num_complq)
+ return -EINVAL;
+ }
+
+ if (iecm_is_queue_model_split(vport->rxq_model)) {
+ q_type = VIRTCHNL2_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 -EINVAL;
+ num_ids = __iecm_vport_queue_ids_init(vport, qids, num_ids,
+ q_type);
+ if (num_ids != vport->num_bufq)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * iecm_is_capability_ena - Default implementation of capability checking
+ * @adapter: Private data struct
+ * @all: all or one flag
+ * @field: caps field to check for flags
+ * @flag: flag to check
+ *
+ * Return true if all capabilities are supported, false otherwise
+ */
+static bool iecm_is_capability_ena(struct iecm_adapter *adapter, bool all,
+ enum iecm_cap_field field, u64 flag)
+{
+ u8 *caps = (u8 *)adapter->caps;
+ u32 *cap_field;
+
+ if (field == IECM_BASE_CAPS)
+ return false;
+ if (field >= IECM_CAP_FIELD_LAST) {
+ dev_err(&adapter->pdev->dev, "Bad capability field: %d\n",
+ field);
+ return false;
+ }
+ cap_field = (u32 *)(caps + field);
+
+ if (all)
+ return (*cap_field & flag) == flag;
+ else
+ return !!(*cap_field & flag);
+}
+
+/**
+ * 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)
+{
+ struct iecm_virtchnl_ops *vc_ops = &adapter->dev_ops.vc_ops;
+
+ vc_ops->core_init = iecm_vc_core_init;
+ vc_ops->vport_init = iecm_vport_init;
+ vc_ops->vport_queue_ids_init = iecm_vport_queue_ids_init;
+ vc_ops->get_caps = iecm_send_get_caps_msg;
+ vc_ops->is_cap_ena = iecm_is_capability_ena;
+ vc_ops->get_reserved_vecs = NULL;
+ vc_ops->config_queues = NULL;
+ vc_ops->enable_queues = NULL;
+ vc_ops->disable_queues = NULL;
+ vc_ops->add_queues = NULL;
+ vc_ops->delete_queues = NULL;
+ vc_ops->irq_map_unmap = NULL;
+ vc_ops->enable_vport = NULL;
+ vc_ops->disable_vport = NULL;
+ vc_ops->destroy_vport = NULL;
+ vc_ops->get_ptype = NULL;
+ vc_ops->get_set_rss_key = NULL;
+ vc_ops->get_set_rss_lut = NULL;
+ vc_ops->get_set_rss_hash = NULL;
+ vc_ops->adjust_qs = NULL;
+ vc_ops->add_del_vlans = NULL;
+ vc_ops->strip_vlan_msg = NULL;
+ vc_ops->insert_vlan_msg = NULL;
+ vc_ops->init_max_queues = NULL;
+ vc_ops->get_max_tx_bufs = NULL;
+ vc_ops->vportq_reg_init = NULL;
+ vc_ops->alloc_vectors = NULL;
+ vc_ops->dealloc_vectors = NULL;
+ vc_ops->get_supported_desc_ids = NULL;
+ vc_ops->get_stats_msg = NULL;
+ vc_ops->recv_mbx_msg = NULL;
+}
+EXPORT_SYMBOL(iecm_vc_ops_init);
diff --git a/drivers/net/ethernet/intel/include/iecm.h b/drivers/net/ethernet/intel/include/iecm.h
index ca9029224e06..994664dfe419 100644
--- a/drivers/net/ethernet/intel/include/iecm.h
+++ b/drivers/net/ethernet/intel/include/iecm.h
@@ -7,10 +7,13 @@
#include <linux/aer.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
#include <linux/ethtool.h>
+#include <net/tcp.h>
#include <linux/version.h>
#include <linux/dim.h>
+#include "virtchnl_2.h"
#include "iecm_txrx.h"
#include "iecm_controlq.h"
@@ -35,10 +38,34 @@
/* available message levels */
#define IECM_AVAIL_NETIF_M (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
+#define IECM_VIRTCHNL_VERSION_MAJOR VIRTCHNL_VERSION_MAJOR_2
+#define IECM_VIRTCHNL_VERSION_MINOR VIRTCHNL_VERSION_MINOR_0
+
/* Forward declaration */
struct iecm_adapter;
struct iecm_vport;
+struct iecm_mac_filter {
+ struct list_head list;
+ u8 macaddr[ETH_ALEN];
+ bool remove; /* filter needs to be removed */
+ bool add; /* filter needs to be added */
+};
+
+#define IECM_VLAN(vid, tpid) ((struct iecm_vlan){ vid, tpid })
+
+struct iecm_vlan {
+ u16 vid;
+ u16 tpid;
+};
+
+struct iecm_vlan_filter {
+ struct list_head list;
+ struct iecm_vlan vlan;
+ bool remove; /* filter needs to be removed */
+ bool add; /* filter needs to be added */
+};
+
enum iecm_state {
__IECM_STARTUP,
__IECM_VER_CHECK,
@@ -90,6 +117,24 @@ enum iecm_flags {
__IECM_FLAGS_NBITS,
};
+/* enum used to distinquish which capability field to check */
+enum iecm_cap_field {
+ IECM_BASE_CAPS = -1,
+ IECM_CSUM_CAPS = offsetof(struct virtchnl2_get_capabilities,
+ csum_caps),
+ IECM_SEG_CAPS = offsetof(struct virtchnl2_get_capabilities,
+ seg_caps),
+ IECM_RSS_CAPS = offsetof(struct virtchnl2_get_capabilities,
+ rss_caps),
+ IECM_HSPLIT_CAPS = offsetof(struct virtchnl2_get_capabilities,
+ hsplit_caps),
+ IECM_RSC_CAPS = offsetof(struct virtchnl2_get_capabilities,
+ rsc_caps),
+ IECM_OTHER_CAPS = offsetof(struct virtchnl2_get_capabilities,
+ other_caps),
+ IECM_CAP_FIELD_LAST,
+};
+
struct iecm_reset_reg {
u32 rstat;
u32 rstat_m;
@@ -105,14 +150,229 @@ struct iecm_reg_ops {
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);
+ int (*vport_queue_ids_init)(struct iecm_vport *vport);
+ int (*get_caps)(struct iecm_adapter *adapter);
+ int (*config_queues)(struct iecm_vport *vport);
+ int (*enable_queues)(struct iecm_vport *vport);
+ int (*disable_queues)(struct iecm_vport *vport);
+ int (*add_queues)(struct iecm_vport *vport, u16 num_tx_q,
+ u16 num_complq, u16 num_rx_q,
+ u16 num_rx_bufq);
+ int (*delete_queues)(struct iecm_vport *vport);
+ int (*irq_map_unmap)(struct iecm_vport *vport, bool map);
+ int (*enable_vport)(struct iecm_vport *vport);
+ int (*disable_vport)(struct iecm_vport *vport);
+ int (*destroy_vport)(struct iecm_vport *vport);
+ int (*get_ptype)(struct iecm_vport *vport);
+ int (*get_set_rss_key)(struct iecm_vport *vport, bool get);
+ int (*get_set_rss_lut)(struct iecm_vport *vport, bool get);
+ int (*get_set_rss_hash)(struct iecm_vport *vport, bool get);
+ void (*adjust_qs)(struct iecm_vport *vport);
+ int (*recv_mbx_msg)(struct iecm_adapter *adapter,
+ void *msg, int msg_size,
+ struct iecm_ctlq_msg *ctlq_msg, bool *work_done);
+ bool (*is_cap_ena)(struct iecm_adapter *adapter, bool all,
+ enum iecm_cap_field field, u64 flag);
+ u16 (*get_reserved_vecs)(struct iecm_adapter *adapter);
+ void (*add_del_vlans)(struct iecm_vport *vport, bool add);
+ int (*strip_vlan_msg)(struct iecm_vport *vport, bool ena);
+ int (*insert_vlan_msg)(struct iecm_vport *vport, bool ena);
+ void (*init_max_queues)(struct iecm_adapter *adapter);
+ unsigned int (*get_max_tx_bufs)(struct iecm_adapter *adapter);
+ int (*vportq_reg_init)(struct iecm_vport *vport);
+ int (*alloc_vectors)(struct iecm_adapter *adapter, u16 num_vectors);
+ int (*dealloc_vectors)(struct iecm_adapter *adapter);
+ int (*get_supported_desc_ids)(struct iecm_vport *vport);
+ int (*get_stats_msg)(struct iecm_vport *vport);
+};
+
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;
+};
+
+/* These macros allow us to generate an enum and a matching char * array of
+ * stringified enums that are always in sync. Checkpatch issues a bogus warning
+ * about this being a complex macro; but it's wrong, these are never used as a
+ * statement and instead only used to define the enum and array.
+ */
+#define IECM_FOREACH_VPORT_VC_STATE(STATE) \
+ STATE(IECM_VC_ENA_VPORT) \
+ STATE(IECM_VC_ENA_VPORT_ERR) \
+ STATE(IECM_VC_DIS_VPORT) \
+ STATE(IECM_VC_DIS_VPORT_ERR) \
+ STATE(IECM_VC_DESTROY_VPORT) \
+ STATE(IECM_VC_DESTROY_VPORT_ERR) \
+ STATE(IECM_VC_CONFIG_TXQ) \
+ STATE(IECM_VC_CONFIG_TXQ_ERR) \
+ STATE(IECM_VC_CONFIG_RXQ) \
+ STATE(IECM_VC_CONFIG_RXQ_ERR) \
+ STATE(IECM_VC_CONFIG_Q) \
+ STATE(IECM_VC_CONFIG_Q_ERR) \
+ STATE(IECM_VC_ENA_QUEUES) \
+ STATE(IECM_VC_ENA_QUEUES_ERR) \
+ STATE(IECM_VC_DIS_QUEUES) \
+ STATE(IECM_VC_DIS_QUEUES_ERR) \
+ STATE(IECM_VC_ENA_CHANNELS) \
+ STATE(IECM_VC_ENA_CHANNELS_ERR) \
+ STATE(IECM_VC_DIS_CHANNELS) \
+ STATE(IECM_VC_DIS_CHANNELS_ERR) \
+ STATE(IECM_VC_MAP_IRQ) \
+ STATE(IECM_VC_MAP_IRQ_ERR) \
+ STATE(IECM_VC_UNMAP_IRQ) \
+ STATE(IECM_VC_UNMAP_IRQ_ERR) \
+ STATE(IECM_VC_ADD_QUEUES) \
+ STATE(IECM_VC_ADD_QUEUES_ERR) \
+ STATE(IECM_VC_DEL_QUEUES) \
+ STATE(IECM_VC_REQUEST_QUEUES) \
+ STATE(IECM_VC_REQUEST_QUEUES_ERR) \
+ STATE(IECM_VC_DEL_QUEUES_ERR) \
+ STATE(IECM_VC_ALLOC_VECTORS) \
+ STATE(IECM_VC_ALLOC_VECTORS_ERR) \
+ STATE(IECM_VC_DEALLOC_VECTORS) \
+ STATE(IECM_VC_DEALLOC_VECTORS_ERR) \
+ STATE(IECM_VC_SET_SRIOV_VFS) \
+ STATE(IECM_VC_SET_SRIOV_VFS_ERR) \
+ STATE(IECM_VC_GET_RSS_HASH) \
+ STATE(IECM_VC_GET_RSS_HASH_ERR) \
+ STATE(IECM_VC_SET_RSS_HASH) \
+ STATE(IECM_VC_SET_RSS_HASH_ERR) \
+ STATE(IECM_VC_GET_RSS_LUT) \
+ STATE(IECM_VC_GET_RSS_LUT_ERR) \
+ STATE(IECM_VC_SET_RSS_LUT) \
+ STATE(IECM_VC_SET_RSS_LUT_ERR) \
+ STATE(IECM_VC_GET_RSS_KEY) \
+ STATE(IECM_VC_GET_RSS_KEY_ERR) \
+ STATE(IECM_VC_SET_RSS_KEY) \
+ STATE(IECM_VC_SET_RSS_KEY_ERR) \
+ STATE(IECM_VC_GET_STATS) \
+ STATE(IECM_VC_GET_STATS_ERR) \
+ STATE(IECM_VC_ENA_STRIP_VLAN_TAG) \
+ STATE(IECM_VC_ENA_STRIP_VLAN_TAG_ERR) \
+ STATE(IECM_VC_DIS_STRIP_VLAN_TAG) \
+ STATE(IECM_VC_DIS_STRIP_VLAN_TAG_ERR) \
+ STATE(IECM_VC_IWARP_IRQ_MAP) \
+ STATE(IECM_VC_IWARP_IRQ_MAP_ERR) \
+ STATE(IECM_VC_ADD_ETH_ADDR) \
+ STATE(IECM_VC_ADD_ETH_ADDR_ERR) \
+ STATE(IECM_VC_DEL_ETH_ADDR) \
+ STATE(IECM_VC_DEL_ETH_ADDR_ERR) \
+ STATE(IECM_VC_PROMISC) \
+ STATE(IECM_VC_ADD_CLOUD_FILTER) \
+ STATE(IECM_VC_ADD_CLOUD_FILTER_ERR) \
+ STATE(IECM_VC_DEL_CLOUD_FILTER) \
+ STATE(IECM_VC_DEL_CLOUD_FILTER_ERR) \
+ STATE(IECM_VC_ADD_RSS_CFG) \
+ STATE(IECM_VC_ADD_RSS_CFG_ERR) \
+ STATE(IECM_VC_DEL_RSS_CFG) \
+ STATE(IECM_VC_DEL_RSS_CFG_ERR) \
+ STATE(IECM_VC_ADD_FDIR_FILTER) \
+ STATE(IECM_VC_ADD_FDIR_FILTER_ERR) \
+ STATE(IECM_VC_DEL_FDIR_FILTER) \
+ STATE(IECM_VC_DEL_FDIR_FILTER_ERR) \
+ STATE(IECM_VC_OFFLOAD_VLAN_V2_CAPS) \
+ STATE(IECM_VC_OFFLOAD_VLAN_V2_CAPS_ERR) \
+ STATE(IECM_VC_INSERTION_ENA_VLAN_V2) \
+ STATE(IECM_VC_INSERTION_ENA_VLAN_V2_ERR)\
+ STATE(IECM_VC_INSERTION_DIS_VLAN_V2) \
+ STATE(IECM_VC_INSERTION_DIS_VLAN_V2_ERR)\
+ STATE(IECM_VC_STRIPPING_ENA_VLAN_V2) \
+ STATE(IECM_VC_STRIPPING_ENA_VLAN_V2_ERR)\
+ STATE(IECM_VC_STRIPPING_DIS_VLAN_V2) \
+ STATE(IECM_VC_STRIPPING_DIS_VLAN_V2_ERR)\
+ STATE(IECM_VC_GET_SUPPORTED_RXDIDS) \
+ STATE(IECM_VC_GET_SUPPORTED_RXDIDS_ERR) \
+ STATE(IECM_VC_GET_PTYPE_INFO) \
+ STATE(IECM_VC_GET_PTYPE_INFO_ERR) \
+ STATE(IECM_VC_NBITS)
+
+#define IECM_GEN_ENUM(ENUM) ENUM,
+#define IECM_GEN_STRING(STRING) #STRING,
+
+enum iecm_vport_vc_state {
+ IECM_FOREACH_VPORT_VC_STATE(IECM_GEN_ENUM)
+};
+
+extern const char * const iecm_vport_vc_state_str[];
+
+enum iecm_vport_flags {
+ __IECM_VPORT_INIT_PROMISC,
+ __IECM_VPORT_FLAGS_NBITS,
+};
+
+struct iecm_port_stats {
+ struct u64_stats_sync stats_sync;
+ u64 rx_hw_csum_err;
+ u64 rx_hsplit;
+ u64 rx_hsplit_hbo;
+ u64 tx_linearize;
+ u64 rx_bad_descs;
+ struct virtchnl2_vport_stats vport_stats;
+ struct virtchnl_eth_stats eth_stats;
};
-/* stub */
struct iecm_vport {
+ /* TX */
+ int num_txq;
+ int num_complq;
+ /* It makes more sense for descriptor count to be part of only idpf
+ * 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.
+ */
+ int txq_desc_count;
+ int complq_desc_count;
+ int compln_clean_budget;
+ int num_txq_grp;
+ struct iecm_txq_group *txq_grps;
+ u32 txq_model;
+ /* Used only in hotpath to get to the right queue very fast */
+ struct iecm_queue **txqs;
+ DECLARE_BITMAP(flags, __IECM_VPORT_FLAGS_NBITS);
+
+ /* RX */
+ int num_rxq;
+ int num_bufq;
+ int rxq_desc_count;
+ u8 num_bufqs_per_qgrp;
+ int bufq_desc_count[IECM_MAX_BUFQS_PER_RXQ_GRP];
+ u32 bufq_size[IECM_MAX_BUFQS_PER_RXQ_GRP];
+ int num_rxq_grp;
+ struct iecm_rxq_group *rxq_grps;
+ u32 rxq_model;
+
+ struct iecm_adapter *adapter;
+ struct net_device *netdev;
+ u16 vport_type;
+ u16 vport_id;
+ u16 idx; /* software index in adapter vports struct */
+ bool base_rxd;
+
+ /* 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;
+ /* ITR profiles for the DIM algorithm */
+#define IECM_DIM_PROFILE_SLOTS 5
+ u16 rx_itr_profile[IECM_DIM_PROFILE_SLOTS];
+ u16 tx_itr_profile[IECM_DIM_PROFILE_SLOTS];
+ struct rtnl_link_stats64 netstats;
+ struct iecm_port_stats port_stats;
+
+ /* lock to protect against multiple stop threads, which can happen when
+ * the driver is in a namespace in a system that is being shutdown
+ */
+ struct mutex stop_mutex;
};
enum iecm_user_flags {
@@ -164,6 +424,7 @@ struct iecm_adapter {
u16 num_msix_entries;
struct msix_entry *msix_entries;
struct virtchnl2_alloc_vectors *req_vec_chunks;
+ struct iecm_q_vector mb_vector;
/* vport structs */
struct iecm_vport **vports; /* vports created by the driver */
@@ -190,6 +451,8 @@ struct iecm_adapter {
wait_queue_head_t vchnl_wq;
wait_queue_head_t sw_marker_wq;
+ DECLARE_BITMAP(vc_state, IECM_VC_NBITS);
+ char vc_msg[IECM_DFLT_MBX_BUF_SIZE];
struct iecm_rss_data rss_data;
struct iecm_dev_ops dev_ops;
s32 link_speed;
@@ -215,6 +478,38 @@ struct iecm_adapter {
spinlock_t fdir_fltr_list_lock;
};
+/**
+ * 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(u16 q_model)
+{
+ return (q_model == VIRTCHNL2_QUEUE_MODEL_SPLIT);
+}
+
+#define iecm_is_cap_ena(adapter, field, flag) \
+ __iecm_is_cap_ena(adapter, false, field, flag)
+#define iecm_is_cap_ena_all(adapter, field, flag) \
+ __iecm_is_cap_ena(adapter, true, field, flag)
+/**
+ * __iecm_is_cap_ena - Determine if HW capability is supported
+ * @adapter: private data struct
+ * @all: all or one flag
+ * @field: cap field to check
+ * @flag: Feature flag to check
+ *
+ * iecm_is_cap_ena_all is used to check if all the capability bits are set
+ * ('AND' operation) where as iecm_is_cap_ena is used to check if
+ * any one of the capability bits is set ('OR' operation)
+ */
+static inline bool __iecm_is_cap_ena(struct iecm_adapter *adapter, bool all,
+ enum iecm_cap_field field, u64 flag)
+{
+ return adapter->dev_ops.vc_ops.is_cap_ena(adapter, all, field, flag);
+}
+
/**
* iecm_is_reset_detected - check if we were reset at some point
* @adapter: driver specific private structure
@@ -233,6 +528,25 @@ int iecm_probe(struct pci_dev *pdev,
void iecm_remove(struct pci_dev *pdev);
int 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);
+int iecm_wait_for_event(struct iecm_adapter *adapter,
+ enum iecm_vport_vc_state state,
+ enum iecm_vport_vc_state err_check);
+int iecm_min_wait_for_event(struct iecm_adapter *adapter,
+ enum iecm_vport_vc_state state,
+ enum iecm_vport_vc_state err_check);
+int iecm_send_get_caps_msg(struct iecm_adapter *adapter);
int iecm_vport_params_buf_alloc(struct iecm_adapter *adapter);
void iecm_vport_params_buf_rel(struct iecm_adapter *adapter);
+int iecm_get_vec_ids(struct iecm_adapter *adapter,
+ u16 *vecids, int num_vecids,
+ struct virtchnl2_vector_chunks *chunks);
+int iecm_recv_mb_msg(struct iecm_adapter *adapter, enum virtchnl_ops op,
+ void *msg, int msg_size);
+int iecm_send_mb_msg(struct iecm_adapter *adapter, enum virtchnl_ops op,
+ u16 msg_size, u8 *msg);
+int iecm_set_msg_pending(struct iecm_adapter *adapter,
+ struct iecm_ctlq_msg *ctlq_msg,
+ enum iecm_vport_vc_state err_enum);
#endif /* !_IECM_H_ */
diff --git a/drivers/net/ethernet/intel/include/iecm_txrx.h b/drivers/net/ethernet/intel/include/iecm_txrx.h
index 602d3b3b19dd..e1348011c991 100644
--- a/drivers/net/ethernet/intel/include/iecm_txrx.h
+++ b/drivers/net/ethernet/intel/include/iecm_txrx.h
@@ -30,4 +30,98 @@
#define IECM_DFLT_SPLITQ_RX_Q_GROUPS 4
#define IECM_DFLT_SPLITQ_TXQ_PER_GROUP 1
#define IECM_DFLT_SPLITQ_RXQ_PER_GROUP 1
+
+/* Default vector sharing */
+#define IECM_NONQ_VEC 1
+#define IECM_MAX_Q_VEC 4 /* For Tx Completion queue and Rx queue */
+#define IECM_MIN_Q_VEC 1
+#define IECM_MAX_RDMA_VEC 2 /* To share with RDMA */
+#define IECM_MIN_RDMA_VEC 1 /* Minimum vectors to be shared with RDMA */
+#define IECM_MIN_VEC 3 /* One for mailbox, one for data queues, one
+ * for RDMA
+ */
+
+#define IECM_DFLT_TX_Q_DESC_COUNT 512
+#define IECM_DFLT_TX_COMPLQ_DESC_COUNT 512
+#define IECM_DFLT_RX_Q_DESC_COUNT 512
+/* IMPORTANT: We absolutely _cannot_ have more buffers in the system than a
+ * given RX completion queue has descriptors. This includes _ALL_ buffer
+ * queues. E.g.: If you have two buffer queues of 512 descriptors and buffers,
+ * you have a total of 1024 buffers so your RX queue _must_ have at least that
+ * many descriptors. This macro divides a given number of RX descriptors by
+ * number of buffer queues to calculate how many descriptors each buffer queue
+ * can have without overrunning the RX queue.
+ *
+ * If you give hardware more buffers than completion descriptors what will
+ * happen is that if hardware gets a chance to post more than ring wrap of
+ * descriptors before SW gets an interrupt and overwrites SW head, the gen bit
+ * in the descriptor will be wrong. Any overwritten descriptors' buffers will
+ * be gone forever and SW has no reasonable way to tell that this has happened.
+ * From SW perspective, when we finally get an interrupt, it looks like we're
+ * still waiting for descriptor to be done, stalling forever.
+ */
+#define IECM_RX_BUFQ_DESC_COUNT(RXD, NUM_BUFQ) ((RXD) / (NUM_BUFQ))
+
+#define IECM_RX_BUFQ_WORKING_SET(R) ((R)->desc_count - 1)
+#define IECM_RX_BUFQ_NON_WORKING_SET(R) ((R)->desc_count - \
+ IECM_RX_BUFQ_WORKING_SET(R))
+
+#define IECM_RX_HDR_SIZE 256
+#define IECM_RX_BUF_2048 2048
+#define IECM_RX_BUF_4096 4096
+#define IECM_RX_BUF_STRIDE 64
+#define IECM_LOW_WATERMARK 64
+#define IECM_HDR_BUF_SIZE 256
+#define IECM_PACKET_HDR_PAD \
+ (ETH_HLEN + ETH_FCS_LEN + (VLAN_HLEN * 2))
+#define IECM_MAX_RXBUFFER 9728
+#define IECM_MAX_MTU \
+ (IECM_MAX_RXBUFFER - IECM_PACKET_HDR_PAD)
+#define IECM_INT_NAME_STR_LEN (IFNAMSIZ + 16)
+
+#define IECM_TX_COMPLQ_CLEAN_BUDGET 256
+
+struct iecm_intr_reg {
+ u32 dyn_ctl;
+ u32 dyn_ctl_intena_m;
+ u32 dyn_ctl_clrpba_m;
+ u32 dyn_ctl_itridx_s;
+ u32 dyn_ctl_itridx_m;
+ u32 dyn_ctl_intrvl_s;
+ u32 rx_itr;
+ u32 tx_itr;
+ u32 icr_ena;
+ u32 icr_ena_ctlq_m;
+};
+
+struct iecm_q_vector {
+ struct iecm_vport *vport;
+ cpumask_t affinity_mask;
+ struct napi_struct napi;
+ u16 v_idx; /* index in the vport->q_vector array */
+ struct iecm_intr_reg intr_reg;
+
+ int num_txq;
+ struct iecm_queue **tx;
+ struct dim tx_dim; /* data for net_dim algorithm */
+ u16 tx_itr_value;
+ bool tx_intr_mode;
+ u32 tx_itr_idx;
+
+ int num_rxq;
+ struct iecm_queue **rx;
+ struct dim rx_dim; /* data for net_dim algorithm */
+ u16 rx_itr_value;
+ bool rx_intr_mode;
+ u32 rx_itr_idx;
+
+ int num_bufq;
+ struct iecm_queue **bufq;
+
+ u16 total_events; /* net_dim(): number of interrupts processed */
+ char name[IECM_INT_NAME_STR_LEN];
+};
+
+irqreturn_t
+iecm_vport_intr_clean_queues(int __always_unused irq, void *data);
#endif /* !_IECM_TXRX_H_ */
--
2.33.0
next prev parent reply other threads:[~2022-01-28 0:09 UTC|newest]
Thread overview: 83+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-28 0:09 [Intel-wired-lan] [PATCH net-next 00/19] Add iecm and idpf Alan Brady
2022-01-28 0:09 ` [Intel-wired-lan] [PATCH net-next 01/19] virtchnl: Add new virtchnl2 ops Alan Brady
2022-02-02 22:13 ` Brady, Alan
2022-01-28 0:09 ` [Intel-wired-lan] [PATCH net-next 02/19] iecm: add basic module init and documentation Alan Brady
2022-01-28 11:56 ` Alexander Lobakin
2022-02-02 22:15 ` Brady, Alan
2022-02-01 19:44 ` Shannon Nelson
2022-02-03 3:08 ` Brady, Alan
2022-01-28 0:09 ` [Intel-wired-lan] [PATCH net-next 03/19] iecm: add probe and remove Alan Brady
2022-02-01 20:02 ` Shannon Nelson
2022-02-03 3:13 ` Brady, Alan
2022-01-28 0:09 ` [Intel-wired-lan] [PATCH net-next 04/19] iecm: add api_init and controlq init Alan Brady
2022-01-28 12:09 ` Alexander Lobakin
2022-02-02 22:16 ` Brady, Alan
2022-02-01 21:26 ` Shannon Nelson
2022-02-03 3:24 ` Brady, Alan
2022-02-03 3:40 ` Brady, Alan
2022-02-03 5:26 ` Shannon Nelson
2022-02-03 13:13 ` Alexander Lobakin
2022-01-28 0:09 ` Alan Brady [this message]
2022-01-28 4:19 ` [Intel-wired-lan] [PATCH net-next 05/19] iecm: add vport alloc and virtchnl messages kernel test robot
2022-01-28 12:39 ` Alexander Lobakin
2022-02-02 22:23 ` Brady, Alan
2022-01-28 12:32 ` Alexander Lobakin
2022-02-02 22:21 ` Brady, Alan
2022-02-03 13:23 ` Alexander Lobakin
2022-01-28 0:09 ` [Intel-wired-lan] [PATCH net-next 06/19] iecm: add virtchnl messages for queues Alan Brady
2022-01-28 13:03 ` Alexander Lobakin
2022-02-02 22:48 ` Brady, Alan
2022-02-03 10:08 ` Maciej Fijalkowski
2022-02-03 14:09 ` Alexander Lobakin
2022-01-28 0:09 ` [Intel-wired-lan] [PATCH net-next 07/19] iecm: finish virtchnl messages Alan Brady
2022-01-28 13:19 ` Alexander Lobakin
2022-02-02 23:06 ` Brady, Alan
2022-02-03 15:05 ` Alexander Lobakin
2022-02-03 15:16 ` Maciej Fijalkowski
2022-01-28 0:09 ` [Intel-wired-lan] [PATCH net-next 08/19] iecm: add interrupts and configure netdev Alan Brady
2022-01-28 13:34 ` Alexander Lobakin
2022-02-02 23:17 ` Brady, Alan
2022-02-03 15:55 ` Alexander Lobakin
2022-01-28 0:09 ` [Intel-wired-lan] [PATCH net-next 09/19] iecm: alloc vport TX resources Alan Brady
2022-02-02 23:45 ` Brady, Alan
2022-02-03 17:56 ` Alexander Lobakin
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 10/19] iecm: alloc vport RX resources Alan Brady
2022-01-28 14:16 ` Alexander Lobakin
2022-02-03 0:13 ` Brady, Alan
2022-02-03 18:29 ` Alexander Lobakin
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 11/19] iecm: add start_xmit and set_rx_mode Alan Brady
2022-01-28 16:35 ` Alexander Lobakin
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 12/19] iecm: finish netdev_ops Alan Brady
2022-01-28 17:06 ` Alexander Lobakin
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 13/19] iecm: implement splitq napi_poll Alan Brady
2022-01-28 5:21 ` kernel test robot
2022-01-28 17:44 ` Alexander Lobakin
2022-02-03 1:15 ` Brady, Alan
2022-01-28 17:38 ` Alexander Lobakin
2022-02-03 1:07 ` Brady, Alan
2022-02-04 11:50 ` Alexander Lobakin
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 14/19] iecm: implement singleq napi_poll Alan Brady
2022-01-28 17:57 ` Alexander Lobakin
2022-02-03 1:45 ` Brady, Alan
2022-02-03 19:05 ` Alexander Lobakin
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 15/19] iecm: implement ethtool callbacks Alan Brady
2022-01-28 18:13 ` Alexander Lobakin
2022-02-03 2:13 ` Brady, Alan
2022-02-03 19:54 ` Alexander Lobakin
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 16/19] iecm: implement flow director Alan Brady
2022-01-28 19:04 ` Alexander Lobakin
2022-02-03 2:41 ` Brady, Alan
2022-02-04 10:08 ` Alexander Lobakin
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 17/19] iecm: implement cloud filters Alan Brady
2022-01-28 19:38 ` Alexander Lobakin
2022-02-03 2:53 ` Brady, Alan
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 18/19] iecm: add advanced rss Alan Brady
2022-01-28 19:53 ` Alexander Lobakin
2022-02-03 2:55 ` Brady, Alan
2022-02-03 10:46 ` Maciej Fijalkowski
2022-02-04 10:22 ` Alexander Lobakin
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 19/19] idpf: introduce idpf driver Alan Brady
2022-01-28 20:08 ` Alexander Lobakin
2022-02-03 3:07 ` Brady, Alan
2022-02-04 10:35 ` Alexander Lobakin
2022-02-04 12:05 ` [Intel-wired-lan] [PATCH net-next 00/19] Add iecm and idpf Alexander Lobakin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220128001009.721392-6-alan.brady@intel.com \
--to=alan.brady@intel.com \
--cc=intel-wired-lan@osuosl.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox