From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 6AF964410E; Thu, 30 May 2024 13:17:15 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id BCE3E42D26; Thu, 30 May 2024 13:15:16 +0200 (CEST) Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) by mails.dpdk.org (Postfix) with ESMTP id B192F427E3 for ; Thu, 30 May 2024 13:15:04 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1717067706; x=1748603706; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=HvruhStqeC+zd8uaMEGVkAuDxKq8D5GKR2Cx518Lhwc=; b=OifCUMc0wR8uiT94lrvAJzW3156Hvpr8ozQj8II2XT0NTnRFx+sKt1hx 8LvOaglNo3EcSjaCgf9w/l6QZ5l+Qmz2k3Czo0+cexQSluGGPzakyqcyz ihFs7t5U37J5t5OC7iRS92eohLimebi6PEJFRdUDnNvRWlCF6TpmEzS9V uIGIzDMdiJuxwAgjv1R8oFNhAHrsm+2lmuaRHvV3aj8aRODo3CVmm7M4+ 5JWib+5uzJyVMcVc5RpurV9u1BgrJsw1UMo51IPQqVr4co1fIQJ/1SE07 /cajAosmkQwIVgmZDVF9+t3yY8kTFIdTIfDO4hN4II96BGxIDhAt4RPLY A==; X-CSE-ConnectionGUID: os9rCtGmRmqzvNxvyk06BA== X-CSE-MsgGUID: 52gkivu7S1StoLPZFtzfEg== X-IronPort-AV: E=McAfee;i="6600,9927,11087"; a="36063945" X-IronPort-AV: E=Sophos;i="6.08,201,1712646000"; d="scan'208";a="36063945" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 30 May 2024 04:15:05 -0700 X-CSE-ConnectionGUID: OrivFZf/TAKX5jCdQV9yqQ== X-CSE-MsgGUID: owXKCLgRRsu7iozZYS0eTA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.08,201,1712646000"; d="scan'208";a="36419479" Received: from silpixa00401119.ir.intel.com ([10.55.129.167]) by orviesa007.jf.intel.com with ESMTP; 30 May 2024 04:15:02 -0700 From: Anatoly Burakov To: dev@dpdk.org Cc: vladimir.medvedkin@intel.com, bruce.richardson@intel.com, Stefan Wegrzyn , Jedrzej Jagielski , Piotr Kwapulinski Subject: [PATCH v3 21/30] net/ixgbe/base: add support for E610 Admin Command Interface Date: Thu, 30 May 2024 12:13:54 +0100 Message-ID: <23c3f21d8d94aa3ccdc659b663cc98e7d836634e.1717067519.git.anatoly.burakov@intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Add low level support for Admin Command Interface (ACI). ACI is the Firmware interface used by a driver to communicate with E610 adapter. Add the following ACI features: - data structures, macros, register definitions - commands handling - events handling Signed-off-by: Stefan Wegrzyn Signed-off-by: Jedrzej Jagielski Signed-off-by: Piotr Kwapulinski Signed-off-by: Anatoly Burakov --- drivers/net/ixgbe/base/ixgbe_e610.c | 624 +++++++++++++++++++++++ drivers/net/ixgbe/base/ixgbe_e610.h | 30 ++ drivers/net/ixgbe/base/ixgbe_osdep.h | 1 + drivers/net/ixgbe/base/ixgbe_type_e610.h | 8 + drivers/net/ixgbe/base/meson.build | 1 + 5 files changed, 664 insertions(+) create mode 100644 drivers/net/ixgbe/base/ixgbe_e610.c create mode 100644 drivers/net/ixgbe/base/ixgbe_e610.h diff --git a/drivers/net/ixgbe/base/ixgbe_e610.c b/drivers/net/ixgbe/base/ixgbe_e610.c new file mode 100644 index 0000000000..3cf57fc3db --- /dev/null +++ b/drivers/net/ixgbe/base/ixgbe_e610.c @@ -0,0 +1,624 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 Intel Corporation + */ + +#include "ixgbe_type.h" +#include "ixgbe_e610.h" +#include "ixgbe_x550.h" +#include "ixgbe_common.h" +#include "ixgbe_phy.h" +#include "ixgbe_api.h" + +/** + * ixgbe_init_aci - initialization routine for Admin Command Interface + * @hw: pointer to the hardware structure + * + * Initialize the ACI lock. + */ +void ixgbe_init_aci(struct ixgbe_hw *hw) +{ + ixgbe_init_lock(&hw->aci.lock); +} + +/** + * ixgbe_shutdown_aci - shutdown routine for Admin Command Interface + * @hw: pointer to the hardware structure + * + * Destroy the ACI lock. + */ +void ixgbe_shutdown_aci(struct ixgbe_hw *hw) +{ + ixgbe_destroy_lock(&hw->aci.lock); +} + +/** + * ixgbe_should_retry_aci_send_cmd_execute - decide if ACI command should + * be resent + * @opcode: ACI opcode + * + * Check if ACI command should be sent again depending on the provided opcode. + * + * Return: true if the sending command routine should be repeated, + * otherwise false. + */ +STATIC bool ixgbe_should_retry_aci_send_cmd_execute(u16 opcode) +{ + + switch (opcode) { + case ixgbe_aci_opc_disable_rxen: + case ixgbe_aci_opc_get_phy_caps: + case ixgbe_aci_opc_get_link_status: + case ixgbe_aci_opc_get_link_topo: + return true; + } + + return false; +} + +/** + * ixgbe_aci_send_cmd_execute - execute sending FW Admin Command to FW Admin + * Command Interface + * @hw: pointer to the HW struct + * @desc: descriptor describing the command + * @buf: buffer to use for indirect commands (NULL for direct commands) + * @buf_size: size of buffer for indirect commands (0 for direct commands) + * + * Admin Command is sent using CSR by setting descriptor and buffer in specific + * registers. + * + * Return: the exit code of the operation. + * * - IXGBE_SUCCESS - success. + * * - IXGBE_ERR_ACI_DISABLED - CSR mechanism is not enabled. + * * - IXGBE_ERR_ACI_BUSY - CSR mechanism is busy. + * * - IXGBE_ERR_PARAM - buf_size is too big or + * invalid argument buf or buf_size. + * * - IXGBE_ERR_ACI_TIMEOUT - Admin Command X command timeout. + * * - IXGBE_ERR_ACI_ERROR - Admin Command X invalid state of HICR register or + * Admin Command failed because of bad opcode was returned or + * Admin Command failed with error Y. + */ +STATIC s32 +ixgbe_aci_send_cmd_execute(struct ixgbe_hw *hw, struct ixgbe_aci_desc *desc, + void *buf, u16 buf_size) +{ + u32 hicr = 0, tmp_buf_size = 0, i = 0; + u32 *raw_desc = (u32 *)desc; + s32 status = IXGBE_SUCCESS; + bool valid_buf = false; + u32 *tmp_buf = NULL; + u16 opcode = 0; + + do { + hw->aci.last_status = IXGBE_ACI_RC_OK; + + /* It's necessary to check if mechanism is enabled */ + hicr = IXGBE_READ_REG(hw, PF_HICR); + if (!(hicr & PF_HICR_EN)) { + status = IXGBE_ERR_ACI_DISABLED; + break; + } + if (hicr & PF_HICR_C) { + hw->aci.last_status = IXGBE_ACI_RC_EBUSY; + status = IXGBE_ERR_ACI_BUSY; + break; + } + opcode = desc->opcode; + + if (buf_size > IXGBE_ACI_MAX_BUFFER_SIZE) { + status = IXGBE_ERR_PARAM; + break; + } + + if (buf) + desc->flags |= IXGBE_CPU_TO_LE16(IXGBE_ACI_FLAG_BUF); + + /* Check if buf and buf_size are proper params */ + if (desc->flags & IXGBE_CPU_TO_LE16(IXGBE_ACI_FLAG_BUF)) { + if ((buf && buf_size == 0) || + (buf == NULL && buf_size)) { + status = IXGBE_ERR_PARAM; + break; + } + if (buf && buf_size) + valid_buf = true; + } + + if (valid_buf == true) { + if (buf_size % 4 == 0) + tmp_buf_size = buf_size; + else + tmp_buf_size = (buf_size & (u16)(~0x03)) + 4; + + tmp_buf = (u32*)ixgbe_malloc(hw, tmp_buf_size); + if (!tmp_buf) + return IXGBE_ERR_OUT_OF_MEM; + + /* tmp_buf will be firstly filled with 0xFF and after + * that the content of buf will be written into it. + * This approach lets us use valid buf_size and + * prevents us from reading past buf area + * when buf_size mod 4 not equal to 0. + */ + memset(tmp_buf, 0xFF, tmp_buf_size); + memcpy(tmp_buf, buf, buf_size); + + if (tmp_buf_size > IXGBE_ACI_LG_BUF) + desc->flags |= + IXGBE_CPU_TO_LE16(IXGBE_ACI_FLAG_LB); + + desc->datalen = IXGBE_CPU_TO_LE16(buf_size); + + if (desc->flags & IXGBE_CPU_TO_LE16(IXGBE_ACI_FLAG_RD)) { + for (i = 0; i < tmp_buf_size / 4; i++) { + IXGBE_WRITE_REG(hw, PF_HIBA(i), + IXGBE_LE32_TO_CPU(tmp_buf[i])); + } + } + } + + /* Descriptor is written to specific registers */ + for (i = 0; i < IXGBE_ACI_DESC_SIZE_IN_DWORDS; i++) + IXGBE_WRITE_REG(hw, PF_HIDA(i), + IXGBE_LE32_TO_CPU(raw_desc[i])); + + /* SW has to set PF_HICR.C bit and clear PF_HICR.SV and + * PF_HICR_EV + */ + hicr = IXGBE_READ_REG(hw, PF_HICR); + hicr = (hicr | PF_HICR_C) & ~(PF_HICR_SV | PF_HICR_EV); + IXGBE_WRITE_REG(hw, PF_HICR, hicr); + + /* Wait for sync Admin Command response */ + for (i = 0; i < IXGBE_ACI_SYNC_RESPONSE_TIMEOUT; i += 1) { + hicr = IXGBE_READ_REG(hw, PF_HICR); + if ((hicr & PF_HICR_SV) || !(hicr & PF_HICR_C)) + break; + + msec_delay(1); + } + + /* Wait for async Admin Command response */ + if ((hicr & PF_HICR_SV) && (hicr & PF_HICR_C)) { + for (i = 0; i < IXGBE_ACI_ASYNC_RESPONSE_TIMEOUT; + i += 1) { + hicr = IXGBE_READ_REG(hw, PF_HICR); + if ((hicr & PF_HICR_EV) || !(hicr & PF_HICR_C)) + break; + + msec_delay(1); + } + } + + /* Read sync Admin Command response */ + if ((hicr & PF_HICR_SV)) { + for (i = 0; i < IXGBE_ACI_DESC_SIZE_IN_DWORDS; i++) { + raw_desc[i] = IXGBE_READ_REG(hw, PF_HIDA(i)); + raw_desc[i] = IXGBE_CPU_TO_LE32(raw_desc[i]); + } + } + + /* Read async Admin Command response */ + if ((hicr & PF_HICR_EV) && !(hicr & PF_HICR_C)) { + for (i = 0; i < IXGBE_ACI_DESC_SIZE_IN_DWORDS; i++) { + raw_desc[i] = IXGBE_READ_REG(hw, PF_HIDA_2(i)); + raw_desc[i] = IXGBE_CPU_TO_LE32(raw_desc[i]); + } + } + + /* Handle timeout and invalid state of HICR register */ + if (hicr & PF_HICR_C) { + status = IXGBE_ERR_ACI_TIMEOUT; + break; + } else if (!(hicr & PF_HICR_SV) && !(hicr & PF_HICR_EV)) { + status = IXGBE_ERR_ACI_ERROR; + break; + } + + /* For every command other than 0x0014 treat opcode mismatch + * as an error. Response to 0x0014 command read from HIDA_2 + * is a descriptor of an event which is expected to contain + * different opcode than the command. + */ + if (desc->opcode != opcode && + opcode != IXGBE_CPU_TO_LE16(ixgbe_aci_opc_get_fw_event)) { + status = IXGBE_ERR_ACI_ERROR; + break; + } + + if (desc->retval != IXGBE_ACI_RC_OK) { + hw->aci.last_status = (enum ixgbe_aci_err)desc->retval; + status = IXGBE_ERR_ACI_ERROR; + break; + } + + /* Write a response values to a buf */ + if (valid_buf && (desc->flags & + IXGBE_CPU_TO_LE16(IXGBE_ACI_FLAG_BUF))) { + for (i = 0; i < tmp_buf_size / 4; i++) { + tmp_buf[i] = IXGBE_READ_REG(hw, PF_HIBA(i)); + tmp_buf[i] = IXGBE_CPU_TO_LE32(tmp_buf[i]); + } + memcpy(buf, tmp_buf, buf_size); + } + } while (0); + + if (tmp_buf) + ixgbe_free(hw, tmp_buf); + + return status; +} + +/** + * ixgbe_aci_send_cmd - send FW Admin Command to FW Admin Command Interface + * @hw: pointer to the HW struct + * @desc: descriptor describing the command + * @buf: buffer to use for indirect commands (NULL for direct commands) + * @buf_size: size of buffer for indirect commands (0 for direct commands) + * + * Helper function to send FW Admin Commands to the FW Admin Command Interface. + * + * Retry sending the FW Admin Command multiple times to the FW ACI + * if the EBUSY Admin Command error is returned. + * + * Return: the exit code of the operation. + */ +s32 ixgbe_aci_send_cmd(struct ixgbe_hw *hw, struct ixgbe_aci_desc *desc, + void *buf, u16 buf_size) +{ + struct ixgbe_aci_desc desc_cpy; + enum ixgbe_aci_err last_status; + bool is_cmd_for_retry; + u8 *buf_cpy = NULL; + s32 status; + u16 opcode; + u8 idx = 0; + + opcode = IXGBE_LE16_TO_CPU(desc->opcode); + is_cmd_for_retry = ixgbe_should_retry_aci_send_cmd_execute(opcode); + memset(&desc_cpy, 0, sizeof(desc_cpy)); + + if (is_cmd_for_retry) { + if (buf) { + buf_cpy = (u8 *)ixgbe_malloc(hw, buf_size); + if (!buf_cpy) + return IXGBE_ERR_OUT_OF_MEM; + } + memcpy(&desc_cpy, desc, sizeof(desc_cpy)); + } + + do { + ixgbe_acquire_lock(&hw->aci.lock); + status = ixgbe_aci_send_cmd_execute(hw, desc, buf, buf_size); + last_status = hw->aci.last_status; + ixgbe_release_lock(&hw->aci.lock); + + if (!is_cmd_for_retry || status == IXGBE_SUCCESS || + last_status != IXGBE_ACI_RC_EBUSY) + break; + + if (buf) + memcpy(buf, buf_cpy, buf_size); + memcpy(desc, &desc_cpy, sizeof(desc_cpy)); + + msec_delay(IXGBE_ACI_SEND_DELAY_TIME_MS); + } while (++idx < IXGBE_ACI_SEND_MAX_EXECUTE); + + if (buf_cpy) + ixgbe_free(hw, buf_cpy); + + return status; +} + +/** + * ixgbe_aci_check_event_pending - check if there are any pending events + * @hw: pointer to the HW struct + * + * Determine if there are any pending events. + * + * Return: true if there are any currently pending events + * otherwise false. + */ +bool ixgbe_aci_check_event_pending(struct ixgbe_hw *hw) +{ + u32 ep_bit_mask; + u32 fwsts; + + ep_bit_mask = hw->bus.func ? GL_FWSTS_EP_PF1 : GL_FWSTS_EP_PF0; + + /* Check state of Event Pending (EP) bit */ + fwsts = IXGBE_READ_REG(hw, GL_FWSTS); + return (fwsts & ep_bit_mask) ? true : false; +} + +/** + * ixgbe_aci_get_event - get an event from ACI + * @hw: pointer to the HW struct + * @e: event information structure + * @pending: optional flag signaling that there are more pending events + * + * Obtain an event from ACI and return its content + * through 'e' using ACI command (0x0014). + * Provide information if there are more events + * to retrieve through 'pending'. + * + * Return: the exit code of the operation. + */ +s32 ixgbe_aci_get_event(struct ixgbe_hw *hw, struct ixgbe_aci_event *e, + bool *pending) +{ + struct ixgbe_aci_desc desc; + s32 status; + + if (!e || (!e->msg_buf && e->buf_len) || (e->msg_buf && !e->buf_len)) + return IXGBE_ERR_PARAM; + + ixgbe_acquire_lock(&hw->aci.lock); + + /* Check if there are any events pending */ + if (!ixgbe_aci_check_event_pending(hw)) { + status = IXGBE_ERR_ACI_NO_EVENTS; + goto aci_get_event_exit; + } + + /* Obtain pending event */ + ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_fw_event); + status = ixgbe_aci_send_cmd_execute(hw, &desc, e->msg_buf, e->buf_len); + if (status) + goto aci_get_event_exit; + + /* Returned 0x0014 opcode indicates that no event was obtained */ + if (desc.opcode == IXGBE_CPU_TO_LE16(ixgbe_aci_opc_get_fw_event)) { + status = IXGBE_ERR_ACI_NO_EVENTS; + goto aci_get_event_exit; + } + + /* Determine size of event data */ + e->msg_len = MIN_T(u16, IXGBE_LE16_TO_CPU(desc.datalen), e->buf_len); + /* Write event descriptor to event info structure */ + memcpy(&e->desc, &desc, sizeof(e->desc)); + + /* Check if there are any further events pending */ + if (pending) { + *pending = ixgbe_aci_check_event_pending(hw); + } + +aci_get_event_exit: + ixgbe_release_lock(&hw->aci.lock); + + return status; +} + +/** + * ixgbe_fill_dflt_direct_cmd_desc - fill ACI descriptor with default values. + * @desc: pointer to the temp descriptor (non DMA mem) + * @opcode: the opcode can be used to decide which flags to turn off or on + * + * Helper function to fill the descriptor desc with default values + * and the provided opcode. + */ +void ixgbe_fill_dflt_direct_cmd_desc(struct ixgbe_aci_desc *desc, u16 opcode) +{ + /* zero out the desc */ + memset(desc, 0, sizeof(*desc)); + desc->opcode = IXGBE_CPU_TO_LE16(opcode); + desc->flags = IXGBE_CPU_TO_LE16(IXGBE_ACI_FLAG_SI); +} + +/** + * ixgbe_aci_req_res - request a common resource + * @hw: pointer to the HW struct + * @res: resource ID + * @access: access type + * @sdp_number: resource number + * @timeout: the maximum time in ms that the driver may hold the resource + * + * Requests a common resource using the ACI command (0x0008). + * Specifies the maximum time the driver may hold the resource. + * If the requested resource is currently occupied by some other driver, + * a busy return value is returned and the timeout field value indicates the + * maximum time the current owner has to free it. + * + * Return: the exit code of the operation. + */ +static s32 +ixgbe_aci_req_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res, + enum ixgbe_aci_res_access_type access, u8 sdp_number, + u32 *timeout) +{ + struct ixgbe_aci_cmd_req_res *cmd_resp; + struct ixgbe_aci_desc desc; + s32 status; + + cmd_resp = &desc.params.res_owner; + + ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_req_res); + + cmd_resp->res_id = IXGBE_CPU_TO_LE16(res); + cmd_resp->access_type = IXGBE_CPU_TO_LE16(access); + cmd_resp->res_number = IXGBE_CPU_TO_LE32(sdp_number); + cmd_resp->timeout = IXGBE_CPU_TO_LE32(*timeout); + *timeout = 0; + + status = ixgbe_aci_send_cmd(hw, &desc, NULL, 0); + + /* The completion specifies the maximum time in ms that the driver + * may hold the resource in the Timeout field. + */ + + /* If the resource is held by some other driver, the command completes + * with a busy return value and the timeout field indicates the maximum + * time the current owner of the resource has to free it. + */ + if (!status || hw->aci.last_status == IXGBE_ACI_RC_EBUSY) + *timeout = IXGBE_LE32_TO_CPU(cmd_resp->timeout); + + return status; +} + +/** + * ixgbe_aci_release_res - release a common resource using ACI + * @hw: pointer to the HW struct + * @res: resource ID + * @sdp_number: resource number + * + * Release a common resource using ACI command (0x0009). + * + * Return: the exit code of the operation. + */ +static s32 +ixgbe_aci_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res, + u8 sdp_number) +{ + struct ixgbe_aci_cmd_req_res *cmd; + struct ixgbe_aci_desc desc; + + cmd = &desc.params.res_owner; + + ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_release_res); + + cmd->res_id = IXGBE_CPU_TO_LE16(res); + cmd->res_number = IXGBE_CPU_TO_LE32(sdp_number); + + return ixgbe_aci_send_cmd(hw, &desc, NULL, 0); +} + +/** + * ixgbe_acquire_res - acquire the ownership of a resource + * @hw: pointer to the HW structure + * @res: resource ID + * @access: access type (read or write) + * @timeout: timeout in milliseconds + * + * Make an attempt to acquire the ownership of a resource using + * the ixgbe_aci_req_res to utilize ACI. + * In case if some other driver has previously acquired the resource and + * performed any necessary updates, the IXGBE_ERR_ACI_NO_WORK is returned, + * and the caller does not obtain the resource and has no further work to do. + * If needed, the function will poll until the current lock owner timeouts. + * + * Return: the exit code of the operation. + */ +s32 ixgbe_acquire_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res, + enum ixgbe_aci_res_access_type access, u32 timeout) +{ +#define IXGBE_RES_POLLING_DELAY_MS 10 + u32 delay = IXGBE_RES_POLLING_DELAY_MS; + u32 res_timeout = timeout; + u32 retry_timeout = 0; + s32 status; + + status = ixgbe_aci_req_res(hw, res, access, 0, &res_timeout); + + /* A return code of IXGBE_ERR_ACI_NO_WORK means that another driver has + * previously acquired the resource and performed any necessary updates; + * in this case the caller does not obtain the resource and has no + * further work to do. + */ + if (status == IXGBE_ERR_ACI_NO_WORK) + goto ixgbe_acquire_res_exit; + + /* If necessary, poll until the current lock owner timeouts. + * Set retry_timeout to the timeout value reported by the FW in the + * response to the "Request Resource Ownership" (0x0008) Admin Command + * as it indicates the maximum time the current owner of the resource + * is allowed to hold it. + */ + retry_timeout = res_timeout; + while (status && retry_timeout && res_timeout) { + msec_delay(delay); + retry_timeout = (retry_timeout > delay) ? + retry_timeout - delay : 0; + status = ixgbe_aci_req_res(hw, res, access, 0, &res_timeout); + + if (status == IXGBE_ERR_ACI_NO_WORK) + /* lock free, but no work to do */ + break; + + if (!status) + /* lock acquired */ + break; + } + +ixgbe_acquire_res_exit: + return status; +} + +/** + * ixgbe_release_res - release a common resource + * @hw: pointer to the HW structure + * @res: resource ID + * + * Release a common resource using ixgbe_aci_release_res. + */ +void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res) +{ + u32 total_delay = 0; + s32 status; + + status = ixgbe_aci_release_res(hw, res, 0); + + /* There are some rare cases when trying to release the resource + * results in an admin command timeout, so handle them correctly. + */ + while ((status == IXGBE_ERR_ACI_TIMEOUT) && + (total_delay < IXGBE_ACI_RELEASE_RES_TIMEOUT)) { + msec_delay(1); + status = ixgbe_aci_release_res(hw, res, 0); + total_delay++; + } +} + +/** + * ixgbe_aci_get_internal_data - get internal FW/HW data + * @hw: pointer to the hardware structure + * @cluster_id: specific cluster to dump + * @table_id: table ID within cluster + * @start: index of line in the block to read + * @buf: dump buffer + * @buf_size: dump buffer size + * @ret_buf_size: return buffer size (returned by FW) + * @ret_next_cluster: next cluster to read (returned by FW) + * @ret_next_table: next block to read (returned by FW) + * @ret_next_index: next index to read (returned by FW) + * + * Get internal FW/HW data using ACI command (0xFF08) for debug purposes. + * + * Return: the exit code of the operation. + */ +s32 ixgbe_aci_get_internal_data(struct ixgbe_hw *hw, u16 cluster_id, + u16 table_id, u32 start, void *buf, + u16 buf_size, u16 *ret_buf_size, + u16 *ret_next_cluster, u16 *ret_next_table, + u32 *ret_next_index) +{ + struct ixgbe_aci_cmd_debug_dump_internals *cmd; + struct ixgbe_aci_desc desc; + s32 status; + + cmd = &desc.params.debug_dump; + + if (buf_size == 0 || !buf) + return IXGBE_ERR_PARAM; + + ixgbe_fill_dflt_direct_cmd_desc(&desc, + ixgbe_aci_opc_debug_dump_internals); + + cmd->cluster_id = IXGBE_CPU_TO_LE16(cluster_id); + cmd->table_id = IXGBE_CPU_TO_LE16(table_id); + cmd->idx = IXGBE_CPU_TO_LE32(start); + + status = ixgbe_aci_send_cmd(hw, &desc, buf, buf_size); + + if (!status) { + if (ret_buf_size) + *ret_buf_size = IXGBE_LE16_TO_CPU(desc.datalen); + if (ret_next_cluster) + *ret_next_cluster = IXGBE_LE16_TO_CPU(cmd->cluster_id); + if (ret_next_table) + *ret_next_table = IXGBE_LE16_TO_CPU(cmd->table_id); + if (ret_next_index) + *ret_next_index = IXGBE_LE32_TO_CPU(cmd->idx); + } + + return status; +} diff --git a/drivers/net/ixgbe/base/ixgbe_e610.h b/drivers/net/ixgbe/base/ixgbe_e610.h new file mode 100644 index 0000000000..605a2161f1 --- /dev/null +++ b/drivers/net/ixgbe/base/ixgbe_e610.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 Intel Corporation + */ + +#ifndef _IXGBE_E610_H_ +#define _IXGBE_E610_H_ + +#include "ixgbe_type.h" + +void ixgbe_init_aci(struct ixgbe_hw *hw); +void ixgbe_shutdown_aci(struct ixgbe_hw *hw); + +s32 ixgbe_aci_send_cmd(struct ixgbe_hw *hw, struct ixgbe_aci_desc *desc, + void *buf, u16 buf_size); +bool ixgbe_aci_check_event_pending(struct ixgbe_hw *hw); +s32 ixgbe_aci_get_event(struct ixgbe_hw *hw, struct ixgbe_aci_event *e, + bool *pending); + +void ixgbe_fill_dflt_direct_cmd_desc(struct ixgbe_aci_desc *desc, u16 opcode); + +s32 ixgbe_acquire_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res, + enum ixgbe_aci_res_access_type access, u32 timeout); +void ixgbe_release_res(struct ixgbe_hw *hw, enum ixgbe_aci_res_ids res); +s32 ixgbe_aci_get_internal_data(struct ixgbe_hw *hw, u16 cluster_id, + u16 table_id, u32 start, void *buf, + u16 buf_size, u16 *ret_buf_size, + u16 *ret_next_cluster, u16 *ret_next_table, + u32 *ret_next_index); + +#endif /* _IXGBE_E610_H_ */ diff --git a/drivers/net/ixgbe/base/ixgbe_osdep.h b/drivers/net/ixgbe/base/ixgbe_osdep.h index 5657777faa..b3266a3c77 100644 --- a/drivers/net/ixgbe/base/ixgbe_osdep.h +++ b/drivers/net/ixgbe/base/ixgbe_osdep.h @@ -80,6 +80,7 @@ enum { #define IXGBE_NTOHS(_i) rte_be_to_cpu_16(_i) #define IXGBE_CPU_TO_LE16(_i) rte_cpu_to_le_16(_i) #define IXGBE_CPU_TO_LE32(_i) rte_cpu_to_le_32(_i) +#define IXGBE_LE16_TO_CPU(_i) rte_le_to_cpu_16(_i) #define IXGBE_LE32_TO_CPU(_i) rte_le_to_cpu_32(_i) #define IXGBE_LE32_TO_CPUS(_i) rte_le_to_cpu_32(_i) #define IXGBE_CPU_TO_BE16(_i) rte_cpu_to_be_16(_i) diff --git a/drivers/net/ixgbe/base/ixgbe_type_e610.h b/drivers/net/ixgbe/base/ixgbe_type_e610.h index a50603d1b7..2f45700fa6 100644 --- a/drivers/net/ixgbe/base/ixgbe_type_e610.h +++ b/drivers/net/ixgbe/base/ixgbe_type_e610.h @@ -167,6 +167,14 @@ /* [ms] timeout of waiting for resource release */ #define IXGBE_ACI_RELEASE_RES_TIMEOUT 10000 +/* Timestamp spacing for Tools ACI: queue is active if spacing is within the range [LO..HI] */ +#define IXGBE_TOOLS_ACI_ACTIVE_STAMP_SPACING_LO 0 +#define IXGBE_TOOLS_ACI_ACTIVE_STAMP_SPACING_HI 200 + +/* Timestamp spacing for Tools ACI: queue is expired if spacing is outside the range [LO..HI] */ +#define IXGBE_TOOLS_ACI_EXPIRED_STAMP_SPACING_LO -5 +#define IXGBE_TOOLS_ACI_EXPIRED_STAMP_SPACING_HI 205 + /* FW defined boundary for a large buffer, 4k >= Large buffer > 512 bytes */ #define IXGBE_ACI_LG_BUF 512 diff --git a/drivers/net/ixgbe/base/meson.build b/drivers/net/ixgbe/base/meson.build index f901d6c965..7e4fbdfa0f 100644 --- a/drivers/net/ixgbe/base/meson.build +++ b/drivers/net/ixgbe/base/meson.build @@ -9,6 +9,7 @@ sources = [ 'ixgbe_dcb_82598.c', 'ixgbe_dcb_82599.c', 'ixgbe_dcb.c', + 'ixgbe_e610.c', 'ixgbe_hv_vf.c', 'ixgbe_mbx.c', 'ixgbe_osdep.c', -- 2.43.0