From: Alan Brady <alan.brady@intel.com>
To: intel-wired-lan@osuosl.org
Subject: [Intel-wired-lan] [PATCH net-next 04/19] iecm: add api_init and controlq init
Date: Thu, 27 Jan 2022 16:09:54 -0800 [thread overview]
Message-ID: <20220128001009.721392-5-alan.brady@intel.com> (raw)
In-Reply-To: <20220128001009.721392-1-alan.brady@intel.com>
Initializing device registers is offloaded into function pointers given
to iecm from the dependent device driver for a given device, as offsets
can vary wildly. This also adds everything needed to setup and use a
controlq which uses some of those registers.
At the end of probe we kicked off a hard reset and this implements what's
needed to handle that reset and continue init.
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 | 3 +
.../net/ethernet/intel/iecm/iecm_controlq.c | 649 ++++++++++++++++++
.../ethernet/intel/iecm/iecm_controlq_setup.c | 175 +++++
drivers/net/ethernet/intel/iecm/iecm_lib.c | 191 +++++-
.../net/ethernet/intel/iecm/iecm_virtchnl.c | 172 +++++
drivers/net/ethernet/intel/include/iecm.h | 52 ++
.../ethernet/intel/include/iecm_controlq.h | 117 ++++
.../intel/include/iecm_controlq_api.h | 185 +++++
drivers/net/ethernet/intel/include/iecm_mem.h | 20 +
9 files changed, 1563 insertions(+), 1 deletion(-)
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_virtchnl.c
create mode 100644 drivers/net/ethernet/intel/include/iecm_controlq.h
create mode 100644 drivers/net/ethernet/intel/include/iecm_controlq_api.h
create mode 100644 drivers/net/ethernet/intel/include/iecm_mem.h
diff --git a/drivers/net/ethernet/intel/iecm/Makefile b/drivers/net/ethernet/intel/iecm/Makefile
index 4f497723419d..db8fecb075a6 100644
--- a/drivers/net/ethernet/intel/iecm/Makefile
+++ b/drivers/net/ethernet/intel/iecm/Makefile
@@ -11,4 +11,7 @@ ccflags-y += -I$(srctree)/drivers/net/ethernet/intel/include
iecm-y := \
iecm_lib.o \
+ iecm_virtchnl.o \
+ iecm_controlq.o \
+ iecm_controlq_setup.o \
iecm_main.o
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..f9682a7b3e44
--- /dev/null
+++ b/drivers/net/ethernet/intel/iecm/iecm_controlq.c
@@ -0,0 +1,649 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2020, Intel Corporation. */
+
+#include "iecm_controlq.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)
+{
+ /* 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;
+}
+
+/**
+ * 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 void iecm_ctlq_init_regs(struct iecm_hw *hw, struct iecm_ctlq_info *cq,
+ bool is_rxq)
+{
+ /* Update tail to post pre-allocated buffers for rx queues */
+ if (is_rxq)
+ wr32(hw, cq->reg.tail, (u32)(cq->ring_size - 1));
+
+ /* For non-Mailbox control queues only TAIL need to be set */
+ if (cq->q_id != -1)
+ return;
+
+ /* Clear Head for both send or receive */
+ wr32(hw, cq->reg.head, 0);
+
+ /* set starting point */
+ wr32(hw, cq->reg.bal, lower_32_bits(cq->desc_ring.pa));
+ wr32(hw, cq->reg.bah, upper_32_bits(cq->desc_ring.pa));
+ wr32(hw, cq->reg.len, (cq->ring_size | cq->reg.len_ena_mask));
+}
+
+/**
+ * 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)
+{
+ 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(upper_32_bits(bi->pa));
+ desc->params.indirect.addr_low =
+ cpu_to_le32(lower_32_bits(bi->pa));
+ desc->params.indirect.param0 = 0;
+ desc->params.indirect.param1 = 0;
+ }
+}
+
+/**
+ * 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)
+{
+ 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);
+}
+
+/**
+ * iecm_ctlq_add - add one control queue
+ * @hw: pointer to hardware struct
+ * @qinfo: info for queue to be created
+ * @cq_out: (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
+ */
+int iecm_ctlq_add(struct iecm_hw *hw,
+ struct iecm_ctlq_create_info *qinfo,
+ struct iecm_ctlq_info **cq_out)
+{
+ bool is_rxq = false;
+ int status = 0;
+
+ if (!qinfo->len || !qinfo->buf_size ||
+ qinfo->len > IECM_CTLQ_MAX_RING_SIZE ||
+ qinfo->buf_size > IECM_CTLQ_MAX_BUF_LEN)
+ return -EINVAL;
+
+ *cq_out = kcalloc(1, sizeof(struct iecm_ctlq_info), GFP_KERNEL);
+ if (!(*cq_out))
+ return -ENOMEM;
+
+ (*cq_out)->cq_type = qinfo->type;
+ (*cq_out)->q_id = qinfo->id;
+ (*cq_out)->buf_size = qinfo->buf_size;
+ (*cq_out)->ring_size = qinfo->len;
+
+ (*cq_out)->next_to_use = 0;
+ (*cq_out)->next_to_clean = 0;
+ (*cq_out)->next_to_post = (*cq_out)->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_out);
+ break;
+ default:
+ status = -EBADR;
+ break;
+ }
+
+ if (status)
+ goto init_free_q;
+
+ if (is_rxq) {
+ iecm_ctlq_init_rxq_bufs(*cq_out);
+ } else {
+ /* Allocate the array of msg pointers for TX queues */
+ (*cq_out)->bi.tx_msg = kcalloc(qinfo->len,
+ sizeof(struct iecm_ctlq_msg *),
+ GFP_KERNEL);
+ if (!(*cq_out)->bi.tx_msg) {
+ status = -ENOMEM;
+ goto init_dealloc_q_mem;
+ }
+ }
+
+ iecm_ctlq_setup_regs(*cq_out, qinfo);
+
+ iecm_ctlq_init_regs(hw, *cq_out, is_rxq);
+
+ mutex_init(&(*cq_out)->cq_lock);
+
+ list_add(&(*cq_out)->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_out);
+init_free_q:
+ kfree(*cq_out);
+
+ return status;
+}
+
+/**
+ * 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)
+{
+ list_del(&cq->cq_list);
+ iecm_ctlq_shutdown(hw, cq);
+ kfree(cq);
+}
+
+/**
+ * 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.
+ */
+int iecm_ctlq_init(struct iecm_hw *hw, u8 num_q,
+ struct iecm_ctlq_create_info *q_info)
+{
+ struct iecm_ctlq_info *cq = NULL, *tmp = NULL;
+ int 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;
+}
+
+/**
+ * iecm_ctlq_deinit - destroy all control queues
+ * @hw: pointer to hw struct
+ */
+int iecm_ctlq_deinit(struct iecm_hw *hw)
+{
+ struct iecm_ctlq_info *cq = NULL, *tmp = NULL;
+ int ret_code = 0;
+
+ list_for_each_entry_safe(cq, tmp, &hw->cq_list_head, cq_list)
+ iecm_ctlq_remove(hw, cq);
+
+ return ret_code;
+}
+
+/**
+ * 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.
+ */
+int iecm_ctlq_send(struct iecm_hw *hw, struct iecm_ctlq_info *cq,
+ u16 num_q_msg, struct iecm_ctlq_msg q_msg[])
+{
+ struct iecm_ctlq_desc *desc;
+ int num_desc_avail = 0;
+ int status = 0;
+ int i = 0;
+
+ if (!cq || !cq->ring_size)
+ return -ENOBUFS;
+
+ 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 = -ENOSPC;
+ 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 = cpu_to_le16(msg->func_id);
+
+ msg_cookie = *(u64 *)&msg->cookie;
+ desc->cookie_high =
+ cpu_to_le32(upper_32_bits(msg_cookie));
+ desc->cookie_low =
+ cpu_to_le32(lower_32_bits(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(upper_32_bits(buff->pa));
+ desc->params.indirect.addr_low =
+ cpu_to_le32(lower_32_bits(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.
+ */
+ dma_wmb();
+
+ wr32(hw, cq->reg.tail, cq->next_to_use);
+
+sq_send_command_out:
+ mutex_unlock(&cq->cq_lock);
+
+ return status;
+}
+
+/**
+ * iecm_ctlq_clean_sq - reclaim send descriptors on HW write back for the
+ * requested queue
+ * @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 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.
+ */
+int iecm_ctlq_clean_sq(struct iecm_ctlq_info *cq, u16 *clean_count,
+ struct iecm_ctlq_msg *msg_status[])
+{
+ struct iecm_ctlq_desc *desc;
+ u16 i = 0, num_to_clean;
+ u16 ntc, desc_err;
+ int ret = 0;
+
+ if (!cq || !cq->ring_size)
+ return -ENOBUFS;
+
+ if (*clean_count == 0)
+ return 0;
+ if (*clean_count > cq->ring_size)
+ return -EBADR;
+
+ 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;
+}
+
+/**
+ * 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
+ */
+int iecm_ctlq_post_rx_buffs(struct iecm_hw *hw, struct iecm_ctlq_info *cq,
+ u16 *buff_count, struct iecm_dma_mem **buffs)
+{
+ struct iecm_ctlq_desc *desc;
+ u16 ntp = cq->next_to_post;
+ bool buffs_avail = false;
+ u16 tbp = ntp + 1;
+ int status = 0;
+ int i = 0;
+
+ if (*buff_count > cq->ring_size)
+ return -EBADR;
+
+ 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])
+ goto fill_desc;
+ 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;
+ }
+
+fill_desc:
+ 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(upper_32_bits(cq->bi.rx_buff[ntp]->pa));
+ desc->params.indirect.addr_low =
+ cpu_to_le32(lower_32_bits(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;
+}
+
+/**
+ * iecm_ctlq_recv - receive control queue message call back
+ * @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
+ */
+int iecm_ctlq_recv(struct iecm_ctlq_info *cq, u16 *num_q_msg,
+ struct iecm_ctlq_msg *q_msg)
+{
+ u16 num_to_clean, ntc, ret_val, flags;
+ struct iecm_ctlq_desc *desc;
+ int ret_code = 0;
+ u16 i = 0;
+
+ if (!cq || !cq->ring_size)
+ return -ENOBUFS;
+
+ if (*num_q_msg == 0)
+ return 0;
+ else if (*num_q_msg > cq->ring_size)
+ return -EBADR;
+
+ /* 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 = -EBADMSG;
+
+ 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 = -ENOMSG;
+
+ 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
new file mode 100644
index 000000000000..a36fc88d6bb5
--- /dev/null
+++ b/drivers/net/ethernet/intel/iecm/iecm_controlq_setup.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2020, Intel Corporation. */
+
+#include "iecm_controlq.h"
+
+/**
+ * iecm_ctlq_alloc_desc_ring - Allocate Control Queue (CQ) rings
+ * @hw: pointer to hw struct
+ * @cq: pointer to the specific Control queue
+ */
+static int
+iecm_ctlq_alloc_desc_ring(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq)
+{
+ 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 -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * 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 int iecm_ctlq_alloc_bufs(struct iecm_hw *hw,
+ struct iecm_ctlq_info *cq)
+{
+ 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 -ENOMEM;
+
+ /* 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 -ENOMEM;
+}
+
+/**
+ * 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)
+{
+ iecm_free_dma_mem(hw, &cq->desc_ring);
+}
+
+/**
+ * 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)
+{
+ 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);
+}
+
+/**
+ * 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)
+{
+ /* free ring buffers and the ring itself */
+ iecm_ctlq_free_bufs(hw, cq);
+ iecm_ctlq_free_desc_ring(hw, cq);
+}
+
+/**
+ * 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
+ */
+int iecm_ctlq_alloc_ring_res(struct iecm_hw *hw, struct iecm_ctlq_info *cq)
+{
+ int ret_code;
+
+ /* verify input for valid configuration */
+ if (!cq->ring_size || !cq->buf_size)
+ return -EINVAL;
+
+ /* 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 e6d0b418a27f..64cdbce2c842 100644
--- a/drivers/net/ethernet/intel/iecm/iecm_lib.c
+++ b/drivers/net/ethernet/intel/iecm/iecm_lib.c
@@ -5,6 +5,25 @@
#include "iecm.h"
+/**
+ * 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)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct iecm_hw *hw = &adapter->hw;
+
+ hw->hw_addr = pcim_iomap_table(pdev)[IECM_BAR0];
+ if (!hw->hw_addr)
+ return -EIO;
+ hw->back = adapter;
+
+ return 0;
+}
+
/**
* iecm_statistics_task - Delayed task to get statistics over mailbox
* @work: work_struct handle to our data
@@ -39,6 +58,32 @@ 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)
+{
+ struct iecm_reg_ops *reg_ops = &adapter->dev_ops.reg_ops;
+ struct pci_dev *pdev = adapter->pdev;
+
+ if (!adapter->dev_ops.reg_ops_init) {
+ dev_err(&pdev->dev, "Invalid device, register API init not defined\n");
+ return -EINVAL;
+ }
+ adapter->dev_ops.reg_ops_init(adapter);
+ if (!(reg_ops->ctlq_reg_init && reg_ops->intr_reg_init &&
+ reg_ops->mb_intr_reg_init && reg_ops->reset_reg_init &&
+ reg_ops->trigger_reset)) {
+ dev_err(&pdev->dev, "Invalid device, missing one or more register functions\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/**
* iecm_deinit_task - Device deinit routine
* @adapter: Driver specific private structue
@@ -51,13 +96,108 @@ static void iecm_deinit_task(struct iecm_adapter *adapter)
/* stub */
}
+/**
+ * iecm_check_reset_complete - check that reset is complete
+ * @hw: pointer to hw struct
+ * @reset_reg: struct with reset registers
+ *
+ * Returns 0 if device is ready to use, or -EBUSY if it's in reset.
+ **/
+static int iecm_check_reset_complete(struct iecm_hw *hw,
+ struct iecm_reset_reg *reset_reg)
+{
+ struct iecm_adapter *adapter = (struct iecm_adapter *)hw->back;
+ int i;
+
+ for (i = 0; i < 2000; i++) {
+ u32 reg_val = rd32(hw, reset_reg->rstat);
+
+ /* 0xFFFFFFFF might be read if other side hasn't cleared the
+ * register for us yet and 0xFFFFFFFF is not a valid value for
+ * the register, so treat that as invalid.
+ */
+ if (reg_val != 0xFFFFFFFF && (reg_val & reset_reg->rstat_m))
+ return 0;
+ usleep_range(5000, 10000);
+ }
+
+ dev_warn(&adapter->pdev->dev, "Device reset timeout!\n");
+ return -EBUSY;
+}
+
+/**
+ * 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. Return 0 on success,
+ * negative on failure.
+ */
+static int iecm_init_hard_reset(struct iecm_adapter *adapter)
+{
+ int err = 0;
+
+ mutex_lock(&adapter->reset_lock);
+
+ /* Prepare for reset */
+ if (test_and_clear_bit(__IECM_HR_DRV_LOAD, adapter->flags)) {
+ adapter->dev_ops.reg_ops.trigger_reset(adapter,
+ __IECM_HR_DRV_LOAD);
+ } else if (test_and_clear_bit(__IECM_HR_FUNC_RESET, adapter->flags)) {
+ bool is_reset = iecm_is_reset_detected(adapter);
+
+ if (adapter->state == __IECM_UP)
+ set_bit(__IECM_UP_REQUESTED, adapter->flags);
+ iecm_deinit_task(adapter);
+ if (!is_reset)
+ adapter->dev_ops.reg_ops.trigger_reset(adapter,
+ __IECM_HR_FUNC_RESET);
+ iecm_deinit_dflt_mbx(adapter);
+ } else if (test_and_clear_bit(__IECM_HR_CORE_RESET, adapter->flags)) {
+ if (adapter->state == __IECM_UP)
+ set_bit(__IECM_UP_REQUESTED, adapter->flags);
+ iecm_deinit_task(adapter);
+ } else {
+ dev_err(&adapter->pdev->dev, "Unhandled hard reset cause\n");
+ err = -EBADRQC;
+ goto handle_err;
+ }
+
+ /* Wait for reset to complete */
+ err = iecm_check_reset_complete(&adapter->hw, &adapter->reset_reg);
+ if (err) {
+ dev_err(&adapter->pdev->dev, "The driver was unable to contact the device's firmware. Check that the FW is running. Driver state=%u\n",
+ adapter->state);
+ goto handle_err;
+ }
+
+ /* Reset is complete and so start building the driver resources again */
+ err = iecm_init_dflt_mbx(adapter);
+ if (err) {
+ dev_err(&adapter->pdev->dev, "Failed to initialize default mailbox: %d\n",
+ err);
+ }
+handle_err:
+ mutex_unlock(&adapter->reset_lock);
+ return err;
+}
+
/**
* iecm_vc_event_task - Handle virtchannel event logic
* @work: work queue struct
*/
static void iecm_vc_event_task(struct work_struct *work)
{
- /* stub */
+ struct iecm_adapter *adapter = container_of(work,
+ struct iecm_adapter,
+ vc_event_task.work);
+
+ if (test_bit(__IECM_HR_CORE_RESET, adapter->flags) ||
+ test_bit(__IECM_HR_FUNC_RESET, adapter->flags) ||
+ test_bit(__IECM_HR_DRV_LOAD, adapter->flags)) {
+ set_bit(__IECM_HR_RESET_IN_PROG, adapter->flags);
+ iecm_init_hard_reset(adapter);
+ }
}
/**
@@ -75,6 +215,11 @@ int iecm_probe(struct pci_dev *pdev,
int err;
adapter->pdev = pdev;
+ err = iecm_api_init(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Device API is incorrectly configured\n");
+ return err;
+ }
err = pcim_enable_device(pdev);
if (err)
@@ -147,6 +292,20 @@ int iecm_probe(struct pci_dev *pdev,
goto err_netdev_alloc;
}
+ err = iecm_vport_params_buf_alloc(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to alloc vport params buffer: %d\n",
+ err);
+ goto err_mb_res;
+ }
+
+ err = iecm_cfg_hw(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to configure HW structure for adapter: %d\n",
+ err);
+ goto err_cfg_hw;
+ }
+
mutex_init(&adapter->sw_mutex);
mutex_init(&adapter->reset_lock);
init_waitqueue_head(&adapter->vchnl_wq);
@@ -166,11 +325,16 @@ int iecm_probe(struct pci_dev *pdev,
INIT_DELAYED_WORK(&adapter->init_task, iecm_init_task);
INIT_DELAYED_WORK(&adapter->vc_event_task, iecm_vc_event_task);
+ adapter->dev_ops.reg_ops.reset_reg_init(&adapter->reset_reg);
set_bit(__IECM_HR_DRV_LOAD, adapter->flags);
queue_delayed_work(adapter->vc_event_wq, &adapter->vc_event_task,
msecs_to_jiffies(10 * (pdev->devfn & 0x07)));
return 0;
+err_cfg_hw:
+ iecm_vport_params_buf_rel(adapter);
+err_mb_res:
+ kfree(adapter->netdevs);
err_netdev_alloc:
kfree(adapter->vports);
err_vport_alloc:
@@ -214,6 +378,7 @@ void iecm_remove(struct pci_dev *pdev)
cancel_delayed_work_sync(&adapter->vc_event_task);
iecm_deinit_task(adapter);
iecm_del_user_cfg_data(adapter);
+ iecm_deinit_dflt_mbx(adapter);
msleep(20);
destroy_workqueue(adapter->serv_wq);
destroy_workqueue(adapter->vc_event_wq);
@@ -222,6 +387,7 @@ void iecm_remove(struct pci_dev *pdev)
kfree(adapter->vports);
kfree(adapter->netdevs);
kfree(adapter->vlan_caps);
+ iecm_vport_params_buf_rel(adapter);
mutex_destroy(&adapter->sw_mutex);
mutex_destroy(&adapter->reset_lock);
pci_disable_pcie_error_reporting(pdev);
@@ -229,3 +395,26 @@ void iecm_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
EXPORT_SYMBOL(iecm_remove);
+
+void *iecm_alloc_dma_mem(struct iecm_hw *hw, struct iecm_dma_mem *mem, u64 size)
+{
+ struct iecm_adapter *adapter = (struct iecm_adapter *)hw->back;
+ size_t sz = ALIGN(size, 4096);
+
+ mem->va = dma_alloc_coherent(&adapter->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)
+{
+ struct iecm_adapter *adapter = (struct iecm_adapter *)hw->back;
+
+ dma_free_coherent(&adapter->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
new file mode 100644
index 000000000000..b8f54b8c700a
--- /dev/null
+++ b/drivers/net/ethernet/intel/iecm/iecm_virtchnl.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2019 Intel Corporation */
+
+#include "iecm.h"
+
+/**
+ * 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 0 on success, negative on failure
+ */
+static int iecm_mb_clean(struct iecm_adapter *adapter)
+{
+ u16 i, num_q_msg = IECM_DFLT_MBX_Q_LEN;
+ struct iecm_ctlq_msg **q_msg;
+ struct iecm_dma_mem *dma_mem;
+ int err = 0;
+
+ q_msg = kcalloc(num_q_msg, sizeof(struct iecm_ctlq_msg *), GFP_KERNEL);
+ if (!q_msg)
+ return -ENOMEM;
+
+ err = iecm_ctlq_clean_sq(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(dma_mem);
+ }
+error:
+ kfree(q_msg);
+ return err;
+}
+
+/**
+ * iecm_find_ctlq - Given a type and id, find ctlq info
+ * @hw: hardware 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)
+{
+ 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;
+}
+
+/**
+ * iecm_init_dflt_mbx - Setup default mailbox parameters and make request
+ * @adapter: adapter info struct
+ *
+ * Returns 0 on success, negative otherwise
+ */
+int iecm_init_dflt_mbx(struct iecm_adapter *adapter)
+{
+ struct iecm_ctlq_create_info ctlq_info[] = {
+ {
+ .type = IECM_CTLQ_TYPE_MAILBOX_TX,
+ .id = IECM_DFLT_MBX_ID,
+ .len = IECM_DFLT_MBX_Q_LEN,
+ .buf_size = IECM_DFLT_MBX_BUF_SIZE
+ },
+ {
+ .type = IECM_CTLQ_TYPE_MAILBOX_RX,
+ .id = IECM_DFLT_MBX_ID,
+ .len = IECM_DFLT_MBX_Q_LEN,
+ .buf_size = IECM_DFLT_MBX_BUF_SIZE
+ }
+ };
+ struct iecm_hw *hw = &adapter->hw;
+ int err;
+
+ adapter->dev_ops.reg_ops.ctlq_reg_init(ctlq_info);
+
+#define NUM_Q 2
+ err = iecm_ctlq_init(hw, NUM_Q, ctlq_info);
+ if (err)
+ return err;
+
+ hw->asq = iecm_find_ctlq(hw, IECM_CTLQ_TYPE_MAILBOX_TX,
+ IECM_DFLT_MBX_ID);
+ hw->arq = iecm_find_ctlq(hw, IECM_CTLQ_TYPE_MAILBOX_RX,
+ IECM_DFLT_MBX_ID);
+
+ if (!hw->asq || !hw->arq) {
+ iecm_ctlq_deinit(hw);
+ return -ENOENT;
+ }
+ adapter->state = __IECM_STARTUP;
+ /* Skew the delay for init tasks for each function based on fn number
+ * to prevent every function from making the same call simulatenously.
+ */
+ queue_delayed_work(adapter->init_wq, &adapter->init_task,
+ msecs_to_jiffies(5 * (adapter->pdev->devfn & 0x07)));
+ return 0;
+}
+
+/**
+ * iecm_deinit_dflt_mbx - Free up ctlqs setup
+ * @adapter: Driver specific private data structure
+ */
+void iecm_deinit_dflt_mbx(struct iecm_adapter *adapter)
+{
+ if (adapter->hw.arq && adapter->hw.asq) {
+ iecm_mb_clean(adapter);
+ iecm_ctlq_deinit(&adapter->hw);
+ }
+ adapter->hw.arq = NULL;
+ adapter->hw.asq = NULL;
+}
+
+/**
+ * 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)
+{
+ 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;
+}
+
+/**
+ * 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)
+{
+ int i = 0;
+
+ for (i = 0; i < IECM_MAX_NUM_VPORTS; i++) {
+ kfree(adapter->vport_params_recvd[i]);
+ kfree(adapter->vport_params_reqd[i]);
+ }
+
+ kfree(adapter->vport_params_recvd);
+ kfree(adapter->vport_params_reqd);
+
+ kfree(adapter->caps);
+ kfree(adapter->config_data.req_qs_chunks);
+}
diff --git a/drivers/net/ethernet/intel/include/iecm.h b/drivers/net/ethernet/intel/include/iecm.h
index e19e014e9817..ca9029224e06 100644
--- a/drivers/net/ethernet/intel/include/iecm.h
+++ b/drivers/net/ethernet/intel/include/iecm.h
@@ -12,15 +12,33 @@
#include <linux/dim.h>
#include "iecm_txrx.h"
+#include "iecm_controlq.h"
#define IECM_BAR0 0
#define IECM_NO_FREE_SLOT 0xffff
+/* Default Mailbox settings */
+#define IECM_DFLT_MBX_BUF_SIZE (4 * 1024)
+#define IECM_NUM_QCTX_PER_MSG 3
+#define IECM_NUM_FILTERS_PER_MSG 20
+#define IECM_VLANS_PER_MSG \
+ ((IECM_DFLT_MBX_BUF_SIZE - sizeof(struct virtchnl_vlan_filter_list)) \
+ / sizeof(u16))
+#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_NUM_CHUNKS_PER_MSG(a, b) ((IECM_DFLT_MBX_BUF_SIZE - (a)) / (b))
+
#define IECM_MAX_NUM_VPORTS 1
/* available message levels */
#define IECM_AVAIL_NETIF_M (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
+/* Forward declaration */
+struct iecm_adapter;
+struct iecm_vport;
+
enum iecm_state {
__IECM_STARTUP,
__IECM_VER_CHECK,
@@ -77,6 +95,22 @@ struct iecm_reset_reg {
u32 rstat_m;
};
+/* product specific register API */
+struct iecm_reg_ops {
+ void (*ctlq_reg_init)(struct iecm_ctlq_create_info *cq);
+ int (*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_dev_ops {
+ void (*reg_ops_init)(struct iecm_adapter *adapter);
+ void (*crc_enable)(u64 *td_cmd);
+ struct iecm_reg_ops reg_ops;
+};
+
/* stub */
struct iecm_vport {
};
@@ -124,6 +158,7 @@ struct iecm_adapter {
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;
@@ -156,6 +191,7 @@ struct iecm_adapter {
wait_queue_head_t vchnl_wq;
wait_queue_head_t sw_marker_wq;
struct iecm_rss_data rss_data;
+ struct iecm_dev_ops dev_ops;
s32 link_speed;
/* This is only populated if the VIRTCHNL_VF_CAP_ADV_LINK_SPEED is set
* in vf_res->vf_cap_flags. This field should be used going forward and
@@ -179,8 +215,24 @@ struct iecm_adapter {
spinlock_t fdir_fltr_list_lock;
};
+/**
+ * iecm_is_reset_detected - check if we were reset at some point
+ * @adapter: driver specific private structure
+ *
+ * Returns true if we are either in reset currently or were previously reset.
+ */
+static inline bool iecm_is_reset_detected(struct iecm_adapter *adapter)
+{
+ return !(rd32(&adapter->hw, adapter->hw.arq->reg.len) &
+ adapter->hw.arq->reg.len_ena_mask);
+}
+
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);
+int iecm_init_dflt_mbx(struct iecm_adapter *adapter);
+void iecm_deinit_dflt_mbx(struct iecm_adapter *adapter);
+int iecm_vport_params_buf_alloc(struct iecm_adapter *adapter);
+void iecm_vport_params_buf_rel(struct iecm_adapter *adapter);
#endif /* !_IECM_H_ */
diff --git a/drivers/net/ethernet/intel/include/iecm_controlq.h b/drivers/net/ethernet/intel/include/iecm_controlq.h
new file mode 100644
index 000000000000..f2539baa2ce1
--- /dev/null
+++ b/drivers/net/ethernet/intel/include/iecm_controlq.h
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2020, Intel Corporation. */
+
+#ifndef _IECM_CONTROLQ_H_
+#define _IECM_CONTROLQ_H_
+
+#include <linux/slab.h>
+
+#include "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))
+
+/* 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 (0x7FF << IECM_CTLQ_DESC_VF_ID_S)
+#define IECM_CTLQ_DESC_PF_ID_S 11
+#define IECM_CTLQ_DESC_PF_ID_M (0x1F << 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 */
+};
+
+/* Define the APF hardware struct to replace other control structs as needed
+ * Align to ctlq_hw_info
+ */
+struct iecm_hw {
+ u8 __iomem *hw_addr;
+ u64 hw_addr_len;
+ void *back;
+
+ /* control queue - send and receive */
+ struct iecm_ctlq_info *asq;
+ struct iecm_ctlq_info *arq;
+
+ /* 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;
+};
+
+int 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);
+
+/* 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_CONTROLQ_H_ */
diff --git a/drivers/net/ethernet/intel/include/iecm_controlq_api.h b/drivers/net/ethernet/intel/include/iecm_controlq_api.h
new file mode 100644
index 000000000000..5f624f005d33
--- /dev/null
+++ b/drivers/net/ethernet/intel/include/iecm_controlq_api.h
@@ -0,0 +1,185 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2020, Intel Corporation. */
+
+#ifndef _IECM_CONTROLQ_API_H_
+#define _IECM_CONTROLQ_API_H_
+
+#include "iecm_mem.h"
+
+struct iecm_hw;
+
+/* 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;
+ int id; /* absolute queue offset passed as input
+ * -1 for default mailbox if present
+ */
+ 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;
+ /* control queue lock */
+ struct mutex cq_lock;
+
+ /* used for interrupt processing */
+ u16 next_to_use;
+ u16 next_to_clean;
+ u16 next_to_post; /* starting descriptor to post buffers
+ * to after recev
+ */
+
+ struct iecm_dma_mem desc_ring; /* descriptor ring memory
+ * iecm_dma_mem is defined in OSdep.h
+ */
+ 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_pf:
+ * usage: used by PF or VF to send a message to its CPF
+ * target: RX queue and function ID of parent PF taken from HW
+ */
+ iecm_mbq_opc_send_msg_to_pf = 0x0801,
+
+ /* iecm_mbq_opc_send_msg_to_vf:
+ * usage: used by PF to send message to a VF
+ * target: VF control queue ID must be specified in descriptor
+ */
+ iecm_mbq_opc_send_msg_to_vf = 0x0802,
+
+ /* iecm_mbq_opc_send_msg_to_peer_pf:
+ * usage: used by any function to send message to any peer PF
+ * target: RX queue and host of parent PF taken from HW
+ */
+ iecm_mbq_opc_send_msg_to_peer_pf = 0x0803,
+
+ /* iecm_mbq_opc_send_msg_to_peer_drv:
+ * usage: used by any function to send message to any peer driver
+ * target: RX queue and target host must be specific in descriptor
+ */
+ iecm_mbq_opc_send_msg_to_peer_drv = 0x0804,
+};
+
+/* API support 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.
+ */
+int 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
+ */
+int 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*/
+int 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
+ */
+int iecm_ctlq_recv(struct iecm_ctlq_info *cq, u16 *num_q_msg,
+ struct iecm_ctlq_msg *q_msg);
+
+/* Reclaims send descriptors on HW write back */
+int iecm_ctlq_clean_sq(struct iecm_ctlq_info *cq, u16 *clean_count,
+ struct iecm_ctlq_msg *msg_status[]);
+
+/* Indicate RX buffers are done being processed */
+int 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 */
+int iecm_ctlq_deinit(struct iecm_hw *hw);
+
+#endif /* _IECM_CONTROLQ_API_H_ */
diff --git a/drivers/net/ethernet/intel/include/iecm_mem.h b/drivers/net/ethernet/intel/include/iecm_mem.h
new file mode 100644
index 000000000000..064dd6e10c24
--- /dev/null
+++ b/drivers/net/ethernet/intel/include/iecm_mem.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2019 Intel Corporation */
+
+#ifndef _IECM_MEM_H_
+#define _IECM_MEM_H_
+
+#include <linux/io.h>
+
+struct iecm_dma_mem {
+ void *va;
+ dma_addr_t pa;
+ size_t size;
+};
+
+#define wr32(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
+#define rd32(a, reg) readl((a)->hw_addr + (reg))
+#define wr64(a, reg, value) writeq((value), ((a)->hw_addr + (reg)))
+#define rd64(a, reg) readq((a)->hw_addr + (reg))
+
+#endif /* _IECM_MEM_H_ */
--
2.33.0
next prev parent reply other threads:[~2022-01-28 0:09 UTC|newest]
Thread overview: 89+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-28 0:09 [Intel-wired-lan] [PATCH net-next 00/19] Add iecm and idpf Alan Brady
2022-01-28 0:09 ` [Intel-wired-lan] [PATCH net-next 01/19] virtchnl: Add new virtchnl2 ops Alan Brady
2022-02-02 22:13 ` Brady, Alan
2022-01-28 0:09 ` [Intel-wired-lan] [PATCH net-next 02/19] iecm: add basic module init and documentation Alan Brady
2022-01-28 11:56 ` Alexander Lobakin
2022-02-02 22:15 ` Brady, Alan
2022-02-01 19:44 ` Shannon Nelson
2022-02-03 3:08 ` Brady, Alan
2022-01-28 0:09 ` [Intel-wired-lan] [PATCH net-next 03/19] iecm: add probe and remove Alan Brady
2022-02-01 20:02 ` Shannon Nelson
2022-02-03 3:13 ` Brady, Alan
2022-01-28 0:09 ` Alan Brady [this message]
2022-01-28 12:09 ` [Intel-wired-lan] [PATCH net-next 04/19] iecm: add api_init and controlq init Alexander Lobakin
2022-02-02 22:16 ` Brady, Alan
2022-02-01 21:26 ` Shannon Nelson
2022-02-03 3:24 ` Brady, Alan
2022-02-03 3:40 ` Brady, Alan
2022-02-03 5:26 ` Shannon Nelson
2022-02-03 13:13 ` Alexander Lobakin
2022-01-28 0:09 ` [Intel-wired-lan] [PATCH net-next 05/19] iecm: add vport alloc and virtchnl messages Alan Brady
2022-01-28 4:19 ` kernel test robot
2022-01-28 4:19 ` kernel test robot
2022-01-28 12:39 ` Alexander Lobakin
2022-01-28 12:39 ` Alexander Lobakin
2022-02-02 22:23 ` Brady, Alan
2022-02-02 22:23 ` Brady, Alan
2022-01-28 12:32 ` Alexander Lobakin
2022-02-02 22:21 ` Brady, Alan
2022-02-03 13:23 ` Alexander Lobakin
2022-01-28 0:09 ` [Intel-wired-lan] [PATCH net-next 06/19] iecm: add virtchnl messages for queues Alan Brady
2022-01-28 13:03 ` Alexander Lobakin
2022-02-02 22:48 ` Brady, Alan
2022-02-03 10:08 ` Maciej Fijalkowski
2022-02-03 14:09 ` Alexander Lobakin
2022-01-28 0:09 ` [Intel-wired-lan] [PATCH net-next 07/19] iecm: finish virtchnl messages Alan Brady
2022-01-28 13:19 ` Alexander Lobakin
2022-02-02 23:06 ` Brady, Alan
2022-02-03 15:05 ` Alexander Lobakin
2022-02-03 15:16 ` Maciej Fijalkowski
2022-01-28 0:09 ` [Intel-wired-lan] [PATCH net-next 08/19] iecm: add interrupts and configure netdev Alan Brady
2022-01-28 13:34 ` Alexander Lobakin
2022-02-02 23:17 ` Brady, Alan
2022-02-03 15:55 ` Alexander Lobakin
2022-01-28 0:09 ` [Intel-wired-lan] [PATCH net-next 09/19] iecm: alloc vport TX resources Alan Brady
2022-02-02 23:45 ` Brady, Alan
2022-02-03 17:56 ` Alexander Lobakin
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 10/19] iecm: alloc vport RX resources Alan Brady
2022-01-28 14:16 ` Alexander Lobakin
2022-02-03 0:13 ` Brady, Alan
2022-02-03 18:29 ` Alexander Lobakin
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 11/19] iecm: add start_xmit and set_rx_mode Alan Brady
2022-01-28 16:35 ` Alexander Lobakin
2022-01-28 0:10 ` [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 5:21 ` kernel test robot
2022-01-28 17:44 ` Alexander Lobakin
2022-01-28 17:44 ` Alexander Lobakin
2022-02-03 1:15 ` Brady, Alan
2022-02-03 1:15 ` Brady, Alan
2022-01-28 17:38 ` Alexander Lobakin
2022-02-03 1:07 ` Brady, Alan
2022-02-04 11:50 ` Alexander Lobakin
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 14/19] iecm: implement singleq napi_poll Alan Brady
2022-01-28 17:57 ` Alexander Lobakin
2022-02-03 1:45 ` Brady, Alan
2022-02-03 19:05 ` Alexander Lobakin
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 15/19] iecm: implement ethtool callbacks Alan Brady
2022-01-28 18:13 ` Alexander Lobakin
2022-02-03 2:13 ` Brady, Alan
2022-02-03 19:54 ` Alexander Lobakin
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 16/19] iecm: implement flow director Alan Brady
2022-01-28 19:04 ` Alexander Lobakin
2022-02-03 2:41 ` Brady, Alan
2022-02-04 10:08 ` Alexander Lobakin
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 17/19] iecm: implement cloud filters Alan Brady
2022-01-28 19:38 ` Alexander Lobakin
2022-02-03 2:53 ` Brady, Alan
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 18/19] iecm: add advanced rss Alan Brady
2022-01-28 19:53 ` Alexander Lobakin
2022-02-03 2:55 ` Brady, Alan
2022-02-03 10:46 ` Maciej Fijalkowski
2022-02-04 10:22 ` Alexander Lobakin
2022-01-28 0:10 ` [Intel-wired-lan] [PATCH net-next 19/19] idpf: introduce idpf driver Alan Brady
2022-01-28 20:08 ` Alexander Lobakin
2022-02-03 3:07 ` Brady, Alan
2022-02-04 10:35 ` Alexander Lobakin
2022-02-04 12:05 ` [Intel-wired-lan] [PATCH net-next 00/19] Add iecm and idpf Alexander Lobakin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220128001009.721392-5-alan.brady@intel.com \
--to=alan.brady@intel.com \
--cc=intel-wired-lan@osuosl.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.