From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id B8D51C7EE25 for ; Wed, 7 Jun 2023 22:25:20 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 6AE0A613CC; Wed, 7 Jun 2023 22:25:20 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 6AE0A613CC DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=osuosl.org; s=default; t=1686176720; bh=EjUZRspzCu/51FQlzYo23vs96tsksezvMWYfV+Krnlc=; h=From:To:Date:In-Reply-To:References:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=xAHIFN/aHw0CUzIRZklSR2W/JpW5gVxzTUvQ0QkLUN2LmcZOiaMHUXBhKhR7mgFHF QSeRG5BvJD/o+F+azw/gcHg3Iob63kGzb3VJVxIBnATnBLmGpBfaD9MkkhdDX7x+iq 4c5bucn26eZNfeIp+yqOzLRylGNY7iAFmoj5qm+1Pq6AwFANhAnWyMv/BGaJXJ5LW+ cRNAauK9uhJKLNq//JD+Qud8TqubBOaVvQGkbPq6MYugzUw/2o2wTYamtpXSLEFByS jw+w+CCe3rX4pkq1vhKGvQJOu7Rr9gwAPdp+n+3BCn/JhXjol+JyFwtJLHSO3UUSrI ge+Zd4KP7ObrA== X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 8LdxcRZnNJxn; Wed, 7 Jun 2023 22:25:18 +0000 (UTC) Received: from ash.osuosl.org (ash.osuosl.org [140.211.166.34]) by smtp3.osuosl.org (Postfix) with ESMTP id 2007F613C6; Wed, 7 Jun 2023 22:25:18 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 2007F613C6 Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by ash.osuosl.org (Postfix) with ESMTP id 39DB71BF3EA for ; Wed, 7 Jun 2023 22:25:01 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 0D2ED4183E for ; Wed, 7 Jun 2023 22:24:59 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 0D2ED4183E X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id BunbSGhVr_fT for ; Wed, 7 Jun 2023 22:24:57 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 991FA4183D Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by smtp2.osuosl.org (Postfix) with ESMTPS id 991FA4183D for ; Wed, 7 Jun 2023 22:24:57 +0000 (UTC) X-IronPort-AV: E=McAfee;i="6600,9927,10734"; a="443493354" X-IronPort-AV: E=Sophos;i="6.00,225,1681196400"; d="scan'208";a="443493354" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Jun 2023 15:24:56 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10734"; a="774804949" X-IronPort-AV: E=Sophos;i="6.00,225,1681196400"; d="scan'208";a="774804949" Received: from pmstillw-desk1.amr.corp.intel.com ([10.212.90.221]) by fmsmga008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Jun 2023 15:24:56 -0700 From: Paul M Stillwell Jr To: intel-wired-lan@lists.osuosl.org Date: Wed, 7 Jun 2023 15:24:42 -0700 Message-Id: <20230607222443.119-4-paul.m.stillwell.jr@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230607222443.119-1-paul.m.stillwell.jr@intel.com> References: <20230607222443.119-1-paul.m.stillwell.jr@intel.com> MIME-Version: 1.0 X-Mailman-Original-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1686176697; x=1717712697; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=h1YNb1FA9BfNeFr//L2LBI2Arhh96vYLZQNeQYFhIE0=; b=ipbNN394Mfrw3JfReBrdrtzYJXgSDwkJhXUzGbF51T4wRRufnG9D71xn o7J3rmPjoTxCwEd/seHjpKSAt4tm9g5uAx0Dh1ME6C53FU3BzWCVQbtTx XJHfFtIR7McEuS+wsK6EPR10PuRI2coZW69Z7l2LzeZay9pIKnwz6eSsg R3PR3a2QC8baclnsDFSg+iMo3NvbmVI7UGfYTDdQjf2oYeBxVNNZ+MdxL j0cMwjya9uGT12LWRCAj8XQoo+zlwey69lRykmtNKYOBGCe/IVWu3YgjV cNgMDn9CJQLZieKP4PUawSaYmjhVMs7oIu5o8AX4Cy9kSxDoQBsVGN4zM Q==; X-Mailman-Original-Authentication-Results: smtp2.osuosl.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=ipbNN394 Subject: [Intel-wired-lan] [PATCH net-next v12 3/4] ice: add ability to read FW log data and configure the number of log buffers X-BeenThere: intel-wired-lan@osuosl.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel Wired Ethernet Linux Kernel Driver Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: intel-wired-lan-bounces@osuosl.org Sender: "Intel-wired-lan" 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 a 0 to the 'data' file and that will clear the data. In addition to being able to read the data the user can configure how many buffers can be used to store the FW logs within the driver. This allows the user to increase/decrease the number of buffers used based on the users situation. The buffers are used as a ring so if the driver runs out of buffers then it will overwrite data. To change the number of buffers the user can write to the 'nr_buffs' file like this: echo 128 > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/nr_buffs The value written to the file must be a power of 2 value between 1 (not recommended) and 512. Signed-off-by: Paul M Stillwell Jr --- v11->v12: - added fwlog/data file for reading and clearing data - added fwlog/nr_buffs to change the number of data buffers to store log data in --- .../net/ethernet/intel/ice/ice_adminq_cmd.h | 1 + drivers/net/ethernet/intel/ice/ice_common.c | 1 + drivers/net/ethernet/intel/ice/ice_debugfs.c | 248 ++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_fwlog.c | 158 ++++++++++- drivers/net/ethernet/intel/ice/ice_fwlog.h | 20 ++ drivers/net/ethernet/intel/ice/ice_main.c | 29 ++ drivers/net/ethernet/intel/ice/ice_type.h | 1 + 7 files changed, 457 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 26690348e5ac..11304d335d50 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -2407,6 +2407,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_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 373ffa1c90d9..73675c8c90d2 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -1032,6 +1032,7 @@ void ice_deinit_hw(struct ice_hw *hw) ice_free_hw_tbls(hw); mutex_destroy(&hw->tnl_lock); + ice_fwlog_deinit(hw); ice_destroy_all_ctrlq(hw); /* Clear VSI contexts if not already cleared */ diff --git a/drivers/net/ethernet/intel/ice/ice_debugfs.c b/drivers/net/ethernet/intel/ice/ice_debugfs.c index 1061b70980e5..692f05fc2e3c 100644 --- a/drivers/net/ethernet/intel/ice/ice_debugfs.c +++ b/drivers/net/ethernet/intel/ice/ice_debugfs.c @@ -508,6 +508,243 @@ static const struct file_operations ice_debugfs_enable_fops = { .write = ice_debugfs_enable_write, }; +/** + * ice_debugfs_nr_buffs_read - read from 'nr_buffs' 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_nr_buffs_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 status; + + /* don't allow commands if the FW doesn't support it */ + if (!ice_fwlog_supported(&pf->hw)) + return -EOPNOTSUPP; + + snprintf(buff, sizeof(buff), "%d\n", hw->fwlog_ring.size); + + status = simple_read_from_buffer(buffer, count, ppos, buff, + strlen(buff)); + + return status; +} + +/** + * ice_debugfs_nr_buffs_write - write into 'nr_buffs' 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_nr_buffs_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; + char **argv; + int argc; + + /* don't allow commands if the FW doesn't support it */ + if (!ice_fwlog_supported(hw)) + return -EOPNOTSUPP; + + /* don't allow partial writes */ + if (*ppos != 0) + return 0; + + ret = ice_debugfs_parse_cmd_line(buf, count, &argv, &argc); + if (ret) + goto err_copy_from_user; + + if (argc == 1) { + s16 nr_buffs; + + ret = kstrtos16(argv[0], 0, &nr_buffs); + if (ret) + goto nr_buffs_write_error; + + if (nr_buffs < 0 || nr_buffs > ICE_FWLOG_RING_SIZE_MAX) { + dev_info(dev, "nr_buffs '%d' is not within bounds. Please use a value between 1 and %d\n", + nr_buffs, ICE_FWLOG_RING_SIZE_MAX); + ret = -EINVAL; + goto nr_buffs_write_error; + } else if (hweight16(nr_buffs) > 1) { + dev_info(dev, "nr_buffs '%d' is not a power of 2. Please use a value that is a power of 2.\n", + nr_buffs); + ret = -EINVAL; + goto nr_buffs_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 nr_buffs\n"); + ret = -EINVAL; + goto nr_buffs_write_error; + } + + /* free all the buffers and the tracking info and resize */ + ice_fwlog_realloc_rings(hw, nr_buffs); + } else { + dev_info(dev, "unknown or invalid command '%s'\n", argv[0]); + ret = -EINVAL; + goto nr_buffs_write_error; + } + + /* if we get here, nothing went wrong; return bytes copied */ + ret = (ssize_t)count; + +nr_buffs_write_error: + argv_free(argv); +err_copy_from_user: + /* 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_nr_buffs_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = ice_debugfs_nr_buffs_read, + .write = ice_debugfs_nr_buffs_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; + int debug_count; + + /* don't allow commands if the FW doesn't support it */ + if (!ice_fwlog_supported(&pf->hw)) + return -EOPNOTSUPP; + + if (ice_fwlog_ring_empty(&hw->fwlog_ring)) + return 0; + +debug_count = 1; + 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); + debug_count++; + } + + 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; + char **argv; + int argc; + + /* don't allow commands if the FW doesn't support it */ + if (!ice_fwlog_supported(hw)) + return -EOPNOTSUPP; + + /* don't allow partial writes */ + if (*ppos != 0) + return 0; + + ret = ice_debugfs_parse_cmd_line(buf, count, &argv, &argc); + if (ret) + goto err_copy_from_user; + + if (argc == 1) { + 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; + } + } else { + dev_info(dev, "unknown or invalid command '%s'\n", argv[0]); + ret = -EINVAL; + goto nr_buffs_write_error; + } + + /* if we get here, nothing went wrong; return bytes copied */ + ret = (ssize_t)count; + +nr_buffs_write_error: + argv_free(argv); +err_copy_from_user: + /* 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 @@ -539,6 +776,17 @@ void ice_debugfs_fwlog_init(struct ice_pf *pf) debugfs_create_file("resolution", 0600, pf->ice_debugfs_pf_fwlog, pf, &ice_debugfs_resolution_fops); + + debugfs_create_file("enable", 0600, pf->ice_debugfs_pf_fwlog, + pf, &ice_debugfs_enable_fops); + + debugfs_create_file("nr_buffs", 0600, pf->ice_debugfs_pf_fwlog, + pf, &ice_debugfs_nr_buffs_fops); + + debugfs_create_file("data", 0600, pf->ice_debugfs_pf_fwlog, + pf, &ice_debugfs_data_fops); + + return; } /** diff --git a/drivers/net/ethernet/intel/ice/ice_fwlog.c b/drivers/net/ethernet/intel/ice/ice_fwlog.c index ac48eabfcaf1..f3198382af5a 100644 --- a/drivers/net/ethernet/intel/ice/ice_fwlog.c +++ b/drivers/net/ethernet/intel/ice/ice_fwlog.c @@ -5,6 +5,107 @@ #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, ret = 0; + + for (i = 0; i < rings->size; i++) { + struct ice_fwlog_data *ring = &rings->rings[i]; + + ring->data_size = PAGE_SIZE; + ring->data = vzalloc(ring->data_size); + if (!ring->data) { + ret = -ENOMEM; + break; + } + } + + return ret; +} + +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]; + + if (ring->data) + vfree(ring->data); + + ring->data_size = 0; + } +} + +/** + * ice_fwlog_realloc_rings - reallocate the FW log rings + * @hw: pointer to the HW structure + * @ring_size: the new number of rings to allocate + * + */ +void ice_fwlog_realloc_rings(struct ice_hw *hw, int ring_size) +{ + struct ice_fwlog_ring ring; + int status; + + 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(ICE_FWLOG_RING_SIZE_DFLT, + sizeof(*ring.rings), GFP_KERNEL); + if (!ring.rings) { + dev_warn(ice_hw_to_dev(hw), "Unable to allocate memory for FW log ring\n"); + 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.head = 0; + hw->fwlog_ring.tail = 0; +} + /** * ice_fwlog_init - Initialize FW logging configuration * @hw: pointer to the HW structure @@ -14,16 +115,38 @@ */ int ice_fwlog_init(struct ice_hw *hw) { - int status; + /* only support fw log commands on PF 0 */ + if (hw->bus.func) + return -EINVAL; ice_fwlog_set_supported(hw); if (ice_fwlog_supported(hw)) { + int status; + /* read the current config from the FW and store it */ status = ice_fwlog_get(hw, &hw->fwlog_cfg); 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 ring\n"); + return -ENOMEM; + } + + hw->fwlog_ring.size = ICE_FWLOG_RING_SIZE_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"); @@ -32,6 +155,39 @@ int ice_fwlog_init(struct ice_hw *hw) return 0; } +/** + * ice_fwlog_deinit - unroll FW logging configuration + * @hw: pointer to the HW structure + * + * This function should be called in ice_deinit_hw(). + */ +void ice_fwlog_deinit(struct ice_hw *hw) +{ + int status; + + /* only support fw log commands on PF 0 */ + if (hw->bus.func) + return; + + /* make sure FW logging is disabled to not put the FW in a weird state + * for the next driver load + */ + hw->fwlog_cfg.options &= ~ICE_FWLOG_OPTION_ARQ_ENA; + status = ice_fwlog_set(hw, &hw->fwlog_cfg); + if (status) + dev_warn(ice_hw_to_dev(hw), "Unable to turn off FW logging, status: %d\n", status); + + status = ice_fwlog_unregister(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); + } +} + /** * ice_fwlog_supported - Cached for whether FW supports FW logging or not * @hw: pointer to the HW structure diff --git a/drivers/net/ethernet/intel/ice/ice_fwlog.h b/drivers/net/ethernet/intel/ice/ice_fwlog.h index fcfceb9f6ec2..43d980832b42 100644 --- a/drivers/net/ethernet/intel/ice/ice_fwlog.h +++ b/drivers/net/ethernet/intel/ice/ice_fwlog.h @@ -47,11 +47,31 @@ 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 size; + u16 head; + u16 tail; +}; + +#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); +void ice_fwlog_deinit(struct ice_hw *hw); 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 num_rings); #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 d05d8a603861..024970640a9f 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -1239,6 +1239,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); + } +} + enum ice_aq_task_state { ICE_AQ_TASK_WAITING = 0, ICE_AQ_TASK_COMPLETE, @@ -1519,6 +1545,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 f32a4c310daa..54213cadd08f 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -864,6 +864,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.35.1 _______________________________________________ Intel-wired-lan mailing list Intel-wired-lan@osuosl.org https://lists.osuosl.org/mailman/listinfo/intel-wired-lan