
Intel listed total 28 commits that need us to back port. There are 9 commits that are already included in our code base. The commit "ice: Add support for E825-C TS PLL handling" will not be back ported since we're not dealing with E825 for 24.09. So we need back port 18 commits. These commits were introduced in linux-6.9.y and linux-6.10.y. To back port these 18 commits successfully, we totally back ported 37 upstream commits. 1) The patches 1-15 are cherry picked to fix the conflicts for patch 16 ("ice: introduce PTP state machine") and patch 36 "ice: Introduce ice_ptp_hw struct". Also will be helpful for the subsequent commits back porting. 2) The patches 24-27 are cherry picked to fix the conflicts for patch 28 ("ice: Fix debugfs with devlink reload") 3) The minor adjust was done for the patches 17, 21, 23 and 33 to fit with the context change. Verification: - installs from iso succeed on servers with ice(Intel Ethernet Controller E810-XXVDA4T Westport Channel) and i40e hw(Intel Ethernet Controller X710) for rt and std. - interfaces are up and pass packets for rt and std. - create vfs, ensure that they are picked up by the new iavf driver and that the interface can come up and pass packets on rt and std system. - Check dmesg to see DDP package is loaded successfully and the version is 1.3.36.0 for rt and std. Story: 2011056 Task: 50950 Change-Id: I9aef0378ea01451684341093a167eaead3edc458 Signed-off-by: Jiping Ma <jiping.ma2@windriver.com>
573 lines
17 KiB
Diff
573 lines
17 KiB
Diff
From a584ea88cfdc8ac3f782be1d5d67fa92c3423290 Mon Sep 17 00:00:00 2001
|
|
From: Paul M Stillwell Jr <paul.m.stillwell.jr@intel.com>
|
|
Date: Tue, 12 Dec 2023 21:07:14 -0800
|
|
Subject: [PATCH 27/36] ice: add ability to read and configure FW log data
|
|
|
|
Once logging is enabled the user should read the data from the 'data'
|
|
file. The data is in the form of a binary blob that can be sent to Intel
|
|
for decoding. To read the data use a command like:
|
|
|
|
# cat /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/data > log_data.bin
|
|
|
|
If the user wants to clear the FW log data that has been stored in the
|
|
driver then they can write any value to the 'data' file and that will clear
|
|
the data. An example is:
|
|
|
|
# echo 34 > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/data
|
|
|
|
In addition to being able to read the data the user can configure how
|
|
much memory is used to store FW log data. This allows the user to
|
|
increase/decrease the amount of memory based on the users situation.
|
|
The data is stored such that if the memory fills up then the oldest data
|
|
will get overwritten in a circular manner. To change the amount of
|
|
memory the user can write to the 'log_size' file like this:
|
|
|
|
# echo <value> > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/log_size
|
|
|
|
Where <value> is one of 128K, 256K, 512K, 1M, and 2M. The default value
|
|
is 1M.
|
|
|
|
The user can see the current value of 'log_size' by reading the file:
|
|
|
|
# cat /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/log_size
|
|
|
|
Signed-off-by: Paul M Stillwell Jr <paul.m.stillwell.jr@intel.com>
|
|
Tested-by: Pucha Himasekhar Reddy <himasekharx.reddy.pucha@intel.com> (A Contingent worker at Intel)
|
|
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
|
|
(cherry picked from commit 9d3535e71985beb738c4ad2b772c6f0efdce0202)
|
|
Signed-off-by: Jiping Ma <jiping.ma2@windriver.com>
|
|
---
|
|
.../net/ethernet/intel/ice/ice_adminq_cmd.h | 2 +
|
|
drivers/net/ethernet/intel/ice/ice_debugfs.c | 210 ++++++++++++++++++
|
|
drivers/net/ethernet/intel/ice/ice_fwlog.c | 142 ++++++++++++
|
|
drivers/net/ethernet/intel/ice/ice_fwlog.h | 21 ++
|
|
drivers/net/ethernet/intel/ice/ice_main.c | 29 +++
|
|
drivers/net/ethernet/intel/ice/ice_type.h | 1 +
|
|
6 files changed, 405 insertions(+)
|
|
|
|
diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
|
|
index 11391be4efc2..f63b57ff2a3d 100644
|
|
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
|
|
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
|
|
@@ -2338,6 +2338,7 @@ enum ice_aqc_fw_logging_mod {
|
|
/* Set FW Logging configuration (indirect 0xFF30)
|
|
* Register for FW Logging (indirect 0xFF31)
|
|
* Query FW Logging (indirect 0xFF32)
|
|
+ * FW Log Event (indirect 0xFF33)
|
|
*/
|
|
struct ice_aqc_fw_log {
|
|
u8 cmd_flags;
|
|
@@ -2666,6 +2667,7 @@ enum ice_adminq_opc {
|
|
ice_aqc_opc_fw_logs_config = 0xFF30,
|
|
ice_aqc_opc_fw_logs_register = 0xFF31,
|
|
ice_aqc_opc_fw_logs_query = 0xFF32,
|
|
+ ice_aqc_opc_fw_logs_event = 0xFF33,
|
|
};
|
|
|
|
#endif /* _ICE_ADMINQ_CMD_H_ */
|
|
diff --git a/drivers/net/ethernet/intel/ice/ice_debugfs.c b/drivers/net/ethernet/intel/ice/ice_debugfs.c
|
|
index 3dde99969132..c2bfba6b9ead 100644
|
|
--- a/drivers/net/ethernet/intel/ice/ice_debugfs.c
|
|
+++ b/drivers/net/ethernet/intel/ice/ice_debugfs.c
|
|
@@ -64,6 +64,17 @@ static const char * const ice_fwlog_level_string[] = {
|
|
"verbose",
|
|
};
|
|
|
|
+/* the order in this array is important. it matches the ordering of the
|
|
+ * values in the FW so the index is the same value as in ice_fwlog_level
|
|
+ */
|
|
+static const char * const ice_fwlog_log_size[] = {
|
|
+ "128K",
|
|
+ "256K",
|
|
+ "512K",
|
|
+ "1M",
|
|
+ "2M",
|
|
+};
|
|
+
|
|
/**
|
|
* ice_fwlog_print_module_cfg - print current FW logging module configuration
|
|
* @hw: pointer to the HW structure
|
|
@@ -376,6 +387,199 @@ static const struct file_operations ice_debugfs_enable_fops = {
|
|
.write = ice_debugfs_enable_write,
|
|
};
|
|
|
|
+/**
|
|
+ * ice_debugfs_log_size_read - read from 'log_size' file
|
|
+ * @filp: the opened file
|
|
+ * @buffer: where to write the data for the user to read
|
|
+ * @count: the size of the user's buffer
|
|
+ * @ppos: file position offset
|
|
+ */
|
|
+static ssize_t ice_debugfs_log_size_read(struct file *filp,
|
|
+ char __user *buffer, size_t count,
|
|
+ loff_t *ppos)
|
|
+{
|
|
+ struct ice_pf *pf = filp->private_data;
|
|
+ struct ice_hw *hw = &pf->hw;
|
|
+ char buff[32] = {};
|
|
+ int index;
|
|
+
|
|
+ index = hw->fwlog_ring.index;
|
|
+ snprintf(buff, sizeof(buff), "%s\n", ice_fwlog_log_size[index]);
|
|
+
|
|
+ return simple_read_from_buffer(buffer, count, ppos, buff, strlen(buff));
|
|
+}
|
|
+
|
|
+/**
|
|
+ * ice_debugfs_log_size_write - write into 'log_size' file
|
|
+ * @filp: the opened file
|
|
+ * @buf: where to find the user's data
|
|
+ * @count: the length of the user's data
|
|
+ * @ppos: file position offset
|
|
+ */
|
|
+static ssize_t
|
|
+ice_debugfs_log_size_write(struct file *filp, const char __user *buf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ice_pf *pf = filp->private_data;
|
|
+ struct device *dev = ice_pf_to_dev(pf);
|
|
+ struct ice_hw *hw = &pf->hw;
|
|
+ char user_val[8], *cmd_buf;
|
|
+ ssize_t ret;
|
|
+ int index;
|
|
+
|
|
+ /* don't allow partial writes or invalid input */
|
|
+ if (*ppos != 0 || count > 5)
|
|
+ return -EINVAL;
|
|
+
|
|
+ cmd_buf = memdup_user(buf, count);
|
|
+ if (IS_ERR(cmd_buf))
|
|
+ return PTR_ERR(cmd_buf);
|
|
+
|
|
+ ret = sscanf(cmd_buf, "%s", user_val);
|
|
+ if (ret != 1)
|
|
+ return -EINVAL;
|
|
+
|
|
+ index = sysfs_match_string(ice_fwlog_log_size, user_val);
|
|
+ if (index < 0) {
|
|
+ dev_info(dev, "Invalid log size '%s'. The value must be one of 128K, 256K, 512K, 1M, 2M\n",
|
|
+ user_val);
|
|
+ ret = -EINVAL;
|
|
+ goto log_size_write_error;
|
|
+ } else if (hw->fwlog_cfg.options & ICE_FWLOG_OPTION_IS_REGISTERED) {
|
|
+ dev_info(dev, "FW logging is currently running. Please disable FW logging to change log_size\n");
|
|
+ ret = -EINVAL;
|
|
+ goto log_size_write_error;
|
|
+ }
|
|
+
|
|
+ /* free all the buffers and the tracking info and resize */
|
|
+ ice_fwlog_realloc_rings(hw, index);
|
|
+
|
|
+ /* if we get here, nothing went wrong; return count since we didn't
|
|
+ * really write anything
|
|
+ */
|
|
+ ret = (ssize_t)count;
|
|
+
|
|
+log_size_write_error:
|
|
+ /* This function always consumes all of the written input, or produces
|
|
+ * an error. Check and enforce this. Otherwise, the write operation
|
|
+ * won't complete properly.
|
|
+ */
|
|
+ if (WARN_ON(ret != (ssize_t)count && ret >= 0))
|
|
+ ret = -EIO;
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct file_operations ice_debugfs_log_size_fops = {
|
|
+ .owner = THIS_MODULE,
|
|
+ .open = simple_open,
|
|
+ .read = ice_debugfs_log_size_read,
|
|
+ .write = ice_debugfs_log_size_write,
|
|
+};
|
|
+
|
|
+/**
|
|
+ * ice_debugfs_data_read - read from 'data' file
|
|
+ * @filp: the opened file
|
|
+ * @buffer: where to write the data for the user to read
|
|
+ * @count: the size of the user's buffer
|
|
+ * @ppos: file position offset
|
|
+ */
|
|
+static ssize_t ice_debugfs_data_read(struct file *filp, char __user *buffer,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ice_pf *pf = filp->private_data;
|
|
+ struct ice_hw *hw = &pf->hw;
|
|
+ int data_copied = 0;
|
|
+ bool done = false;
|
|
+
|
|
+ if (ice_fwlog_ring_empty(&hw->fwlog_ring))
|
|
+ return 0;
|
|
+
|
|
+ while (!ice_fwlog_ring_empty(&hw->fwlog_ring) && !done) {
|
|
+ struct ice_fwlog_data *log;
|
|
+ u16 cur_buf_len;
|
|
+
|
|
+ log = &hw->fwlog_ring.rings[hw->fwlog_ring.head];
|
|
+ cur_buf_len = log->data_size;
|
|
+ if (cur_buf_len >= count) {
|
|
+ done = true;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (copy_to_user(buffer, log->data, cur_buf_len)) {
|
|
+ /* if there is an error then bail and return whatever
|
|
+ * the driver has copied so far
|
|
+ */
|
|
+ done = true;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ data_copied += cur_buf_len;
|
|
+ buffer += cur_buf_len;
|
|
+ count -= cur_buf_len;
|
|
+ *ppos += cur_buf_len;
|
|
+ ice_fwlog_ring_increment(&hw->fwlog_ring.head,
|
|
+ hw->fwlog_ring.size);
|
|
+ }
|
|
+
|
|
+ return data_copied;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * ice_debugfs_data_write - write into 'data' file
|
|
+ * @filp: the opened file
|
|
+ * @buf: where to find the user's data
|
|
+ * @count: the length of the user's data
|
|
+ * @ppos: file position offset
|
|
+ */
|
|
+static ssize_t
|
|
+ice_debugfs_data_write(struct file *filp, const char __user *buf, size_t count,
|
|
+ loff_t *ppos)
|
|
+{
|
|
+ struct ice_pf *pf = filp->private_data;
|
|
+ struct device *dev = ice_pf_to_dev(pf);
|
|
+ struct ice_hw *hw = &pf->hw;
|
|
+ ssize_t ret;
|
|
+
|
|
+ /* don't allow partial writes */
|
|
+ if (*ppos != 0)
|
|
+ return 0;
|
|
+
|
|
+ /* any value is allowed to clear the buffer so no need to even look at
|
|
+ * what the value is
|
|
+ */
|
|
+ if (!(hw->fwlog_cfg.options & ICE_FWLOG_OPTION_IS_REGISTERED)) {
|
|
+ hw->fwlog_ring.head = 0;
|
|
+ hw->fwlog_ring.tail = 0;
|
|
+ } else {
|
|
+ dev_info(dev, "Can't clear FW log data while FW log running\n");
|
|
+ ret = -EINVAL;
|
|
+ goto nr_buffs_write_error;
|
|
+ }
|
|
+
|
|
+ /* if we get here, nothing went wrong; return count since we didn't
|
|
+ * really write anything
|
|
+ */
|
|
+ ret = (ssize_t)count;
|
|
+
|
|
+nr_buffs_write_error:
|
|
+ /* This function always consumes all of the written input, or produces
|
|
+ * an error. Check and enforce this. Otherwise, the write operation
|
|
+ * won't complete properly.
|
|
+ */
|
|
+ if (WARN_ON(ret != (ssize_t)count && ret >= 0))
|
|
+ ret = -EIO;
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct file_operations ice_debugfs_data_fops = {
|
|
+ .owner = THIS_MODULE,
|
|
+ .open = simple_open,
|
|
+ .read = ice_debugfs_data_read,
|
|
+ .write = ice_debugfs_data_write,
|
|
+};
|
|
+
|
|
/**
|
|
* ice_debugfs_fwlog_init - setup the debugfs directory
|
|
* @pf: the ice that is starting up
|
|
@@ -430,6 +634,12 @@ void ice_debugfs_fwlog_init(struct ice_pf *pf)
|
|
debugfs_create_file("enable", 0600, pf->ice_debugfs_pf_fwlog,
|
|
pf, &ice_debugfs_enable_fops);
|
|
|
|
+ debugfs_create_file("log_size", 0600, pf->ice_debugfs_pf_fwlog,
|
|
+ pf, &ice_debugfs_log_size_fops);
|
|
+
|
|
+ debugfs_create_file("data", 0600, pf->ice_debugfs_pf_fwlog,
|
|
+ pf, &ice_debugfs_data_fops);
|
|
+
|
|
return;
|
|
|
|
err_create_module_files:
|
|
diff --git a/drivers/net/ethernet/intel/ice/ice_fwlog.c b/drivers/net/ethernet/intel/ice/ice_fwlog.c
|
|
index 25a17cbc1d34..92b5dac481cd 100644
|
|
--- a/drivers/net/ethernet/intel/ice/ice_fwlog.c
|
|
+++ b/drivers/net/ethernet/intel/ice/ice_fwlog.c
|
|
@@ -1,10 +1,128 @@
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright (c) 2022, Intel Corporation. */
|
|
|
|
+#include <linux/vmalloc.h>
|
|
#include "ice.h"
|
|
#include "ice_common.h"
|
|
#include "ice_fwlog.h"
|
|
|
|
+bool ice_fwlog_ring_full(struct ice_fwlog_ring *rings)
|
|
+{
|
|
+ u16 head, tail;
|
|
+
|
|
+ head = rings->head;
|
|
+ tail = rings->tail;
|
|
+
|
|
+ if (head < tail && (tail - head == (rings->size - 1)))
|
|
+ return true;
|
|
+ else if (head > tail && (tail == (head - 1)))
|
|
+ return true;
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
+bool ice_fwlog_ring_empty(struct ice_fwlog_ring *rings)
|
|
+{
|
|
+ return rings->head == rings->tail;
|
|
+}
|
|
+
|
|
+void ice_fwlog_ring_increment(u16 *item, u16 size)
|
|
+{
|
|
+ *item = (*item + 1) & (size - 1);
|
|
+}
|
|
+
|
|
+static int ice_fwlog_alloc_ring_buffs(struct ice_fwlog_ring *rings)
|
|
+{
|
|
+ int i, nr_bytes;
|
|
+ u8 *mem;
|
|
+
|
|
+ nr_bytes = rings->size * ICE_AQ_MAX_BUF_LEN;
|
|
+ mem = vzalloc(nr_bytes);
|
|
+ if (!mem)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ for (i = 0; i < rings->size; i++) {
|
|
+ struct ice_fwlog_data *ring = &rings->rings[i];
|
|
+
|
|
+ ring->data_size = ICE_AQ_MAX_BUF_LEN;
|
|
+ ring->data = mem;
|
|
+ mem += ICE_AQ_MAX_BUF_LEN;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void ice_fwlog_free_ring_buffs(struct ice_fwlog_ring *rings)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < rings->size; i++) {
|
|
+ struct ice_fwlog_data *ring = &rings->rings[i];
|
|
+
|
|
+ /* the first ring is the base memory for the whole range so
|
|
+ * free it
|
|
+ */
|
|
+ if (!i)
|
|
+ vfree(ring->data);
|
|
+
|
|
+ ring->data = NULL;
|
|
+ ring->data_size = 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+#define ICE_FWLOG_INDEX_TO_BYTES(n) ((128 * 1024) << (n))
|
|
+/**
|
|
+ * ice_fwlog_realloc_rings - reallocate the FW log rings
|
|
+ * @hw: pointer to the HW structure
|
|
+ * @index: the new index to use to allocate memory for the log data
|
|
+ *
|
|
+ */
|
|
+void ice_fwlog_realloc_rings(struct ice_hw *hw, int index)
|
|
+{
|
|
+ struct ice_fwlog_ring ring;
|
|
+ int status, ring_size;
|
|
+
|
|
+ /* convert the number of bytes into a number of 4K buffers. externally
|
|
+ * the driver presents the interface to the FW log data as a number of
|
|
+ * bytes because that's easy for users to understand. internally the
|
|
+ * driver uses a ring of buffers because the driver doesn't know where
|
|
+ * the beginning and end of any line of log data is so the driver has
|
|
+ * to overwrite data as complete blocks. when the data is returned to
|
|
+ * the user the driver knows that the data is correct and the FW log
|
|
+ * can be correctly parsed by the tools
|
|
+ */
|
|
+ ring_size = ICE_FWLOG_INDEX_TO_BYTES(index) / ICE_AQ_MAX_BUF_LEN;
|
|
+ if (ring_size == hw->fwlog_ring.size)
|
|
+ return;
|
|
+
|
|
+ /* allocate space for the new rings and buffers then release the
|
|
+ * old rings and buffers. that way if we don't have enough
|
|
+ * memory then we at least have what we had before
|
|
+ */
|
|
+ ring.rings = kcalloc(ring_size, sizeof(*ring.rings), GFP_KERNEL);
|
|
+ if (!ring.rings)
|
|
+ return;
|
|
+
|
|
+ ring.size = ring_size;
|
|
+
|
|
+ status = ice_fwlog_alloc_ring_buffs(&ring);
|
|
+ if (status) {
|
|
+ dev_warn(ice_hw_to_dev(hw), "Unable to allocate memory for FW log ring data buffers\n");
|
|
+ ice_fwlog_free_ring_buffs(&ring);
|
|
+ kfree(ring.rings);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ice_fwlog_free_ring_buffs(&hw->fwlog_ring);
|
|
+ kfree(hw->fwlog_ring.rings);
|
|
+
|
|
+ hw->fwlog_ring.rings = ring.rings;
|
|
+ hw->fwlog_ring.size = ring.size;
|
|
+ hw->fwlog_ring.index = index;
|
|
+ hw->fwlog_ring.head = 0;
|
|
+ hw->fwlog_ring.tail = 0;
|
|
+}
|
|
+
|
|
/**
|
|
* ice_fwlog_init - Initialize FW logging configuration
|
|
* @hw: pointer to the HW structure
|
|
@@ -28,6 +146,25 @@ int ice_fwlog_init(struct ice_hw *hw)
|
|
if (status)
|
|
return status;
|
|
|
|
+ hw->fwlog_ring.rings = kcalloc(ICE_FWLOG_RING_SIZE_DFLT,
|
|
+ sizeof(*hw->fwlog_ring.rings),
|
|
+ GFP_KERNEL);
|
|
+ if (!hw->fwlog_ring.rings) {
|
|
+ dev_warn(ice_hw_to_dev(hw), "Unable to allocate memory for FW log rings\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ hw->fwlog_ring.size = ICE_FWLOG_RING_SIZE_DFLT;
|
|
+ hw->fwlog_ring.index = ICE_FWLOG_RING_SIZE_INDEX_DFLT;
|
|
+
|
|
+ status = ice_fwlog_alloc_ring_buffs(&hw->fwlog_ring);
|
|
+ if (status) {
|
|
+ dev_warn(ice_hw_to_dev(hw), "Unable to allocate memory for FW log ring data buffers\n");
|
|
+ ice_fwlog_free_ring_buffs(&hw->fwlog_ring);
|
|
+ kfree(hw->fwlog_ring.rings);
|
|
+ return status;
|
|
+ }
|
|
+
|
|
ice_debugfs_fwlog_init(hw->back);
|
|
} else {
|
|
dev_warn(ice_hw_to_dev(hw), "FW logging is not supported in this NVM image. Please update the NVM to get FW log support\n");
|
|
@@ -68,6 +205,11 @@ void ice_fwlog_deinit(struct ice_hw *hw)
|
|
if (status)
|
|
dev_warn(ice_hw_to_dev(hw), "Unable to unregister FW logging, status: %d\n",
|
|
status);
|
|
+
|
|
+ if (hw->fwlog_ring.rings) {
|
|
+ ice_fwlog_free_ring_buffs(&hw->fwlog_ring);
|
|
+ kfree(hw->fwlog_ring.rings);
|
|
+ }
|
|
}
|
|
|
|
/**
|
|
diff --git a/drivers/net/ethernet/intel/ice/ice_fwlog.h b/drivers/net/ethernet/intel/ice/ice_fwlog.h
|
|
index 45865558425d..287e71fa4b86 100644
|
|
--- a/drivers/net/ethernet/intel/ice/ice_fwlog.h
|
|
+++ b/drivers/net/ethernet/intel/ice/ice_fwlog.h
|
|
@@ -47,6 +47,26 @@ struct ice_fwlog_cfg {
|
|
u16 log_resolution;
|
|
};
|
|
|
|
+struct ice_fwlog_data {
|
|
+ u16 data_size;
|
|
+ u8 *data;
|
|
+};
|
|
+
|
|
+struct ice_fwlog_ring {
|
|
+ struct ice_fwlog_data *rings;
|
|
+ u16 index;
|
|
+ u16 size;
|
|
+ u16 head;
|
|
+ u16 tail;
|
|
+};
|
|
+
|
|
+#define ICE_FWLOG_RING_SIZE_INDEX_DFLT 3
|
|
+#define ICE_FWLOG_RING_SIZE_DFLT 256
|
|
+#define ICE_FWLOG_RING_SIZE_MAX 512
|
|
+
|
|
+bool ice_fwlog_ring_full(struct ice_fwlog_ring *rings);
|
|
+bool ice_fwlog_ring_empty(struct ice_fwlog_ring *rings);
|
|
+void ice_fwlog_ring_increment(u16 *item, u16 size);
|
|
void ice_fwlog_set_supported(struct ice_hw *hw);
|
|
bool ice_fwlog_supported(struct ice_hw *hw);
|
|
int ice_fwlog_init(struct ice_hw *hw);
|
|
@@ -55,4 +75,5 @@ int ice_fwlog_set(struct ice_hw *hw, struct ice_fwlog_cfg *cfg);
|
|
int ice_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg);
|
|
int ice_fwlog_register(struct ice_hw *hw);
|
|
int ice_fwlog_unregister(struct ice_hw *hw);
|
|
+void ice_fwlog_realloc_rings(struct ice_hw *hw, int index);
|
|
#endif /* _ICE_FWLOG_H_ */
|
|
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
|
|
index 614e10ab4159..6c6ca5353f28 100644
|
|
--- a/drivers/net/ethernet/intel/ice/ice_main.c
|
|
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
|
|
@@ -1254,6 +1254,32 @@ ice_handle_link_event(struct ice_pf *pf, struct ice_rq_event_info *event)
|
|
return status;
|
|
}
|
|
|
|
+/**
|
|
+ * ice_get_fwlog_data - copy the FW log data from ARQ event
|
|
+ * @pf: PF that the FW log event is associated with
|
|
+ * @event: event structure containing FW log data
|
|
+ */
|
|
+static void
|
|
+ice_get_fwlog_data(struct ice_pf *pf, struct ice_rq_event_info *event)
|
|
+{
|
|
+ struct ice_fwlog_data *fwlog;
|
|
+ struct ice_hw *hw = &pf->hw;
|
|
+
|
|
+ fwlog = &hw->fwlog_ring.rings[hw->fwlog_ring.tail];
|
|
+
|
|
+ memset(fwlog->data, 0, PAGE_SIZE);
|
|
+ fwlog->data_size = le16_to_cpu(event->desc.datalen);
|
|
+
|
|
+ memcpy(fwlog->data, event->msg_buf, fwlog->data_size);
|
|
+ ice_fwlog_ring_increment(&hw->fwlog_ring.tail, hw->fwlog_ring.size);
|
|
+
|
|
+ if (ice_fwlog_ring_full(&hw->fwlog_ring)) {
|
|
+ /* the rings are full so bump the head to create room */
|
|
+ ice_fwlog_ring_increment(&hw->fwlog_ring.head,
|
|
+ hw->fwlog_ring.size);
|
|
+ }
|
|
+}
|
|
+
|
|
/**
|
|
* ice_aq_prep_for_event - Prepare to wait for an AdminQ event from firmware
|
|
* @pf: pointer to the PF private structure
|
|
@@ -1535,6 +1561,9 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type)
|
|
|
|
ice_vc_process_vf_msg(pf, &event, &data);
|
|
break;
|
|
+ case ice_aqc_opc_fw_logs_event:
|
|
+ ice_get_fwlog_data(pf, &event);
|
|
+ break;
|
|
case ice_aqc_opc_lldp_set_mib_change:
|
|
ice_dcb_process_lldp_set_mib_change(pf, &event);
|
|
break;
|
|
diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h
|
|
index 84bb61aa7409..28e47bb78eaf 100644
|
|
--- a/drivers/net/ethernet/intel/ice/ice_type.h
|
|
+++ b/drivers/net/ethernet/intel/ice/ice_type.h
|
|
@@ -875,6 +875,7 @@ struct ice_hw {
|
|
|
|
struct ice_fwlog_cfg fwlog_cfg;
|
|
bool fwlog_supported; /* does hardware support FW logging? */
|
|
+ struct ice_fwlog_ring fwlog_ring;
|
|
|
|
/* Device max aggregate bandwidths corresponding to the GL_PWR_MODE_CTL
|
|
* register. Used for determining the ITR/INTRL granularity during
|
|
--
|
|
2.43.0
|
|
|