/** * 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. * It may happen when CSR is busy during link state changes. * * Return: true if the sending command routine should be repeated, * otherwise false.
*/ staticbool 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: returntrue;
}
returnfalse;
}
/** * 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. * * - 0 - success. * * - -EIO - CSR mechanism is not enabled. * * - -EBUSY - CSR mechanism is busy. * * - -EINVAL - buf_size is too big or * invalid argument buf or buf_size. * * - -ETIME - Admin Command X command timeout. * * - -EIO - 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.
*/ staticint ixgbe_aci_send_cmd_execute(struct ixgbe_hw *hw, struct libie_aq_desc *desc, void *buf, u16 buf_size)
{
u16 opcode, buf_tail_size = buf_size % 4;
u32 *raw_desc = (u32 *)desc;
u32 hicr, i, buf_tail = 0; bool valid_buf = false;
hw->aci.last_status = LIBIE_AQ_RC_OK;
/* It's necessary to check if mechanism is enabled */
hicr = IXGBE_READ_REG(hw, IXGBE_PF_HICR);
if (desc->flags & cpu_to_le16(LIBIE_AQ_FLAG_RD)) { for (i = 0; i < buf_size / 4; i++)
IXGBE_WRITE_REG(hw, IXGBE_PF_HIBA(i), ((u32 *)buf)[i]); if (buf_tail_size)
IXGBE_WRITE_REG(hw, IXGBE_PF_HIBA(i), buf_tail);
}
}
/* Descriptor is written to specific registers */ for (i = 0; i < IXGBE_ACI_DESC_SIZE_IN_DWORDS; i++)
IXGBE_WRITE_REG(hw, IXGBE_PF_HIDA(i), 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, IXGBE_PF_HICR) | IXGBE_PF_HICR_C) &
~(IXGBE_PF_HICR_SV | IXGBE_PF_HICR_EV);
IXGBE_WRITE_REG(hw, IXGBE_PF_HICR, hicr);
/* Read sync Admin Command response */ if ((hicr & IXGBE_PF_HICR_SV)) { for (i = 0; i < IXGBE_ACI_DESC_SIZE_IN_DWORDS; i++) {
raw_desc[i] = IXGBE_READ_REG(hw, IXGBE_PF_HIDA(i));
raw_desc[i] = raw_desc[i];
}
}
/* Read async Admin Command response */ if ((hicr & IXGBE_PF_HICR_EV) && !(hicr & IXGBE_PF_HICR_C)) { for (i = 0; i < IXGBE_ACI_DESC_SIZE_IN_DWORDS; i++) {
raw_desc[i] = IXGBE_READ_REG(hw, IXGBE_PF_HIDA_2(i));
raw_desc[i] = raw_desc[i];
}
}
/* Handle timeout and invalid state of HICR register */ if (hicr & IXGBE_PF_HICR_C) return -ETIME;
if (!(hicr & IXGBE_PF_HICR_SV) && !(hicr & IXGBE_PF_HICR_EV)) return -EIO;
/* 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 != cpu_to_le16(opcode) &&
opcode != ixgbe_aci_opc_get_fw_event) return -EIO;
/* Write a response values to a buf */ if (valid_buf) { for (i = 0; i < buf_size / 4; i++)
((u32 *)buf)[i] = IXGBE_READ_REG(hw, IXGBE_PF_HIBA(i)); if (buf_tail_size) {
buf_tail = IXGBE_READ_REG(hw, IXGBE_PF_HIBA(i));
memcpy(buf + buf_size - buf_tail_size, &buf_tail,
buf_tail_size);
}
}
return 0;
}
/** * 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.
*/ int ixgbe_aci_send_cmd(struct ixgbe_hw *hw, struct libie_aq_desc *desc, void *buf, u16 buf_size)
{
u16 opcode = le16_to_cpu(desc->opcode); struct libie_aq_desc desc_cpy; enum libie_aq_err last_status;
u8 idx = 0, *buf_cpy = NULL; bool is_cmd_for_retry; unsignedlong timeout; int err;
is_cmd_for_retry = ixgbe_should_retry_aci_send_cmd_execute(opcode); if (is_cmd_for_retry) { if (buf) {
buf_cpy = kmalloc(buf_size, GFP_KERNEL); if (!buf_cpy) return -ENOMEM;
*buf_cpy = *(u8 *)buf;
}
desc_cpy = *desc;
}
if (!is_cmd_for_retry || !err ||
last_status != LIBIE_AQ_RC_EBUSY) break;
if (buf)
memcpy(buf, buf_cpy, buf_size);
*desc = desc_cpy;
msleep(IXGBE_ACI_SEND_DELAY_TIME_MS);
} while (++idx < IXGBE_ACI_SEND_MAX_EXECUTE &&
time_before(jiffies, timeout));
kfree(buf_cpy);
return err;
}
/** * 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 = hw->bus.func ? GL_FWSTS_EP_PF1 : GL_FWSTS_EP_PF0;
u32 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.
*/ int ixgbe_aci_get_event(struct ixgbe_hw *hw, struct ixgbe_aci_event *e, bool *pending)
{ struct libie_aq_desc desc; int err;
if (!e || (!e->msg_buf && e->buf_len)) return -EINVAL;
mutex_lock(&hw->aci.lock);
/* Check if there are any events pending */ if (!ixgbe_aci_check_event_pending(hw)) {
err = -ENOENT; goto aci_get_event_exit;
}
/* Returned 0x0014 opcode indicates that no event was obtained */ if (desc.opcode == cpu_to_le16(ixgbe_aci_opc_get_fw_event)) {
err = -ENOENT; goto aci_get_event_exit;
}
/* Determine size of event data */
e->msg_len = min_t(u16, 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:
mutex_unlock(&hw->aci.lock);
return err;
}
/** * 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 libie_aq_desc *desc, u16 opcode)
{ /* Zero out the desc. */
memset(desc, 0, sizeof(*desc));
desc->opcode = cpu_to_le16(opcode);
desc->flags = cpu_to_le16(LIBIE_AQ_FLAG_SI);
}
/** * ixgbe_aci_get_fw_ver - Get the firmware version * @hw: pointer to the HW struct * * Get the firmware version using ACI command (0x0001). * * Return: the exit code of the operation.
*/ staticint ixgbe_aci_get_fw_ver(struct ixgbe_hw *hw)
{ struct libie_aqc_get_ver *resp; struct libie_aq_desc desc; int err;
/** * 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.
*/ staticint ixgbe_aci_req_res(struct ixgbe_hw *hw, enum libie_aq_res_id res, enum libie_aq_res_access_type access,
u8 sdp_number, u32 *timeout)
{ struct libie_aqc_req_res *cmd_resp; struct libie_aq_desc desc; int err;
/* 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 (!err || hw->aci.last_status == LIBIE_AQ_RC_EBUSY)
*timeout = le32_to_cpu(cmd_resp->timeout);
return err;
}
/** * 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.
*/ staticint ixgbe_aci_release_res(struct ixgbe_hw *hw, enum libie_aq_res_id res,
u8 sdp_number)
{ struct libie_aqc_req_res *cmd; struct libie_aq_desc desc;
/** * 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 -EALREADY 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.
*/ int ixgbe_acquire_res(struct ixgbe_hw *hw, enum libie_aq_res_id res, enum libie_aq_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; int err;
/* A return code of -EALREADY 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 (err == -EALREADY) return err;
/* 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 (err && retry_timeout && res_timeout) {
msleep(delay);
retry_timeout = (retry_timeout > delay) ?
retry_timeout - delay : 0;
err = ixgbe_aci_req_res(hw, res, access, 0, &res_timeout);
/* Success - lock acquired. * -EALREADY - lock free, no work to do.
*/ if (!err || err == -EALREADY) break;
}
return err;
}
/** * 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 libie_aq_res_id res)
{
u32 total_delay = 0; int err;
err = 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 (err == -ETIME &&
total_delay < IXGBE_ACI_RELEASE_RES_TIMEOUT) {
usleep_range(1000, 1500);
err = ixgbe_aci_release_res(hw, res, 0);
total_delay++;
}
}
/** * ixgbe_parse_e610_caps - Parse common device/function capabilities * @hw: pointer to the HW struct * @caps: pointer to common capabilities structure * @elem: the capability element to parse * @prefix: message prefix for tracing capabilities * * Given a capability element, extract relevant details into the common * capability structure. * * Return: true if the capability matches one of the common capability ids, * false otherwise.
*/ staticbool ixgbe_parse_e610_caps(struct ixgbe_hw *hw, struct ixgbe_hw_caps *caps, struct libie_aqc_list_caps_elem *elem, constchar *prefix)
{
u32 logical_id = le32_to_cpu(elem->logical_id);
u32 phys_id = le32_to_cpu(elem->phys_id);
u32 number = le32_to_cpu(elem->number);
u16 cap = le16_to_cpu(elem->cap);
switch (cap) { case LIBIE_AQC_CAPS_VALID_FUNCTIONS:
caps->valid_functions = number; break; case LIBIE_AQC_CAPS_SRIOV:
caps->sr_iov_1_1 = (number == 1); break; case LIBIE_AQC_CAPS_VMDQ:
caps->vmdq = (number == 1); break; case LIBIE_AQC_CAPS_DCB:
caps->dcb = (number == 1);
caps->active_tc_bitmap = logical_id;
caps->maxtc = phys_id; break; case LIBIE_AQC_CAPS_RSS:
caps->rss_table_size = number;
caps->rss_table_entry_width = logical_id; break; case LIBIE_AQC_CAPS_RXQS:
caps->num_rxq = number;
caps->rxq_first_id = phys_id; break; case LIBIE_AQC_CAPS_TXQS:
caps->num_txq = number;
caps->txq_first_id = phys_id; break; case LIBIE_AQC_CAPS_MSIX:
caps->num_msix_vectors = number;
caps->msix_vector_first_id = phys_id; break; case LIBIE_AQC_CAPS_NVM_VER: break; case LIBIE_AQC_CAPS_PENDING_NVM_VER:
caps->nvm_update_pending_nvm = true; break; case LIBIE_AQC_CAPS_PENDING_OROM_VER:
caps->nvm_update_pending_orom = true; break; case LIBIE_AQC_CAPS_PENDING_NET_VER:
caps->nvm_update_pending_netlist = true; break; case LIBIE_AQC_CAPS_NVM_MGMT:
caps->nvm_unified_update =
(number & IXGBE_NVM_MGMT_UNIFIED_UPD_SUPPORT) ? true : false; break; case LIBIE_AQC_CAPS_MAX_MTU:
caps->max_mtu = number; break; case LIBIE_AQC_CAPS_PCIE_RESET_AVOIDANCE:
caps->pcie_reset_avoidance = (number > 0); break; case LIBIE_AQC_CAPS_POST_UPDATE_RESET_RESTRICT:
caps->reset_restrict_support = (number == 1); break; case LIBIE_AQC_CAPS_EXT_TOPO_DEV_IMG0: case LIBIE_AQC_CAPS_EXT_TOPO_DEV_IMG1: case LIBIE_AQC_CAPS_EXT_TOPO_DEV_IMG2: case LIBIE_AQC_CAPS_EXT_TOPO_DEV_IMG3:
{
u8 index = cap - LIBIE_AQC_CAPS_EXT_TOPO_DEV_IMG0;
caps->ext_topo_dev_img_ver_high[index] = number;
caps->ext_topo_dev_img_ver_low[index] = logical_id;
caps->ext_topo_dev_img_part_num[index] =
FIELD_GET(IXGBE_EXT_TOPO_DEV_IMG_PART_NUM_M, phys_id);
caps->ext_topo_dev_img_load_en[index] =
(phys_id & IXGBE_EXT_TOPO_DEV_IMG_LOAD_EN) != 0;
caps->ext_topo_dev_img_prog_en[index] =
(phys_id & IXGBE_EXT_TOPO_DEV_IMG_PROG_EN) != 0; break;
} default: /* Not one of the recognized common capabilities */ returnfalse;
}
returntrue;
}
/** * ixgbe_parse_valid_functions_cap - Parse LIBIE_AQC_CAPS_VALID_FUNCTIONS caps * @hw: pointer to the HW struct * @dev_p: pointer to device capabilities structure * @cap: capability element to parse * * Parse LIBIE_AQC_CAPS_VALID_FUNCTIONS for device capabilities.
*/ staticvoid
ixgbe_parse_valid_functions_cap(struct ixgbe_hw *hw, struct ixgbe_hw_dev_caps *dev_p, struct libie_aqc_list_caps_elem *cap)
{
dev_p->num_funcs = hweight32(le32_to_cpu(cap->number));
}
/** * ixgbe_parse_vf_dev_caps - Parse LIBIE_AQC_CAPS_VF device caps * @hw: pointer to the HW struct * @dev_p: pointer to device capabilities structure * @cap: capability element to parse * * Parse LIBIE_AQC_CAPS_VF for device capabilities.
*/ staticvoid ixgbe_parse_vf_dev_caps(struct ixgbe_hw *hw, struct ixgbe_hw_dev_caps *dev_p, struct libie_aqc_list_caps_elem *cap)
{
dev_p->num_vfs_exposed = le32_to_cpu(cap->number);
}
/** * ixgbe_parse_vsi_dev_caps - Parse LIBIE_AQC_CAPS_VSI device caps * @hw: pointer to the HW struct * @dev_p: pointer to device capabilities structure * @cap: capability element to parse * * Parse LIBIE_AQC_CAPS_VSI for device capabilities.
*/ staticvoid ixgbe_parse_vsi_dev_caps(struct ixgbe_hw *hw, struct ixgbe_hw_dev_caps *dev_p, struct libie_aqc_list_caps_elem *cap)
{
dev_p->num_vsi_allocd_to_host = le32_to_cpu(cap->number);
}
/** * ixgbe_parse_fdir_dev_caps - Parse LIBIE_AQC_CAPS_FD device caps * @hw: pointer to the HW struct * @dev_p: pointer to device capabilities structure * @cap: capability element to parse * * Parse LIBIE_AQC_CAPS_FD for device capabilities.
*/ staticvoid ixgbe_parse_fdir_dev_caps(struct ixgbe_hw *hw, struct ixgbe_hw_dev_caps *dev_p, struct libie_aqc_list_caps_elem *cap)
{
dev_p->num_flow_director_fltr = le32_to_cpu(cap->number);
}
/** * ixgbe_parse_dev_caps - Parse device capabilities * @hw: pointer to the HW struct * @dev_p: pointer to device capabilities structure * @buf: buffer containing the device capability records * @cap_count: the number of capabilities * * Helper device to parse device (0x000B) capabilities list. For * capabilities shared between device and function, this relies on * ixgbe_parse_e610_caps. * * Loop through the list of provided capabilities and extract the relevant * data into the device capabilities structured.
*/ staticvoid ixgbe_parse_dev_caps(struct ixgbe_hw *hw, struct ixgbe_hw_dev_caps *dev_p, void *buf, u32 cap_count)
{ struct libie_aqc_list_caps_elem *cap_resp;
u32 i;
switch (cap) { case LIBIE_AQC_CAPS_VALID_FUNCTIONS:
ixgbe_parse_valid_functions_cap(hw, dev_p,
&cap_resp[i]); break; case LIBIE_AQC_CAPS_VF:
ixgbe_parse_vf_dev_caps(hw, dev_p, &cap_resp[i]); break; case LIBIE_AQC_CAPS_VSI:
ixgbe_parse_vsi_dev_caps(hw, dev_p, &cap_resp[i]); break; case LIBIE_AQC_CAPS_FD:
ixgbe_parse_fdir_dev_caps(hw, dev_p, &cap_resp[i]); break; default: /* Don't list common capabilities as unknown */ break;
}
}
}
/** * ixgbe_parse_vf_func_caps - Parse LIBIE_AQC_CAPS_VF function caps * @hw: pointer to the HW struct * @func_p: pointer to function capabilities structure * @cap: pointer to the capability element to parse * * Extract function capabilities for LIBIE_AQC_CAPS_VF.
*/ staticvoid ixgbe_parse_vf_func_caps(struct ixgbe_hw *hw, struct ixgbe_hw_func_caps *func_p, struct libie_aqc_list_caps_elem *cap)
{
func_p->num_allocd_vfs = le32_to_cpu(cap->number);
func_p->vf_base_id = le32_to_cpu(cap->logical_id);
}
/** * ixgbe_get_num_per_func - determine number of resources per PF * @hw: pointer to the HW structure * @max: value to be evenly split between each PF * * Determine the number of valid functions by going through the bitmap returned * from parsing capabilities and use this to calculate the number of resources * per PF based on the max value passed in. * * Return: the number of resources per PF or 0, if no PH are available.
*/ static u32 ixgbe_get_num_per_func(struct ixgbe_hw *hw, u32 max)
{ #define IXGBE_CAPS_VALID_FUNCS_M GENMASK(7, 0)
u8 funcs = hweight8(hw->dev_caps.common_cap.valid_functions &
IXGBE_CAPS_VALID_FUNCS_M);
return funcs ? (max / funcs) : 0;
}
/** * ixgbe_parse_vsi_func_caps - Parse LIBIE_AQC_CAPS_VSI function caps * @hw: pointer to the HW struct * @func_p: pointer to function capabilities structure * @cap: pointer to the capability element to parse * * Extract function capabilities for LIBIE_AQC_CAPS_VSI.
*/ staticvoid ixgbe_parse_vsi_func_caps(struct ixgbe_hw *hw, struct ixgbe_hw_func_caps *func_p, struct libie_aqc_list_caps_elem *cap)
{
func_p->guar_num_vsi = ixgbe_get_num_per_func(hw, IXGBE_MAX_VSI);
}
/** * ixgbe_parse_func_caps - Parse function capabilities * @hw: pointer to the HW struct * @func_p: pointer to function capabilities structure * @buf: buffer containing the function capability records * @cap_count: the number of capabilities * * Helper function to parse function (0x000A) capabilities list. For * capabilities shared between device and function, this relies on * ixgbe_parse_e610_caps. * * Loop through the list of provided capabilities and extract the relevant * data into the function capabilities structured.
*/ staticvoid ixgbe_parse_func_caps(struct ixgbe_hw *hw, struct ixgbe_hw_func_caps *func_p, void *buf, u32 cap_count)
{ struct libie_aqc_list_caps_elem *cap_resp;
u32 i;
switch (cap) { case LIBIE_AQC_CAPS_VF:
ixgbe_parse_vf_func_caps(hw, func_p, &cap_resp[i]); break; case LIBIE_AQC_CAPS_VSI:
ixgbe_parse_vsi_func_caps(hw, func_p, &cap_resp[i]); break; default: /* Don't list common capabilities as unknown */ break;
}
}
}
/** * ixgbe_aci_list_caps - query function/device capabilities * @hw: pointer to the HW struct * @buf: a buffer to hold the capabilities * @buf_size: size of the buffer * @cap_count: if not NULL, set to the number of capabilities reported * @opc: capabilities type to discover, device or function * * Get the function (0x000A) or device (0x000B) capabilities description from * firmware and store it in the buffer. * * If the cap_count pointer is not NULL, then it is set to the number of * capabilities firmware will report. Note that if the buffer size is too * small, it is possible the command will return -ENOMEM. The * cap_count will still be updated in this case. It is recommended that the * buffer size be set to IXGBE_ACI_MAX_BUFFER_SIZE (the largest possible * buffer that firmware could return) to avoid this. * * Return: the exit code of the operation. * Exit code of -ENOMEM means the buffer size is too small.
*/ int ixgbe_aci_list_caps(struct ixgbe_hw *hw, void *buf, u16 buf_size,
u32 *cap_count, enum ixgbe_aci_opc opc)
{ struct libie_aqc_list_caps *cmd; struct libie_aq_desc desc; int err;
cmd = &desc.params.get_cap;
if (opc != ixgbe_aci_opc_list_func_caps &&
opc != ixgbe_aci_opc_list_dev_caps) return -EINVAL;
if (cap_count)
*cap_count = le32_to_cpu(cmd->count);
return err;
}
/** * ixgbe_discover_dev_caps - Read and extract device capabilities * @hw: pointer to the hardware structure * @dev_caps: pointer to device capabilities structure * * Read the device capabilities and extract them into the dev_caps structure * for later use. * * Return: the exit code of the operation.
*/ int ixgbe_discover_dev_caps(struct ixgbe_hw *hw, struct ixgbe_hw_dev_caps *dev_caps)
{
u32 cap_count;
u8 *cbuf; int err;
cbuf = kzalloc(IXGBE_ACI_MAX_BUFFER_SIZE, GFP_KERNEL); if (!cbuf) return -ENOMEM;
/* Although the driver doesn't know the number of capabilities the * device will return, we can simply send a 4KB buffer, the maximum * possible size that firmware can return.
*/
cap_count = IXGBE_ACI_MAX_BUFFER_SIZE / sizeof(struct libie_aqc_list_caps_elem);
/** * ixgbe_discover_func_caps - Read and extract function capabilities * @hw: pointer to the hardware structure * @func_caps: pointer to function capabilities structure * * Read the function capabilities and extract them into the func_caps structure * for later use. * * Return: the exit code of the operation.
*/ int ixgbe_discover_func_caps(struct ixgbe_hw *hw, struct ixgbe_hw_func_caps *func_caps)
{
u32 cap_count;
u8 *cbuf; int err;
cbuf = kzalloc(IXGBE_ACI_MAX_BUFFER_SIZE, GFP_KERNEL); if (!cbuf) return -ENOMEM;
/* Although the driver doesn't know the number of capabilities the * device will return, we can simply send a 4KB buffer, the maximum * possible size that firmware can return.
*/
cap_count = IXGBE_ACI_MAX_BUFFER_SIZE / sizeof(struct libie_aqc_list_caps_elem);
/** * ixgbe_get_caps - get info about the HW * @hw: pointer to the hardware structure * * Retrieve both device and function capabilities. * * Return: the exit code of the operation.
*/ int ixgbe_get_caps(struct ixgbe_hw *hw)
{ int err;
err = ixgbe_discover_dev_caps(hw, &hw->dev_caps); if (err) return err;
/** * ixgbe_copy_phy_caps_to_cfg - Copy PHY ability data to configuration data * @caps: PHY ability structure to copy data from * @cfg: PHY configuration structure to copy data to * * Helper function to copy data from PHY capabilities data structure * to PHY configuration data structure
*/ void ixgbe_copy_phy_caps_to_cfg(struct ixgbe_aci_cmd_get_phy_caps_data *caps, struct ixgbe_aci_cmd_set_phy_cfg_data *cfg)
{ if (!caps || !cfg) return;
/** * ixgbe_aci_set_phy_cfg - set PHY configuration * @hw: pointer to the HW struct * @cfg: structure with PHY configuration data to be set * * Set the various PHY configuration parameters supported on the Port * using ACI command (0x0601). * One or more of the Set PHY config parameters may be ignored in an MFP * mode as the PF may not have the privilege to set some of the PHY Config * parameters. * * Return: the exit code of the operation.
*/ int ixgbe_aci_set_phy_cfg(struct ixgbe_hw *hw, struct ixgbe_aci_cmd_set_phy_cfg_data *cfg)
{ struct ixgbe_aci_cmd_set_phy_cfg *cmd; struct libie_aq_desc desc; int err;
if (!cfg) return -EINVAL;
cmd = libie_aq_raw(&desc); /* Ensure that only valid bits of cfg->caps can be turned on. */
cfg->caps &= IXGBE_ACI_PHY_ENA_VALID_MASK;
/** * ixgbe_aci_set_link_restart_an - set up link and restart AN * @hw: pointer to the HW struct * @ena_link: if true: enable link, if false: disable link * * Function sets up the link and restarts the Auto-Negotiation over the link. * * Return: the exit code of the operation.
*/ int ixgbe_aci_set_link_restart_an(struct ixgbe_hw *hw, bool ena_link)
{ struct ixgbe_aci_cmd_restart_an *cmd; struct libie_aq_desc desc;
/** * ixgbe_is_media_cage_present - check if media cage is present * @hw: pointer to the HW struct * * Identify presence of media cage using the ACI command (0x06E0). * * Return: true if media cage is present, else false. If no cage, then * media type is backplane or BASE-T.
*/ staticbool ixgbe_is_media_cage_present(struct ixgbe_hw *hw)
{ struct ixgbe_aci_cmd_get_link_topo *cmd; struct libie_aq_desc desc;
/* Set node type. */
cmd->addr.topo_params.node_type_ctx |=
FIELD_PREP(IXGBE_ACI_LINK_TOPO_NODE_TYPE_M,
IXGBE_ACI_LINK_TOPO_NODE_TYPE_CAGE);
/* Node type cage can be used to determine if cage is present. If AQC * returns error (ENOENT), then no cage present. If no cage present then * connection type is backplane or BASE-T.
*/ return !ixgbe_aci_get_netlist_node(hw, cmd, NULL, NULL);
}
/** * ixgbe_get_media_type_from_phy_type - Gets media type based on phy type * @hw: pointer to the HW struct * * Try to identify the media type based on the phy type. * If more than one media type, the ixgbe_media_type_unknown is returned. * First, phy_type_low is checked, then phy_type_high. * If none are identified, the ixgbe_media_type_unknown is returned * * Return: type of a media based on phy type in form of enum.
*/ staticenum ixgbe_media_type
ixgbe_get_media_type_from_phy_type(struct ixgbe_hw *hw)
{ struct ixgbe_link_status *hw_link_info;
if (!hw) return ixgbe_media_type_unknown;
hw_link_info = &hw->link.link_info; if (hw_link_info->phy_type_low && hw_link_info->phy_type_high) /* If more than one media type is selected, report unknown */ return ixgbe_media_type_unknown;
if (hw_link_info->phy_type_low) { /* 1G SGMII is a special case where some DA cable PHYs * may show this as an option when it really shouldn't * be since SGMII is meant to be between a MAC and a PHY * in a backplane. Try to detect this case and handle it
*/ if (hw_link_info->phy_type_low == IXGBE_PHY_TYPE_LOW_1G_SGMII &&
(hw_link_info->module_type[IXGBE_ACI_MOD_TYPE_IDENT] ==
IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_ACTIVE ||
hw_link_info->module_type[IXGBE_ACI_MOD_TYPE_IDENT] ==
IXGBE_ACI_MOD_TYPE_BYTE1_SFP_PLUS_CU_PASSIVE)) return ixgbe_media_type_da;
switch (hw_link_info->phy_type_low) { case IXGBE_PHY_TYPE_LOW_1000BASE_SX: case IXGBE_PHY_TYPE_LOW_1000BASE_LX: case IXGBE_PHY_TYPE_LOW_10GBASE_SR: case IXGBE_PHY_TYPE_LOW_10GBASE_LR: case IXGBE_PHY_TYPE_LOW_25GBASE_SR: case IXGBE_PHY_TYPE_LOW_25GBASE_LR: return ixgbe_media_type_fiber; case IXGBE_PHY_TYPE_LOW_10G_SFI_AOC_ACC: case IXGBE_PHY_TYPE_LOW_25G_AUI_AOC_ACC: return ixgbe_media_type_fiber; case IXGBE_PHY_TYPE_LOW_100BASE_TX: case IXGBE_PHY_TYPE_LOW_1000BASE_T: case IXGBE_PHY_TYPE_LOW_2500BASE_T: case IXGBE_PHY_TYPE_LOW_5GBASE_T: case IXGBE_PHY_TYPE_LOW_10GBASE_T: case IXGBE_PHY_TYPE_LOW_25GBASE_T: return ixgbe_media_type_copper; case IXGBE_PHY_TYPE_LOW_10G_SFI_DA: case IXGBE_PHY_TYPE_LOW_25GBASE_CR: case IXGBE_PHY_TYPE_LOW_25GBASE_CR_S: case IXGBE_PHY_TYPE_LOW_25GBASE_CR1: return ixgbe_media_type_da; case IXGBE_PHY_TYPE_LOW_25G_AUI_C2C: if (ixgbe_is_media_cage_present(hw)) return ixgbe_media_type_aui;
fallthrough; case IXGBE_PHY_TYPE_LOW_1000BASE_KX: case IXGBE_PHY_TYPE_LOW_2500BASE_KX: case IXGBE_PHY_TYPE_LOW_2500BASE_X: case IXGBE_PHY_TYPE_LOW_5GBASE_KR: case IXGBE_PHY_TYPE_LOW_10GBASE_KR_CR1: case IXGBE_PHY_TYPE_LOW_10G_SFI_C2C: case IXGBE_PHY_TYPE_LOW_25GBASE_KR: case IXGBE_PHY_TYPE_LOW_25GBASE_KR1: case IXGBE_PHY_TYPE_LOW_25GBASE_KR_S: return ixgbe_media_type_backplane;
}
} else { switch (hw_link_info->phy_type_high) { case IXGBE_PHY_TYPE_HIGH_10BASE_T: return ixgbe_media_type_copper;
}
} return ixgbe_media_type_unknown;
}
/** * ixgbe_update_link_info - update status of the HW network link * @hw: pointer to the HW struct * * Update the status of the HW network link. * * Return: the exit code of the operation.
*/ int ixgbe_update_link_info(struct ixgbe_hw *hw)
{ struct ixgbe_aci_cmd_get_phy_caps_data *pcaps; struct ixgbe_link_status *li; int err;
if (!hw) return -EINVAL;
li = &hw->link.link_info;
err = ixgbe_aci_get_link_info(hw, true, NULL); if (err) return err;
if (!(li->link_info & IXGBE_ACI_MEDIA_AVAILABLE)) return 0;
pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL); if (!pcaps) return -ENOMEM;
if (!err)
memcpy(li->module_type, &pcaps->module_type, sizeof(li->module_type));
kfree(pcaps);
return err;
}
/** * ixgbe_get_link_status - get status of the HW network link * @hw: pointer to the HW struct * @link_up: pointer to bool (true/false = linkup/linkdown) * * Variable link_up is true if link is up, false if link is down. * The variable link_up is invalid if status is non zero. As a * result of this call, link status reporting becomes enabled * * Return: the exit code of the operation.
*/ int ixgbe_get_link_status(struct ixgbe_hw *hw, bool *link_up)
{ if (!hw || !link_up) return -EINVAL;
if (hw->link.get_link_info) { int err = ixgbe_update_link_info(hw);
/** * ixgbe_aci_get_link_info - get the link status * @hw: pointer to the HW struct * @ena_lse: enable/disable LinkStatusEvent reporting * @link: pointer to link status structure - optional * * Get the current Link Status using ACI command (0x607). * The current link can be optionally provided to update * the status. * * Return: the link status of the adapter.
*/ int ixgbe_aci_get_link_info(struct ixgbe_hw *hw, bool ena_lse, struct ixgbe_link_status *link)
{ struct ixgbe_aci_cmd_get_link_status_data link_data = {}; struct ixgbe_aci_cmd_get_link_status *resp; struct ixgbe_link_status *li_old, *li; struct ixgbe_fc_info *hw_fc_info; struct libie_aq_desc desc; bool tx_pause, rx_pause;
u8 cmd_flags; int err;
if (!hw) return -EINVAL;
li_old = &hw->link.link_info_old;
li = &hw->link.link_info;
hw_fc_info = &hw->fc;
/* Save link status information. */ if (link)
*link = *li;
/* Flag cleared so calling functions don't call AQ again. */
hw->link.get_link_info = false;
return 0;
}
/** * ixgbe_aci_set_event_mask - set event mask * @hw: pointer to the HW struct * @port_num: port number of the physical function * @mask: event mask to be set * * Set the event mask using ACI command (0x0613). * * Return: the exit code of the operation.
*/ int ixgbe_aci_set_event_mask(struct ixgbe_hw *hw, u8 port_num, u16 mask)
{ struct ixgbe_aci_cmd_set_event_mask *cmd; struct libie_aq_desc desc;
/** * ixgbe_configure_lse - enable/disable link status events * @hw: pointer to the HW struct * @activate: true for enable lse, false otherwise * @mask: event mask to be set; a set bit means deactivation of the * corresponding event * * Set the event mask and then enable or disable link status events * * Return: the exit code of the operation.
*/ int ixgbe_configure_lse(struct ixgbe_hw *hw, bool activate, u16 mask)
{ int err;
err = ixgbe_aci_set_event_mask(hw, (u8)hw->bus.func, mask); if (err) return err;
/* Enabling link status events generation by fw. */ return ixgbe_aci_get_link_info(hw, activate, NULL);
}
/** * ixgbe_start_hw_e610 - Prepare hardware for Tx/Rx * @hw: pointer to hardware structure * * Get firmware version and start the hardware using the generic * start_hw() and ixgbe_start_hw_gen2() functions. * * Return: the exit code of the operation.
*/ staticint ixgbe_start_hw_e610(struct ixgbe_hw *hw)
{ int err;
err = ixgbe_aci_get_fw_ver(hw); if (err) return err;
err = ixgbe_start_hw_generic(hw); if (err) return err;
ixgbe_start_hw_gen2(hw);
return 0;
}
/** * ixgbe_aci_set_port_id_led - set LED value for the given port * @hw: pointer to the HW struct * @orig_mode: set LED original mode * * Set LED value for the given port (0x06E9) * * Return: the exit code of the operation.
*/ int ixgbe_aci_set_port_id_led(struct ixgbe_hw *hw, bool orig_mode)
{ struct ixgbe_aci_cmd_set_port_id_led *cmd; struct libie_aq_desc desc;
if (orig_mode)
cmd->ident_mode = IXGBE_ACI_PORT_IDENT_LED_ORIG; else
cmd->ident_mode = IXGBE_ACI_PORT_IDENT_LED_BLINK;
return ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
}
/** * ixgbe_get_media_type_e610 - Gets media type * @hw: pointer to the HW struct * * In order to get the media type, the function gets PHY * capabilities and later on use them to identify the PHY type * checking phy_type_high and phy_type_low. * * Return: the type of media in form of ixgbe_media_type enum * or ixgbe_media_type_unknown in case of an error.
*/ enum ixgbe_media_type ixgbe_get_media_type_e610(struct ixgbe_hw *hw)
{ struct ixgbe_aci_cmd_get_phy_caps_data pcaps; int rc;
rc = ixgbe_update_link_info(hw); if (rc) return ixgbe_media_type_unknown;
/* If there is no link but PHY (dongle) is available SW should use * Get PHY Caps admin command instead of Get Link Status, find most * significant bit that is set in PHY types reported by the command * and use it to discover media type.
*/ if (!(hw->link.link_info.link_info & IXGBE_ACI_LINK_UP) &&
(hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE)) { int highest_bit;
/* Get PHY Capabilities */
rc = ixgbe_aci_get_phy_caps(hw, false,
IXGBE_ACI_REPORT_TOPO_CAP_MEDIA,
&pcaps); if (rc) return ixgbe_media_type_unknown;
/* Based on link status or search above try to discover media type. */
hw->phy.media_type = ixgbe_get_media_type_from_phy_type(hw);
return hw->phy.media_type;
}
/** * ixgbe_setup_link_e610 - Set up link * @hw: pointer to hardware structure * @speed: new link speed * @autoneg_wait: true when waiting for completion is needed * * Set up the link with the specified speed. * * Return: the exit code of the operation.
*/ int ixgbe_setup_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait)
{ /* Simply request FW to perform proper PHY setup */ return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait);
}
/** * ixgbe_check_link_e610 - Determine link and speed status * @hw: pointer to hardware structure * @speed: pointer to link speed * @link_up: true when link is up * @link_up_wait_to_complete: bool used to wait for link up or not * * Determine if the link is up and the current link speed * using ACI command (0x0607). * * Return: the exit code of the operation.
*/ int ixgbe_check_link_e610(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *link_up, bool link_up_wait_to_complete)
{ int err;
u32 i;
if (!speed || !link_up) return -EINVAL;
/* Set get_link_info flag to ensure that fresh * link information will be obtained from FW * by sending Get Link Status admin command.
*/
hw->link.get_link_info = true;
/* Update link information in adapter context. */
err = ixgbe_get_link_status(hw, link_up); if (err) return err;
/* Wait for link up if it was requested. */ if (link_up_wait_to_complete && !(*link_up)) { for (i = 0; i < hw->mac.max_link_up_time; i++) {
msleep(100);
hw->link.get_link_info = true;
err = ixgbe_get_link_status(hw, link_up); if (err) return err; if (*link_up) break;
}
}
/* Use link information in adapter context updated by the call * to ixgbe_get_link_status() to determine current link speed. * Link speed information is valid only when link up was * reported by FW.
*/ if (*link_up) { switch (hw->link.link_info.link_speed) { case IXGBE_ACI_LINK_SPEED_10MB:
*speed = IXGBE_LINK_SPEED_10_FULL; break; case IXGBE_ACI_LINK_SPEED_100MB:
*speed = IXGBE_LINK_SPEED_100_FULL; break; case IXGBE_ACI_LINK_SPEED_1000MB:
*speed = IXGBE_LINK_SPEED_1GB_FULL; break; case IXGBE_ACI_LINK_SPEED_2500MB:
*speed = IXGBE_LINK_SPEED_2_5GB_FULL; break; case IXGBE_ACI_LINK_SPEED_5GB:
*speed = IXGBE_LINK_SPEED_5GB_FULL; break; case IXGBE_ACI_LINK_SPEED_10GB:
*speed = IXGBE_LINK_SPEED_10GB_FULL; break; default:
*speed = IXGBE_LINK_SPEED_UNKNOWN; break;
}
} else {
*speed = IXGBE_LINK_SPEED_UNKNOWN;
}
return 0;
}
/** * ixgbe_get_link_capabilities_e610 - Determine link capabilities * @hw: pointer to hardware structure * @speed: pointer to link speed * @autoneg: true when autoneg or autotry is enabled * * Determine speed and AN parameters of a link. * * Return: the exit code of the operation.
*/ int ixgbe_get_link_capabilities_e610(struct ixgbe_hw *hw,
ixgbe_link_speed *speed, bool *autoneg)
{ if (!speed || !autoneg) return -EINVAL;
/** * ixgbe_cfg_phy_fc - Configure PHY Flow Control (FC) data based on FC mode * @hw: pointer to hardware structure * @cfg: PHY configuration data to set FC mode * @req_mode: FC mode to configure * * Configures PHY Flow Control according to the provided configuration. * * Return: the exit code of the operation.
*/ int ixgbe_cfg_phy_fc(struct ixgbe_hw *hw, struct ixgbe_aci_cmd_set_phy_cfg_data *cfg, enum ixgbe_fc_mode req_mode)
{
u8 pause_mask = 0x0;
if (!cfg) return -EINVAL;
switch (req_mode) { case ixgbe_fc_full:
pause_mask |= IXGBE_ACI_PHY_EN_TX_LINK_PAUSE;
pause_mask |= IXGBE_ACI_PHY_EN_RX_LINK_PAUSE; break; case ixgbe_fc_rx_pause:
pause_mask |= IXGBE_ACI_PHY_EN_RX_LINK_PAUSE; break; case ixgbe_fc_tx_pause:
pause_mask |= IXGBE_ACI_PHY_EN_TX_LINK_PAUSE; break; default: break;
}
/* Clear the old pause settings. */
cfg->caps &= ~(IXGBE_ACI_PHY_EN_TX_LINK_PAUSE |
IXGBE_ACI_PHY_EN_RX_LINK_PAUSE);
/* Set the new capabilities. */
cfg->caps |= pause_mask;
return 0;
}
/** * ixgbe_setup_fc_e610 - Set up flow control * @hw: pointer to hardware structure * * Set up flow control. This has to be done during init time. * * Return: the exit code of the operation.
*/ int ixgbe_setup_fc_e610(struct ixgbe_hw *hw)
{ struct ixgbe_aci_cmd_get_phy_caps_data pcaps = {}; struct ixgbe_aci_cmd_set_phy_cfg_data cfg = {}; int err;
/* Get the current PHY config */
err = ixgbe_aci_get_phy_caps(hw, false,
IXGBE_ACI_REPORT_ACTIVE_CFG, &pcaps); if (err) return err;
ixgbe_copy_phy_caps_to_cfg(&pcaps, &cfg);
/* Configure the set PHY data */
err = ixgbe_cfg_phy_fc(hw, &cfg, hw->fc.requested_mode); if (err) return err;
/* If the capabilities have changed, then set the new config */ if (cfg.caps != pcaps.caps) {
cfg.caps |= IXGBE_ACI_PHY_ENA_AUTO_LINK_UPDT;
err = ixgbe_aci_set_phy_cfg(hw, &cfg); if (err) return err;
}
return err;
}
/** * ixgbe_fc_autoneg_e610 - Configure flow control * @hw: pointer to hardware structure * * Configure Flow Control.
*/ void ixgbe_fc_autoneg_e610(struct ixgbe_hw *hw)
{ int err;
/* Get current link err. * Current FC mode will be stored in the hw context.
*/
err = ixgbe_aci_get_link_info(hw, false, NULL); if (err) goto no_autoneg;
/* Check if the link is up */ if (!(hw->link.link_info.link_info & IXGBE_ACI_LINK_UP)) goto no_autoneg;
/* Check if auto-negotiation has completed */ if (!(hw->link.link_info.an_info & IXGBE_ACI_AN_COMPLETED)) goto no_autoneg;
/** * ixgbe_disable_rx_e610 - Disable RX unit * @hw: pointer to hardware structure * * Disable RX DMA unit on E610 with use of ACI command (0x000C). * * Return: the exit code of the operation.
*/ void ixgbe_disable_rx_e610(struct ixgbe_hw *hw)
{
u32 rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
u32 pfdtxgswc; int err;
/* If we fail - disable RX using register write */ if (err) {
rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); if (rxctrl & IXGBE_RXCTRL_RXEN) {
rxctrl &= ~IXGBE_RXCTRL_RXEN;
IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl);
}
}
}
/** * ixgbe_fw_recovery_mode_e610 - Check FW NVM recovery mode * @hw: pointer to hardware structure * * Check FW NVM recovery mode by reading the value of * the dedicated register. * * Return: true if FW is in recovery mode, otherwise false.
*/ staticbool ixgbe_fw_recovery_mode_e610(struct ixgbe_hw *hw)
{
u32 fwsm = IXGBE_READ_REG(hw, IXGBE_GL_MNG_FWSM);
return !!(fwsm & IXGBE_GL_MNG_FWSM_RECOVERY_M);
}
/** * ixgbe_fw_rollback_mode_e610 - Check FW NVM rollback mode * @hw: pointer to hardware structure * * Check FW NVM rollback mode by reading the value of * the dedicated register. * * Return: true if FW is in rollback mode, otherwise false.
*/ staticbool ixgbe_fw_rollback_mode_e610(struct ixgbe_hw *hw)
{
u32 fwsm = IXGBE_READ_REG(hw, IXGBE_GL_MNG_FWSM);
return !!(fwsm & IXGBE_GL_MNG_FWSM_ROLLBACK_M);
}
/** * ixgbe_init_phy_ops_e610 - PHY specific init * @hw: pointer to hardware structure * * Initialize any function pointers that were not able to be * set during init_shared_code because the PHY type was not known. * * Return: the exit code of the operation.
*/ int ixgbe_init_phy_ops_e610(struct ixgbe_hw *hw)
{ struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_phy_info *phy = &hw->phy;
/* 2.5 and 5 Gbps link speeds must be excluded from the * auto-negotiation set used during driver initialization due to * compatibility issues with certain switches. Those issues do not * exist in case of E610 2.5G SKU device (0x57b1).
*/ if (!hw->phy.autoneg_advertised &&
hw->device_id != IXGBE_DEV_ID_E610_2_5G_T)
hw->phy.autoneg_advertised = hw->phy.speeds_supported;
/** * ixgbe_setup_phy_link_e610 - Sets up firmware-controlled PHYs * @hw: pointer to hardware structure * * Set the parameters for the firmware-controlled PHYs. * * Return: the exit code of the operation.
*/ int ixgbe_setup_phy_link_e610(struct ixgbe_hw *hw)
{ struct ixgbe_aci_cmd_get_phy_caps_data pcaps; struct ixgbe_aci_cmd_set_phy_cfg_data pcfg;
u8 rmode = IXGBE_ACI_REPORT_TOPO_CAP_MEDIA;
u64 sup_phy_type_low, sup_phy_type_high;
u64 phy_type_low = 0, phy_type_high = 0; int err;
err = ixgbe_aci_get_link_info(hw, false, NULL); if (err) return err;
/* If media is not available get default config. */ if (!(hw->link.link_info.link_info & IXGBE_ACI_MEDIA_AVAILABLE))
rmode = IXGBE_ACI_REPORT_DFLT_CFG;
err = ixgbe_aci_get_phy_caps(hw, false, rmode, &pcaps); if (err) return err;
/* Get Active configuration to avoid unintended changes. */
err = ixgbe_aci_get_phy_caps(hw, false, IXGBE_ACI_REPORT_ACTIVE_CFG,
&pcaps); if (err) return err;
err = ixgbe_aci_set_phy_cfg(hw, &pcfg); if (err) return err;
}
return 0;
}
/** * ixgbe_set_phy_power_e610 - Control power for copper PHY * @hw: pointer to hardware structure * @on: true for on, false for off * * Set the power on/off of the PHY * by getting its capabilities and setting the appropriate * configuration parameters. * * Return: the exit code of the operation.
*/ int ixgbe_set_phy_power_e610(struct ixgbe_hw *hw, bool on)
{ struct ixgbe_aci_cmd_get_phy_caps_data phy_caps = {}; struct ixgbe_aci_cmd_set_phy_cfg_data phy_cfg = {}; int err;
err = ixgbe_aci_get_phy_caps(hw, false,
IXGBE_ACI_REPORT_ACTIVE_CFG,
&phy_caps); if (err) return err;
ixgbe_copy_phy_caps_to_cfg(&phy_caps, &phy_cfg);
if (on)
phy_cfg.caps &= ~IXGBE_ACI_PHY_ENA_LOW_POWER; else
phy_cfg.caps |= IXGBE_ACI_PHY_ENA_LOW_POWER;
/* PHY is already in requested power mode. */ if (phy_caps.caps == phy_cfg.caps) return 0;
/** * ixgbe_enter_lplu_e610 - Transition to low power states * @hw: pointer to hardware structure * * Configures Low Power Link Up on transition to low power states * (from D0 to non-D0). Link is required to enter LPLU so avoid resetting the * X557 PHY immediately prior to entering LPLU. * * Return: the exit code of the operation.
*/ int ixgbe_enter_lplu_e610(struct ixgbe_hw *hw)
{ struct ixgbe_aci_cmd_get_phy_caps_data phy_caps = {}; struct ixgbe_aci_cmd_set_phy_cfg_data phy_cfg = {}; int err;
err = ixgbe_aci_get_phy_caps(hw, false,
IXGBE_ACI_REPORT_ACTIVE_CFG,
&phy_caps); if (err) return err;
/** * ixgbe_init_eeprom_params_e610 - Initialize EEPROM params * @hw: pointer to hardware structure * * Initialize the EEPROM parameters ixgbe_eeprom_info within the ixgbe_hw * struct in order to set up EEPROM access. * * Return: the operation exit code.
*/ int ixgbe_init_eeprom_params_e610(struct ixgbe_hw *hw)
{ struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
u32 gens_stat;
u8 sr_size;
if (eeprom->type != ixgbe_eeprom_uninitialized) return 0;
/** * ixgbe_aci_get_netlist_node - get a node handle * @hw: pointer to the hw struct * @cmd: get_link_topo AQ structure * @node_part_number: output node part number if node found * @node_handle: output node handle parameter if node found * * Get the netlist node and assigns it to * the provided handle using ACI command (0x06E0). * * Return: the exit code of the operation.
*/ int ixgbe_aci_get_netlist_node(struct ixgbe_hw *hw, struct ixgbe_aci_cmd_get_link_topo *cmd,
u8 *node_part_number, u16 *node_handle)
{ struct ixgbe_aci_cmd_get_link_topo *resp; struct libie_aq_desc desc;
if (ixgbe_aci_send_cmd(hw, &desc, NULL, 0)) return -EOPNOTSUPP;
if (node_handle)
*node_handle = le16_to_cpu(resp->addr.handle); if (node_part_number)
*node_part_number = resp->node_part_num;
return 0;
}
/** * ixgbe_acquire_nvm - Generic request for acquiring the NVM ownership * @hw: pointer to the HW structure * @access: NVM access type (read or write) * * Request NVM ownership. * * Return: the exit code of the operation.
*/
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.