162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2005 - 2016 Broadcom 462306a36Sopenharmony_ci * All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Contact Information: 762306a36Sopenharmony_ci * linux-drivers@emulex.com 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Emulex 1062306a36Sopenharmony_ci * 3333 Susan Street 1162306a36Sopenharmony_ci * Costa Mesa, CA 92626 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include "be.h" 1662306a36Sopenharmony_ci#include "be_cmds.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ciconst char * const be_misconfig_evt_port_state[] = { 1962306a36Sopenharmony_ci "Physical Link is functional", 2062306a36Sopenharmony_ci "Optics faulted/incorrectly installed/not installed - Reseat optics. If issue not resolved, replace.", 2162306a36Sopenharmony_ci "Optics of two types installed – Remove one optic or install matching pair of optics.", 2262306a36Sopenharmony_ci "Incompatible optics – Replace with compatible optics for card to function.", 2362306a36Sopenharmony_ci "Unqualified optics – Replace with Avago optics for Warranty and Technical Support.", 2462306a36Sopenharmony_ci "Uncertified optics – Replace with Avago-certified optics to enable link operation." 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic char *be_port_misconfig_evt_severity[] = { 2862306a36Sopenharmony_ci "KERN_WARN", 2962306a36Sopenharmony_ci "KERN_INFO", 3062306a36Sopenharmony_ci "KERN_ERR", 3162306a36Sopenharmony_ci "KERN_WARN" 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic char *phy_state_oper_desc[] = { 3562306a36Sopenharmony_ci "Link is non-operational", 3662306a36Sopenharmony_ci "Link is operational", 3762306a36Sopenharmony_ci "" 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic struct be_cmd_priv_map cmd_priv_map[] = { 4162306a36Sopenharmony_ci { 4262306a36Sopenharmony_ci OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, 4362306a36Sopenharmony_ci CMD_SUBSYSTEM_ETH, 4462306a36Sopenharmony_ci BE_PRIV_LNKMGMT | BE_PRIV_VHADM | 4562306a36Sopenharmony_ci BE_PRIV_DEVCFG | BE_PRIV_DEVSEC 4662306a36Sopenharmony_ci }, 4762306a36Sopenharmony_ci { 4862306a36Sopenharmony_ci OPCODE_COMMON_GET_FLOW_CONTROL, 4962306a36Sopenharmony_ci CMD_SUBSYSTEM_COMMON, 5062306a36Sopenharmony_ci BE_PRIV_LNKQUERY | BE_PRIV_VHADM | 5162306a36Sopenharmony_ci BE_PRIV_DEVCFG | BE_PRIV_DEVSEC 5262306a36Sopenharmony_ci }, 5362306a36Sopenharmony_ci { 5462306a36Sopenharmony_ci OPCODE_COMMON_SET_FLOW_CONTROL, 5562306a36Sopenharmony_ci CMD_SUBSYSTEM_COMMON, 5662306a36Sopenharmony_ci BE_PRIV_LNKMGMT | BE_PRIV_VHADM | 5762306a36Sopenharmony_ci BE_PRIV_DEVCFG | BE_PRIV_DEVSEC 5862306a36Sopenharmony_ci }, 5962306a36Sopenharmony_ci { 6062306a36Sopenharmony_ci OPCODE_ETH_GET_PPORT_STATS, 6162306a36Sopenharmony_ci CMD_SUBSYSTEM_ETH, 6262306a36Sopenharmony_ci BE_PRIV_LNKMGMT | BE_PRIV_VHADM | 6362306a36Sopenharmony_ci BE_PRIV_DEVCFG | BE_PRIV_DEVSEC 6462306a36Sopenharmony_ci }, 6562306a36Sopenharmony_ci { 6662306a36Sopenharmony_ci OPCODE_COMMON_GET_PHY_DETAILS, 6762306a36Sopenharmony_ci CMD_SUBSYSTEM_COMMON, 6862306a36Sopenharmony_ci BE_PRIV_LNKMGMT | BE_PRIV_VHADM | 6962306a36Sopenharmony_ci BE_PRIV_DEVCFG | BE_PRIV_DEVSEC 7062306a36Sopenharmony_ci }, 7162306a36Sopenharmony_ci { 7262306a36Sopenharmony_ci OPCODE_LOWLEVEL_HOST_DDR_DMA, 7362306a36Sopenharmony_ci CMD_SUBSYSTEM_LOWLEVEL, 7462306a36Sopenharmony_ci BE_PRIV_DEVCFG | BE_PRIV_DEVSEC 7562306a36Sopenharmony_ci }, 7662306a36Sopenharmony_ci { 7762306a36Sopenharmony_ci OPCODE_LOWLEVEL_LOOPBACK_TEST, 7862306a36Sopenharmony_ci CMD_SUBSYSTEM_LOWLEVEL, 7962306a36Sopenharmony_ci BE_PRIV_DEVCFG | BE_PRIV_DEVSEC 8062306a36Sopenharmony_ci }, 8162306a36Sopenharmony_ci { 8262306a36Sopenharmony_ci OPCODE_LOWLEVEL_SET_LOOPBACK_MODE, 8362306a36Sopenharmony_ci CMD_SUBSYSTEM_LOWLEVEL, 8462306a36Sopenharmony_ci BE_PRIV_DEVCFG | BE_PRIV_DEVSEC 8562306a36Sopenharmony_ci }, 8662306a36Sopenharmony_ci { 8762306a36Sopenharmony_ci OPCODE_COMMON_SET_HSW_CONFIG, 8862306a36Sopenharmony_ci CMD_SUBSYSTEM_COMMON, 8962306a36Sopenharmony_ci BE_PRIV_DEVCFG | BE_PRIV_VHADM | 9062306a36Sopenharmony_ci BE_PRIV_DEVSEC 9162306a36Sopenharmony_ci }, 9262306a36Sopenharmony_ci { 9362306a36Sopenharmony_ci OPCODE_COMMON_GET_EXT_FAT_CAPABILITIES, 9462306a36Sopenharmony_ci CMD_SUBSYSTEM_COMMON, 9562306a36Sopenharmony_ci BE_PRIV_DEVCFG 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic bool be_cmd_allowed(struct be_adapter *adapter, u8 opcode, u8 subsystem) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci int i; 10262306a36Sopenharmony_ci int num_entries = ARRAY_SIZE(cmd_priv_map); 10362306a36Sopenharmony_ci u32 cmd_privileges = adapter->cmd_privileges; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci for (i = 0; i < num_entries; i++) 10662306a36Sopenharmony_ci if (opcode == cmd_priv_map[i].opcode && 10762306a36Sopenharmony_ci subsystem == cmd_priv_map[i].subsystem) 10862306a36Sopenharmony_ci if (!(cmd_privileges & cmd_priv_map[i].priv_mask)) 10962306a36Sopenharmony_ci return false; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return true; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic inline void *embedded_payload(struct be_mcc_wrb *wrb) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci return wrb->payload.embedded_payload; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int be_mcc_notify(struct be_adapter *adapter) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct be_queue_info *mccq = &adapter->mcc_obj.q; 12262306a36Sopenharmony_ci u32 val = 0; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (be_check_error(adapter, BE_ERROR_ANY)) 12562306a36Sopenharmony_ci return -EIO; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci val |= mccq->id & DB_MCCQ_RING_ID_MASK; 12862306a36Sopenharmony_ci val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci wmb(); 13162306a36Sopenharmony_ci iowrite32(val, adapter->db + DB_MCCQ_OFFSET); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci return 0; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/* To check if valid bit is set, check the entire word as we don't know 13762306a36Sopenharmony_ci * the endianness of the data (old entry is host endian while a new entry is 13862306a36Sopenharmony_ci * little endian) 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_cistatic inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci u32 flags; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (compl->flags != 0) { 14562306a36Sopenharmony_ci flags = le32_to_cpu(compl->flags); 14662306a36Sopenharmony_ci if (flags & CQE_FLAGS_VALID_MASK) { 14762306a36Sopenharmony_ci compl->flags = flags; 14862306a36Sopenharmony_ci return true; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci return false; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* Need to reset the entire word that houses the valid bit */ 15562306a36Sopenharmony_cistatic inline void be_mcc_compl_use(struct be_mcc_compl *compl) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci compl->flags = 0; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic struct be_cmd_resp_hdr *be_decode_resp_hdr(u32 tag0, u32 tag1) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci unsigned long addr; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci addr = tag1; 16562306a36Sopenharmony_ci addr = ((addr << 16) << 16) | tag0; 16662306a36Sopenharmony_ci return (void *)addr; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic bool be_skip_err_log(u8 opcode, u16 base_status, u16 addl_status) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci if (base_status == MCC_STATUS_NOT_SUPPORTED || 17262306a36Sopenharmony_ci base_status == MCC_STATUS_ILLEGAL_REQUEST || 17362306a36Sopenharmony_ci addl_status == MCC_ADDL_STATUS_TOO_MANY_INTERFACES || 17462306a36Sopenharmony_ci addl_status == MCC_ADDL_STATUS_INSUFFICIENT_VLANS || 17562306a36Sopenharmony_ci (opcode == OPCODE_COMMON_WRITE_FLASHROM && 17662306a36Sopenharmony_ci (base_status == MCC_STATUS_ILLEGAL_FIELD || 17762306a36Sopenharmony_ci addl_status == MCC_ADDL_STATUS_FLASH_IMAGE_CRC_MISMATCH))) 17862306a36Sopenharmony_ci return true; 17962306a36Sopenharmony_ci else 18062306a36Sopenharmony_ci return false; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* Place holder for all the async MCC cmds wherein the caller is not in a busy 18462306a36Sopenharmony_ci * loop (has not issued be_mcc_notify_wait()) 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_cistatic void be_async_cmd_process(struct be_adapter *adapter, 18762306a36Sopenharmony_ci struct be_mcc_compl *compl, 18862306a36Sopenharmony_ci struct be_cmd_resp_hdr *resp_hdr) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci enum mcc_base_status base_status = base_status(compl->status); 19162306a36Sopenharmony_ci u8 opcode = 0, subsystem = 0; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (resp_hdr) { 19462306a36Sopenharmony_ci opcode = resp_hdr->opcode; 19562306a36Sopenharmony_ci subsystem = resp_hdr->subsystem; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (opcode == OPCODE_LOWLEVEL_LOOPBACK_TEST && 19962306a36Sopenharmony_ci subsystem == CMD_SUBSYSTEM_LOWLEVEL) { 20062306a36Sopenharmony_ci complete(&adapter->et_cmd_compl); 20162306a36Sopenharmony_ci return; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (opcode == OPCODE_LOWLEVEL_SET_LOOPBACK_MODE && 20562306a36Sopenharmony_ci subsystem == CMD_SUBSYSTEM_LOWLEVEL) { 20662306a36Sopenharmony_ci complete(&adapter->et_cmd_compl); 20762306a36Sopenharmony_ci return; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if ((opcode == OPCODE_COMMON_WRITE_FLASHROM || 21162306a36Sopenharmony_ci opcode == OPCODE_COMMON_WRITE_OBJECT) && 21262306a36Sopenharmony_ci subsystem == CMD_SUBSYSTEM_COMMON) { 21362306a36Sopenharmony_ci adapter->flash_status = compl->status; 21462306a36Sopenharmony_ci complete(&adapter->et_cmd_compl); 21562306a36Sopenharmony_ci return; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if ((opcode == OPCODE_ETH_GET_STATISTICS || 21962306a36Sopenharmony_ci opcode == OPCODE_ETH_GET_PPORT_STATS) && 22062306a36Sopenharmony_ci subsystem == CMD_SUBSYSTEM_ETH && 22162306a36Sopenharmony_ci base_status == MCC_STATUS_SUCCESS) { 22262306a36Sopenharmony_ci be_parse_stats(adapter); 22362306a36Sopenharmony_ci adapter->stats_cmd_sent = false; 22462306a36Sopenharmony_ci return; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (opcode == OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES && 22862306a36Sopenharmony_ci subsystem == CMD_SUBSYSTEM_COMMON) { 22962306a36Sopenharmony_ci if (base_status == MCC_STATUS_SUCCESS) { 23062306a36Sopenharmony_ci struct be_cmd_resp_get_cntl_addnl_attribs *resp = 23162306a36Sopenharmony_ci (void *)resp_hdr; 23262306a36Sopenharmony_ci adapter->hwmon_info.be_on_die_temp = 23362306a36Sopenharmony_ci resp->on_die_temperature; 23462306a36Sopenharmony_ci } else { 23562306a36Sopenharmony_ci adapter->be_get_temp_freq = 0; 23662306a36Sopenharmony_ci adapter->hwmon_info.be_on_die_temp = 23762306a36Sopenharmony_ci BE_INVALID_DIE_TEMP; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci return; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic int be_mcc_compl_process(struct be_adapter *adapter, 24462306a36Sopenharmony_ci struct be_mcc_compl *compl) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci enum mcc_base_status base_status; 24762306a36Sopenharmony_ci enum mcc_addl_status addl_status; 24862306a36Sopenharmony_ci struct be_cmd_resp_hdr *resp_hdr; 24962306a36Sopenharmony_ci u8 opcode = 0, subsystem = 0; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Just swap the status to host endian; mcc tag is opaquely copied 25262306a36Sopenharmony_ci * from mcc_wrb 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_ci be_dws_le_to_cpu(compl, 4); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci base_status = base_status(compl->status); 25762306a36Sopenharmony_ci addl_status = addl_status(compl->status); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci resp_hdr = be_decode_resp_hdr(compl->tag0, compl->tag1); 26062306a36Sopenharmony_ci if (resp_hdr) { 26162306a36Sopenharmony_ci opcode = resp_hdr->opcode; 26262306a36Sopenharmony_ci subsystem = resp_hdr->subsystem; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci be_async_cmd_process(adapter, compl, resp_hdr); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (base_status != MCC_STATUS_SUCCESS && 26862306a36Sopenharmony_ci !be_skip_err_log(opcode, base_status, addl_status)) { 26962306a36Sopenharmony_ci if (base_status == MCC_STATUS_UNAUTHORIZED_REQUEST || 27062306a36Sopenharmony_ci addl_status == MCC_ADDL_STATUS_INSUFFICIENT_PRIVILEGES) { 27162306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, 27262306a36Sopenharmony_ci "VF is not privileged to issue opcode %d-%d\n", 27362306a36Sopenharmony_ci opcode, subsystem); 27462306a36Sopenharmony_ci } else { 27562306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 27662306a36Sopenharmony_ci "opcode %d-%d failed:status %d-%d\n", 27762306a36Sopenharmony_ci opcode, subsystem, base_status, addl_status); 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci return compl->status; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/* Link state evt is a string of bytes; no need for endian swapping */ 28462306a36Sopenharmony_cistatic void be_async_link_state_process(struct be_adapter *adapter, 28562306a36Sopenharmony_ci struct be_mcc_compl *compl) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct be_async_event_link_state *evt = 28862306a36Sopenharmony_ci (struct be_async_event_link_state *)compl; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* When link status changes, link speed must be re-queried from FW */ 29162306a36Sopenharmony_ci adapter->phy.link_speed = -1; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* On BEx the FW does not send a separate link status 29462306a36Sopenharmony_ci * notification for physical and logical link. 29562306a36Sopenharmony_ci * On other chips just process the logical link 29662306a36Sopenharmony_ci * status notification 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_ci if (!BEx_chip(adapter) && 29962306a36Sopenharmony_ci !(evt->port_link_status & LOGICAL_LINK_STATUS_MASK)) 30062306a36Sopenharmony_ci return; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* For the initial link status do not rely on the ASYNC event as 30362306a36Sopenharmony_ci * it may not be received in some cases. 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_ci if (adapter->flags & BE_FLAGS_LINK_STATUS_INIT) 30662306a36Sopenharmony_ci be_link_status_update(adapter, 30762306a36Sopenharmony_ci evt->port_link_status & LINK_STATUS_MASK); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic void be_async_port_misconfig_event_process(struct be_adapter *adapter, 31162306a36Sopenharmony_ci struct be_mcc_compl *compl) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct be_async_event_misconfig_port *evt = 31462306a36Sopenharmony_ci (struct be_async_event_misconfig_port *)compl; 31562306a36Sopenharmony_ci u32 sfp_misconfig_evt_word1 = le32_to_cpu(evt->event_data_word1); 31662306a36Sopenharmony_ci u32 sfp_misconfig_evt_word2 = le32_to_cpu(evt->event_data_word2); 31762306a36Sopenharmony_ci u8 phy_oper_state = PHY_STATE_OPER_MSG_NONE; 31862306a36Sopenharmony_ci struct device *dev = &adapter->pdev->dev; 31962306a36Sopenharmony_ci u8 msg_severity = DEFAULT_MSG_SEVERITY; 32062306a36Sopenharmony_ci u8 phy_state_info; 32162306a36Sopenharmony_ci u8 new_phy_state; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci new_phy_state = 32462306a36Sopenharmony_ci (sfp_misconfig_evt_word1 >> (adapter->hba_port_num * 8)) & 0xff; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (new_phy_state == adapter->phy_state) 32762306a36Sopenharmony_ci return; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci adapter->phy_state = new_phy_state; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* for older fw that doesn't populate link effect data */ 33262306a36Sopenharmony_ci if (!sfp_misconfig_evt_word2) 33362306a36Sopenharmony_ci goto log_message; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci phy_state_info = 33662306a36Sopenharmony_ci (sfp_misconfig_evt_word2 >> (adapter->hba_port_num * 8)) & 0xff; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (phy_state_info & PHY_STATE_INFO_VALID) { 33962306a36Sopenharmony_ci msg_severity = (phy_state_info & PHY_STATE_MSG_SEVERITY) >> 1; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (be_phy_unqualified(new_phy_state)) 34262306a36Sopenharmony_ci phy_oper_state = (phy_state_info & PHY_STATE_OPER); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cilog_message: 34662306a36Sopenharmony_ci /* Log an error message that would allow a user to determine 34762306a36Sopenharmony_ci * whether the SFPs have an issue 34862306a36Sopenharmony_ci */ 34962306a36Sopenharmony_ci if (be_phy_state_unknown(new_phy_state)) 35062306a36Sopenharmony_ci dev_printk(be_port_misconfig_evt_severity[msg_severity], dev, 35162306a36Sopenharmony_ci "Port %c: Unrecognized Optics state: 0x%x. %s", 35262306a36Sopenharmony_ci adapter->port_name, 35362306a36Sopenharmony_ci new_phy_state, 35462306a36Sopenharmony_ci phy_state_oper_desc[phy_oper_state]); 35562306a36Sopenharmony_ci else 35662306a36Sopenharmony_ci dev_printk(be_port_misconfig_evt_severity[msg_severity], dev, 35762306a36Sopenharmony_ci "Port %c: %s %s", 35862306a36Sopenharmony_ci adapter->port_name, 35962306a36Sopenharmony_ci be_misconfig_evt_port_state[new_phy_state], 36062306a36Sopenharmony_ci phy_state_oper_desc[phy_oper_state]); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci /* Log Vendor name and part no. if a misconfigured SFP is detected */ 36362306a36Sopenharmony_ci if (be_phy_misconfigured(new_phy_state)) 36462306a36Sopenharmony_ci adapter->flags |= BE_FLAGS_PHY_MISCONFIGURED; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci/* Grp5 CoS Priority evt */ 36862306a36Sopenharmony_cistatic void be_async_grp5_cos_priority_process(struct be_adapter *adapter, 36962306a36Sopenharmony_ci struct be_mcc_compl *compl) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci struct be_async_event_grp5_cos_priority *evt = 37262306a36Sopenharmony_ci (struct be_async_event_grp5_cos_priority *)compl; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci if (evt->valid) { 37562306a36Sopenharmony_ci adapter->vlan_prio_bmap = evt->available_priority_bmap; 37662306a36Sopenharmony_ci adapter->recommended_prio_bits = 37762306a36Sopenharmony_ci evt->reco_default_priority << VLAN_PRIO_SHIFT; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci/* Grp5 QOS Speed evt: qos_link_speed is in units of 10 Mbps */ 38262306a36Sopenharmony_cistatic void be_async_grp5_qos_speed_process(struct be_adapter *adapter, 38362306a36Sopenharmony_ci struct be_mcc_compl *compl) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct be_async_event_grp5_qos_link_speed *evt = 38662306a36Sopenharmony_ci (struct be_async_event_grp5_qos_link_speed *)compl; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (adapter->phy.link_speed >= 0 && 38962306a36Sopenharmony_ci evt->physical_port == adapter->port_num) 39062306a36Sopenharmony_ci adapter->phy.link_speed = le16_to_cpu(evt->qos_link_speed) * 10; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci/*Grp5 PVID evt*/ 39462306a36Sopenharmony_cistatic void be_async_grp5_pvid_state_process(struct be_adapter *adapter, 39562306a36Sopenharmony_ci struct be_mcc_compl *compl) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci struct be_async_event_grp5_pvid_state *evt = 39862306a36Sopenharmony_ci (struct be_async_event_grp5_pvid_state *)compl; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (evt->enabled) { 40162306a36Sopenharmony_ci adapter->pvid = le16_to_cpu(evt->tag) & VLAN_VID_MASK; 40262306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "LPVID: %d\n", adapter->pvid); 40362306a36Sopenharmony_ci } else { 40462306a36Sopenharmony_ci adapter->pvid = 0; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci#define MGMT_ENABLE_MASK 0x4 40962306a36Sopenharmony_cistatic void be_async_grp5_fw_control_process(struct be_adapter *adapter, 41062306a36Sopenharmony_ci struct be_mcc_compl *compl) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci struct be_async_fw_control *evt = (struct be_async_fw_control *)compl; 41362306a36Sopenharmony_ci u32 evt_dw1 = le32_to_cpu(evt->event_data_word1); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (evt_dw1 & MGMT_ENABLE_MASK) { 41662306a36Sopenharmony_ci adapter->flags |= BE_FLAGS_OS2BMC; 41762306a36Sopenharmony_ci adapter->bmc_filt_mask = le32_to_cpu(evt->event_data_word2); 41862306a36Sopenharmony_ci } else { 41962306a36Sopenharmony_ci adapter->flags &= ~BE_FLAGS_OS2BMC; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic void be_async_grp5_evt_process(struct be_adapter *adapter, 42462306a36Sopenharmony_ci struct be_mcc_compl *compl) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci u8 event_type = (compl->flags >> ASYNC_EVENT_TYPE_SHIFT) & 42762306a36Sopenharmony_ci ASYNC_EVENT_TYPE_MASK; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci switch (event_type) { 43062306a36Sopenharmony_ci case ASYNC_EVENT_COS_PRIORITY: 43162306a36Sopenharmony_ci be_async_grp5_cos_priority_process(adapter, compl); 43262306a36Sopenharmony_ci break; 43362306a36Sopenharmony_ci case ASYNC_EVENT_QOS_SPEED: 43462306a36Sopenharmony_ci be_async_grp5_qos_speed_process(adapter, compl); 43562306a36Sopenharmony_ci break; 43662306a36Sopenharmony_ci case ASYNC_EVENT_PVID_STATE: 43762306a36Sopenharmony_ci be_async_grp5_pvid_state_process(adapter, compl); 43862306a36Sopenharmony_ci break; 43962306a36Sopenharmony_ci /* Async event to disable/enable os2bmc and/or mac-learning */ 44062306a36Sopenharmony_ci case ASYNC_EVENT_FW_CONTROL: 44162306a36Sopenharmony_ci be_async_grp5_fw_control_process(adapter, compl); 44262306a36Sopenharmony_ci break; 44362306a36Sopenharmony_ci default: 44462306a36Sopenharmony_ci break; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic void be_async_dbg_evt_process(struct be_adapter *adapter, 44962306a36Sopenharmony_ci struct be_mcc_compl *cmp) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci u8 event_type = 0; 45262306a36Sopenharmony_ci struct be_async_event_qnq *evt = (struct be_async_event_qnq *)cmp; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci event_type = (cmp->flags >> ASYNC_EVENT_TYPE_SHIFT) & 45562306a36Sopenharmony_ci ASYNC_EVENT_TYPE_MASK; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci switch (event_type) { 45862306a36Sopenharmony_ci case ASYNC_DEBUG_EVENT_TYPE_QNQ: 45962306a36Sopenharmony_ci if (evt->valid) 46062306a36Sopenharmony_ci adapter->qnq_vid = le16_to_cpu(evt->vlan_tag); 46162306a36Sopenharmony_ci adapter->flags |= BE_FLAGS_QNQ_ASYNC_EVT_RCVD; 46262306a36Sopenharmony_ci break; 46362306a36Sopenharmony_ci default: 46462306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, "Unknown debug event 0x%x!\n", 46562306a36Sopenharmony_ci event_type); 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic void be_async_sliport_evt_process(struct be_adapter *adapter, 47162306a36Sopenharmony_ci struct be_mcc_compl *cmp) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci u8 event_type = (cmp->flags >> ASYNC_EVENT_TYPE_SHIFT) & 47462306a36Sopenharmony_ci ASYNC_EVENT_TYPE_MASK; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (event_type == ASYNC_EVENT_PORT_MISCONFIG) 47762306a36Sopenharmony_ci be_async_port_misconfig_event_process(adapter, cmp); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic inline bool is_link_state_evt(u32 flags) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) == 48362306a36Sopenharmony_ci ASYNC_EVENT_CODE_LINK_STATE; 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic inline bool is_grp5_evt(u32 flags) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) == 48962306a36Sopenharmony_ci ASYNC_EVENT_CODE_GRP_5; 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic inline bool is_dbg_evt(u32 flags) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) == 49562306a36Sopenharmony_ci ASYNC_EVENT_CODE_QNQ; 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic inline bool is_sliport_evt(u32 flags) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) == 50162306a36Sopenharmony_ci ASYNC_EVENT_CODE_SLIPORT; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic void be_mcc_event_process(struct be_adapter *adapter, 50562306a36Sopenharmony_ci struct be_mcc_compl *compl) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci if (is_link_state_evt(compl->flags)) 50862306a36Sopenharmony_ci be_async_link_state_process(adapter, compl); 50962306a36Sopenharmony_ci else if (is_grp5_evt(compl->flags)) 51062306a36Sopenharmony_ci be_async_grp5_evt_process(adapter, compl); 51162306a36Sopenharmony_ci else if (is_dbg_evt(compl->flags)) 51262306a36Sopenharmony_ci be_async_dbg_evt_process(adapter, compl); 51362306a36Sopenharmony_ci else if (is_sliport_evt(compl->flags)) 51462306a36Sopenharmony_ci be_async_sliport_evt_process(adapter, compl); 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter) 51862306a36Sopenharmony_ci{ 51962306a36Sopenharmony_ci struct be_queue_info *mcc_cq = &adapter->mcc_obj.cq; 52062306a36Sopenharmony_ci struct be_mcc_compl *compl = queue_tail_node(mcc_cq); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (be_mcc_compl_is_new(compl)) { 52362306a36Sopenharmony_ci queue_tail_inc(mcc_cq); 52462306a36Sopenharmony_ci return compl; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci return NULL; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_civoid be_async_mcc_enable(struct be_adapter *adapter) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci spin_lock_bh(&adapter->mcc_cq_lock); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci be_cq_notify(adapter, adapter->mcc_obj.cq.id, true, 0); 53462306a36Sopenharmony_ci adapter->mcc_obj.rearm_cq = true; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci spin_unlock_bh(&adapter->mcc_cq_lock); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_civoid be_async_mcc_disable(struct be_adapter *adapter) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci spin_lock_bh(&adapter->mcc_cq_lock); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci adapter->mcc_obj.rearm_cq = false; 54462306a36Sopenharmony_ci be_cq_notify(adapter, adapter->mcc_obj.cq.id, false, 0); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci spin_unlock_bh(&adapter->mcc_cq_lock); 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ciint be_process_mcc(struct be_adapter *adapter) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci struct be_mcc_compl *compl; 55262306a36Sopenharmony_ci int num = 0, status = 0; 55362306a36Sopenharmony_ci struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci spin_lock(&adapter->mcc_cq_lock); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci while ((compl = be_mcc_compl_get(adapter))) { 55862306a36Sopenharmony_ci if (compl->flags & CQE_FLAGS_ASYNC_MASK) { 55962306a36Sopenharmony_ci be_mcc_event_process(adapter, compl); 56062306a36Sopenharmony_ci } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) { 56162306a36Sopenharmony_ci status = be_mcc_compl_process(adapter, compl); 56262306a36Sopenharmony_ci atomic_dec(&mcc_obj->q.used); 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci be_mcc_compl_use(compl); 56562306a36Sopenharmony_ci num++; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (num) 56962306a36Sopenharmony_ci be_cq_notify(adapter, mcc_obj->cq.id, mcc_obj->rearm_cq, num); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci spin_unlock(&adapter->mcc_cq_lock); 57262306a36Sopenharmony_ci return status; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci/* Wait till no more pending mcc requests are present */ 57662306a36Sopenharmony_cistatic int be_mcc_wait_compl(struct be_adapter *adapter) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci#define mcc_timeout 12000 /* 12s timeout */ 57962306a36Sopenharmony_ci int i, status = 0; 58062306a36Sopenharmony_ci struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci for (i = 0; i < mcc_timeout; i++) { 58362306a36Sopenharmony_ci if (be_check_error(adapter, BE_ERROR_ANY)) 58462306a36Sopenharmony_ci return -EIO; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci local_bh_disable(); 58762306a36Sopenharmony_ci status = be_process_mcc(adapter); 58862306a36Sopenharmony_ci local_bh_enable(); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (atomic_read(&mcc_obj->q.used) == 0) 59162306a36Sopenharmony_ci break; 59262306a36Sopenharmony_ci usleep_range(500, 1000); 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci if (i == mcc_timeout) { 59562306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "FW not responding\n"); 59662306a36Sopenharmony_ci be_set_error(adapter, BE_ERROR_FW); 59762306a36Sopenharmony_ci return -EIO; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci return status; 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci/* Notify MCC requests and wait for completion */ 60362306a36Sopenharmony_cistatic int be_mcc_notify_wait(struct be_adapter *adapter) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci int status; 60662306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 60762306a36Sopenharmony_ci struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; 60862306a36Sopenharmony_ci u32 index = mcc_obj->q.head; 60962306a36Sopenharmony_ci struct be_cmd_resp_hdr *resp; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci index_dec(&index, mcc_obj->q.len); 61262306a36Sopenharmony_ci wrb = queue_index_node(&mcc_obj->q, index); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci resp = be_decode_resp_hdr(wrb->tag0, wrb->tag1); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci status = be_mcc_notify(adapter); 61762306a36Sopenharmony_ci if (status) 61862306a36Sopenharmony_ci goto out; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci status = be_mcc_wait_compl(adapter); 62162306a36Sopenharmony_ci if (status == -EIO) 62262306a36Sopenharmony_ci goto out; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci status = (resp->base_status | 62562306a36Sopenharmony_ci ((resp->addl_status & CQE_ADDL_STATUS_MASK) << 62662306a36Sopenharmony_ci CQE_ADDL_STATUS_SHIFT)); 62762306a36Sopenharmony_ciout: 62862306a36Sopenharmony_ci return status; 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci int msecs = 0; 63462306a36Sopenharmony_ci u32 ready; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci do { 63762306a36Sopenharmony_ci if (be_check_error(adapter, BE_ERROR_ANY)) 63862306a36Sopenharmony_ci return -EIO; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci ready = ioread32(db); 64162306a36Sopenharmony_ci if (ready == 0xffffffff) 64262306a36Sopenharmony_ci return -1; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci ready &= MPU_MAILBOX_DB_RDY_MASK; 64562306a36Sopenharmony_ci if (ready) 64662306a36Sopenharmony_ci break; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (msecs > 4000) { 64962306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "FW not responding\n"); 65062306a36Sopenharmony_ci be_set_error(adapter, BE_ERROR_FW); 65162306a36Sopenharmony_ci be_detect_error(adapter); 65262306a36Sopenharmony_ci return -1; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci msleep(1); 65662306a36Sopenharmony_ci msecs++; 65762306a36Sopenharmony_ci } while (true); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci return 0; 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci/* Insert the mailbox address into the doorbell in two steps 66362306a36Sopenharmony_ci * Polls on the mbox doorbell till a command completion (or a timeout) occurs 66462306a36Sopenharmony_ci */ 66562306a36Sopenharmony_cistatic int be_mbox_notify_wait(struct be_adapter *adapter) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci int status; 66862306a36Sopenharmony_ci u32 val = 0; 66962306a36Sopenharmony_ci void __iomem *db = adapter->db + MPU_MAILBOX_DB_OFFSET; 67062306a36Sopenharmony_ci struct be_dma_mem *mbox_mem = &adapter->mbox_mem; 67162306a36Sopenharmony_ci struct be_mcc_mailbox *mbox = mbox_mem->va; 67262306a36Sopenharmony_ci struct be_mcc_compl *compl = &mbox->compl; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* wait for ready to be set */ 67562306a36Sopenharmony_ci status = be_mbox_db_ready_wait(adapter, db); 67662306a36Sopenharmony_ci if (status != 0) 67762306a36Sopenharmony_ci return status; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci val |= MPU_MAILBOX_DB_HI_MASK; 68062306a36Sopenharmony_ci /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */ 68162306a36Sopenharmony_ci val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2; 68262306a36Sopenharmony_ci iowrite32(val, db); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* wait for ready to be set */ 68562306a36Sopenharmony_ci status = be_mbox_db_ready_wait(adapter, db); 68662306a36Sopenharmony_ci if (status != 0) 68762306a36Sopenharmony_ci return status; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci val = 0; 69062306a36Sopenharmony_ci /* at bits 2 - 31 place mbox dma addr lsb bits 4 - 33 */ 69162306a36Sopenharmony_ci val |= (u32)(mbox_mem->dma >> 4) << 2; 69262306a36Sopenharmony_ci iowrite32(val, db); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci status = be_mbox_db_ready_wait(adapter, db); 69562306a36Sopenharmony_ci if (status != 0) 69662306a36Sopenharmony_ci return status; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci /* A cq entry has been made now */ 69962306a36Sopenharmony_ci if (be_mcc_compl_is_new(compl)) { 70062306a36Sopenharmony_ci status = be_mcc_compl_process(adapter, &mbox->compl); 70162306a36Sopenharmony_ci be_mcc_compl_use(compl); 70262306a36Sopenharmony_ci if (status) 70362306a36Sopenharmony_ci return status; 70462306a36Sopenharmony_ci } else { 70562306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "invalid mailbox completion\n"); 70662306a36Sopenharmony_ci return -1; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci return 0; 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ciu16 be_POST_stage_get(struct be_adapter *adapter) 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci u32 sem; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci if (BEx_chip(adapter)) 71662306a36Sopenharmony_ci sem = ioread32(adapter->csr + SLIPORT_SEMAPHORE_OFFSET_BEx); 71762306a36Sopenharmony_ci else 71862306a36Sopenharmony_ci pci_read_config_dword(adapter->pdev, 71962306a36Sopenharmony_ci SLIPORT_SEMAPHORE_OFFSET_SH, &sem); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return sem & POST_STAGE_MASK; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic int lancer_wait_ready(struct be_adapter *adapter) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci#define SLIPORT_READY_TIMEOUT 30 72762306a36Sopenharmony_ci u32 sliport_status; 72862306a36Sopenharmony_ci int i; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci for (i = 0; i < SLIPORT_READY_TIMEOUT; i++) { 73162306a36Sopenharmony_ci sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); 73262306a36Sopenharmony_ci if (sliport_status & SLIPORT_STATUS_RDY_MASK) 73362306a36Sopenharmony_ci return 0; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci if (sliport_status & SLIPORT_STATUS_ERR_MASK && 73662306a36Sopenharmony_ci !(sliport_status & SLIPORT_STATUS_RN_MASK)) 73762306a36Sopenharmony_ci return -EIO; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci msleep(1000); 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci return sliport_status ? : -1; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ciint be_fw_wait_ready(struct be_adapter *adapter) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci u16 stage; 74862306a36Sopenharmony_ci int status, timeout = 0; 74962306a36Sopenharmony_ci struct device *dev = &adapter->pdev->dev; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (lancer_chip(adapter)) { 75262306a36Sopenharmony_ci status = lancer_wait_ready(adapter); 75362306a36Sopenharmony_ci if (status) { 75462306a36Sopenharmony_ci stage = status; 75562306a36Sopenharmony_ci goto err; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci return 0; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci do { 76162306a36Sopenharmony_ci /* There's no means to poll POST state on BE2/3 VFs */ 76262306a36Sopenharmony_ci if (BEx_chip(adapter) && be_virtfn(adapter)) 76362306a36Sopenharmony_ci return 0; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci stage = be_POST_stage_get(adapter); 76662306a36Sopenharmony_ci if (stage == POST_STAGE_ARMFW_RDY) 76762306a36Sopenharmony_ci return 0; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci dev_info(dev, "Waiting for POST, %ds elapsed\n", timeout); 77062306a36Sopenharmony_ci if (msleep_interruptible(2000)) { 77162306a36Sopenharmony_ci dev_err(dev, "Waiting for POST aborted\n"); 77262306a36Sopenharmony_ci return -EINTR; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci timeout += 2; 77562306a36Sopenharmony_ci } while (timeout < 60); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cierr: 77862306a36Sopenharmony_ci dev_err(dev, "POST timeout; stage=%#x\n", stage); 77962306a36Sopenharmony_ci return -ETIMEDOUT; 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_cistatic inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci return &wrb->payload.sgl[0]; 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic inline void fill_wrb_tags(struct be_mcc_wrb *wrb, unsigned long addr) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci wrb->tag0 = addr & 0xFFFFFFFF; 79062306a36Sopenharmony_ci wrb->tag1 = upper_32_bits(addr); 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci/* Don't touch the hdr after it's prepared */ 79462306a36Sopenharmony_ci/* mem will be NULL for embedded commands */ 79562306a36Sopenharmony_cistatic void be_wrb_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr, 79662306a36Sopenharmony_ci u8 subsystem, u8 opcode, int cmd_len, 79762306a36Sopenharmony_ci struct be_mcc_wrb *wrb, 79862306a36Sopenharmony_ci struct be_dma_mem *mem) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci struct be_sge *sge; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci req_hdr->opcode = opcode; 80362306a36Sopenharmony_ci req_hdr->subsystem = subsystem; 80462306a36Sopenharmony_ci req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr)); 80562306a36Sopenharmony_ci req_hdr->version = 0; 80662306a36Sopenharmony_ci fill_wrb_tags(wrb, (ulong)req_hdr); 80762306a36Sopenharmony_ci wrb->payload_length = cmd_len; 80862306a36Sopenharmony_ci if (mem) { 80962306a36Sopenharmony_ci wrb->embedded |= (1 & MCC_WRB_SGE_CNT_MASK) << 81062306a36Sopenharmony_ci MCC_WRB_SGE_CNT_SHIFT; 81162306a36Sopenharmony_ci sge = nonembedded_sgl(wrb); 81262306a36Sopenharmony_ci sge->pa_hi = cpu_to_le32(upper_32_bits(mem->dma)); 81362306a36Sopenharmony_ci sge->pa_lo = cpu_to_le32(mem->dma & 0xFFFFFFFF); 81462306a36Sopenharmony_ci sge->len = cpu_to_le32(mem->size); 81562306a36Sopenharmony_ci } else 81662306a36Sopenharmony_ci wrb->embedded |= MCC_WRB_EMBEDDED_MASK; 81762306a36Sopenharmony_ci be_dws_cpu_to_le(wrb, 8); 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cistatic void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages, 82162306a36Sopenharmony_ci struct be_dma_mem *mem) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci int i, buf_pages = min(PAGES_4K_SPANNED(mem->va, mem->size), max_pages); 82462306a36Sopenharmony_ci u64 dma = (u64)mem->dma; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci for (i = 0; i < buf_pages; i++) { 82762306a36Sopenharmony_ci pages[i].lo = cpu_to_le32(dma & 0xFFFFFFFF); 82862306a36Sopenharmony_ci pages[i].hi = cpu_to_le32(upper_32_bits(dma)); 82962306a36Sopenharmony_ci dma += PAGE_SIZE_4K; 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci} 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_cistatic inline struct be_mcc_wrb *wrb_from_mbox(struct be_adapter *adapter) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci struct be_dma_mem *mbox_mem = &adapter->mbox_mem; 83662306a36Sopenharmony_ci struct be_mcc_wrb *wrb = &((struct be_mcc_mailbox *)(mbox_mem->va))->wrb; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci memset(wrb, 0, sizeof(*wrb)); 83962306a36Sopenharmony_ci return wrb; 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_cistatic struct be_mcc_wrb *wrb_from_mccq(struct be_adapter *adapter) 84362306a36Sopenharmony_ci{ 84462306a36Sopenharmony_ci struct be_queue_info *mccq = &adapter->mcc_obj.q; 84562306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci if (!mccq->created) 84862306a36Sopenharmony_ci return NULL; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if (atomic_read(&mccq->used) >= mccq->len) 85162306a36Sopenharmony_ci return NULL; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci wrb = queue_head_node(mccq); 85462306a36Sopenharmony_ci queue_head_inc(mccq); 85562306a36Sopenharmony_ci atomic_inc(&mccq->used); 85662306a36Sopenharmony_ci memset(wrb, 0, sizeof(*wrb)); 85762306a36Sopenharmony_ci return wrb; 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_cistatic bool use_mcc(struct be_adapter *adapter) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci return adapter->mcc_obj.q.created; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci/* Must be used only in process context */ 86662306a36Sopenharmony_cistatic int be_cmd_lock(struct be_adapter *adapter) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci if (use_mcc(adapter)) { 86962306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 87062306a36Sopenharmony_ci return 0; 87162306a36Sopenharmony_ci } else { 87262306a36Sopenharmony_ci return mutex_lock_interruptible(&adapter->mbox_lock); 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci/* Must be used only in process context */ 87762306a36Sopenharmony_cistatic void be_cmd_unlock(struct be_adapter *adapter) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci if (use_mcc(adapter)) 88062306a36Sopenharmony_ci return mutex_unlock(&adapter->mcc_lock); 88162306a36Sopenharmony_ci else 88262306a36Sopenharmony_ci return mutex_unlock(&adapter->mbox_lock); 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cistatic struct be_mcc_wrb *be_cmd_copy(struct be_adapter *adapter, 88662306a36Sopenharmony_ci struct be_mcc_wrb *wrb) 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci struct be_mcc_wrb *dest_wrb; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if (use_mcc(adapter)) { 89162306a36Sopenharmony_ci dest_wrb = wrb_from_mccq(adapter); 89262306a36Sopenharmony_ci if (!dest_wrb) 89362306a36Sopenharmony_ci return NULL; 89462306a36Sopenharmony_ci } else { 89562306a36Sopenharmony_ci dest_wrb = wrb_from_mbox(adapter); 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci memcpy(dest_wrb, wrb, sizeof(*wrb)); 89962306a36Sopenharmony_ci if (wrb->embedded & cpu_to_le32(MCC_WRB_EMBEDDED_MASK)) 90062306a36Sopenharmony_ci fill_wrb_tags(dest_wrb, (ulong)embedded_payload(wrb)); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci return dest_wrb; 90362306a36Sopenharmony_ci} 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci/* Must be used only in process context */ 90662306a36Sopenharmony_cistatic int be_cmd_notify_wait(struct be_adapter *adapter, 90762306a36Sopenharmony_ci struct be_mcc_wrb *wrb) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci struct be_mcc_wrb *dest_wrb; 91062306a36Sopenharmony_ci int status; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci status = be_cmd_lock(adapter); 91362306a36Sopenharmony_ci if (status) 91462306a36Sopenharmony_ci return status; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci dest_wrb = be_cmd_copy(adapter, wrb); 91762306a36Sopenharmony_ci if (!dest_wrb) { 91862306a36Sopenharmony_ci status = -EBUSY; 91962306a36Sopenharmony_ci goto unlock; 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (use_mcc(adapter)) 92362306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 92462306a36Sopenharmony_ci else 92562306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci if (!status) 92862306a36Sopenharmony_ci memcpy(wrb, dest_wrb, sizeof(*wrb)); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ciunlock: 93162306a36Sopenharmony_ci be_cmd_unlock(adapter); 93262306a36Sopenharmony_ci return status; 93362306a36Sopenharmony_ci} 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci/* Tell fw we're about to start firing cmds by writing a 93662306a36Sopenharmony_ci * special pattern across the wrb hdr; uses mbox 93762306a36Sopenharmony_ci */ 93862306a36Sopenharmony_ciint be_cmd_fw_init(struct be_adapter *adapter) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci u8 *wrb; 94162306a36Sopenharmony_ci int status; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci if (lancer_chip(adapter)) 94462306a36Sopenharmony_ci return 0; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 94762306a36Sopenharmony_ci return -1; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci wrb = (u8 *)wrb_from_mbox(adapter); 95062306a36Sopenharmony_ci *wrb++ = 0xFF; 95162306a36Sopenharmony_ci *wrb++ = 0x12; 95262306a36Sopenharmony_ci *wrb++ = 0x34; 95362306a36Sopenharmony_ci *wrb++ = 0xFF; 95462306a36Sopenharmony_ci *wrb++ = 0xFF; 95562306a36Sopenharmony_ci *wrb++ = 0x56; 95662306a36Sopenharmony_ci *wrb++ = 0x78; 95762306a36Sopenharmony_ci *wrb = 0xFF; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 96262306a36Sopenharmony_ci return status; 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci/* Tell fw we're done with firing cmds by writing a 96662306a36Sopenharmony_ci * special pattern across the wrb hdr; uses mbox 96762306a36Sopenharmony_ci */ 96862306a36Sopenharmony_ciint be_cmd_fw_clean(struct be_adapter *adapter) 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci u8 *wrb; 97162306a36Sopenharmony_ci int status; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci if (lancer_chip(adapter)) 97462306a36Sopenharmony_ci return 0; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 97762306a36Sopenharmony_ci return -1; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci wrb = (u8 *)wrb_from_mbox(adapter); 98062306a36Sopenharmony_ci *wrb++ = 0xFF; 98162306a36Sopenharmony_ci *wrb++ = 0xAA; 98262306a36Sopenharmony_ci *wrb++ = 0xBB; 98362306a36Sopenharmony_ci *wrb++ = 0xFF; 98462306a36Sopenharmony_ci *wrb++ = 0xFF; 98562306a36Sopenharmony_ci *wrb++ = 0xCC; 98662306a36Sopenharmony_ci *wrb++ = 0xDD; 98762306a36Sopenharmony_ci *wrb = 0xFF; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 99262306a36Sopenharmony_ci return status; 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ciint be_cmd_eq_create(struct be_adapter *adapter, struct be_eq_obj *eqo) 99662306a36Sopenharmony_ci{ 99762306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 99862306a36Sopenharmony_ci struct be_cmd_req_eq_create *req; 99962306a36Sopenharmony_ci struct be_dma_mem *q_mem = &eqo->q.dma_mem; 100062306a36Sopenharmony_ci int status, ver = 0; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 100362306a36Sopenharmony_ci return -1; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci wrb = wrb_from_mbox(adapter); 100662306a36Sopenharmony_ci req = embedded_payload(wrb); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 100962306a36Sopenharmony_ci OPCODE_COMMON_EQ_CREATE, sizeof(*req), wrb, 101062306a36Sopenharmony_ci NULL); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci /* Support for EQ_CREATEv2 available only SH-R onwards */ 101362306a36Sopenharmony_ci if (!(BEx_chip(adapter) || lancer_chip(adapter))) 101462306a36Sopenharmony_ci ver = 2; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci req->hdr.version = ver; 101762306a36Sopenharmony_ci req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1); 102062306a36Sopenharmony_ci /* 4byte eqe*/ 102162306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0); 102262306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_eq_context, count, req->context, 102362306a36Sopenharmony_ci __ilog2_u32(eqo->q.len / 256)); 102462306a36Sopenharmony_ci be_dws_cpu_to_le(req->context, sizeof(req->context)); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 102962306a36Sopenharmony_ci if (!status) { 103062306a36Sopenharmony_ci struct be_cmd_resp_eq_create *resp = embedded_payload(wrb); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci eqo->q.id = le16_to_cpu(resp->eq_id); 103362306a36Sopenharmony_ci eqo->msix_idx = 103462306a36Sopenharmony_ci (ver == 2) ? le16_to_cpu(resp->msix_idx) : eqo->idx; 103562306a36Sopenharmony_ci eqo->q.created = true; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 103962306a36Sopenharmony_ci return status; 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci/* Use MCC */ 104362306a36Sopenharmony_ciint be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, 104462306a36Sopenharmony_ci bool permanent, u32 if_handle, u32 pmac_id) 104562306a36Sopenharmony_ci{ 104662306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 104762306a36Sopenharmony_ci struct be_cmd_req_mac_query *req; 104862306a36Sopenharmony_ci int status; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 105362306a36Sopenharmony_ci if (!wrb) { 105462306a36Sopenharmony_ci status = -EBUSY; 105562306a36Sopenharmony_ci goto err; 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci req = embedded_payload(wrb); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 106062306a36Sopenharmony_ci OPCODE_COMMON_NTWK_MAC_QUERY, sizeof(*req), wrb, 106162306a36Sopenharmony_ci NULL); 106262306a36Sopenharmony_ci req->type = MAC_ADDRESS_TYPE_NETWORK; 106362306a36Sopenharmony_ci if (permanent) { 106462306a36Sopenharmony_ci req->permanent = 1; 106562306a36Sopenharmony_ci } else { 106662306a36Sopenharmony_ci req->if_id = cpu_to_le16((u16)if_handle); 106762306a36Sopenharmony_ci req->pmac_id = cpu_to_le32(pmac_id); 106862306a36Sopenharmony_ci req->permanent = 0; 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 107262306a36Sopenharmony_ci if (!status) { 107362306a36Sopenharmony_ci struct be_cmd_resp_mac_query *resp = embedded_payload(wrb); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci memcpy(mac_addr, resp->mac.addr, ETH_ALEN); 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_cierr: 107962306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 108062306a36Sopenharmony_ci return status; 108162306a36Sopenharmony_ci} 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci/* Uses synchronous MCCQ */ 108462306a36Sopenharmony_ciint be_cmd_pmac_add(struct be_adapter *adapter, const u8 *mac_addr, 108562306a36Sopenharmony_ci u32 if_id, u32 *pmac_id, u32 domain) 108662306a36Sopenharmony_ci{ 108762306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 108862306a36Sopenharmony_ci struct be_cmd_req_pmac_add *req; 108962306a36Sopenharmony_ci int status; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 109462306a36Sopenharmony_ci if (!wrb) { 109562306a36Sopenharmony_ci status = -EBUSY; 109662306a36Sopenharmony_ci goto err; 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci req = embedded_payload(wrb); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 110162306a36Sopenharmony_ci OPCODE_COMMON_NTWK_PMAC_ADD, sizeof(*req), wrb, 110262306a36Sopenharmony_ci NULL); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci req->hdr.domain = domain; 110562306a36Sopenharmony_ci req->if_id = cpu_to_le32(if_id); 110662306a36Sopenharmony_ci memcpy(req->mac_address, mac_addr, ETH_ALEN); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 110962306a36Sopenharmony_ci if (!status) { 111062306a36Sopenharmony_ci struct be_cmd_resp_pmac_add *resp = embedded_payload(wrb); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci *pmac_id = le32_to_cpu(resp->pmac_id); 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_cierr: 111662306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci if (base_status(status) == MCC_STATUS_UNAUTHORIZED_REQUEST) 111962306a36Sopenharmony_ci status = -EPERM; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci return status; 112262306a36Sopenharmony_ci} 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci/* Uses synchronous MCCQ */ 112562306a36Sopenharmony_ciint be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, int pmac_id, u32 dom) 112662306a36Sopenharmony_ci{ 112762306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 112862306a36Sopenharmony_ci struct be_cmd_req_pmac_del *req; 112962306a36Sopenharmony_ci int status; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci if (pmac_id == -1) 113262306a36Sopenharmony_ci return 0; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 113762306a36Sopenharmony_ci if (!wrb) { 113862306a36Sopenharmony_ci status = -EBUSY; 113962306a36Sopenharmony_ci goto err; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci req = embedded_payload(wrb); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 114462306a36Sopenharmony_ci OPCODE_COMMON_NTWK_PMAC_DEL, sizeof(*req), 114562306a36Sopenharmony_ci wrb, NULL); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci req->hdr.domain = dom; 114862306a36Sopenharmony_ci req->if_id = cpu_to_le32(if_id); 114962306a36Sopenharmony_ci req->pmac_id = cpu_to_le32(pmac_id); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_cierr: 115462306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 115562306a36Sopenharmony_ci return status; 115662306a36Sopenharmony_ci} 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci/* Uses Mbox */ 115962306a36Sopenharmony_ciint be_cmd_cq_create(struct be_adapter *adapter, struct be_queue_info *cq, 116062306a36Sopenharmony_ci struct be_queue_info *eq, bool no_delay, int coalesce_wm) 116162306a36Sopenharmony_ci{ 116262306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 116362306a36Sopenharmony_ci struct be_cmd_req_cq_create *req; 116462306a36Sopenharmony_ci struct be_dma_mem *q_mem = &cq->dma_mem; 116562306a36Sopenharmony_ci void *ctxt; 116662306a36Sopenharmony_ci int status; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 116962306a36Sopenharmony_ci return -1; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci wrb = wrb_from_mbox(adapter); 117262306a36Sopenharmony_ci req = embedded_payload(wrb); 117362306a36Sopenharmony_ci ctxt = &req->context; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 117662306a36Sopenharmony_ci OPCODE_COMMON_CQ_CREATE, sizeof(*req), wrb, 117762306a36Sopenharmony_ci NULL); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci if (BEx_chip(adapter)) { 118262306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_cq_context_be, coalescwm, ctxt, 118362306a36Sopenharmony_ci coalesce_wm); 118462306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_cq_context_be, nodelay, 118562306a36Sopenharmony_ci ctxt, no_delay); 118662306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_cq_context_be, count, ctxt, 118762306a36Sopenharmony_ci __ilog2_u32(cq->len / 256)); 118862306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_cq_context_be, valid, ctxt, 1); 118962306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_cq_context_be, eventable, ctxt, 1); 119062306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_cq_context_be, eqid, ctxt, eq->id); 119162306a36Sopenharmony_ci } else { 119262306a36Sopenharmony_ci req->hdr.version = 2; 119362306a36Sopenharmony_ci req->page_size = 1; /* 1 for 4K */ 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci /* coalesce-wm field in this cmd is not relevant to Lancer. 119662306a36Sopenharmony_ci * Lancer uses COMMON_MODIFY_CQ to set this field 119762306a36Sopenharmony_ci */ 119862306a36Sopenharmony_ci if (!lancer_chip(adapter)) 119962306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_cq_context_v2, coalescwm, 120062306a36Sopenharmony_ci ctxt, coalesce_wm); 120162306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_cq_context_v2, nodelay, ctxt, 120262306a36Sopenharmony_ci no_delay); 120362306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_cq_context_v2, count, ctxt, 120462306a36Sopenharmony_ci __ilog2_u32(cq->len / 256)); 120562306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_cq_context_v2, valid, ctxt, 1); 120662306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_cq_context_v2, eventable, ctxt, 1); 120762306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_cq_context_v2, eqid, ctxt, eq->id); 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci be_dws_cpu_to_le(ctxt, sizeof(req->context)); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 121562306a36Sopenharmony_ci if (!status) { 121662306a36Sopenharmony_ci struct be_cmd_resp_cq_create *resp = embedded_payload(wrb); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci cq->id = le16_to_cpu(resp->cq_id); 121962306a36Sopenharmony_ci cq->created = true; 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci return status; 122562306a36Sopenharmony_ci} 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_cistatic u32 be_encoded_q_len(int q_len) 122862306a36Sopenharmony_ci{ 122962306a36Sopenharmony_ci u32 len_encoded = fls(q_len); /* log2(len) + 1 */ 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci if (len_encoded == 16) 123262306a36Sopenharmony_ci len_encoded = 0; 123362306a36Sopenharmony_ci return len_encoded; 123462306a36Sopenharmony_ci} 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_cistatic int be_cmd_mccq_ext_create(struct be_adapter *adapter, 123762306a36Sopenharmony_ci struct be_queue_info *mccq, 123862306a36Sopenharmony_ci struct be_queue_info *cq) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 124162306a36Sopenharmony_ci struct be_cmd_req_mcc_ext_create *req; 124262306a36Sopenharmony_ci struct be_dma_mem *q_mem = &mccq->dma_mem; 124362306a36Sopenharmony_ci void *ctxt; 124462306a36Sopenharmony_ci int status; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 124762306a36Sopenharmony_ci return -1; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci wrb = wrb_from_mbox(adapter); 125062306a36Sopenharmony_ci req = embedded_payload(wrb); 125162306a36Sopenharmony_ci ctxt = &req->context; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 125462306a36Sopenharmony_ci OPCODE_COMMON_MCC_CREATE_EXT, sizeof(*req), wrb, 125562306a36Sopenharmony_ci NULL); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); 125862306a36Sopenharmony_ci if (BEx_chip(adapter)) { 125962306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1); 126062306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt, 126162306a36Sopenharmony_ci be_encoded_q_len(mccq->len)); 126262306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id); 126362306a36Sopenharmony_ci } else { 126462306a36Sopenharmony_ci req->hdr.version = 1; 126562306a36Sopenharmony_ci req->cq_id = cpu_to_le16(cq->id); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_mcc_context_v1, ring_size, ctxt, 126862306a36Sopenharmony_ci be_encoded_q_len(mccq->len)); 126962306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_mcc_context_v1, valid, ctxt, 1); 127062306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_mcc_context_v1, async_cq_id, 127162306a36Sopenharmony_ci ctxt, cq->id); 127262306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_mcc_context_v1, async_cq_valid, 127362306a36Sopenharmony_ci ctxt, 1); 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci /* Subscribe to Link State, Sliport Event and Group 5 Events 127762306a36Sopenharmony_ci * (bits 1, 5 and 17 set) 127862306a36Sopenharmony_ci */ 127962306a36Sopenharmony_ci req->async_event_bitmap[0] = 128062306a36Sopenharmony_ci cpu_to_le32(BIT(ASYNC_EVENT_CODE_LINK_STATE) | 128162306a36Sopenharmony_ci BIT(ASYNC_EVENT_CODE_GRP_5) | 128262306a36Sopenharmony_ci BIT(ASYNC_EVENT_CODE_QNQ) | 128362306a36Sopenharmony_ci BIT(ASYNC_EVENT_CODE_SLIPORT)); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci be_dws_cpu_to_le(ctxt, sizeof(req->context)); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 129062306a36Sopenharmony_ci if (!status) { 129162306a36Sopenharmony_ci struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci mccq->id = le16_to_cpu(resp->id); 129462306a36Sopenharmony_ci mccq->created = true; 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci return status; 129962306a36Sopenharmony_ci} 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_cistatic int be_cmd_mccq_org_create(struct be_adapter *adapter, 130262306a36Sopenharmony_ci struct be_queue_info *mccq, 130362306a36Sopenharmony_ci struct be_queue_info *cq) 130462306a36Sopenharmony_ci{ 130562306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 130662306a36Sopenharmony_ci struct be_cmd_req_mcc_create *req; 130762306a36Sopenharmony_ci struct be_dma_mem *q_mem = &mccq->dma_mem; 130862306a36Sopenharmony_ci void *ctxt; 130962306a36Sopenharmony_ci int status; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 131262306a36Sopenharmony_ci return -1; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci wrb = wrb_from_mbox(adapter); 131562306a36Sopenharmony_ci req = embedded_payload(wrb); 131662306a36Sopenharmony_ci ctxt = &req->context; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 131962306a36Sopenharmony_ci OPCODE_COMMON_MCC_CREATE, sizeof(*req), wrb, 132062306a36Sopenharmony_ci NULL); 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1); 132562306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt, 132662306a36Sopenharmony_ci be_encoded_q_len(mccq->len)); 132762306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci be_dws_cpu_to_le(ctxt, sizeof(req->context)); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 133462306a36Sopenharmony_ci if (!status) { 133562306a36Sopenharmony_ci struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci mccq->id = le16_to_cpu(resp->id); 133862306a36Sopenharmony_ci mccq->created = true; 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 134262306a36Sopenharmony_ci return status; 134362306a36Sopenharmony_ci} 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ciint be_cmd_mccq_create(struct be_adapter *adapter, 134662306a36Sopenharmony_ci struct be_queue_info *mccq, struct be_queue_info *cq) 134762306a36Sopenharmony_ci{ 134862306a36Sopenharmony_ci int status; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci status = be_cmd_mccq_ext_create(adapter, mccq, cq); 135162306a36Sopenharmony_ci if (status && BEx_chip(adapter)) { 135262306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, "Upgrade to F/W ver 2.102.235.0 " 135362306a36Sopenharmony_ci "or newer to avoid conflicting priorities between NIC " 135462306a36Sopenharmony_ci "and FCoE traffic"); 135562306a36Sopenharmony_ci status = be_cmd_mccq_org_create(adapter, mccq, cq); 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci return status; 135862306a36Sopenharmony_ci} 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ciint be_cmd_txq_create(struct be_adapter *adapter, struct be_tx_obj *txo) 136162306a36Sopenharmony_ci{ 136262306a36Sopenharmony_ci struct be_mcc_wrb wrb = {0}; 136362306a36Sopenharmony_ci struct be_cmd_req_eth_tx_create *req; 136462306a36Sopenharmony_ci struct be_queue_info *txq = &txo->q; 136562306a36Sopenharmony_ci struct be_queue_info *cq = &txo->cq; 136662306a36Sopenharmony_ci struct be_dma_mem *q_mem = &txq->dma_mem; 136762306a36Sopenharmony_ci int status, ver = 0; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci req = embedded_payload(&wrb); 137062306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, 137162306a36Sopenharmony_ci OPCODE_ETH_TX_CREATE, sizeof(*req), &wrb, NULL); 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci if (lancer_chip(adapter)) { 137462306a36Sopenharmony_ci req->hdr.version = 1; 137562306a36Sopenharmony_ci } else if (BEx_chip(adapter)) { 137662306a36Sopenharmony_ci if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC) 137762306a36Sopenharmony_ci req->hdr.version = 2; 137862306a36Sopenharmony_ci } else { /* For SH */ 137962306a36Sopenharmony_ci req->hdr.version = 2; 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci if (req->hdr.version > 0) 138362306a36Sopenharmony_ci req->if_id = cpu_to_le16(adapter->if_handle); 138462306a36Sopenharmony_ci req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); 138562306a36Sopenharmony_ci req->ulp_num = BE_ULP1_NUM; 138662306a36Sopenharmony_ci req->type = BE_ETH_TX_RING_TYPE_STANDARD; 138762306a36Sopenharmony_ci req->cq_id = cpu_to_le16(cq->id); 138862306a36Sopenharmony_ci req->queue_size = be_encoded_q_len(txq->len); 138962306a36Sopenharmony_ci be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); 139062306a36Sopenharmony_ci ver = req->hdr.version; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci status = be_cmd_notify_wait(adapter, &wrb); 139362306a36Sopenharmony_ci if (!status) { 139462306a36Sopenharmony_ci struct be_cmd_resp_eth_tx_create *resp = embedded_payload(&wrb); 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci txq->id = le16_to_cpu(resp->cid); 139762306a36Sopenharmony_ci if (ver == 2) 139862306a36Sopenharmony_ci txo->db_offset = le32_to_cpu(resp->db_offset); 139962306a36Sopenharmony_ci else 140062306a36Sopenharmony_ci txo->db_offset = DB_TXULP1_OFFSET; 140162306a36Sopenharmony_ci txq->created = true; 140262306a36Sopenharmony_ci } 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci return status; 140562306a36Sopenharmony_ci} 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci/* Uses MCC */ 140862306a36Sopenharmony_ciint be_cmd_rxq_create(struct be_adapter *adapter, 140962306a36Sopenharmony_ci struct be_queue_info *rxq, u16 cq_id, u16 frag_size, 141062306a36Sopenharmony_ci u32 if_id, u32 rss, u8 *rss_id) 141162306a36Sopenharmony_ci{ 141262306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 141362306a36Sopenharmony_ci struct be_cmd_req_eth_rx_create *req; 141462306a36Sopenharmony_ci struct be_dma_mem *q_mem = &rxq->dma_mem; 141562306a36Sopenharmony_ci int status; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 142062306a36Sopenharmony_ci if (!wrb) { 142162306a36Sopenharmony_ci status = -EBUSY; 142262306a36Sopenharmony_ci goto err; 142362306a36Sopenharmony_ci } 142462306a36Sopenharmony_ci req = embedded_payload(wrb); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, 142762306a36Sopenharmony_ci OPCODE_ETH_RX_CREATE, sizeof(*req), wrb, NULL); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci req->cq_id = cpu_to_le16(cq_id); 143062306a36Sopenharmony_ci req->frag_size = fls(frag_size) - 1; 143162306a36Sopenharmony_ci req->num_pages = 2; 143262306a36Sopenharmony_ci be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); 143362306a36Sopenharmony_ci req->interface_id = cpu_to_le32(if_id); 143462306a36Sopenharmony_ci req->max_frame_size = cpu_to_le16(BE_MAX_JUMBO_FRAME_SIZE); 143562306a36Sopenharmony_ci req->rss_queue = cpu_to_le32(rss); 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 143862306a36Sopenharmony_ci if (!status) { 143962306a36Sopenharmony_ci struct be_cmd_resp_eth_rx_create *resp = embedded_payload(wrb); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci rxq->id = le16_to_cpu(resp->id); 144262306a36Sopenharmony_ci rxq->created = true; 144362306a36Sopenharmony_ci *rss_id = resp->rss_id; 144462306a36Sopenharmony_ci } 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_cierr: 144762306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 144862306a36Sopenharmony_ci return status; 144962306a36Sopenharmony_ci} 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci/* Generic destroyer function for all types of queues 145262306a36Sopenharmony_ci * Uses Mbox 145362306a36Sopenharmony_ci */ 145462306a36Sopenharmony_ciint be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, 145562306a36Sopenharmony_ci int queue_type) 145662306a36Sopenharmony_ci{ 145762306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 145862306a36Sopenharmony_ci struct be_cmd_req_q_destroy *req; 145962306a36Sopenharmony_ci u8 subsys = 0, opcode = 0; 146062306a36Sopenharmony_ci int status; 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 146362306a36Sopenharmony_ci return -1; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci wrb = wrb_from_mbox(adapter); 146662306a36Sopenharmony_ci req = embedded_payload(wrb); 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci switch (queue_type) { 146962306a36Sopenharmony_ci case QTYPE_EQ: 147062306a36Sopenharmony_ci subsys = CMD_SUBSYSTEM_COMMON; 147162306a36Sopenharmony_ci opcode = OPCODE_COMMON_EQ_DESTROY; 147262306a36Sopenharmony_ci break; 147362306a36Sopenharmony_ci case QTYPE_CQ: 147462306a36Sopenharmony_ci subsys = CMD_SUBSYSTEM_COMMON; 147562306a36Sopenharmony_ci opcode = OPCODE_COMMON_CQ_DESTROY; 147662306a36Sopenharmony_ci break; 147762306a36Sopenharmony_ci case QTYPE_TXQ: 147862306a36Sopenharmony_ci subsys = CMD_SUBSYSTEM_ETH; 147962306a36Sopenharmony_ci opcode = OPCODE_ETH_TX_DESTROY; 148062306a36Sopenharmony_ci break; 148162306a36Sopenharmony_ci case QTYPE_RXQ: 148262306a36Sopenharmony_ci subsys = CMD_SUBSYSTEM_ETH; 148362306a36Sopenharmony_ci opcode = OPCODE_ETH_RX_DESTROY; 148462306a36Sopenharmony_ci break; 148562306a36Sopenharmony_ci case QTYPE_MCCQ: 148662306a36Sopenharmony_ci subsys = CMD_SUBSYSTEM_COMMON; 148762306a36Sopenharmony_ci opcode = OPCODE_COMMON_MCC_DESTROY; 148862306a36Sopenharmony_ci break; 148962306a36Sopenharmony_ci default: 149062306a36Sopenharmony_ci BUG(); 149162306a36Sopenharmony_ci } 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req), wrb, 149462306a36Sopenharmony_ci NULL); 149562306a36Sopenharmony_ci req->id = cpu_to_le16(q->id); 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 149862306a36Sopenharmony_ci q->created = false; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 150162306a36Sopenharmony_ci return status; 150262306a36Sopenharmony_ci} 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci/* Uses MCC */ 150562306a36Sopenharmony_ciint be_cmd_rxq_destroy(struct be_adapter *adapter, struct be_queue_info *q) 150662306a36Sopenharmony_ci{ 150762306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 150862306a36Sopenharmony_ci struct be_cmd_req_q_destroy *req; 150962306a36Sopenharmony_ci int status; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 151462306a36Sopenharmony_ci if (!wrb) { 151562306a36Sopenharmony_ci status = -EBUSY; 151662306a36Sopenharmony_ci goto err; 151762306a36Sopenharmony_ci } 151862306a36Sopenharmony_ci req = embedded_payload(wrb); 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, 152162306a36Sopenharmony_ci OPCODE_ETH_RX_DESTROY, sizeof(*req), wrb, NULL); 152262306a36Sopenharmony_ci req->id = cpu_to_le16(q->id); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 152562306a36Sopenharmony_ci q->created = false; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_cierr: 152862306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 152962306a36Sopenharmony_ci return status; 153062306a36Sopenharmony_ci} 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci/* Create an rx filtering policy configuration on an i/f 153362306a36Sopenharmony_ci * Will use MBOX only if MCCQ has not been created. 153462306a36Sopenharmony_ci */ 153562306a36Sopenharmony_ciint be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags, 153662306a36Sopenharmony_ci u32 *if_handle, u32 domain) 153762306a36Sopenharmony_ci{ 153862306a36Sopenharmony_ci struct be_mcc_wrb wrb = {0}; 153962306a36Sopenharmony_ci struct be_cmd_req_if_create *req; 154062306a36Sopenharmony_ci int status; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci req = embedded_payload(&wrb); 154362306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 154462306a36Sopenharmony_ci OPCODE_COMMON_NTWK_INTERFACE_CREATE, 154562306a36Sopenharmony_ci sizeof(*req), &wrb, NULL); 154662306a36Sopenharmony_ci req->hdr.domain = domain; 154762306a36Sopenharmony_ci req->capability_flags = cpu_to_le32(cap_flags); 154862306a36Sopenharmony_ci req->enable_flags = cpu_to_le32(en_flags); 154962306a36Sopenharmony_ci req->pmac_invalid = true; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci status = be_cmd_notify_wait(adapter, &wrb); 155262306a36Sopenharmony_ci if (!status) { 155362306a36Sopenharmony_ci struct be_cmd_resp_if_create *resp = embedded_payload(&wrb); 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci *if_handle = le32_to_cpu(resp->interface_id); 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci /* Hack to retrieve VF's pmac-id on BE3 */ 155862306a36Sopenharmony_ci if (BE3_chip(adapter) && be_virtfn(adapter)) 155962306a36Sopenharmony_ci adapter->pmac_id[0] = le32_to_cpu(resp->pmac_id); 156062306a36Sopenharmony_ci } 156162306a36Sopenharmony_ci return status; 156262306a36Sopenharmony_ci} 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci/* Uses MCCQ if available else MBOX */ 156562306a36Sopenharmony_ciint be_cmd_if_destroy(struct be_adapter *adapter, int interface_id, u32 domain) 156662306a36Sopenharmony_ci{ 156762306a36Sopenharmony_ci struct be_mcc_wrb wrb = {0}; 156862306a36Sopenharmony_ci struct be_cmd_req_if_destroy *req; 156962306a36Sopenharmony_ci int status; 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci if (interface_id == -1) 157262306a36Sopenharmony_ci return 0; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci req = embedded_payload(&wrb); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 157762306a36Sopenharmony_ci OPCODE_COMMON_NTWK_INTERFACE_DESTROY, 157862306a36Sopenharmony_ci sizeof(*req), &wrb, NULL); 157962306a36Sopenharmony_ci req->hdr.domain = domain; 158062306a36Sopenharmony_ci req->interface_id = cpu_to_le32(interface_id); 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci status = be_cmd_notify_wait(adapter, &wrb); 158362306a36Sopenharmony_ci return status; 158462306a36Sopenharmony_ci} 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci/* Get stats is a non embedded command: the request is not embedded inside 158762306a36Sopenharmony_ci * WRB but is a separate dma memory block 158862306a36Sopenharmony_ci * Uses asynchronous MCC 158962306a36Sopenharmony_ci */ 159062306a36Sopenharmony_ciint be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) 159162306a36Sopenharmony_ci{ 159262306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 159362306a36Sopenharmony_ci struct be_cmd_req_hdr *hdr; 159462306a36Sopenharmony_ci int status = 0; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 159962306a36Sopenharmony_ci if (!wrb) { 160062306a36Sopenharmony_ci status = -EBUSY; 160162306a36Sopenharmony_ci goto err; 160262306a36Sopenharmony_ci } 160362306a36Sopenharmony_ci hdr = nonemb_cmd->va; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(hdr, CMD_SUBSYSTEM_ETH, 160662306a36Sopenharmony_ci OPCODE_ETH_GET_STATISTICS, nonemb_cmd->size, wrb, 160762306a36Sopenharmony_ci nonemb_cmd); 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci /* version 1 of the cmd is not supported only by BE2 */ 161062306a36Sopenharmony_ci if (BE2_chip(adapter)) 161162306a36Sopenharmony_ci hdr->version = 0; 161262306a36Sopenharmony_ci if (BE3_chip(adapter) || lancer_chip(adapter)) 161362306a36Sopenharmony_ci hdr->version = 1; 161462306a36Sopenharmony_ci else 161562306a36Sopenharmony_ci hdr->version = 2; 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci status = be_mcc_notify(adapter); 161862306a36Sopenharmony_ci if (status) 161962306a36Sopenharmony_ci goto err; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci adapter->stats_cmd_sent = true; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_cierr: 162462306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 162562306a36Sopenharmony_ci return status; 162662306a36Sopenharmony_ci} 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci/* Lancer Stats */ 162962306a36Sopenharmony_ciint lancer_cmd_get_pport_stats(struct be_adapter *adapter, 163062306a36Sopenharmony_ci struct be_dma_mem *nonemb_cmd) 163162306a36Sopenharmony_ci{ 163262306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 163362306a36Sopenharmony_ci struct lancer_cmd_req_pport_stats *req; 163462306a36Sopenharmony_ci int status = 0; 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci if (!be_cmd_allowed(adapter, OPCODE_ETH_GET_PPORT_STATS, 163762306a36Sopenharmony_ci CMD_SUBSYSTEM_ETH)) 163862306a36Sopenharmony_ci return -EPERM; 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 164362306a36Sopenharmony_ci if (!wrb) { 164462306a36Sopenharmony_ci status = -EBUSY; 164562306a36Sopenharmony_ci goto err; 164662306a36Sopenharmony_ci } 164762306a36Sopenharmony_ci req = nonemb_cmd->va; 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, 165062306a36Sopenharmony_ci OPCODE_ETH_GET_PPORT_STATS, nonemb_cmd->size, 165162306a36Sopenharmony_ci wrb, nonemb_cmd); 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci req->cmd_params.params.pport_num = cpu_to_le16(adapter->hba_port_num); 165462306a36Sopenharmony_ci req->cmd_params.params.reset_stats = 0; 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci status = be_mcc_notify(adapter); 165762306a36Sopenharmony_ci if (status) 165862306a36Sopenharmony_ci goto err; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci adapter->stats_cmd_sent = true; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_cierr: 166362306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 166462306a36Sopenharmony_ci return status; 166562306a36Sopenharmony_ci} 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_cistatic int be_mac_to_link_speed(int mac_speed) 166862306a36Sopenharmony_ci{ 166962306a36Sopenharmony_ci switch (mac_speed) { 167062306a36Sopenharmony_ci case PHY_LINK_SPEED_ZERO: 167162306a36Sopenharmony_ci return 0; 167262306a36Sopenharmony_ci case PHY_LINK_SPEED_10MBPS: 167362306a36Sopenharmony_ci return 10; 167462306a36Sopenharmony_ci case PHY_LINK_SPEED_100MBPS: 167562306a36Sopenharmony_ci return 100; 167662306a36Sopenharmony_ci case PHY_LINK_SPEED_1GBPS: 167762306a36Sopenharmony_ci return 1000; 167862306a36Sopenharmony_ci case PHY_LINK_SPEED_10GBPS: 167962306a36Sopenharmony_ci return 10000; 168062306a36Sopenharmony_ci case PHY_LINK_SPEED_20GBPS: 168162306a36Sopenharmony_ci return 20000; 168262306a36Sopenharmony_ci case PHY_LINK_SPEED_25GBPS: 168362306a36Sopenharmony_ci return 25000; 168462306a36Sopenharmony_ci case PHY_LINK_SPEED_40GBPS: 168562306a36Sopenharmony_ci return 40000; 168662306a36Sopenharmony_ci } 168762306a36Sopenharmony_ci return 0; 168862306a36Sopenharmony_ci} 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci/* Uses synchronous mcc 169162306a36Sopenharmony_ci * Returns link_speed in Mbps 169262306a36Sopenharmony_ci */ 169362306a36Sopenharmony_ciint be_cmd_link_status_query(struct be_adapter *adapter, u16 *link_speed, 169462306a36Sopenharmony_ci u8 *link_status, u32 dom) 169562306a36Sopenharmony_ci{ 169662306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 169762306a36Sopenharmony_ci struct be_cmd_req_link_status *req; 169862306a36Sopenharmony_ci int status; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci if (link_status) 170362306a36Sopenharmony_ci *link_status = LINK_DOWN; 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 170662306a36Sopenharmony_ci if (!wrb) { 170762306a36Sopenharmony_ci status = -EBUSY; 170862306a36Sopenharmony_ci goto err; 170962306a36Sopenharmony_ci } 171062306a36Sopenharmony_ci req = embedded_payload(wrb); 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 171362306a36Sopenharmony_ci OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, 171462306a36Sopenharmony_ci sizeof(*req), wrb, NULL); 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci /* version 1 of the cmd is not supported only by BE2 */ 171762306a36Sopenharmony_ci if (!BE2_chip(adapter)) 171862306a36Sopenharmony_ci req->hdr.version = 1; 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci req->hdr.domain = dom; 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 172362306a36Sopenharmony_ci if (!status) { 172462306a36Sopenharmony_ci struct be_cmd_resp_link_status *resp = embedded_payload(wrb); 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci if (link_speed) { 172762306a36Sopenharmony_ci *link_speed = resp->link_speed ? 172862306a36Sopenharmony_ci le16_to_cpu(resp->link_speed) * 10 : 172962306a36Sopenharmony_ci be_mac_to_link_speed(resp->mac_speed); 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci if (!resp->logical_link_status) 173262306a36Sopenharmony_ci *link_speed = 0; 173362306a36Sopenharmony_ci } 173462306a36Sopenharmony_ci if (link_status) 173562306a36Sopenharmony_ci *link_status = resp->logical_link_status; 173662306a36Sopenharmony_ci } 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_cierr: 173962306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 174062306a36Sopenharmony_ci return status; 174162306a36Sopenharmony_ci} 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci/* Uses synchronous mcc */ 174462306a36Sopenharmony_ciint be_cmd_get_die_temperature(struct be_adapter *adapter) 174562306a36Sopenharmony_ci{ 174662306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 174762306a36Sopenharmony_ci struct be_cmd_req_get_cntl_addnl_attribs *req; 174862306a36Sopenharmony_ci int status = 0; 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 175362306a36Sopenharmony_ci if (!wrb) { 175462306a36Sopenharmony_ci status = -EBUSY; 175562306a36Sopenharmony_ci goto err; 175662306a36Sopenharmony_ci } 175762306a36Sopenharmony_ci req = embedded_payload(wrb); 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 176062306a36Sopenharmony_ci OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES, 176162306a36Sopenharmony_ci sizeof(*req), wrb, NULL); 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci status = be_mcc_notify(adapter); 176462306a36Sopenharmony_cierr: 176562306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 176662306a36Sopenharmony_ci return status; 176762306a36Sopenharmony_ci} 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci/* Uses synchronous mcc */ 177062306a36Sopenharmony_ciint be_cmd_get_fat_dump_len(struct be_adapter *adapter, u32 *dump_size) 177162306a36Sopenharmony_ci{ 177262306a36Sopenharmony_ci struct be_mcc_wrb wrb = {0}; 177362306a36Sopenharmony_ci struct be_cmd_req_get_fat *req; 177462306a36Sopenharmony_ci int status; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci req = embedded_payload(&wrb); 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 177962306a36Sopenharmony_ci OPCODE_COMMON_MANAGE_FAT, sizeof(*req), 178062306a36Sopenharmony_ci &wrb, NULL); 178162306a36Sopenharmony_ci req->fat_operation = cpu_to_le32(QUERY_FAT); 178262306a36Sopenharmony_ci status = be_cmd_notify_wait(adapter, &wrb); 178362306a36Sopenharmony_ci if (!status) { 178462306a36Sopenharmony_ci struct be_cmd_resp_get_fat *resp = embedded_payload(&wrb); 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci if (dump_size && resp->log_size) 178762306a36Sopenharmony_ci *dump_size = le32_to_cpu(resp->log_size) - 178862306a36Sopenharmony_ci sizeof(u32); 178962306a36Sopenharmony_ci } 179062306a36Sopenharmony_ci return status; 179162306a36Sopenharmony_ci} 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ciint be_cmd_get_fat_dump(struct be_adapter *adapter, u32 buf_len, void *buf) 179462306a36Sopenharmony_ci{ 179562306a36Sopenharmony_ci struct be_dma_mem get_fat_cmd; 179662306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 179762306a36Sopenharmony_ci struct be_cmd_req_get_fat *req; 179862306a36Sopenharmony_ci u32 offset = 0, total_size, buf_size, 179962306a36Sopenharmony_ci log_offset = sizeof(u32), payload_len; 180062306a36Sopenharmony_ci int status; 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci if (buf_len == 0) 180362306a36Sopenharmony_ci return 0; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci total_size = buf_len; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci get_fat_cmd.size = sizeof(struct be_cmd_req_get_fat) + 60 * 1024; 180862306a36Sopenharmony_ci get_fat_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, 180962306a36Sopenharmony_ci get_fat_cmd.size, 181062306a36Sopenharmony_ci &get_fat_cmd.dma, GFP_ATOMIC); 181162306a36Sopenharmony_ci if (!get_fat_cmd.va) 181262306a36Sopenharmony_ci return -ENOMEM; 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci while (total_size) { 181762306a36Sopenharmony_ci buf_size = min(total_size, (u32)60 * 1024); 181862306a36Sopenharmony_ci total_size -= buf_size; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 182162306a36Sopenharmony_ci if (!wrb) { 182262306a36Sopenharmony_ci status = -EBUSY; 182362306a36Sopenharmony_ci goto err; 182462306a36Sopenharmony_ci } 182562306a36Sopenharmony_ci req = get_fat_cmd.va; 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci payload_len = sizeof(struct be_cmd_req_get_fat) + buf_size; 182862306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 182962306a36Sopenharmony_ci OPCODE_COMMON_MANAGE_FAT, payload_len, 183062306a36Sopenharmony_ci wrb, &get_fat_cmd); 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci req->fat_operation = cpu_to_le32(RETRIEVE_FAT); 183362306a36Sopenharmony_ci req->read_log_offset = cpu_to_le32(log_offset); 183462306a36Sopenharmony_ci req->read_log_length = cpu_to_le32(buf_size); 183562306a36Sopenharmony_ci req->data_buffer_size = cpu_to_le32(buf_size); 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 183862306a36Sopenharmony_ci if (!status) { 183962306a36Sopenharmony_ci struct be_cmd_resp_get_fat *resp = get_fat_cmd.va; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci memcpy(buf + offset, 184262306a36Sopenharmony_ci resp->data_buffer, 184362306a36Sopenharmony_ci le32_to_cpu(resp->read_log_length)); 184462306a36Sopenharmony_ci } else { 184562306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "FAT Table Retrieve error\n"); 184662306a36Sopenharmony_ci goto err; 184762306a36Sopenharmony_ci } 184862306a36Sopenharmony_ci offset += buf_size; 184962306a36Sopenharmony_ci log_offset += buf_size; 185062306a36Sopenharmony_ci } 185162306a36Sopenharmony_cierr: 185262306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, get_fat_cmd.size, 185362306a36Sopenharmony_ci get_fat_cmd.va, get_fat_cmd.dma); 185462306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 185562306a36Sopenharmony_ci return status; 185662306a36Sopenharmony_ci} 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci/* Uses synchronous mcc */ 185962306a36Sopenharmony_ciint be_cmd_get_fw_ver(struct be_adapter *adapter) 186062306a36Sopenharmony_ci{ 186162306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 186262306a36Sopenharmony_ci struct be_cmd_req_get_fw_version *req; 186362306a36Sopenharmony_ci int status; 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 186862306a36Sopenharmony_ci if (!wrb) { 186962306a36Sopenharmony_ci status = -EBUSY; 187062306a36Sopenharmony_ci goto err; 187162306a36Sopenharmony_ci } 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci req = embedded_payload(wrb); 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 187662306a36Sopenharmony_ci OPCODE_COMMON_GET_FW_VERSION, sizeof(*req), wrb, 187762306a36Sopenharmony_ci NULL); 187862306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 187962306a36Sopenharmony_ci if (!status) { 188062306a36Sopenharmony_ci struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb); 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci strscpy(adapter->fw_ver, resp->firmware_version_string, 188362306a36Sopenharmony_ci sizeof(adapter->fw_ver)); 188462306a36Sopenharmony_ci strscpy(adapter->fw_on_flash, resp->fw_on_flash_version_string, 188562306a36Sopenharmony_ci sizeof(adapter->fw_on_flash)); 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_cierr: 188862306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 188962306a36Sopenharmony_ci return status; 189062306a36Sopenharmony_ci} 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci/* set the EQ delay interval of an EQ to specified value 189362306a36Sopenharmony_ci * Uses async mcc 189462306a36Sopenharmony_ci */ 189562306a36Sopenharmony_cistatic int __be_cmd_modify_eqd(struct be_adapter *adapter, 189662306a36Sopenharmony_ci struct be_set_eqd *set_eqd, int num) 189762306a36Sopenharmony_ci{ 189862306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 189962306a36Sopenharmony_ci struct be_cmd_req_modify_eq_delay *req; 190062306a36Sopenharmony_ci int status = 0, i; 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 190562306a36Sopenharmony_ci if (!wrb) { 190662306a36Sopenharmony_ci status = -EBUSY; 190762306a36Sopenharmony_ci goto err; 190862306a36Sopenharmony_ci } 190962306a36Sopenharmony_ci req = embedded_payload(wrb); 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 191262306a36Sopenharmony_ci OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req), wrb, 191362306a36Sopenharmony_ci NULL); 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci req->num_eq = cpu_to_le32(num); 191662306a36Sopenharmony_ci for (i = 0; i < num; i++) { 191762306a36Sopenharmony_ci req->set_eqd[i].eq_id = cpu_to_le32(set_eqd[i].eq_id); 191862306a36Sopenharmony_ci req->set_eqd[i].phase = 0; 191962306a36Sopenharmony_ci req->set_eqd[i].delay_multiplier = 192062306a36Sopenharmony_ci cpu_to_le32(set_eqd[i].delay_multiplier); 192162306a36Sopenharmony_ci } 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci status = be_mcc_notify(adapter); 192462306a36Sopenharmony_cierr: 192562306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 192662306a36Sopenharmony_ci return status; 192762306a36Sopenharmony_ci} 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ciint be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *set_eqd, 193062306a36Sopenharmony_ci int num) 193162306a36Sopenharmony_ci{ 193262306a36Sopenharmony_ci int num_eqs, i = 0; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci while (num) { 193562306a36Sopenharmony_ci num_eqs = min(num, 8); 193662306a36Sopenharmony_ci __be_cmd_modify_eqd(adapter, &set_eqd[i], num_eqs); 193762306a36Sopenharmony_ci i += num_eqs; 193862306a36Sopenharmony_ci num -= num_eqs; 193962306a36Sopenharmony_ci } 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci return 0; 194262306a36Sopenharmony_ci} 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci/* Uses sycnhronous mcc */ 194562306a36Sopenharmony_ciint be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, 194662306a36Sopenharmony_ci u32 num, u32 domain) 194762306a36Sopenharmony_ci{ 194862306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 194962306a36Sopenharmony_ci struct be_cmd_req_vlan_config *req; 195062306a36Sopenharmony_ci int status; 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 195562306a36Sopenharmony_ci if (!wrb) { 195662306a36Sopenharmony_ci status = -EBUSY; 195762306a36Sopenharmony_ci goto err; 195862306a36Sopenharmony_ci } 195962306a36Sopenharmony_ci req = embedded_payload(wrb); 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 196262306a36Sopenharmony_ci OPCODE_COMMON_NTWK_VLAN_CONFIG, sizeof(*req), 196362306a36Sopenharmony_ci wrb, NULL); 196462306a36Sopenharmony_ci req->hdr.domain = domain; 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci req->interface_id = if_id; 196762306a36Sopenharmony_ci req->untagged = BE_IF_FLAGS_UNTAGGED & be_if_cap_flags(adapter) ? 1 : 0; 196862306a36Sopenharmony_ci req->num_vlan = num; 196962306a36Sopenharmony_ci memcpy(req->normal_vlan, vtag_array, 197062306a36Sopenharmony_ci req->num_vlan * sizeof(vtag_array[0])); 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 197362306a36Sopenharmony_cierr: 197462306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 197562306a36Sopenharmony_ci return status; 197662306a36Sopenharmony_ci} 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_cistatic int __be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) 197962306a36Sopenharmony_ci{ 198062306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 198162306a36Sopenharmony_ci struct be_dma_mem *mem = &adapter->rx_filter; 198262306a36Sopenharmony_ci struct be_cmd_req_rx_filter *req = mem->va; 198362306a36Sopenharmony_ci int status; 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 198862306a36Sopenharmony_ci if (!wrb) { 198962306a36Sopenharmony_ci status = -EBUSY; 199062306a36Sopenharmony_ci goto err; 199162306a36Sopenharmony_ci } 199262306a36Sopenharmony_ci memset(req, 0, sizeof(*req)); 199362306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 199462306a36Sopenharmony_ci OPCODE_COMMON_NTWK_RX_FILTER, sizeof(*req), 199562306a36Sopenharmony_ci wrb, mem); 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci req->if_id = cpu_to_le32(adapter->if_handle); 199862306a36Sopenharmony_ci req->if_flags_mask = cpu_to_le32(flags); 199962306a36Sopenharmony_ci req->if_flags = (value == ON) ? req->if_flags_mask : 0; 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci if (flags & BE_IF_FLAGS_MULTICAST) { 200262306a36Sopenharmony_ci int i; 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci /* Reset mcast promisc mode if already set by setting mask 200562306a36Sopenharmony_ci * and not setting flags field 200662306a36Sopenharmony_ci */ 200762306a36Sopenharmony_ci req->if_flags_mask |= 200862306a36Sopenharmony_ci cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS & 200962306a36Sopenharmony_ci be_if_cap_flags(adapter)); 201062306a36Sopenharmony_ci req->mcast_num = cpu_to_le32(adapter->mc_count); 201162306a36Sopenharmony_ci for (i = 0; i < adapter->mc_count; i++) 201262306a36Sopenharmony_ci ether_addr_copy(req->mcast_mac[i].byte, 201362306a36Sopenharmony_ci adapter->mc_list[i].mac); 201462306a36Sopenharmony_ci } 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 201762306a36Sopenharmony_cierr: 201862306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 201962306a36Sopenharmony_ci return status; 202062306a36Sopenharmony_ci} 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ciint be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) 202362306a36Sopenharmony_ci{ 202462306a36Sopenharmony_ci struct device *dev = &adapter->pdev->dev; 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci if ((flags & be_if_cap_flags(adapter)) != flags) { 202762306a36Sopenharmony_ci dev_warn(dev, "Cannot set rx filter flags 0x%x\n", flags); 202862306a36Sopenharmony_ci dev_warn(dev, "Interface is capable of 0x%x flags only\n", 202962306a36Sopenharmony_ci be_if_cap_flags(adapter)); 203062306a36Sopenharmony_ci } 203162306a36Sopenharmony_ci flags &= be_if_cap_flags(adapter); 203262306a36Sopenharmony_ci if (!flags) 203362306a36Sopenharmony_ci return -ENOTSUPP; 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci return __be_cmd_rx_filter(adapter, flags, value); 203662306a36Sopenharmony_ci} 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci/* Uses synchrounous mcc */ 203962306a36Sopenharmony_ciint be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc) 204062306a36Sopenharmony_ci{ 204162306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 204262306a36Sopenharmony_ci struct be_cmd_req_set_flow_control *req; 204362306a36Sopenharmony_ci int status; 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci if (!be_cmd_allowed(adapter, OPCODE_COMMON_SET_FLOW_CONTROL, 204662306a36Sopenharmony_ci CMD_SUBSYSTEM_COMMON)) 204762306a36Sopenharmony_ci return -EPERM; 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 205262306a36Sopenharmony_ci if (!wrb) { 205362306a36Sopenharmony_ci status = -EBUSY; 205462306a36Sopenharmony_ci goto err; 205562306a36Sopenharmony_ci } 205662306a36Sopenharmony_ci req = embedded_payload(wrb); 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 205962306a36Sopenharmony_ci OPCODE_COMMON_SET_FLOW_CONTROL, sizeof(*req), 206062306a36Sopenharmony_ci wrb, NULL); 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci req->hdr.version = 1; 206362306a36Sopenharmony_ci req->tx_flow_control = cpu_to_le16((u16)tx_fc); 206462306a36Sopenharmony_ci req->rx_flow_control = cpu_to_le16((u16)rx_fc); 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_cierr: 206962306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci if (base_status(status) == MCC_STATUS_FEATURE_NOT_SUPPORTED) 207262306a36Sopenharmony_ci return -EOPNOTSUPP; 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci return status; 207562306a36Sopenharmony_ci} 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci/* Uses sycn mcc */ 207862306a36Sopenharmony_ciint be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc) 207962306a36Sopenharmony_ci{ 208062306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 208162306a36Sopenharmony_ci struct be_cmd_req_get_flow_control *req; 208262306a36Sopenharmony_ci int status; 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci if (!be_cmd_allowed(adapter, OPCODE_COMMON_GET_FLOW_CONTROL, 208562306a36Sopenharmony_ci CMD_SUBSYSTEM_COMMON)) 208662306a36Sopenharmony_ci return -EPERM; 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 209162306a36Sopenharmony_ci if (!wrb) { 209262306a36Sopenharmony_ci status = -EBUSY; 209362306a36Sopenharmony_ci goto err; 209462306a36Sopenharmony_ci } 209562306a36Sopenharmony_ci req = embedded_payload(wrb); 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 209862306a36Sopenharmony_ci OPCODE_COMMON_GET_FLOW_CONTROL, sizeof(*req), 209962306a36Sopenharmony_ci wrb, NULL); 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 210262306a36Sopenharmony_ci if (!status) { 210362306a36Sopenharmony_ci struct be_cmd_resp_get_flow_control *resp = 210462306a36Sopenharmony_ci embedded_payload(wrb); 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci *tx_fc = le16_to_cpu(resp->tx_flow_control); 210762306a36Sopenharmony_ci *rx_fc = le16_to_cpu(resp->rx_flow_control); 210862306a36Sopenharmony_ci } 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_cierr: 211162306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 211262306a36Sopenharmony_ci return status; 211362306a36Sopenharmony_ci} 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci/* Uses mbox */ 211662306a36Sopenharmony_ciint be_cmd_query_fw_cfg(struct be_adapter *adapter) 211762306a36Sopenharmony_ci{ 211862306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 211962306a36Sopenharmony_ci struct be_cmd_req_query_fw_cfg *req; 212062306a36Sopenharmony_ci int status; 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 212362306a36Sopenharmony_ci return -1; 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci wrb = wrb_from_mbox(adapter); 212662306a36Sopenharmony_ci req = embedded_payload(wrb); 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 212962306a36Sopenharmony_ci OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, 213062306a36Sopenharmony_ci sizeof(*req), wrb, NULL); 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 213362306a36Sopenharmony_ci if (!status) { 213462306a36Sopenharmony_ci struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb); 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci adapter->port_num = le32_to_cpu(resp->phys_port); 213762306a36Sopenharmony_ci adapter->function_mode = le32_to_cpu(resp->function_mode); 213862306a36Sopenharmony_ci adapter->function_caps = le32_to_cpu(resp->function_caps); 213962306a36Sopenharmony_ci adapter->asic_rev = le32_to_cpu(resp->asic_revision) & 0xFF; 214062306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, 214162306a36Sopenharmony_ci "FW config: function_mode=0x%x, function_caps=0x%x\n", 214262306a36Sopenharmony_ci adapter->function_mode, adapter->function_caps); 214362306a36Sopenharmony_ci } 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 214662306a36Sopenharmony_ci return status; 214762306a36Sopenharmony_ci} 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci/* Uses mbox */ 215062306a36Sopenharmony_ciint be_cmd_reset_function(struct be_adapter *adapter) 215162306a36Sopenharmony_ci{ 215262306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 215362306a36Sopenharmony_ci struct be_cmd_req_hdr *req; 215462306a36Sopenharmony_ci int status; 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci if (lancer_chip(adapter)) { 215762306a36Sopenharmony_ci iowrite32(SLI_PORT_CONTROL_IP_MASK, 215862306a36Sopenharmony_ci adapter->db + SLIPORT_CONTROL_OFFSET); 215962306a36Sopenharmony_ci status = lancer_wait_ready(adapter); 216062306a36Sopenharmony_ci if (status) 216162306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 216262306a36Sopenharmony_ci "Adapter in non recoverable error\n"); 216362306a36Sopenharmony_ci return status; 216462306a36Sopenharmony_ci } 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 216762306a36Sopenharmony_ci return -1; 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci wrb = wrb_from_mbox(adapter); 217062306a36Sopenharmony_ci req = embedded_payload(wrb); 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(req, CMD_SUBSYSTEM_COMMON, 217362306a36Sopenharmony_ci OPCODE_COMMON_FUNCTION_RESET, sizeof(*req), wrb, 217462306a36Sopenharmony_ci NULL); 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 217962306a36Sopenharmony_ci return status; 218062306a36Sopenharmony_ci} 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ciint be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, 218362306a36Sopenharmony_ci u32 rss_hash_opts, u16 table_size, const u8 *rss_hkey) 218462306a36Sopenharmony_ci{ 218562306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 218662306a36Sopenharmony_ci struct be_cmd_req_rss_config *req; 218762306a36Sopenharmony_ci int status; 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci if (!(be_if_cap_flags(adapter) & BE_IF_FLAGS_RSS)) 219062306a36Sopenharmony_ci return 0; 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 219562306a36Sopenharmony_ci if (!wrb) { 219662306a36Sopenharmony_ci status = -EBUSY; 219762306a36Sopenharmony_ci goto err; 219862306a36Sopenharmony_ci } 219962306a36Sopenharmony_ci req = embedded_payload(wrb); 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, 220262306a36Sopenharmony_ci OPCODE_ETH_RSS_CONFIG, sizeof(*req), wrb, NULL); 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci req->if_id = cpu_to_le32(adapter->if_handle); 220562306a36Sopenharmony_ci req->enable_rss = cpu_to_le16(rss_hash_opts); 220662306a36Sopenharmony_ci req->cpu_table_size_log2 = cpu_to_le16(fls(table_size) - 1); 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci if (!BEx_chip(adapter)) 220962306a36Sopenharmony_ci req->hdr.version = 1; 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci memcpy(req->cpu_table, rsstable, table_size); 221262306a36Sopenharmony_ci memcpy(req->hash, rss_hkey, RSS_HASH_KEY_LEN); 221362306a36Sopenharmony_ci be_dws_cpu_to_le(req->hash, sizeof(req->hash)); 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 221662306a36Sopenharmony_cierr: 221762306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 221862306a36Sopenharmony_ci return status; 221962306a36Sopenharmony_ci} 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci/* Uses sync mcc */ 222262306a36Sopenharmony_ciint be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num, 222362306a36Sopenharmony_ci u8 bcn, u8 sts, u8 state) 222462306a36Sopenharmony_ci{ 222562306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 222662306a36Sopenharmony_ci struct be_cmd_req_enable_disable_beacon *req; 222762306a36Sopenharmony_ci int status; 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 223262306a36Sopenharmony_ci if (!wrb) { 223362306a36Sopenharmony_ci status = -EBUSY; 223462306a36Sopenharmony_ci goto err; 223562306a36Sopenharmony_ci } 223662306a36Sopenharmony_ci req = embedded_payload(wrb); 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 223962306a36Sopenharmony_ci OPCODE_COMMON_ENABLE_DISABLE_BEACON, 224062306a36Sopenharmony_ci sizeof(*req), wrb, NULL); 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci req->port_num = port_num; 224362306a36Sopenharmony_ci req->beacon_state = state; 224462306a36Sopenharmony_ci req->beacon_duration = bcn; 224562306a36Sopenharmony_ci req->status_duration = sts; 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_cierr: 225062306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 225162306a36Sopenharmony_ci return status; 225262306a36Sopenharmony_ci} 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci/* Uses sync mcc */ 225562306a36Sopenharmony_ciint be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, u32 *state) 225662306a36Sopenharmony_ci{ 225762306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 225862306a36Sopenharmony_ci struct be_cmd_req_get_beacon_state *req; 225962306a36Sopenharmony_ci int status; 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 226462306a36Sopenharmony_ci if (!wrb) { 226562306a36Sopenharmony_ci status = -EBUSY; 226662306a36Sopenharmony_ci goto err; 226762306a36Sopenharmony_ci } 226862306a36Sopenharmony_ci req = embedded_payload(wrb); 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 227162306a36Sopenharmony_ci OPCODE_COMMON_GET_BEACON_STATE, sizeof(*req), 227262306a36Sopenharmony_ci wrb, NULL); 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci req->port_num = port_num; 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 227762306a36Sopenharmony_ci if (!status) { 227862306a36Sopenharmony_ci struct be_cmd_resp_get_beacon_state *resp = 227962306a36Sopenharmony_ci embedded_payload(wrb); 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci *state = resp->beacon_state; 228262306a36Sopenharmony_ci } 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_cierr: 228562306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 228662306a36Sopenharmony_ci return status; 228762306a36Sopenharmony_ci} 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_ci/* Uses sync mcc */ 229062306a36Sopenharmony_ciint be_cmd_read_port_transceiver_data(struct be_adapter *adapter, 229162306a36Sopenharmony_ci u8 page_num, u32 off, u32 len, u8 *data) 229262306a36Sopenharmony_ci{ 229362306a36Sopenharmony_ci struct be_dma_mem cmd; 229462306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 229562306a36Sopenharmony_ci struct be_cmd_req_port_type *req; 229662306a36Sopenharmony_ci int status; 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_ci if (page_num > TR_PAGE_A2) 229962306a36Sopenharmony_ci return -EINVAL; 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci cmd.size = sizeof(struct be_cmd_resp_port_type); 230262306a36Sopenharmony_ci cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, 230362306a36Sopenharmony_ci GFP_ATOMIC); 230462306a36Sopenharmony_ci if (!cmd.va) { 230562306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Memory allocation failed\n"); 230662306a36Sopenharmony_ci return -ENOMEM; 230762306a36Sopenharmony_ci } 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 231262306a36Sopenharmony_ci if (!wrb) { 231362306a36Sopenharmony_ci status = -EBUSY; 231462306a36Sopenharmony_ci goto err; 231562306a36Sopenharmony_ci } 231662306a36Sopenharmony_ci req = cmd.va; 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 231962306a36Sopenharmony_ci OPCODE_COMMON_READ_TRANSRECV_DATA, 232062306a36Sopenharmony_ci cmd.size, wrb, &cmd); 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci req->port = cpu_to_le32(adapter->hba_port_num); 232362306a36Sopenharmony_ci req->page_num = cpu_to_le32(page_num); 232462306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 232562306a36Sopenharmony_ci if (!status && len > 0) { 232662306a36Sopenharmony_ci struct be_cmd_resp_port_type *resp = cmd.va; 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci memcpy(data, resp->page_data + off, len); 232962306a36Sopenharmony_ci } 233062306a36Sopenharmony_cierr: 233162306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 233262306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, cmd.dma); 233362306a36Sopenharmony_ci return status; 233462306a36Sopenharmony_ci} 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_cistatic int lancer_cmd_write_object(struct be_adapter *adapter, 233762306a36Sopenharmony_ci struct be_dma_mem *cmd, u32 data_size, 233862306a36Sopenharmony_ci u32 data_offset, const char *obj_name, 233962306a36Sopenharmony_ci u32 *data_written, u8 *change_status, 234062306a36Sopenharmony_ci u8 *addn_status) 234162306a36Sopenharmony_ci{ 234262306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 234362306a36Sopenharmony_ci struct lancer_cmd_req_write_object *req; 234462306a36Sopenharmony_ci struct lancer_cmd_resp_write_object *resp; 234562306a36Sopenharmony_ci void *ctxt = NULL; 234662306a36Sopenharmony_ci int status; 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 234962306a36Sopenharmony_ci adapter->flash_status = 0; 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 235262306a36Sopenharmony_ci if (!wrb) { 235362306a36Sopenharmony_ci status = -EBUSY; 235462306a36Sopenharmony_ci goto err_unlock; 235562306a36Sopenharmony_ci } 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci req = embedded_payload(wrb); 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 236062306a36Sopenharmony_ci OPCODE_COMMON_WRITE_OBJECT, 236162306a36Sopenharmony_ci sizeof(struct lancer_cmd_req_write_object), wrb, 236262306a36Sopenharmony_ci NULL); 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci ctxt = &req->context; 236562306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_lancer_write_obj_context, 236662306a36Sopenharmony_ci write_length, ctxt, data_size); 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci if (data_size == 0) 236962306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_lancer_write_obj_context, 237062306a36Sopenharmony_ci eof, ctxt, 1); 237162306a36Sopenharmony_ci else 237262306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_lancer_write_obj_context, 237362306a36Sopenharmony_ci eof, ctxt, 0); 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci be_dws_cpu_to_le(ctxt, sizeof(req->context)); 237662306a36Sopenharmony_ci req->write_offset = cpu_to_le32(data_offset); 237762306a36Sopenharmony_ci strscpy(req->object_name, obj_name, sizeof(req->object_name)); 237862306a36Sopenharmony_ci req->descriptor_count = cpu_to_le32(1); 237962306a36Sopenharmony_ci req->buf_len = cpu_to_le32(data_size); 238062306a36Sopenharmony_ci req->addr_low = cpu_to_le32((cmd->dma + 238162306a36Sopenharmony_ci sizeof(struct lancer_cmd_req_write_object)) 238262306a36Sopenharmony_ci & 0xFFFFFFFF); 238362306a36Sopenharmony_ci req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma + 238462306a36Sopenharmony_ci sizeof(struct lancer_cmd_req_write_object))); 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci status = be_mcc_notify(adapter); 238762306a36Sopenharmony_ci if (status) 238862306a36Sopenharmony_ci goto err_unlock; 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci if (!wait_for_completion_timeout(&adapter->et_cmd_compl, 239362306a36Sopenharmony_ci msecs_to_jiffies(60000))) 239462306a36Sopenharmony_ci status = -ETIMEDOUT; 239562306a36Sopenharmony_ci else 239662306a36Sopenharmony_ci status = adapter->flash_status; 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci resp = embedded_payload(wrb); 239962306a36Sopenharmony_ci if (!status) { 240062306a36Sopenharmony_ci *data_written = le32_to_cpu(resp->actual_write_len); 240162306a36Sopenharmony_ci *change_status = resp->change_status; 240262306a36Sopenharmony_ci } else { 240362306a36Sopenharmony_ci *addn_status = resp->additional_status; 240462306a36Sopenharmony_ci } 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci return status; 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_cierr_unlock: 240962306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 241062306a36Sopenharmony_ci return status; 241162306a36Sopenharmony_ci} 241262306a36Sopenharmony_ci 241362306a36Sopenharmony_ciint be_cmd_query_cable_type(struct be_adapter *adapter) 241462306a36Sopenharmony_ci{ 241562306a36Sopenharmony_ci u8 page_data[PAGE_DATA_LEN]; 241662306a36Sopenharmony_ci int status; 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0, 241962306a36Sopenharmony_ci 0, PAGE_DATA_LEN, page_data); 242062306a36Sopenharmony_ci if (!status) { 242162306a36Sopenharmony_ci switch (adapter->phy.interface_type) { 242262306a36Sopenharmony_ci case PHY_TYPE_QSFP: 242362306a36Sopenharmony_ci adapter->phy.cable_type = 242462306a36Sopenharmony_ci page_data[QSFP_PLUS_CABLE_TYPE_OFFSET]; 242562306a36Sopenharmony_ci break; 242662306a36Sopenharmony_ci case PHY_TYPE_SFP_PLUS_10GB: 242762306a36Sopenharmony_ci adapter->phy.cable_type = 242862306a36Sopenharmony_ci page_data[SFP_PLUS_CABLE_TYPE_OFFSET]; 242962306a36Sopenharmony_ci break; 243062306a36Sopenharmony_ci default: 243162306a36Sopenharmony_ci adapter->phy.cable_type = 0; 243262306a36Sopenharmony_ci break; 243362306a36Sopenharmony_ci } 243462306a36Sopenharmony_ci } 243562306a36Sopenharmony_ci return status; 243662306a36Sopenharmony_ci} 243762306a36Sopenharmony_ci 243862306a36Sopenharmony_ciint be_cmd_query_sfp_info(struct be_adapter *adapter) 243962306a36Sopenharmony_ci{ 244062306a36Sopenharmony_ci u8 page_data[PAGE_DATA_LEN]; 244162306a36Sopenharmony_ci int status; 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_ci status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0, 244462306a36Sopenharmony_ci 0, PAGE_DATA_LEN, page_data); 244562306a36Sopenharmony_ci if (!status) { 244662306a36Sopenharmony_ci strscpy(adapter->phy.vendor_name, page_data + 244762306a36Sopenharmony_ci SFP_VENDOR_NAME_OFFSET, SFP_VENDOR_NAME_LEN - 1); 244862306a36Sopenharmony_ci strscpy(adapter->phy.vendor_pn, 244962306a36Sopenharmony_ci page_data + SFP_VENDOR_PN_OFFSET, 245062306a36Sopenharmony_ci SFP_VENDOR_NAME_LEN - 1); 245162306a36Sopenharmony_ci } 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci return status; 245462306a36Sopenharmony_ci} 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_cistatic int lancer_cmd_delete_object(struct be_adapter *adapter, 245762306a36Sopenharmony_ci const char *obj_name) 245862306a36Sopenharmony_ci{ 245962306a36Sopenharmony_ci struct lancer_cmd_req_delete_object *req; 246062306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 246162306a36Sopenharmony_ci int status; 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 246662306a36Sopenharmony_ci if (!wrb) { 246762306a36Sopenharmony_ci status = -EBUSY; 246862306a36Sopenharmony_ci goto err; 246962306a36Sopenharmony_ci } 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_ci req = embedded_payload(wrb); 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 247462306a36Sopenharmony_ci OPCODE_COMMON_DELETE_OBJECT, 247562306a36Sopenharmony_ci sizeof(*req), wrb, NULL); 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci strscpy(req->object_name, obj_name, sizeof(req->object_name)); 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 248062306a36Sopenharmony_cierr: 248162306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 248262306a36Sopenharmony_ci return status; 248362306a36Sopenharmony_ci} 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ciint lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd, 248662306a36Sopenharmony_ci u32 data_size, u32 data_offset, const char *obj_name, 248762306a36Sopenharmony_ci u32 *data_read, u32 *eof, u8 *addn_status) 248862306a36Sopenharmony_ci{ 248962306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 249062306a36Sopenharmony_ci struct lancer_cmd_req_read_object *req; 249162306a36Sopenharmony_ci struct lancer_cmd_resp_read_object *resp; 249262306a36Sopenharmony_ci int status; 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 249762306a36Sopenharmony_ci if (!wrb) { 249862306a36Sopenharmony_ci status = -EBUSY; 249962306a36Sopenharmony_ci goto err_unlock; 250062306a36Sopenharmony_ci } 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci req = embedded_payload(wrb); 250362306a36Sopenharmony_ci 250462306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 250562306a36Sopenharmony_ci OPCODE_COMMON_READ_OBJECT, 250662306a36Sopenharmony_ci sizeof(struct lancer_cmd_req_read_object), wrb, 250762306a36Sopenharmony_ci NULL); 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci req->desired_read_len = cpu_to_le32(data_size); 251062306a36Sopenharmony_ci req->read_offset = cpu_to_le32(data_offset); 251162306a36Sopenharmony_ci strcpy(req->object_name, obj_name); 251262306a36Sopenharmony_ci req->descriptor_count = cpu_to_le32(1); 251362306a36Sopenharmony_ci req->buf_len = cpu_to_le32(data_size); 251462306a36Sopenharmony_ci req->addr_low = cpu_to_le32((cmd->dma & 0xFFFFFFFF)); 251562306a36Sopenharmony_ci req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma)); 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci resp = embedded_payload(wrb); 252062306a36Sopenharmony_ci if (!status) { 252162306a36Sopenharmony_ci *data_read = le32_to_cpu(resp->actual_read_len); 252262306a36Sopenharmony_ci *eof = le32_to_cpu(resp->eof); 252362306a36Sopenharmony_ci } else { 252462306a36Sopenharmony_ci *addn_status = resp->additional_status; 252562306a36Sopenharmony_ci } 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_cierr_unlock: 252862306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 252962306a36Sopenharmony_ci return status; 253062306a36Sopenharmony_ci} 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_cistatic int be_cmd_write_flashrom(struct be_adapter *adapter, 253362306a36Sopenharmony_ci struct be_dma_mem *cmd, u32 flash_type, 253462306a36Sopenharmony_ci u32 flash_opcode, u32 img_offset, u32 buf_size) 253562306a36Sopenharmony_ci{ 253662306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 253762306a36Sopenharmony_ci struct be_cmd_write_flashrom *req; 253862306a36Sopenharmony_ci int status; 253962306a36Sopenharmony_ci 254062306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 254162306a36Sopenharmony_ci adapter->flash_status = 0; 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 254462306a36Sopenharmony_ci if (!wrb) { 254562306a36Sopenharmony_ci status = -EBUSY; 254662306a36Sopenharmony_ci goto err_unlock; 254762306a36Sopenharmony_ci } 254862306a36Sopenharmony_ci req = cmd->va; 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 255162306a36Sopenharmony_ci OPCODE_COMMON_WRITE_FLASHROM, cmd->size, wrb, 255262306a36Sopenharmony_ci cmd); 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_ci req->params.op_type = cpu_to_le32(flash_type); 255562306a36Sopenharmony_ci if (flash_type == OPTYPE_OFFSET_SPECIFIED) 255662306a36Sopenharmony_ci req->params.offset = cpu_to_le32(img_offset); 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci req->params.op_code = cpu_to_le32(flash_opcode); 255962306a36Sopenharmony_ci req->params.data_buf_size = cpu_to_le32(buf_size); 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci status = be_mcc_notify(adapter); 256262306a36Sopenharmony_ci if (status) 256362306a36Sopenharmony_ci goto err_unlock; 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci if (!wait_for_completion_timeout(&adapter->et_cmd_compl, 256862306a36Sopenharmony_ci msecs_to_jiffies(40000))) 256962306a36Sopenharmony_ci status = -ETIMEDOUT; 257062306a36Sopenharmony_ci else 257162306a36Sopenharmony_ci status = adapter->flash_status; 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci return status; 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_cierr_unlock: 257662306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 257762306a36Sopenharmony_ci return status; 257862306a36Sopenharmony_ci} 257962306a36Sopenharmony_ci 258062306a36Sopenharmony_cistatic int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, 258162306a36Sopenharmony_ci u16 img_optype, u32 img_offset, u32 crc_offset) 258262306a36Sopenharmony_ci{ 258362306a36Sopenharmony_ci struct be_cmd_read_flash_crc *req; 258462306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 258562306a36Sopenharmony_ci int status; 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 259062306a36Sopenharmony_ci if (!wrb) { 259162306a36Sopenharmony_ci status = -EBUSY; 259262306a36Sopenharmony_ci goto err; 259362306a36Sopenharmony_ci } 259462306a36Sopenharmony_ci req = embedded_payload(wrb); 259562306a36Sopenharmony_ci 259662306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 259762306a36Sopenharmony_ci OPCODE_COMMON_READ_FLASHROM, sizeof(*req), 259862306a36Sopenharmony_ci wrb, NULL); 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_ci req->params.op_type = cpu_to_le32(img_optype); 260162306a36Sopenharmony_ci if (img_optype == OPTYPE_OFFSET_SPECIFIED) 260262306a36Sopenharmony_ci req->params.offset = cpu_to_le32(img_offset + crc_offset); 260362306a36Sopenharmony_ci else 260462306a36Sopenharmony_ci req->params.offset = cpu_to_le32(crc_offset); 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_ci req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT); 260762306a36Sopenharmony_ci req->params.data_buf_size = cpu_to_le32(0x4); 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 261062306a36Sopenharmony_ci if (!status) 261162306a36Sopenharmony_ci memcpy(flashed_crc, req->crc, 4); 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_cierr: 261462306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 261562306a36Sopenharmony_ci return status; 261662306a36Sopenharmony_ci} 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_cistatic char flash_cookie[2][16] = {"*** SE FLAS", "H DIRECTORY *** "}; 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_cistatic bool phy_flashing_required(struct be_adapter *adapter) 262162306a36Sopenharmony_ci{ 262262306a36Sopenharmony_ci return (adapter->phy.phy_type == PHY_TYPE_TN_8022 && 262362306a36Sopenharmony_ci adapter->phy.interface_type == PHY_TYPE_BASET_10GB); 262462306a36Sopenharmony_ci} 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_cistatic bool is_comp_in_ufi(struct be_adapter *adapter, 262762306a36Sopenharmony_ci struct flash_section_info *fsec, int type) 262862306a36Sopenharmony_ci{ 262962306a36Sopenharmony_ci int i = 0, img_type = 0; 263062306a36Sopenharmony_ci struct flash_section_info_g2 *fsec_g2 = NULL; 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_ci if (BE2_chip(adapter)) 263362306a36Sopenharmony_ci fsec_g2 = (struct flash_section_info_g2 *)fsec; 263462306a36Sopenharmony_ci 263562306a36Sopenharmony_ci for (i = 0; i < MAX_FLASH_COMP; i++) { 263662306a36Sopenharmony_ci if (fsec_g2) 263762306a36Sopenharmony_ci img_type = le32_to_cpu(fsec_g2->fsec_entry[i].type); 263862306a36Sopenharmony_ci else 263962306a36Sopenharmony_ci img_type = le32_to_cpu(fsec->fsec_entry[i].type); 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci if (img_type == type) 264262306a36Sopenharmony_ci return true; 264362306a36Sopenharmony_ci } 264462306a36Sopenharmony_ci return false; 264562306a36Sopenharmony_ci} 264662306a36Sopenharmony_ci 264762306a36Sopenharmony_cistatic struct flash_section_info *get_fsec_info(struct be_adapter *adapter, 264862306a36Sopenharmony_ci int header_size, 264962306a36Sopenharmony_ci const struct firmware *fw) 265062306a36Sopenharmony_ci{ 265162306a36Sopenharmony_ci struct flash_section_info *fsec = NULL; 265262306a36Sopenharmony_ci const u8 *p = fw->data; 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci p += header_size; 265562306a36Sopenharmony_ci while (p < (fw->data + fw->size)) { 265662306a36Sopenharmony_ci fsec = (struct flash_section_info *)p; 265762306a36Sopenharmony_ci if (!memcmp(flash_cookie, fsec->cookie, sizeof(flash_cookie))) 265862306a36Sopenharmony_ci return fsec; 265962306a36Sopenharmony_ci p += 32; 266062306a36Sopenharmony_ci } 266162306a36Sopenharmony_ci return NULL; 266262306a36Sopenharmony_ci} 266362306a36Sopenharmony_ci 266462306a36Sopenharmony_cistatic int be_check_flash_crc(struct be_adapter *adapter, const u8 *p, 266562306a36Sopenharmony_ci u32 img_offset, u32 img_size, int hdr_size, 266662306a36Sopenharmony_ci u16 img_optype, bool *crc_match) 266762306a36Sopenharmony_ci{ 266862306a36Sopenharmony_ci u32 crc_offset; 266962306a36Sopenharmony_ci int status; 267062306a36Sopenharmony_ci u8 crc[4]; 267162306a36Sopenharmony_ci 267262306a36Sopenharmony_ci status = be_cmd_get_flash_crc(adapter, crc, img_optype, img_offset, 267362306a36Sopenharmony_ci img_size - 4); 267462306a36Sopenharmony_ci if (status) 267562306a36Sopenharmony_ci return status; 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci crc_offset = hdr_size + img_offset + img_size - 4; 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci /* Skip flashing, if crc of flashed region matches */ 268062306a36Sopenharmony_ci if (!memcmp(crc, p + crc_offset, 4)) 268162306a36Sopenharmony_ci *crc_match = true; 268262306a36Sopenharmony_ci else 268362306a36Sopenharmony_ci *crc_match = false; 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ci return status; 268662306a36Sopenharmony_ci} 268762306a36Sopenharmony_ci 268862306a36Sopenharmony_cistatic int be_flash(struct be_adapter *adapter, const u8 *img, 268962306a36Sopenharmony_ci struct be_dma_mem *flash_cmd, int optype, int img_size, 269062306a36Sopenharmony_ci u32 img_offset) 269162306a36Sopenharmony_ci{ 269262306a36Sopenharmony_ci u32 flash_op, num_bytes, total_bytes = img_size, bytes_sent = 0; 269362306a36Sopenharmony_ci struct be_cmd_write_flashrom *req = flash_cmd->va; 269462306a36Sopenharmony_ci int status; 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_ci while (total_bytes) { 269762306a36Sopenharmony_ci num_bytes = min_t(u32, 32 * 1024, total_bytes); 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_ci total_bytes -= num_bytes; 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci if (!total_bytes) { 270262306a36Sopenharmony_ci if (optype == OPTYPE_PHY_FW) 270362306a36Sopenharmony_ci flash_op = FLASHROM_OPER_PHY_FLASH; 270462306a36Sopenharmony_ci else 270562306a36Sopenharmony_ci flash_op = FLASHROM_OPER_FLASH; 270662306a36Sopenharmony_ci } else { 270762306a36Sopenharmony_ci if (optype == OPTYPE_PHY_FW) 270862306a36Sopenharmony_ci flash_op = FLASHROM_OPER_PHY_SAVE; 270962306a36Sopenharmony_ci else 271062306a36Sopenharmony_ci flash_op = FLASHROM_OPER_SAVE; 271162306a36Sopenharmony_ci } 271262306a36Sopenharmony_ci 271362306a36Sopenharmony_ci memcpy(req->data_buf, img, num_bytes); 271462306a36Sopenharmony_ci img += num_bytes; 271562306a36Sopenharmony_ci status = be_cmd_write_flashrom(adapter, flash_cmd, optype, 271662306a36Sopenharmony_ci flash_op, img_offset + 271762306a36Sopenharmony_ci bytes_sent, num_bytes); 271862306a36Sopenharmony_ci if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST && 271962306a36Sopenharmony_ci optype == OPTYPE_PHY_FW) 272062306a36Sopenharmony_ci break; 272162306a36Sopenharmony_ci else if (status) 272262306a36Sopenharmony_ci return status; 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci bytes_sent += num_bytes; 272562306a36Sopenharmony_ci } 272662306a36Sopenharmony_ci return 0; 272762306a36Sopenharmony_ci} 272862306a36Sopenharmony_ci 272962306a36Sopenharmony_ci#define NCSI_UPDATE_LOG "NCSI section update is not supported in FW ver %s\n" 273062306a36Sopenharmony_cistatic bool be_fw_ncsi_supported(char *ver) 273162306a36Sopenharmony_ci{ 273262306a36Sopenharmony_ci int v1[4] = {3, 102, 148, 0}; /* Min ver that supports NCSI FW */ 273362306a36Sopenharmony_ci int v2[4]; 273462306a36Sopenharmony_ci int i; 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci if (sscanf(ver, "%d.%d.%d.%d", &v2[0], &v2[1], &v2[2], &v2[3]) != 4) 273762306a36Sopenharmony_ci return false; 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 274062306a36Sopenharmony_ci if (v1[i] < v2[i]) 274162306a36Sopenharmony_ci return true; 274262306a36Sopenharmony_ci else if (v1[i] > v2[i]) 274362306a36Sopenharmony_ci return false; 274462306a36Sopenharmony_ci } 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_ci return true; 274762306a36Sopenharmony_ci} 274862306a36Sopenharmony_ci 274962306a36Sopenharmony_ci/* For BE2, BE3 and BE3-R */ 275062306a36Sopenharmony_cistatic int be_flash_BEx(struct be_adapter *adapter, 275162306a36Sopenharmony_ci const struct firmware *fw, 275262306a36Sopenharmony_ci struct be_dma_mem *flash_cmd, int num_of_images) 275362306a36Sopenharmony_ci{ 275462306a36Sopenharmony_ci int img_hdrs_size = (num_of_images * sizeof(struct image_hdr)); 275562306a36Sopenharmony_ci struct device *dev = &adapter->pdev->dev; 275662306a36Sopenharmony_ci struct flash_section_info *fsec = NULL; 275762306a36Sopenharmony_ci int status, i, filehdr_size, num_comp; 275862306a36Sopenharmony_ci const struct flash_comp *pflashcomp; 275962306a36Sopenharmony_ci bool crc_match; 276062306a36Sopenharmony_ci const u8 *p; 276162306a36Sopenharmony_ci 276262306a36Sopenharmony_ci static const struct flash_comp gen3_flash_types[] = { 276362306a36Sopenharmony_ci { BE3_ISCSI_PRIMARY_IMAGE_START, OPTYPE_ISCSI_ACTIVE, 276462306a36Sopenharmony_ci BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_ISCSI}, 276562306a36Sopenharmony_ci { BE3_REDBOOT_START, OPTYPE_REDBOOT, 276662306a36Sopenharmony_ci BE3_REDBOOT_COMP_MAX_SIZE, IMAGE_BOOT_CODE}, 276762306a36Sopenharmony_ci { BE3_ISCSI_BIOS_START, OPTYPE_BIOS, 276862306a36Sopenharmony_ci BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_ISCSI}, 276962306a36Sopenharmony_ci { BE3_PXE_BIOS_START, OPTYPE_PXE_BIOS, 277062306a36Sopenharmony_ci BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_PXE}, 277162306a36Sopenharmony_ci { BE3_FCOE_BIOS_START, OPTYPE_FCOE_BIOS, 277262306a36Sopenharmony_ci BE3_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_FCOE}, 277362306a36Sopenharmony_ci { BE3_ISCSI_BACKUP_IMAGE_START, OPTYPE_ISCSI_BACKUP, 277462306a36Sopenharmony_ci BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_ISCSI}, 277562306a36Sopenharmony_ci { BE3_FCOE_PRIMARY_IMAGE_START, OPTYPE_FCOE_FW_ACTIVE, 277662306a36Sopenharmony_ci BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_FCOE}, 277762306a36Sopenharmony_ci { BE3_FCOE_BACKUP_IMAGE_START, OPTYPE_FCOE_FW_BACKUP, 277862306a36Sopenharmony_ci BE3_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_FCOE}, 277962306a36Sopenharmony_ci { BE3_NCSI_START, OPTYPE_NCSI_FW, 278062306a36Sopenharmony_ci BE3_NCSI_COMP_MAX_SIZE, IMAGE_NCSI}, 278162306a36Sopenharmony_ci { BE3_PHY_FW_START, OPTYPE_PHY_FW, 278262306a36Sopenharmony_ci BE3_PHY_FW_COMP_MAX_SIZE, IMAGE_FIRMWARE_PHY} 278362306a36Sopenharmony_ci }; 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_ci static const struct flash_comp gen2_flash_types[] = { 278662306a36Sopenharmony_ci { BE2_ISCSI_PRIMARY_IMAGE_START, OPTYPE_ISCSI_ACTIVE, 278762306a36Sopenharmony_ci BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_ISCSI}, 278862306a36Sopenharmony_ci { BE2_REDBOOT_START, OPTYPE_REDBOOT, 278962306a36Sopenharmony_ci BE2_REDBOOT_COMP_MAX_SIZE, IMAGE_BOOT_CODE}, 279062306a36Sopenharmony_ci { BE2_ISCSI_BIOS_START, OPTYPE_BIOS, 279162306a36Sopenharmony_ci BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_ISCSI}, 279262306a36Sopenharmony_ci { BE2_PXE_BIOS_START, OPTYPE_PXE_BIOS, 279362306a36Sopenharmony_ci BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_PXE}, 279462306a36Sopenharmony_ci { BE2_FCOE_BIOS_START, OPTYPE_FCOE_BIOS, 279562306a36Sopenharmony_ci BE2_BIOS_COMP_MAX_SIZE, IMAGE_OPTION_ROM_FCOE}, 279662306a36Sopenharmony_ci { BE2_ISCSI_BACKUP_IMAGE_START, OPTYPE_ISCSI_BACKUP, 279762306a36Sopenharmony_ci BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_ISCSI}, 279862306a36Sopenharmony_ci { BE2_FCOE_PRIMARY_IMAGE_START, OPTYPE_FCOE_FW_ACTIVE, 279962306a36Sopenharmony_ci BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_FCOE}, 280062306a36Sopenharmony_ci { BE2_FCOE_BACKUP_IMAGE_START, OPTYPE_FCOE_FW_BACKUP, 280162306a36Sopenharmony_ci BE2_COMP_MAX_SIZE, IMAGE_FIRMWARE_BACKUP_FCOE} 280262306a36Sopenharmony_ci }; 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci if (BE3_chip(adapter)) { 280562306a36Sopenharmony_ci pflashcomp = gen3_flash_types; 280662306a36Sopenharmony_ci filehdr_size = sizeof(struct flash_file_hdr_g3); 280762306a36Sopenharmony_ci num_comp = ARRAY_SIZE(gen3_flash_types); 280862306a36Sopenharmony_ci } else { 280962306a36Sopenharmony_ci pflashcomp = gen2_flash_types; 281062306a36Sopenharmony_ci filehdr_size = sizeof(struct flash_file_hdr_g2); 281162306a36Sopenharmony_ci num_comp = ARRAY_SIZE(gen2_flash_types); 281262306a36Sopenharmony_ci img_hdrs_size = 0; 281362306a36Sopenharmony_ci } 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci /* Get flash section info*/ 281662306a36Sopenharmony_ci fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw); 281762306a36Sopenharmony_ci if (!fsec) { 281862306a36Sopenharmony_ci dev_err(dev, "Invalid Cookie. FW image may be corrupted\n"); 281962306a36Sopenharmony_ci return -1; 282062306a36Sopenharmony_ci } 282162306a36Sopenharmony_ci for (i = 0; i < num_comp; i++) { 282262306a36Sopenharmony_ci if (!is_comp_in_ufi(adapter, fsec, pflashcomp[i].img_type)) 282362306a36Sopenharmony_ci continue; 282462306a36Sopenharmony_ci 282562306a36Sopenharmony_ci if ((pflashcomp[i].optype == OPTYPE_NCSI_FW) && 282662306a36Sopenharmony_ci !be_fw_ncsi_supported(adapter->fw_ver)) { 282762306a36Sopenharmony_ci dev_info(dev, NCSI_UPDATE_LOG, adapter->fw_ver); 282862306a36Sopenharmony_ci continue; 282962306a36Sopenharmony_ci } 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci if (pflashcomp[i].optype == OPTYPE_PHY_FW && 283262306a36Sopenharmony_ci !phy_flashing_required(adapter)) 283362306a36Sopenharmony_ci continue; 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ci if (pflashcomp[i].optype == OPTYPE_REDBOOT) { 283662306a36Sopenharmony_ci status = be_check_flash_crc(adapter, fw->data, 283762306a36Sopenharmony_ci pflashcomp[i].offset, 283862306a36Sopenharmony_ci pflashcomp[i].size, 283962306a36Sopenharmony_ci filehdr_size + 284062306a36Sopenharmony_ci img_hdrs_size, 284162306a36Sopenharmony_ci OPTYPE_REDBOOT, &crc_match); 284262306a36Sopenharmony_ci if (status) { 284362306a36Sopenharmony_ci dev_err(dev, 284462306a36Sopenharmony_ci "Could not get CRC for 0x%x region\n", 284562306a36Sopenharmony_ci pflashcomp[i].optype); 284662306a36Sopenharmony_ci continue; 284762306a36Sopenharmony_ci } 284862306a36Sopenharmony_ci 284962306a36Sopenharmony_ci if (crc_match) 285062306a36Sopenharmony_ci continue; 285162306a36Sopenharmony_ci } 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci p = fw->data + filehdr_size + pflashcomp[i].offset + 285462306a36Sopenharmony_ci img_hdrs_size; 285562306a36Sopenharmony_ci if (p + pflashcomp[i].size > fw->data + fw->size) 285662306a36Sopenharmony_ci return -1; 285762306a36Sopenharmony_ci 285862306a36Sopenharmony_ci status = be_flash(adapter, p, flash_cmd, pflashcomp[i].optype, 285962306a36Sopenharmony_ci pflashcomp[i].size, 0); 286062306a36Sopenharmony_ci if (status) { 286162306a36Sopenharmony_ci dev_err(dev, "Flashing section type 0x%x failed\n", 286262306a36Sopenharmony_ci pflashcomp[i].img_type); 286362306a36Sopenharmony_ci return status; 286462306a36Sopenharmony_ci } 286562306a36Sopenharmony_ci } 286662306a36Sopenharmony_ci return 0; 286762306a36Sopenharmony_ci} 286862306a36Sopenharmony_ci 286962306a36Sopenharmony_cistatic u16 be_get_img_optype(struct flash_section_entry fsec_entry) 287062306a36Sopenharmony_ci{ 287162306a36Sopenharmony_ci u32 img_type = le32_to_cpu(fsec_entry.type); 287262306a36Sopenharmony_ci u16 img_optype = le16_to_cpu(fsec_entry.optype); 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_ci if (img_optype != 0xFFFF) 287562306a36Sopenharmony_ci return img_optype; 287662306a36Sopenharmony_ci 287762306a36Sopenharmony_ci switch (img_type) { 287862306a36Sopenharmony_ci case IMAGE_FIRMWARE_ISCSI: 287962306a36Sopenharmony_ci img_optype = OPTYPE_ISCSI_ACTIVE; 288062306a36Sopenharmony_ci break; 288162306a36Sopenharmony_ci case IMAGE_BOOT_CODE: 288262306a36Sopenharmony_ci img_optype = OPTYPE_REDBOOT; 288362306a36Sopenharmony_ci break; 288462306a36Sopenharmony_ci case IMAGE_OPTION_ROM_ISCSI: 288562306a36Sopenharmony_ci img_optype = OPTYPE_BIOS; 288662306a36Sopenharmony_ci break; 288762306a36Sopenharmony_ci case IMAGE_OPTION_ROM_PXE: 288862306a36Sopenharmony_ci img_optype = OPTYPE_PXE_BIOS; 288962306a36Sopenharmony_ci break; 289062306a36Sopenharmony_ci case IMAGE_OPTION_ROM_FCOE: 289162306a36Sopenharmony_ci img_optype = OPTYPE_FCOE_BIOS; 289262306a36Sopenharmony_ci break; 289362306a36Sopenharmony_ci case IMAGE_FIRMWARE_BACKUP_ISCSI: 289462306a36Sopenharmony_ci img_optype = OPTYPE_ISCSI_BACKUP; 289562306a36Sopenharmony_ci break; 289662306a36Sopenharmony_ci case IMAGE_NCSI: 289762306a36Sopenharmony_ci img_optype = OPTYPE_NCSI_FW; 289862306a36Sopenharmony_ci break; 289962306a36Sopenharmony_ci case IMAGE_FLASHISM_JUMPVECTOR: 290062306a36Sopenharmony_ci img_optype = OPTYPE_FLASHISM_JUMPVECTOR; 290162306a36Sopenharmony_ci break; 290262306a36Sopenharmony_ci case IMAGE_FIRMWARE_PHY: 290362306a36Sopenharmony_ci img_optype = OPTYPE_SH_PHY_FW; 290462306a36Sopenharmony_ci break; 290562306a36Sopenharmony_ci case IMAGE_REDBOOT_DIR: 290662306a36Sopenharmony_ci img_optype = OPTYPE_REDBOOT_DIR; 290762306a36Sopenharmony_ci break; 290862306a36Sopenharmony_ci case IMAGE_REDBOOT_CONFIG: 290962306a36Sopenharmony_ci img_optype = OPTYPE_REDBOOT_CONFIG; 291062306a36Sopenharmony_ci break; 291162306a36Sopenharmony_ci case IMAGE_UFI_DIR: 291262306a36Sopenharmony_ci img_optype = OPTYPE_UFI_DIR; 291362306a36Sopenharmony_ci break; 291462306a36Sopenharmony_ci default: 291562306a36Sopenharmony_ci break; 291662306a36Sopenharmony_ci } 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_ci return img_optype; 291962306a36Sopenharmony_ci} 292062306a36Sopenharmony_ci 292162306a36Sopenharmony_cistatic int be_flash_skyhawk(struct be_adapter *adapter, 292262306a36Sopenharmony_ci const struct firmware *fw, 292362306a36Sopenharmony_ci struct be_dma_mem *flash_cmd, int num_of_images) 292462306a36Sopenharmony_ci{ 292562306a36Sopenharmony_ci int img_hdrs_size = num_of_images * sizeof(struct image_hdr); 292662306a36Sopenharmony_ci bool crc_match, old_fw_img, flash_offset_support = true; 292762306a36Sopenharmony_ci struct device *dev = &adapter->pdev->dev; 292862306a36Sopenharmony_ci struct flash_section_info *fsec = NULL; 292962306a36Sopenharmony_ci u32 img_offset, img_size, img_type; 293062306a36Sopenharmony_ci u16 img_optype, flash_optype; 293162306a36Sopenharmony_ci int status, i, filehdr_size; 293262306a36Sopenharmony_ci const u8 *p; 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci filehdr_size = sizeof(struct flash_file_hdr_g3); 293562306a36Sopenharmony_ci fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw); 293662306a36Sopenharmony_ci if (!fsec) { 293762306a36Sopenharmony_ci dev_err(dev, "Invalid Cookie. FW image may be corrupted\n"); 293862306a36Sopenharmony_ci return -EINVAL; 293962306a36Sopenharmony_ci } 294062306a36Sopenharmony_ci 294162306a36Sopenharmony_ciretry_flash: 294262306a36Sopenharmony_ci for (i = 0; i < le32_to_cpu(fsec->fsec_hdr.num_images); i++) { 294362306a36Sopenharmony_ci img_offset = le32_to_cpu(fsec->fsec_entry[i].offset); 294462306a36Sopenharmony_ci img_size = le32_to_cpu(fsec->fsec_entry[i].pad_size); 294562306a36Sopenharmony_ci img_type = le32_to_cpu(fsec->fsec_entry[i].type); 294662306a36Sopenharmony_ci img_optype = be_get_img_optype(fsec->fsec_entry[i]); 294762306a36Sopenharmony_ci old_fw_img = fsec->fsec_entry[i].optype == 0xFFFF; 294862306a36Sopenharmony_ci 294962306a36Sopenharmony_ci if (img_optype == 0xFFFF) 295062306a36Sopenharmony_ci continue; 295162306a36Sopenharmony_ci 295262306a36Sopenharmony_ci if (flash_offset_support) 295362306a36Sopenharmony_ci flash_optype = OPTYPE_OFFSET_SPECIFIED; 295462306a36Sopenharmony_ci else 295562306a36Sopenharmony_ci flash_optype = img_optype; 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci /* Don't bother verifying CRC if an old FW image is being 295862306a36Sopenharmony_ci * flashed 295962306a36Sopenharmony_ci */ 296062306a36Sopenharmony_ci if (old_fw_img) 296162306a36Sopenharmony_ci goto flash; 296262306a36Sopenharmony_ci 296362306a36Sopenharmony_ci status = be_check_flash_crc(adapter, fw->data, img_offset, 296462306a36Sopenharmony_ci img_size, filehdr_size + 296562306a36Sopenharmony_ci img_hdrs_size, flash_optype, 296662306a36Sopenharmony_ci &crc_match); 296762306a36Sopenharmony_ci if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST || 296862306a36Sopenharmony_ci base_status(status) == MCC_STATUS_ILLEGAL_FIELD) { 296962306a36Sopenharmony_ci /* The current FW image on the card does not support 297062306a36Sopenharmony_ci * OFFSET based flashing. Retry using older mechanism 297162306a36Sopenharmony_ci * of OPTYPE based flashing 297262306a36Sopenharmony_ci */ 297362306a36Sopenharmony_ci if (flash_optype == OPTYPE_OFFSET_SPECIFIED) { 297462306a36Sopenharmony_ci flash_offset_support = false; 297562306a36Sopenharmony_ci goto retry_flash; 297662306a36Sopenharmony_ci } 297762306a36Sopenharmony_ci 297862306a36Sopenharmony_ci /* The current FW image on the card does not recognize 297962306a36Sopenharmony_ci * the new FLASH op_type. The FW download is partially 298062306a36Sopenharmony_ci * complete. Reboot the server now to enable FW image 298162306a36Sopenharmony_ci * to recognize the new FLASH op_type. To complete the 298262306a36Sopenharmony_ci * remaining process, download the same FW again after 298362306a36Sopenharmony_ci * the reboot. 298462306a36Sopenharmony_ci */ 298562306a36Sopenharmony_ci dev_err(dev, "Flash incomplete. Reset the server\n"); 298662306a36Sopenharmony_ci dev_err(dev, "Download FW image again after reset\n"); 298762306a36Sopenharmony_ci return -EAGAIN; 298862306a36Sopenharmony_ci } else if (status) { 298962306a36Sopenharmony_ci dev_err(dev, "Could not get CRC for 0x%x region\n", 299062306a36Sopenharmony_ci img_optype); 299162306a36Sopenharmony_ci return -EFAULT; 299262306a36Sopenharmony_ci } 299362306a36Sopenharmony_ci 299462306a36Sopenharmony_ci if (crc_match) 299562306a36Sopenharmony_ci continue; 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ciflash: 299862306a36Sopenharmony_ci p = fw->data + filehdr_size + img_offset + img_hdrs_size; 299962306a36Sopenharmony_ci if (p + img_size > fw->data + fw->size) 300062306a36Sopenharmony_ci return -1; 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_ci status = be_flash(adapter, p, flash_cmd, flash_optype, img_size, 300362306a36Sopenharmony_ci img_offset); 300462306a36Sopenharmony_ci 300562306a36Sopenharmony_ci /* The current FW image on the card does not support OFFSET 300662306a36Sopenharmony_ci * based flashing. Retry using older mechanism of OPTYPE based 300762306a36Sopenharmony_ci * flashing 300862306a36Sopenharmony_ci */ 300962306a36Sopenharmony_ci if (base_status(status) == MCC_STATUS_ILLEGAL_FIELD && 301062306a36Sopenharmony_ci flash_optype == OPTYPE_OFFSET_SPECIFIED) { 301162306a36Sopenharmony_ci flash_offset_support = false; 301262306a36Sopenharmony_ci goto retry_flash; 301362306a36Sopenharmony_ci } 301462306a36Sopenharmony_ci 301562306a36Sopenharmony_ci /* For old FW images ignore ILLEGAL_FIELD error or errors on 301662306a36Sopenharmony_ci * UFI_DIR region 301762306a36Sopenharmony_ci */ 301862306a36Sopenharmony_ci if (old_fw_img && 301962306a36Sopenharmony_ci (base_status(status) == MCC_STATUS_ILLEGAL_FIELD || 302062306a36Sopenharmony_ci (img_optype == OPTYPE_UFI_DIR && 302162306a36Sopenharmony_ci base_status(status) == MCC_STATUS_FAILED))) { 302262306a36Sopenharmony_ci continue; 302362306a36Sopenharmony_ci } else if (status) { 302462306a36Sopenharmony_ci dev_err(dev, "Flashing section type 0x%x failed\n", 302562306a36Sopenharmony_ci img_type); 302662306a36Sopenharmony_ci 302762306a36Sopenharmony_ci switch (addl_status(status)) { 302862306a36Sopenharmony_ci case MCC_ADDL_STATUS_MISSING_SIGNATURE: 302962306a36Sopenharmony_ci dev_err(dev, 303062306a36Sopenharmony_ci "Digital signature missing in FW\n"); 303162306a36Sopenharmony_ci return -EINVAL; 303262306a36Sopenharmony_ci case MCC_ADDL_STATUS_INVALID_SIGNATURE: 303362306a36Sopenharmony_ci dev_err(dev, 303462306a36Sopenharmony_ci "Invalid digital signature in FW\n"); 303562306a36Sopenharmony_ci return -EINVAL; 303662306a36Sopenharmony_ci default: 303762306a36Sopenharmony_ci return -EFAULT; 303862306a36Sopenharmony_ci } 303962306a36Sopenharmony_ci } 304062306a36Sopenharmony_ci } 304162306a36Sopenharmony_ci return 0; 304262306a36Sopenharmony_ci} 304362306a36Sopenharmony_ci 304462306a36Sopenharmony_ciint lancer_fw_download(struct be_adapter *adapter, 304562306a36Sopenharmony_ci const struct firmware *fw) 304662306a36Sopenharmony_ci{ 304762306a36Sopenharmony_ci struct device *dev = &adapter->pdev->dev; 304862306a36Sopenharmony_ci struct be_dma_mem flash_cmd; 304962306a36Sopenharmony_ci const u8 *data_ptr = NULL; 305062306a36Sopenharmony_ci u8 *dest_image_ptr = NULL; 305162306a36Sopenharmony_ci size_t image_size = 0; 305262306a36Sopenharmony_ci u32 chunk_size = 0; 305362306a36Sopenharmony_ci u32 data_written = 0; 305462306a36Sopenharmony_ci u32 offset = 0; 305562306a36Sopenharmony_ci int status = 0; 305662306a36Sopenharmony_ci u8 add_status = 0; 305762306a36Sopenharmony_ci u8 change_status; 305862306a36Sopenharmony_ci 305962306a36Sopenharmony_ci if (!IS_ALIGNED(fw->size, sizeof(u32))) { 306062306a36Sopenharmony_ci dev_err(dev, "FW image size should be multiple of 4\n"); 306162306a36Sopenharmony_ci return -EINVAL; 306262306a36Sopenharmony_ci } 306362306a36Sopenharmony_ci 306462306a36Sopenharmony_ci flash_cmd.size = sizeof(struct lancer_cmd_req_write_object) 306562306a36Sopenharmony_ci + LANCER_FW_DOWNLOAD_CHUNK; 306662306a36Sopenharmony_ci flash_cmd.va = dma_alloc_coherent(dev, flash_cmd.size, &flash_cmd.dma, 306762306a36Sopenharmony_ci GFP_KERNEL); 306862306a36Sopenharmony_ci if (!flash_cmd.va) 306962306a36Sopenharmony_ci return -ENOMEM; 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci dest_image_ptr = flash_cmd.va + 307262306a36Sopenharmony_ci sizeof(struct lancer_cmd_req_write_object); 307362306a36Sopenharmony_ci image_size = fw->size; 307462306a36Sopenharmony_ci data_ptr = fw->data; 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci while (image_size) { 307762306a36Sopenharmony_ci chunk_size = min_t(u32, image_size, LANCER_FW_DOWNLOAD_CHUNK); 307862306a36Sopenharmony_ci 307962306a36Sopenharmony_ci /* Copy the image chunk content. */ 308062306a36Sopenharmony_ci memcpy(dest_image_ptr, data_ptr, chunk_size); 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_ci status = lancer_cmd_write_object(adapter, &flash_cmd, 308362306a36Sopenharmony_ci chunk_size, offset, 308462306a36Sopenharmony_ci LANCER_FW_DOWNLOAD_LOCATION, 308562306a36Sopenharmony_ci &data_written, &change_status, 308662306a36Sopenharmony_ci &add_status); 308762306a36Sopenharmony_ci if (status) 308862306a36Sopenharmony_ci break; 308962306a36Sopenharmony_ci 309062306a36Sopenharmony_ci offset += data_written; 309162306a36Sopenharmony_ci data_ptr += data_written; 309262306a36Sopenharmony_ci image_size -= data_written; 309362306a36Sopenharmony_ci } 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_ci if (!status) { 309662306a36Sopenharmony_ci /* Commit the FW written */ 309762306a36Sopenharmony_ci status = lancer_cmd_write_object(adapter, &flash_cmd, 309862306a36Sopenharmony_ci 0, offset, 309962306a36Sopenharmony_ci LANCER_FW_DOWNLOAD_LOCATION, 310062306a36Sopenharmony_ci &data_written, &change_status, 310162306a36Sopenharmony_ci &add_status); 310262306a36Sopenharmony_ci } 310362306a36Sopenharmony_ci 310462306a36Sopenharmony_ci dma_free_coherent(dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma); 310562306a36Sopenharmony_ci if (status) { 310662306a36Sopenharmony_ci dev_err(dev, "Firmware load error\n"); 310762306a36Sopenharmony_ci return be_cmd_status(status); 310862306a36Sopenharmony_ci } 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_ci dev_info(dev, "Firmware flashed successfully\n"); 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_ci if (change_status == LANCER_FW_RESET_NEEDED) { 311362306a36Sopenharmony_ci dev_info(dev, "Resetting adapter to activate new FW\n"); 311462306a36Sopenharmony_ci status = lancer_physdev_ctrl(adapter, 311562306a36Sopenharmony_ci PHYSDEV_CONTROL_FW_RESET_MASK); 311662306a36Sopenharmony_ci if (status) { 311762306a36Sopenharmony_ci dev_err(dev, "Adapter busy, could not reset FW\n"); 311862306a36Sopenharmony_ci dev_err(dev, "Reboot server to activate new FW\n"); 311962306a36Sopenharmony_ci } 312062306a36Sopenharmony_ci } else if (change_status != LANCER_NO_RESET_NEEDED) { 312162306a36Sopenharmony_ci dev_info(dev, "Reboot server to activate new FW\n"); 312262306a36Sopenharmony_ci } 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_ci return 0; 312562306a36Sopenharmony_ci} 312662306a36Sopenharmony_ci 312762306a36Sopenharmony_ci/* Check if the flash image file is compatible with the adapter that 312862306a36Sopenharmony_ci * is being flashed. 312962306a36Sopenharmony_ci */ 313062306a36Sopenharmony_cistatic bool be_check_ufi_compatibility(struct be_adapter *adapter, 313162306a36Sopenharmony_ci struct flash_file_hdr_g3 *fhdr) 313262306a36Sopenharmony_ci{ 313362306a36Sopenharmony_ci if (!fhdr) { 313462306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Invalid FW UFI file"); 313562306a36Sopenharmony_ci return false; 313662306a36Sopenharmony_ci } 313762306a36Sopenharmony_ci 313862306a36Sopenharmony_ci /* First letter of the build version is used to identify 313962306a36Sopenharmony_ci * which chip this image file is meant for. 314062306a36Sopenharmony_ci */ 314162306a36Sopenharmony_ci switch (fhdr->build[0]) { 314262306a36Sopenharmony_ci case BLD_STR_UFI_TYPE_SH: 314362306a36Sopenharmony_ci if (!skyhawk_chip(adapter)) 314462306a36Sopenharmony_ci return false; 314562306a36Sopenharmony_ci break; 314662306a36Sopenharmony_ci case BLD_STR_UFI_TYPE_BE3: 314762306a36Sopenharmony_ci if (!BE3_chip(adapter)) 314862306a36Sopenharmony_ci return false; 314962306a36Sopenharmony_ci break; 315062306a36Sopenharmony_ci case BLD_STR_UFI_TYPE_BE2: 315162306a36Sopenharmony_ci if (!BE2_chip(adapter)) 315262306a36Sopenharmony_ci return false; 315362306a36Sopenharmony_ci break; 315462306a36Sopenharmony_ci default: 315562306a36Sopenharmony_ci return false; 315662306a36Sopenharmony_ci } 315762306a36Sopenharmony_ci 315862306a36Sopenharmony_ci /* In BE3 FW images the "asic_type_rev" field doesn't track the 315962306a36Sopenharmony_ci * asic_rev of the chips it is compatible with. 316062306a36Sopenharmony_ci * When asic_type_rev is 0 the image is compatible only with 316162306a36Sopenharmony_ci * pre-BE3-R chips (asic_rev < 0x10) 316262306a36Sopenharmony_ci */ 316362306a36Sopenharmony_ci if (BEx_chip(adapter) && fhdr->asic_type_rev == 0) 316462306a36Sopenharmony_ci return adapter->asic_rev < 0x10; 316562306a36Sopenharmony_ci else 316662306a36Sopenharmony_ci return (fhdr->asic_type_rev >= adapter->asic_rev); 316762306a36Sopenharmony_ci} 316862306a36Sopenharmony_ci 316962306a36Sopenharmony_ciint be_fw_download(struct be_adapter *adapter, const struct firmware *fw) 317062306a36Sopenharmony_ci{ 317162306a36Sopenharmony_ci struct device *dev = &adapter->pdev->dev; 317262306a36Sopenharmony_ci struct flash_file_hdr_g3 *fhdr3; 317362306a36Sopenharmony_ci struct image_hdr *img_hdr_ptr; 317462306a36Sopenharmony_ci int status = 0, i, num_imgs; 317562306a36Sopenharmony_ci struct be_dma_mem flash_cmd; 317662306a36Sopenharmony_ci 317762306a36Sopenharmony_ci fhdr3 = (struct flash_file_hdr_g3 *)fw->data; 317862306a36Sopenharmony_ci if (!be_check_ufi_compatibility(adapter, fhdr3)) { 317962306a36Sopenharmony_ci dev_err(dev, "Flash image is not compatible with adapter\n"); 318062306a36Sopenharmony_ci return -EINVAL; 318162306a36Sopenharmony_ci } 318262306a36Sopenharmony_ci 318362306a36Sopenharmony_ci flash_cmd.size = sizeof(struct be_cmd_write_flashrom); 318462306a36Sopenharmony_ci flash_cmd.va = dma_alloc_coherent(dev, flash_cmd.size, &flash_cmd.dma, 318562306a36Sopenharmony_ci GFP_KERNEL); 318662306a36Sopenharmony_ci if (!flash_cmd.va) 318762306a36Sopenharmony_ci return -ENOMEM; 318862306a36Sopenharmony_ci 318962306a36Sopenharmony_ci num_imgs = le32_to_cpu(fhdr3->num_imgs); 319062306a36Sopenharmony_ci for (i = 0; i < num_imgs; i++) { 319162306a36Sopenharmony_ci img_hdr_ptr = (struct image_hdr *)(fw->data + 319262306a36Sopenharmony_ci (sizeof(struct flash_file_hdr_g3) + 319362306a36Sopenharmony_ci i * sizeof(struct image_hdr))); 319462306a36Sopenharmony_ci if (!BE2_chip(adapter) && 319562306a36Sopenharmony_ci le32_to_cpu(img_hdr_ptr->imageid) != 1) 319662306a36Sopenharmony_ci continue; 319762306a36Sopenharmony_ci 319862306a36Sopenharmony_ci if (skyhawk_chip(adapter)) 319962306a36Sopenharmony_ci status = be_flash_skyhawk(adapter, fw, &flash_cmd, 320062306a36Sopenharmony_ci num_imgs); 320162306a36Sopenharmony_ci else 320262306a36Sopenharmony_ci status = be_flash_BEx(adapter, fw, &flash_cmd, 320362306a36Sopenharmony_ci num_imgs); 320462306a36Sopenharmony_ci } 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ci dma_free_coherent(dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma); 320762306a36Sopenharmony_ci if (!status) 320862306a36Sopenharmony_ci dev_info(dev, "Firmware flashed successfully\n"); 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci return status; 321162306a36Sopenharmony_ci} 321262306a36Sopenharmony_ci 321362306a36Sopenharmony_ciint be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, 321462306a36Sopenharmony_ci struct be_dma_mem *nonemb_cmd) 321562306a36Sopenharmony_ci{ 321662306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 321762306a36Sopenharmony_ci struct be_cmd_req_acpi_wol_magic_config *req; 321862306a36Sopenharmony_ci int status; 321962306a36Sopenharmony_ci 322062306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 322162306a36Sopenharmony_ci 322262306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 322362306a36Sopenharmony_ci if (!wrb) { 322462306a36Sopenharmony_ci status = -EBUSY; 322562306a36Sopenharmony_ci goto err; 322662306a36Sopenharmony_ci } 322762306a36Sopenharmony_ci req = nonemb_cmd->va; 322862306a36Sopenharmony_ci 322962306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, 323062306a36Sopenharmony_ci OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, sizeof(*req), 323162306a36Sopenharmony_ci wrb, nonemb_cmd); 323262306a36Sopenharmony_ci memcpy(req->magic_mac, mac, ETH_ALEN); 323362306a36Sopenharmony_ci 323462306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 323562306a36Sopenharmony_ci 323662306a36Sopenharmony_cierr: 323762306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 323862306a36Sopenharmony_ci return status; 323962306a36Sopenharmony_ci} 324062306a36Sopenharmony_ci 324162306a36Sopenharmony_ciint be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num, 324262306a36Sopenharmony_ci u8 loopback_type, u8 enable) 324362306a36Sopenharmony_ci{ 324462306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 324562306a36Sopenharmony_ci struct be_cmd_req_set_lmode *req; 324662306a36Sopenharmony_ci int status; 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci if (!be_cmd_allowed(adapter, OPCODE_LOWLEVEL_SET_LOOPBACK_MODE, 324962306a36Sopenharmony_ci CMD_SUBSYSTEM_LOWLEVEL)) 325062306a36Sopenharmony_ci return -EPERM; 325162306a36Sopenharmony_ci 325262306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 325562306a36Sopenharmony_ci if (!wrb) { 325662306a36Sopenharmony_ci status = -EBUSY; 325762306a36Sopenharmony_ci goto err_unlock; 325862306a36Sopenharmony_ci } 325962306a36Sopenharmony_ci 326062306a36Sopenharmony_ci req = embedded_payload(wrb); 326162306a36Sopenharmony_ci 326262306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL, 326362306a36Sopenharmony_ci OPCODE_LOWLEVEL_SET_LOOPBACK_MODE, sizeof(*req), 326462306a36Sopenharmony_ci wrb, NULL); 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_ci req->src_port = port_num; 326762306a36Sopenharmony_ci req->dest_port = port_num; 326862306a36Sopenharmony_ci req->loopback_type = loopback_type; 326962306a36Sopenharmony_ci req->loopback_state = enable; 327062306a36Sopenharmony_ci 327162306a36Sopenharmony_ci status = be_mcc_notify(adapter); 327262306a36Sopenharmony_ci if (status) 327362306a36Sopenharmony_ci goto err_unlock; 327462306a36Sopenharmony_ci 327562306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 327662306a36Sopenharmony_ci 327762306a36Sopenharmony_ci if (!wait_for_completion_timeout(&adapter->et_cmd_compl, 327862306a36Sopenharmony_ci msecs_to_jiffies(SET_LB_MODE_TIMEOUT))) 327962306a36Sopenharmony_ci status = -ETIMEDOUT; 328062306a36Sopenharmony_ci 328162306a36Sopenharmony_ci return status; 328262306a36Sopenharmony_ci 328362306a36Sopenharmony_cierr_unlock: 328462306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 328562306a36Sopenharmony_ci return status; 328662306a36Sopenharmony_ci} 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_ciint be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num, 328962306a36Sopenharmony_ci u32 loopback_type, u32 pkt_size, u32 num_pkts, 329062306a36Sopenharmony_ci u64 pattern) 329162306a36Sopenharmony_ci{ 329262306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 329362306a36Sopenharmony_ci struct be_cmd_req_loopback_test *req; 329462306a36Sopenharmony_ci struct be_cmd_resp_loopback_test *resp; 329562306a36Sopenharmony_ci int status; 329662306a36Sopenharmony_ci 329762306a36Sopenharmony_ci if (!be_cmd_allowed(adapter, OPCODE_LOWLEVEL_LOOPBACK_TEST, 329862306a36Sopenharmony_ci CMD_SUBSYSTEM_LOWLEVEL)) 329962306a36Sopenharmony_ci return -EPERM; 330062306a36Sopenharmony_ci 330162306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 330262306a36Sopenharmony_ci 330362306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 330462306a36Sopenharmony_ci if (!wrb) { 330562306a36Sopenharmony_ci status = -EBUSY; 330662306a36Sopenharmony_ci goto err; 330762306a36Sopenharmony_ci } 330862306a36Sopenharmony_ci 330962306a36Sopenharmony_ci req = embedded_payload(wrb); 331062306a36Sopenharmony_ci 331162306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL, 331262306a36Sopenharmony_ci OPCODE_LOWLEVEL_LOOPBACK_TEST, sizeof(*req), wrb, 331362306a36Sopenharmony_ci NULL); 331462306a36Sopenharmony_ci 331562306a36Sopenharmony_ci req->hdr.timeout = cpu_to_le32(15); 331662306a36Sopenharmony_ci req->pattern = cpu_to_le64(pattern); 331762306a36Sopenharmony_ci req->src_port = cpu_to_le32(port_num); 331862306a36Sopenharmony_ci req->dest_port = cpu_to_le32(port_num); 331962306a36Sopenharmony_ci req->pkt_size = cpu_to_le32(pkt_size); 332062306a36Sopenharmony_ci req->num_pkts = cpu_to_le32(num_pkts); 332162306a36Sopenharmony_ci req->loopback_type = cpu_to_le32(loopback_type); 332262306a36Sopenharmony_ci 332362306a36Sopenharmony_ci status = be_mcc_notify(adapter); 332462306a36Sopenharmony_ci if (status) 332562306a36Sopenharmony_ci goto err; 332662306a36Sopenharmony_ci 332762306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 332862306a36Sopenharmony_ci 332962306a36Sopenharmony_ci wait_for_completion(&adapter->et_cmd_compl); 333062306a36Sopenharmony_ci resp = embedded_payload(wrb); 333162306a36Sopenharmony_ci status = le32_to_cpu(resp->status); 333262306a36Sopenharmony_ci 333362306a36Sopenharmony_ci return status; 333462306a36Sopenharmony_cierr: 333562306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 333662306a36Sopenharmony_ci return status; 333762306a36Sopenharmony_ci} 333862306a36Sopenharmony_ci 333962306a36Sopenharmony_ciint be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern, 334062306a36Sopenharmony_ci u32 byte_cnt, struct be_dma_mem *cmd) 334162306a36Sopenharmony_ci{ 334262306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 334362306a36Sopenharmony_ci struct be_cmd_req_ddrdma_test *req; 334462306a36Sopenharmony_ci int status; 334562306a36Sopenharmony_ci int i, j = 0; 334662306a36Sopenharmony_ci 334762306a36Sopenharmony_ci if (!be_cmd_allowed(adapter, OPCODE_LOWLEVEL_HOST_DDR_DMA, 334862306a36Sopenharmony_ci CMD_SUBSYSTEM_LOWLEVEL)) 334962306a36Sopenharmony_ci return -EPERM; 335062306a36Sopenharmony_ci 335162306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 335262306a36Sopenharmony_ci 335362306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 335462306a36Sopenharmony_ci if (!wrb) { 335562306a36Sopenharmony_ci status = -EBUSY; 335662306a36Sopenharmony_ci goto err; 335762306a36Sopenharmony_ci } 335862306a36Sopenharmony_ci req = cmd->va; 335962306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL, 336062306a36Sopenharmony_ci OPCODE_LOWLEVEL_HOST_DDR_DMA, cmd->size, wrb, 336162306a36Sopenharmony_ci cmd); 336262306a36Sopenharmony_ci 336362306a36Sopenharmony_ci req->pattern = cpu_to_le64(pattern); 336462306a36Sopenharmony_ci req->byte_count = cpu_to_le32(byte_cnt); 336562306a36Sopenharmony_ci for (i = 0; i < byte_cnt; i++) { 336662306a36Sopenharmony_ci req->snd_buff[i] = (u8)(pattern >> (j * 8)); 336762306a36Sopenharmony_ci j++; 336862306a36Sopenharmony_ci if (j > 7) 336962306a36Sopenharmony_ci j = 0; 337062306a36Sopenharmony_ci } 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 337362306a36Sopenharmony_ci 337462306a36Sopenharmony_ci if (!status) { 337562306a36Sopenharmony_ci struct be_cmd_resp_ddrdma_test *resp; 337662306a36Sopenharmony_ci 337762306a36Sopenharmony_ci resp = cmd->va; 337862306a36Sopenharmony_ci if ((memcmp(resp->rcv_buff, req->snd_buff, byte_cnt) != 0) || 337962306a36Sopenharmony_ci resp->snd_err) { 338062306a36Sopenharmony_ci status = -1; 338162306a36Sopenharmony_ci } 338262306a36Sopenharmony_ci } 338362306a36Sopenharmony_ci 338462306a36Sopenharmony_cierr: 338562306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 338662306a36Sopenharmony_ci return status; 338762306a36Sopenharmony_ci} 338862306a36Sopenharmony_ci 338962306a36Sopenharmony_ciint be_cmd_get_seeprom_data(struct be_adapter *adapter, 339062306a36Sopenharmony_ci struct be_dma_mem *nonemb_cmd) 339162306a36Sopenharmony_ci{ 339262306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 339362306a36Sopenharmony_ci struct be_cmd_req_seeprom_read *req; 339462306a36Sopenharmony_ci int status; 339562306a36Sopenharmony_ci 339662306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 339762306a36Sopenharmony_ci 339862306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 339962306a36Sopenharmony_ci if (!wrb) { 340062306a36Sopenharmony_ci status = -EBUSY; 340162306a36Sopenharmony_ci goto err; 340262306a36Sopenharmony_ci } 340362306a36Sopenharmony_ci req = nonemb_cmd->va; 340462306a36Sopenharmony_ci 340562306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 340662306a36Sopenharmony_ci OPCODE_COMMON_SEEPROM_READ, sizeof(*req), wrb, 340762306a36Sopenharmony_ci nonemb_cmd); 340862306a36Sopenharmony_ci 340962306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 341062306a36Sopenharmony_ci 341162306a36Sopenharmony_cierr: 341262306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 341362306a36Sopenharmony_ci return status; 341462306a36Sopenharmony_ci} 341562306a36Sopenharmony_ci 341662306a36Sopenharmony_ciint be_cmd_get_phy_info(struct be_adapter *adapter) 341762306a36Sopenharmony_ci{ 341862306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 341962306a36Sopenharmony_ci struct be_cmd_req_get_phy_info *req; 342062306a36Sopenharmony_ci struct be_dma_mem cmd; 342162306a36Sopenharmony_ci int status; 342262306a36Sopenharmony_ci 342362306a36Sopenharmony_ci if (!be_cmd_allowed(adapter, OPCODE_COMMON_GET_PHY_DETAILS, 342462306a36Sopenharmony_ci CMD_SUBSYSTEM_COMMON)) 342562306a36Sopenharmony_ci return -EPERM; 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 342862306a36Sopenharmony_ci 342962306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 343062306a36Sopenharmony_ci if (!wrb) { 343162306a36Sopenharmony_ci status = -EBUSY; 343262306a36Sopenharmony_ci goto err; 343362306a36Sopenharmony_ci } 343462306a36Sopenharmony_ci cmd.size = sizeof(struct be_cmd_req_get_phy_info); 343562306a36Sopenharmony_ci cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, 343662306a36Sopenharmony_ci GFP_ATOMIC); 343762306a36Sopenharmony_ci if (!cmd.va) { 343862306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Memory alloc failure\n"); 343962306a36Sopenharmony_ci status = -ENOMEM; 344062306a36Sopenharmony_ci goto err; 344162306a36Sopenharmony_ci } 344262306a36Sopenharmony_ci 344362306a36Sopenharmony_ci req = cmd.va; 344462306a36Sopenharmony_ci 344562306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 344662306a36Sopenharmony_ci OPCODE_COMMON_GET_PHY_DETAILS, sizeof(*req), 344762306a36Sopenharmony_ci wrb, &cmd); 344862306a36Sopenharmony_ci 344962306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 345062306a36Sopenharmony_ci if (!status) { 345162306a36Sopenharmony_ci struct be_phy_info *resp_phy_info = 345262306a36Sopenharmony_ci cmd.va + sizeof(struct be_cmd_req_hdr); 345362306a36Sopenharmony_ci 345462306a36Sopenharmony_ci adapter->phy.phy_type = le16_to_cpu(resp_phy_info->phy_type); 345562306a36Sopenharmony_ci adapter->phy.interface_type = 345662306a36Sopenharmony_ci le16_to_cpu(resp_phy_info->interface_type); 345762306a36Sopenharmony_ci adapter->phy.auto_speeds_supported = 345862306a36Sopenharmony_ci le16_to_cpu(resp_phy_info->auto_speeds_supported); 345962306a36Sopenharmony_ci adapter->phy.fixed_speeds_supported = 346062306a36Sopenharmony_ci le16_to_cpu(resp_phy_info->fixed_speeds_supported); 346162306a36Sopenharmony_ci adapter->phy.misc_params = 346262306a36Sopenharmony_ci le32_to_cpu(resp_phy_info->misc_params); 346362306a36Sopenharmony_ci 346462306a36Sopenharmony_ci if (BE2_chip(adapter)) { 346562306a36Sopenharmony_ci adapter->phy.fixed_speeds_supported = 346662306a36Sopenharmony_ci BE_SUPPORTED_SPEED_10GBPS | 346762306a36Sopenharmony_ci BE_SUPPORTED_SPEED_1GBPS; 346862306a36Sopenharmony_ci } 346962306a36Sopenharmony_ci } 347062306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, cmd.dma); 347162306a36Sopenharmony_cierr: 347262306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 347362306a36Sopenharmony_ci return status; 347462306a36Sopenharmony_ci} 347562306a36Sopenharmony_ci 347662306a36Sopenharmony_cistatic int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain) 347762306a36Sopenharmony_ci{ 347862306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 347962306a36Sopenharmony_ci struct be_cmd_req_set_qos *req; 348062306a36Sopenharmony_ci int status; 348162306a36Sopenharmony_ci 348262306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 348362306a36Sopenharmony_ci 348462306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 348562306a36Sopenharmony_ci if (!wrb) { 348662306a36Sopenharmony_ci status = -EBUSY; 348762306a36Sopenharmony_ci goto err; 348862306a36Sopenharmony_ci } 348962306a36Sopenharmony_ci 349062306a36Sopenharmony_ci req = embedded_payload(wrb); 349162306a36Sopenharmony_ci 349262306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 349362306a36Sopenharmony_ci OPCODE_COMMON_SET_QOS, sizeof(*req), wrb, NULL); 349462306a36Sopenharmony_ci 349562306a36Sopenharmony_ci req->hdr.domain = domain; 349662306a36Sopenharmony_ci req->valid_bits = cpu_to_le32(BE_QOS_BITS_NIC); 349762306a36Sopenharmony_ci req->max_bps_nic = cpu_to_le32(bps); 349862306a36Sopenharmony_ci 349962306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 350062306a36Sopenharmony_ci 350162306a36Sopenharmony_cierr: 350262306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 350362306a36Sopenharmony_ci return status; 350462306a36Sopenharmony_ci} 350562306a36Sopenharmony_ci 350662306a36Sopenharmony_ciint be_cmd_get_cntl_attributes(struct be_adapter *adapter) 350762306a36Sopenharmony_ci{ 350862306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 350962306a36Sopenharmony_ci struct be_cmd_req_cntl_attribs *req; 351062306a36Sopenharmony_ci struct be_cmd_resp_cntl_attribs *resp; 351162306a36Sopenharmony_ci int status, i; 351262306a36Sopenharmony_ci int payload_len = max(sizeof(*req), sizeof(*resp)); 351362306a36Sopenharmony_ci struct mgmt_controller_attrib *attribs; 351462306a36Sopenharmony_ci struct be_dma_mem attribs_cmd; 351562306a36Sopenharmony_ci u32 *serial_num; 351662306a36Sopenharmony_ci 351762306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 351862306a36Sopenharmony_ci return -1; 351962306a36Sopenharmony_ci 352062306a36Sopenharmony_ci memset(&attribs_cmd, 0, sizeof(struct be_dma_mem)); 352162306a36Sopenharmony_ci attribs_cmd.size = sizeof(struct be_cmd_resp_cntl_attribs); 352262306a36Sopenharmony_ci attribs_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, 352362306a36Sopenharmony_ci attribs_cmd.size, 352462306a36Sopenharmony_ci &attribs_cmd.dma, GFP_ATOMIC); 352562306a36Sopenharmony_ci if (!attribs_cmd.va) { 352662306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Memory allocation failure\n"); 352762306a36Sopenharmony_ci status = -ENOMEM; 352862306a36Sopenharmony_ci goto err; 352962306a36Sopenharmony_ci } 353062306a36Sopenharmony_ci 353162306a36Sopenharmony_ci wrb = wrb_from_mbox(adapter); 353262306a36Sopenharmony_ci if (!wrb) { 353362306a36Sopenharmony_ci status = -EBUSY; 353462306a36Sopenharmony_ci goto err; 353562306a36Sopenharmony_ci } 353662306a36Sopenharmony_ci req = attribs_cmd.va; 353762306a36Sopenharmony_ci 353862306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 353962306a36Sopenharmony_ci OPCODE_COMMON_GET_CNTL_ATTRIBUTES, payload_len, 354062306a36Sopenharmony_ci wrb, &attribs_cmd); 354162306a36Sopenharmony_ci 354262306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 354362306a36Sopenharmony_ci if (!status) { 354462306a36Sopenharmony_ci attribs = attribs_cmd.va + sizeof(struct be_cmd_resp_hdr); 354562306a36Sopenharmony_ci adapter->hba_port_num = attribs->hba_attribs.phy_port; 354662306a36Sopenharmony_ci serial_num = attribs->hba_attribs.controller_serial_number; 354762306a36Sopenharmony_ci for (i = 0; i < CNTL_SERIAL_NUM_WORDS; i++) 354862306a36Sopenharmony_ci adapter->serial_num[i] = le32_to_cpu(serial_num[i]) & 354962306a36Sopenharmony_ci (BIT_MASK(16) - 1); 355062306a36Sopenharmony_ci /* For BEx, since GET_FUNC_CONFIG command is not 355162306a36Sopenharmony_ci * supported, we read funcnum here as a workaround. 355262306a36Sopenharmony_ci */ 355362306a36Sopenharmony_ci if (BEx_chip(adapter)) 355462306a36Sopenharmony_ci adapter->pf_num = attribs->hba_attribs.pci_funcnum; 355562306a36Sopenharmony_ci } 355662306a36Sopenharmony_ci 355762306a36Sopenharmony_cierr: 355862306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 355962306a36Sopenharmony_ci if (attribs_cmd.va) 356062306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, attribs_cmd.size, 356162306a36Sopenharmony_ci attribs_cmd.va, attribs_cmd.dma); 356262306a36Sopenharmony_ci return status; 356362306a36Sopenharmony_ci} 356462306a36Sopenharmony_ci 356562306a36Sopenharmony_ci/* Uses mbox */ 356662306a36Sopenharmony_ciint be_cmd_req_native_mode(struct be_adapter *adapter) 356762306a36Sopenharmony_ci{ 356862306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 356962306a36Sopenharmony_ci struct be_cmd_req_set_func_cap *req; 357062306a36Sopenharmony_ci int status; 357162306a36Sopenharmony_ci 357262306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 357362306a36Sopenharmony_ci return -1; 357462306a36Sopenharmony_ci 357562306a36Sopenharmony_ci wrb = wrb_from_mbox(adapter); 357662306a36Sopenharmony_ci if (!wrb) { 357762306a36Sopenharmony_ci status = -EBUSY; 357862306a36Sopenharmony_ci goto err; 357962306a36Sopenharmony_ci } 358062306a36Sopenharmony_ci 358162306a36Sopenharmony_ci req = embedded_payload(wrb); 358262306a36Sopenharmony_ci 358362306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 358462306a36Sopenharmony_ci OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP, 358562306a36Sopenharmony_ci sizeof(*req), wrb, NULL); 358662306a36Sopenharmony_ci 358762306a36Sopenharmony_ci req->valid_cap_flags = cpu_to_le32(CAPABILITY_SW_TIMESTAMPS | 358862306a36Sopenharmony_ci CAPABILITY_BE3_NATIVE_ERX_API); 358962306a36Sopenharmony_ci req->cap_flags = cpu_to_le32(CAPABILITY_BE3_NATIVE_ERX_API); 359062306a36Sopenharmony_ci 359162306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 359262306a36Sopenharmony_ci if (!status) { 359362306a36Sopenharmony_ci struct be_cmd_resp_set_func_cap *resp = embedded_payload(wrb); 359462306a36Sopenharmony_ci 359562306a36Sopenharmony_ci adapter->be3_native = le32_to_cpu(resp->cap_flags) & 359662306a36Sopenharmony_ci CAPABILITY_BE3_NATIVE_ERX_API; 359762306a36Sopenharmony_ci if (!adapter->be3_native) 359862306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, 359962306a36Sopenharmony_ci "adapter not in advanced mode\n"); 360062306a36Sopenharmony_ci } 360162306a36Sopenharmony_cierr: 360262306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 360362306a36Sopenharmony_ci return status; 360462306a36Sopenharmony_ci} 360562306a36Sopenharmony_ci 360662306a36Sopenharmony_ci/* Get privilege(s) for a function */ 360762306a36Sopenharmony_ciint be_cmd_get_fn_privileges(struct be_adapter *adapter, u32 *privilege, 360862306a36Sopenharmony_ci u32 domain) 360962306a36Sopenharmony_ci{ 361062306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 361162306a36Sopenharmony_ci struct be_cmd_req_get_fn_privileges *req; 361262306a36Sopenharmony_ci int status; 361362306a36Sopenharmony_ci 361462306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 361562306a36Sopenharmony_ci 361662306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 361762306a36Sopenharmony_ci if (!wrb) { 361862306a36Sopenharmony_ci status = -EBUSY; 361962306a36Sopenharmony_ci goto err; 362062306a36Sopenharmony_ci } 362162306a36Sopenharmony_ci 362262306a36Sopenharmony_ci req = embedded_payload(wrb); 362362306a36Sopenharmony_ci 362462306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 362562306a36Sopenharmony_ci OPCODE_COMMON_GET_FN_PRIVILEGES, sizeof(*req), 362662306a36Sopenharmony_ci wrb, NULL); 362762306a36Sopenharmony_ci 362862306a36Sopenharmony_ci req->hdr.domain = domain; 362962306a36Sopenharmony_ci 363062306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 363162306a36Sopenharmony_ci if (!status) { 363262306a36Sopenharmony_ci struct be_cmd_resp_get_fn_privileges *resp = 363362306a36Sopenharmony_ci embedded_payload(wrb); 363462306a36Sopenharmony_ci 363562306a36Sopenharmony_ci *privilege = le32_to_cpu(resp->privilege_mask); 363662306a36Sopenharmony_ci 363762306a36Sopenharmony_ci /* In UMC mode FW does not return right privileges. 363862306a36Sopenharmony_ci * Override with correct privilege equivalent to PF. 363962306a36Sopenharmony_ci */ 364062306a36Sopenharmony_ci if (BEx_chip(adapter) && be_is_mc(adapter) && 364162306a36Sopenharmony_ci be_physfn(adapter)) 364262306a36Sopenharmony_ci *privilege = MAX_PRIVILEGES; 364362306a36Sopenharmony_ci } 364462306a36Sopenharmony_ci 364562306a36Sopenharmony_cierr: 364662306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 364762306a36Sopenharmony_ci return status; 364862306a36Sopenharmony_ci} 364962306a36Sopenharmony_ci 365062306a36Sopenharmony_ci/* Set privilege(s) for a function */ 365162306a36Sopenharmony_ciint be_cmd_set_fn_privileges(struct be_adapter *adapter, u32 privileges, 365262306a36Sopenharmony_ci u32 domain) 365362306a36Sopenharmony_ci{ 365462306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 365562306a36Sopenharmony_ci struct be_cmd_req_set_fn_privileges *req; 365662306a36Sopenharmony_ci int status; 365762306a36Sopenharmony_ci 365862306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 365962306a36Sopenharmony_ci 366062306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 366162306a36Sopenharmony_ci if (!wrb) { 366262306a36Sopenharmony_ci status = -EBUSY; 366362306a36Sopenharmony_ci goto err; 366462306a36Sopenharmony_ci } 366562306a36Sopenharmony_ci 366662306a36Sopenharmony_ci req = embedded_payload(wrb); 366762306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 366862306a36Sopenharmony_ci OPCODE_COMMON_SET_FN_PRIVILEGES, sizeof(*req), 366962306a36Sopenharmony_ci wrb, NULL); 367062306a36Sopenharmony_ci req->hdr.domain = domain; 367162306a36Sopenharmony_ci if (lancer_chip(adapter)) 367262306a36Sopenharmony_ci req->privileges_lancer = cpu_to_le32(privileges); 367362306a36Sopenharmony_ci else 367462306a36Sopenharmony_ci req->privileges = cpu_to_le32(privileges); 367562306a36Sopenharmony_ci 367662306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 367762306a36Sopenharmony_cierr: 367862306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 367962306a36Sopenharmony_ci return status; 368062306a36Sopenharmony_ci} 368162306a36Sopenharmony_ci 368262306a36Sopenharmony_ci/* pmac_id_valid: true => pmac_id is supplied and MAC address is requested. 368362306a36Sopenharmony_ci * pmac_id_valid: false => pmac_id or MAC address is requested. 368462306a36Sopenharmony_ci * If pmac_id is returned, pmac_id_valid is returned as true 368562306a36Sopenharmony_ci */ 368662306a36Sopenharmony_ciint be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac, 368762306a36Sopenharmony_ci bool *pmac_id_valid, u32 *pmac_id, u32 if_handle, 368862306a36Sopenharmony_ci u8 domain) 368962306a36Sopenharmony_ci{ 369062306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 369162306a36Sopenharmony_ci struct be_cmd_req_get_mac_list *req; 369262306a36Sopenharmony_ci int status; 369362306a36Sopenharmony_ci int mac_count; 369462306a36Sopenharmony_ci struct be_dma_mem get_mac_list_cmd; 369562306a36Sopenharmony_ci int i; 369662306a36Sopenharmony_ci 369762306a36Sopenharmony_ci memset(&get_mac_list_cmd, 0, sizeof(struct be_dma_mem)); 369862306a36Sopenharmony_ci get_mac_list_cmd.size = sizeof(struct be_cmd_resp_get_mac_list); 369962306a36Sopenharmony_ci get_mac_list_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, 370062306a36Sopenharmony_ci get_mac_list_cmd.size, 370162306a36Sopenharmony_ci &get_mac_list_cmd.dma, 370262306a36Sopenharmony_ci GFP_ATOMIC); 370362306a36Sopenharmony_ci 370462306a36Sopenharmony_ci if (!get_mac_list_cmd.va) { 370562306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 370662306a36Sopenharmony_ci "Memory allocation failure during GET_MAC_LIST\n"); 370762306a36Sopenharmony_ci return -ENOMEM; 370862306a36Sopenharmony_ci } 370962306a36Sopenharmony_ci 371062306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 371162306a36Sopenharmony_ci 371262306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 371362306a36Sopenharmony_ci if (!wrb) { 371462306a36Sopenharmony_ci status = -EBUSY; 371562306a36Sopenharmony_ci goto out; 371662306a36Sopenharmony_ci } 371762306a36Sopenharmony_ci 371862306a36Sopenharmony_ci req = get_mac_list_cmd.va; 371962306a36Sopenharmony_ci 372062306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 372162306a36Sopenharmony_ci OPCODE_COMMON_GET_MAC_LIST, 372262306a36Sopenharmony_ci get_mac_list_cmd.size, wrb, &get_mac_list_cmd); 372362306a36Sopenharmony_ci req->hdr.domain = domain; 372462306a36Sopenharmony_ci req->mac_type = MAC_ADDRESS_TYPE_NETWORK; 372562306a36Sopenharmony_ci if (*pmac_id_valid) { 372662306a36Sopenharmony_ci req->mac_id = cpu_to_le32(*pmac_id); 372762306a36Sopenharmony_ci req->iface_id = cpu_to_le16(if_handle); 372862306a36Sopenharmony_ci req->perm_override = 0; 372962306a36Sopenharmony_ci } else { 373062306a36Sopenharmony_ci req->perm_override = 1; 373162306a36Sopenharmony_ci } 373262306a36Sopenharmony_ci 373362306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 373462306a36Sopenharmony_ci if (!status) { 373562306a36Sopenharmony_ci struct be_cmd_resp_get_mac_list *resp = 373662306a36Sopenharmony_ci get_mac_list_cmd.va; 373762306a36Sopenharmony_ci 373862306a36Sopenharmony_ci if (*pmac_id_valid) { 373962306a36Sopenharmony_ci memcpy(mac, resp->macid_macaddr.mac_addr_id.macaddr, 374062306a36Sopenharmony_ci ETH_ALEN); 374162306a36Sopenharmony_ci goto out; 374262306a36Sopenharmony_ci } 374362306a36Sopenharmony_ci 374462306a36Sopenharmony_ci mac_count = resp->true_mac_count + resp->pseudo_mac_count; 374562306a36Sopenharmony_ci /* Mac list returned could contain one or more active mac_ids 374662306a36Sopenharmony_ci * or one or more true or pseudo permanent mac addresses. 374762306a36Sopenharmony_ci * If an active mac_id is present, return first active mac_id 374862306a36Sopenharmony_ci * found. 374962306a36Sopenharmony_ci */ 375062306a36Sopenharmony_ci for (i = 0; i < mac_count; i++) { 375162306a36Sopenharmony_ci struct get_list_macaddr *mac_entry; 375262306a36Sopenharmony_ci u16 mac_addr_size; 375362306a36Sopenharmony_ci u32 mac_id; 375462306a36Sopenharmony_ci 375562306a36Sopenharmony_ci mac_entry = &resp->macaddr_list[i]; 375662306a36Sopenharmony_ci mac_addr_size = le16_to_cpu(mac_entry->mac_addr_size); 375762306a36Sopenharmony_ci /* mac_id is a 32 bit value and mac_addr size 375862306a36Sopenharmony_ci * is 6 bytes 375962306a36Sopenharmony_ci */ 376062306a36Sopenharmony_ci if (mac_addr_size == sizeof(u32)) { 376162306a36Sopenharmony_ci *pmac_id_valid = true; 376262306a36Sopenharmony_ci mac_id = mac_entry->mac_addr_id.s_mac_id.mac_id; 376362306a36Sopenharmony_ci *pmac_id = le32_to_cpu(mac_id); 376462306a36Sopenharmony_ci goto out; 376562306a36Sopenharmony_ci } 376662306a36Sopenharmony_ci } 376762306a36Sopenharmony_ci /* If no active mac_id found, return first mac addr */ 376862306a36Sopenharmony_ci *pmac_id_valid = false; 376962306a36Sopenharmony_ci memcpy(mac, resp->macaddr_list[0].mac_addr_id.macaddr, 377062306a36Sopenharmony_ci ETH_ALEN); 377162306a36Sopenharmony_ci } 377262306a36Sopenharmony_ci 377362306a36Sopenharmony_ciout: 377462306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 377562306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, get_mac_list_cmd.size, 377662306a36Sopenharmony_ci get_mac_list_cmd.va, get_mac_list_cmd.dma); 377762306a36Sopenharmony_ci return status; 377862306a36Sopenharmony_ci} 377962306a36Sopenharmony_ci 378062306a36Sopenharmony_ciint be_cmd_get_active_mac(struct be_adapter *adapter, u32 curr_pmac_id, 378162306a36Sopenharmony_ci u8 *mac, u32 if_handle, bool active, u32 domain) 378262306a36Sopenharmony_ci{ 378362306a36Sopenharmony_ci if (!active) 378462306a36Sopenharmony_ci be_cmd_get_mac_from_list(adapter, mac, &active, &curr_pmac_id, 378562306a36Sopenharmony_ci if_handle, domain); 378662306a36Sopenharmony_ci if (BEx_chip(adapter)) 378762306a36Sopenharmony_ci return be_cmd_mac_addr_query(adapter, mac, false, 378862306a36Sopenharmony_ci if_handle, curr_pmac_id); 378962306a36Sopenharmony_ci else 379062306a36Sopenharmony_ci /* Fetch the MAC address using pmac_id */ 379162306a36Sopenharmony_ci return be_cmd_get_mac_from_list(adapter, mac, &active, 379262306a36Sopenharmony_ci &curr_pmac_id, 379362306a36Sopenharmony_ci if_handle, domain); 379462306a36Sopenharmony_ci} 379562306a36Sopenharmony_ci 379662306a36Sopenharmony_ciint be_cmd_get_perm_mac(struct be_adapter *adapter, u8 *mac) 379762306a36Sopenharmony_ci{ 379862306a36Sopenharmony_ci int status; 379962306a36Sopenharmony_ci bool pmac_valid = false; 380062306a36Sopenharmony_ci 380162306a36Sopenharmony_ci eth_zero_addr(mac); 380262306a36Sopenharmony_ci 380362306a36Sopenharmony_ci if (BEx_chip(adapter)) { 380462306a36Sopenharmony_ci if (be_physfn(adapter)) 380562306a36Sopenharmony_ci status = be_cmd_mac_addr_query(adapter, mac, true, 0, 380662306a36Sopenharmony_ci 0); 380762306a36Sopenharmony_ci else 380862306a36Sopenharmony_ci status = be_cmd_mac_addr_query(adapter, mac, false, 380962306a36Sopenharmony_ci adapter->if_handle, 0); 381062306a36Sopenharmony_ci } else { 381162306a36Sopenharmony_ci status = be_cmd_get_mac_from_list(adapter, mac, &pmac_valid, 381262306a36Sopenharmony_ci NULL, adapter->if_handle, 0); 381362306a36Sopenharmony_ci } 381462306a36Sopenharmony_ci 381562306a36Sopenharmony_ci return status; 381662306a36Sopenharmony_ci} 381762306a36Sopenharmony_ci 381862306a36Sopenharmony_ci/* Uses synchronous MCCQ */ 381962306a36Sopenharmony_ciint be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, 382062306a36Sopenharmony_ci u8 mac_count, u32 domain) 382162306a36Sopenharmony_ci{ 382262306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 382362306a36Sopenharmony_ci struct be_cmd_req_set_mac_list *req; 382462306a36Sopenharmony_ci int status; 382562306a36Sopenharmony_ci struct be_dma_mem cmd; 382662306a36Sopenharmony_ci 382762306a36Sopenharmony_ci memset(&cmd, 0, sizeof(struct be_dma_mem)); 382862306a36Sopenharmony_ci cmd.size = sizeof(struct be_cmd_req_set_mac_list); 382962306a36Sopenharmony_ci cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, 383062306a36Sopenharmony_ci GFP_KERNEL); 383162306a36Sopenharmony_ci if (!cmd.va) 383262306a36Sopenharmony_ci return -ENOMEM; 383362306a36Sopenharmony_ci 383462306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 383562306a36Sopenharmony_ci 383662306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 383762306a36Sopenharmony_ci if (!wrb) { 383862306a36Sopenharmony_ci status = -EBUSY; 383962306a36Sopenharmony_ci goto err; 384062306a36Sopenharmony_ci } 384162306a36Sopenharmony_ci 384262306a36Sopenharmony_ci req = cmd.va; 384362306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 384462306a36Sopenharmony_ci OPCODE_COMMON_SET_MAC_LIST, sizeof(*req), 384562306a36Sopenharmony_ci wrb, &cmd); 384662306a36Sopenharmony_ci 384762306a36Sopenharmony_ci req->hdr.domain = domain; 384862306a36Sopenharmony_ci req->mac_count = mac_count; 384962306a36Sopenharmony_ci if (mac_count) 385062306a36Sopenharmony_ci memcpy(req->mac, mac_array, ETH_ALEN * mac_count); 385162306a36Sopenharmony_ci 385262306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 385362306a36Sopenharmony_ci 385462306a36Sopenharmony_cierr: 385562306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, cmd.dma); 385662306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 385762306a36Sopenharmony_ci return status; 385862306a36Sopenharmony_ci} 385962306a36Sopenharmony_ci 386062306a36Sopenharmony_ci/* Wrapper to delete any active MACs and provision the new mac. 386162306a36Sopenharmony_ci * Changes to MAC_LIST are allowed iff none of the MAC addresses in the 386262306a36Sopenharmony_ci * current list are active. 386362306a36Sopenharmony_ci */ 386462306a36Sopenharmony_ciint be_cmd_set_mac(struct be_adapter *adapter, u8 *mac, int if_id, u32 dom) 386562306a36Sopenharmony_ci{ 386662306a36Sopenharmony_ci bool active_mac = false; 386762306a36Sopenharmony_ci u8 old_mac[ETH_ALEN]; 386862306a36Sopenharmony_ci u32 pmac_id; 386962306a36Sopenharmony_ci int status; 387062306a36Sopenharmony_ci 387162306a36Sopenharmony_ci status = be_cmd_get_mac_from_list(adapter, old_mac, &active_mac, 387262306a36Sopenharmony_ci &pmac_id, if_id, dom); 387362306a36Sopenharmony_ci 387462306a36Sopenharmony_ci if (!status && active_mac) 387562306a36Sopenharmony_ci be_cmd_pmac_del(adapter, if_id, pmac_id, dom); 387662306a36Sopenharmony_ci 387762306a36Sopenharmony_ci return be_cmd_set_mac_list(adapter, mac, mac ? 1 : 0, dom); 387862306a36Sopenharmony_ci} 387962306a36Sopenharmony_ci 388062306a36Sopenharmony_ciint be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid, 388162306a36Sopenharmony_ci u32 domain, u16 intf_id, u16 hsw_mode, u8 spoofchk) 388262306a36Sopenharmony_ci{ 388362306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 388462306a36Sopenharmony_ci struct be_cmd_req_set_hsw_config *req; 388562306a36Sopenharmony_ci void *ctxt; 388662306a36Sopenharmony_ci int status; 388762306a36Sopenharmony_ci 388862306a36Sopenharmony_ci if (!be_cmd_allowed(adapter, OPCODE_COMMON_SET_HSW_CONFIG, 388962306a36Sopenharmony_ci CMD_SUBSYSTEM_COMMON)) 389062306a36Sopenharmony_ci return -EPERM; 389162306a36Sopenharmony_ci 389262306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 389362306a36Sopenharmony_ci 389462306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 389562306a36Sopenharmony_ci if (!wrb) { 389662306a36Sopenharmony_ci status = -EBUSY; 389762306a36Sopenharmony_ci goto err; 389862306a36Sopenharmony_ci } 389962306a36Sopenharmony_ci 390062306a36Sopenharmony_ci req = embedded_payload(wrb); 390162306a36Sopenharmony_ci ctxt = &req->context; 390262306a36Sopenharmony_ci 390362306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 390462306a36Sopenharmony_ci OPCODE_COMMON_SET_HSW_CONFIG, sizeof(*req), wrb, 390562306a36Sopenharmony_ci NULL); 390662306a36Sopenharmony_ci 390762306a36Sopenharmony_ci req->hdr.domain = domain; 390862306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_set_hsw_context, interface_id, ctxt, intf_id); 390962306a36Sopenharmony_ci if (pvid) { 391062306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_set_hsw_context, pvid_valid, ctxt, 1); 391162306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_set_hsw_context, pvid, ctxt, pvid); 391262306a36Sopenharmony_ci } 391362306a36Sopenharmony_ci if (hsw_mode) { 391462306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_set_hsw_context, interface_id, 391562306a36Sopenharmony_ci ctxt, adapter->hba_port_num); 391662306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_set_hsw_context, pport, ctxt, 1); 391762306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_set_hsw_context, port_fwd_type, 391862306a36Sopenharmony_ci ctxt, hsw_mode); 391962306a36Sopenharmony_ci } 392062306a36Sopenharmony_ci 392162306a36Sopenharmony_ci /* Enable/disable both mac and vlan spoof checking */ 392262306a36Sopenharmony_ci if (!BEx_chip(adapter) && spoofchk) { 392362306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_set_hsw_context, mac_spoofchk, 392462306a36Sopenharmony_ci ctxt, spoofchk); 392562306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_set_hsw_context, vlan_spoofchk, 392662306a36Sopenharmony_ci ctxt, spoofchk); 392762306a36Sopenharmony_ci } 392862306a36Sopenharmony_ci 392962306a36Sopenharmony_ci be_dws_cpu_to_le(req->context, sizeof(req->context)); 393062306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 393162306a36Sopenharmony_ci 393262306a36Sopenharmony_cierr: 393362306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 393462306a36Sopenharmony_ci return status; 393562306a36Sopenharmony_ci} 393662306a36Sopenharmony_ci 393762306a36Sopenharmony_ci/* Get Hyper switch config */ 393862306a36Sopenharmony_ciint be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid, 393962306a36Sopenharmony_ci u32 domain, u16 intf_id, u8 *mode, bool *spoofchk) 394062306a36Sopenharmony_ci{ 394162306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 394262306a36Sopenharmony_ci struct be_cmd_req_get_hsw_config *req; 394362306a36Sopenharmony_ci void *ctxt; 394462306a36Sopenharmony_ci int status; 394562306a36Sopenharmony_ci u16 vid; 394662306a36Sopenharmony_ci 394762306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 394862306a36Sopenharmony_ci 394962306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 395062306a36Sopenharmony_ci if (!wrb) { 395162306a36Sopenharmony_ci status = -EBUSY; 395262306a36Sopenharmony_ci goto err; 395362306a36Sopenharmony_ci } 395462306a36Sopenharmony_ci 395562306a36Sopenharmony_ci req = embedded_payload(wrb); 395662306a36Sopenharmony_ci ctxt = &req->context; 395762306a36Sopenharmony_ci 395862306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 395962306a36Sopenharmony_ci OPCODE_COMMON_GET_HSW_CONFIG, sizeof(*req), wrb, 396062306a36Sopenharmony_ci NULL); 396162306a36Sopenharmony_ci 396262306a36Sopenharmony_ci req->hdr.domain = domain; 396362306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_get_hsw_req_context, interface_id, 396462306a36Sopenharmony_ci ctxt, intf_id); 396562306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_get_hsw_req_context, pvid_valid, ctxt, 1); 396662306a36Sopenharmony_ci 396762306a36Sopenharmony_ci if (!BEx_chip(adapter) && mode) { 396862306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_get_hsw_req_context, interface_id, 396962306a36Sopenharmony_ci ctxt, adapter->hba_port_num); 397062306a36Sopenharmony_ci AMAP_SET_BITS(struct amap_get_hsw_req_context, pport, ctxt, 1); 397162306a36Sopenharmony_ci } 397262306a36Sopenharmony_ci be_dws_cpu_to_le(req->context, sizeof(req->context)); 397362306a36Sopenharmony_ci 397462306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 397562306a36Sopenharmony_ci if (!status) { 397662306a36Sopenharmony_ci struct be_cmd_resp_get_hsw_config *resp = 397762306a36Sopenharmony_ci embedded_payload(wrb); 397862306a36Sopenharmony_ci 397962306a36Sopenharmony_ci be_dws_le_to_cpu(&resp->context, sizeof(resp->context)); 398062306a36Sopenharmony_ci vid = AMAP_GET_BITS(struct amap_get_hsw_resp_context, 398162306a36Sopenharmony_ci pvid, &resp->context); 398262306a36Sopenharmony_ci if (pvid) 398362306a36Sopenharmony_ci *pvid = le16_to_cpu(vid); 398462306a36Sopenharmony_ci if (mode) 398562306a36Sopenharmony_ci *mode = AMAP_GET_BITS(struct amap_get_hsw_resp_context, 398662306a36Sopenharmony_ci port_fwd_type, &resp->context); 398762306a36Sopenharmony_ci if (spoofchk) 398862306a36Sopenharmony_ci *spoofchk = 398962306a36Sopenharmony_ci AMAP_GET_BITS(struct amap_get_hsw_resp_context, 399062306a36Sopenharmony_ci spoofchk, &resp->context); 399162306a36Sopenharmony_ci } 399262306a36Sopenharmony_ci 399362306a36Sopenharmony_cierr: 399462306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 399562306a36Sopenharmony_ci return status; 399662306a36Sopenharmony_ci} 399762306a36Sopenharmony_ci 399862306a36Sopenharmony_cistatic bool be_is_wol_excluded(struct be_adapter *adapter) 399962306a36Sopenharmony_ci{ 400062306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 400162306a36Sopenharmony_ci 400262306a36Sopenharmony_ci if (be_virtfn(adapter)) 400362306a36Sopenharmony_ci return true; 400462306a36Sopenharmony_ci 400562306a36Sopenharmony_ci switch (pdev->subsystem_device) { 400662306a36Sopenharmony_ci case OC_SUBSYS_DEVICE_ID1: 400762306a36Sopenharmony_ci case OC_SUBSYS_DEVICE_ID2: 400862306a36Sopenharmony_ci case OC_SUBSYS_DEVICE_ID3: 400962306a36Sopenharmony_ci case OC_SUBSYS_DEVICE_ID4: 401062306a36Sopenharmony_ci return true; 401162306a36Sopenharmony_ci default: 401262306a36Sopenharmony_ci return false; 401362306a36Sopenharmony_ci } 401462306a36Sopenharmony_ci} 401562306a36Sopenharmony_ci 401662306a36Sopenharmony_ciint be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) 401762306a36Sopenharmony_ci{ 401862306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 401962306a36Sopenharmony_ci struct be_cmd_req_acpi_wol_magic_config_v1 *req; 402062306a36Sopenharmony_ci int status = 0; 402162306a36Sopenharmony_ci struct be_dma_mem cmd; 402262306a36Sopenharmony_ci 402362306a36Sopenharmony_ci if (!be_cmd_allowed(adapter, OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, 402462306a36Sopenharmony_ci CMD_SUBSYSTEM_ETH)) 402562306a36Sopenharmony_ci return -EPERM; 402662306a36Sopenharmony_ci 402762306a36Sopenharmony_ci if (be_is_wol_excluded(adapter)) 402862306a36Sopenharmony_ci return status; 402962306a36Sopenharmony_ci 403062306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 403162306a36Sopenharmony_ci return -1; 403262306a36Sopenharmony_ci 403362306a36Sopenharmony_ci memset(&cmd, 0, sizeof(struct be_dma_mem)); 403462306a36Sopenharmony_ci cmd.size = sizeof(struct be_cmd_resp_acpi_wol_magic_config_v1); 403562306a36Sopenharmony_ci cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, 403662306a36Sopenharmony_ci GFP_ATOMIC); 403762306a36Sopenharmony_ci if (!cmd.va) { 403862306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Memory allocation failure\n"); 403962306a36Sopenharmony_ci status = -ENOMEM; 404062306a36Sopenharmony_ci goto err; 404162306a36Sopenharmony_ci } 404262306a36Sopenharmony_ci 404362306a36Sopenharmony_ci wrb = wrb_from_mbox(adapter); 404462306a36Sopenharmony_ci if (!wrb) { 404562306a36Sopenharmony_ci status = -EBUSY; 404662306a36Sopenharmony_ci goto err; 404762306a36Sopenharmony_ci } 404862306a36Sopenharmony_ci 404962306a36Sopenharmony_ci req = cmd.va; 405062306a36Sopenharmony_ci 405162306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, 405262306a36Sopenharmony_ci OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, 405362306a36Sopenharmony_ci sizeof(*req), wrb, &cmd); 405462306a36Sopenharmony_ci 405562306a36Sopenharmony_ci req->hdr.version = 1; 405662306a36Sopenharmony_ci req->query_options = BE_GET_WOL_CAP; 405762306a36Sopenharmony_ci 405862306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 405962306a36Sopenharmony_ci if (!status) { 406062306a36Sopenharmony_ci struct be_cmd_resp_acpi_wol_magic_config_v1 *resp; 406162306a36Sopenharmony_ci 406262306a36Sopenharmony_ci resp = (struct be_cmd_resp_acpi_wol_magic_config_v1 *)cmd.va; 406362306a36Sopenharmony_ci 406462306a36Sopenharmony_ci adapter->wol_cap = resp->wol_settings; 406562306a36Sopenharmony_ci 406662306a36Sopenharmony_ci /* Non-zero macaddr indicates WOL is enabled */ 406762306a36Sopenharmony_ci if (adapter->wol_cap & BE_WOL_CAP && 406862306a36Sopenharmony_ci !is_zero_ether_addr(resp->magic_mac)) 406962306a36Sopenharmony_ci adapter->wol_en = true; 407062306a36Sopenharmony_ci } 407162306a36Sopenharmony_cierr: 407262306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 407362306a36Sopenharmony_ci if (cmd.va) 407462306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, 407562306a36Sopenharmony_ci cmd.dma); 407662306a36Sopenharmony_ci return status; 407762306a36Sopenharmony_ci 407862306a36Sopenharmony_ci} 407962306a36Sopenharmony_ci 408062306a36Sopenharmony_ciint be_cmd_set_fw_log_level(struct be_adapter *adapter, u32 level) 408162306a36Sopenharmony_ci{ 408262306a36Sopenharmony_ci struct be_dma_mem extfat_cmd; 408362306a36Sopenharmony_ci struct be_fat_conf_params *cfgs; 408462306a36Sopenharmony_ci int status; 408562306a36Sopenharmony_ci int i, j; 408662306a36Sopenharmony_ci 408762306a36Sopenharmony_ci memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); 408862306a36Sopenharmony_ci extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); 408962306a36Sopenharmony_ci extfat_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, 409062306a36Sopenharmony_ci extfat_cmd.size, &extfat_cmd.dma, 409162306a36Sopenharmony_ci GFP_ATOMIC); 409262306a36Sopenharmony_ci if (!extfat_cmd.va) 409362306a36Sopenharmony_ci return -ENOMEM; 409462306a36Sopenharmony_ci 409562306a36Sopenharmony_ci status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd); 409662306a36Sopenharmony_ci if (status) 409762306a36Sopenharmony_ci goto err; 409862306a36Sopenharmony_ci 409962306a36Sopenharmony_ci cfgs = (struct be_fat_conf_params *) 410062306a36Sopenharmony_ci (extfat_cmd.va + sizeof(struct be_cmd_resp_hdr)); 410162306a36Sopenharmony_ci for (i = 0; i < le32_to_cpu(cfgs->num_modules); i++) { 410262306a36Sopenharmony_ci u32 num_modes = le32_to_cpu(cfgs->module[i].num_modes); 410362306a36Sopenharmony_ci 410462306a36Sopenharmony_ci for (j = 0; j < num_modes; j++) { 410562306a36Sopenharmony_ci if (cfgs->module[i].trace_lvl[j].mode == MODE_UART) 410662306a36Sopenharmony_ci cfgs->module[i].trace_lvl[j].dbg_lvl = 410762306a36Sopenharmony_ci cpu_to_le32(level); 410862306a36Sopenharmony_ci } 410962306a36Sopenharmony_ci } 411062306a36Sopenharmony_ci 411162306a36Sopenharmony_ci status = be_cmd_set_ext_fat_capabilites(adapter, &extfat_cmd, cfgs); 411262306a36Sopenharmony_cierr: 411362306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, extfat_cmd.size, extfat_cmd.va, 411462306a36Sopenharmony_ci extfat_cmd.dma); 411562306a36Sopenharmony_ci return status; 411662306a36Sopenharmony_ci} 411762306a36Sopenharmony_ci 411862306a36Sopenharmony_ciint be_cmd_get_fw_log_level(struct be_adapter *adapter) 411962306a36Sopenharmony_ci{ 412062306a36Sopenharmony_ci struct be_dma_mem extfat_cmd; 412162306a36Sopenharmony_ci struct be_fat_conf_params *cfgs; 412262306a36Sopenharmony_ci int status, j; 412362306a36Sopenharmony_ci int level = 0; 412462306a36Sopenharmony_ci 412562306a36Sopenharmony_ci memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); 412662306a36Sopenharmony_ci extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); 412762306a36Sopenharmony_ci extfat_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, 412862306a36Sopenharmony_ci extfat_cmd.size, &extfat_cmd.dma, 412962306a36Sopenharmony_ci GFP_ATOMIC); 413062306a36Sopenharmony_ci 413162306a36Sopenharmony_ci if (!extfat_cmd.va) { 413262306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n", 413362306a36Sopenharmony_ci __func__); 413462306a36Sopenharmony_ci goto err; 413562306a36Sopenharmony_ci } 413662306a36Sopenharmony_ci 413762306a36Sopenharmony_ci status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd); 413862306a36Sopenharmony_ci if (!status) { 413962306a36Sopenharmony_ci cfgs = (struct be_fat_conf_params *)(extfat_cmd.va + 414062306a36Sopenharmony_ci sizeof(struct be_cmd_resp_hdr)); 414162306a36Sopenharmony_ci 414262306a36Sopenharmony_ci for (j = 0; j < le32_to_cpu(cfgs->module[0].num_modes); j++) { 414362306a36Sopenharmony_ci if (cfgs->module[0].trace_lvl[j].mode == MODE_UART) 414462306a36Sopenharmony_ci level = cfgs->module[0].trace_lvl[j].dbg_lvl; 414562306a36Sopenharmony_ci } 414662306a36Sopenharmony_ci } 414762306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, extfat_cmd.size, extfat_cmd.va, 414862306a36Sopenharmony_ci extfat_cmd.dma); 414962306a36Sopenharmony_cierr: 415062306a36Sopenharmony_ci return level; 415162306a36Sopenharmony_ci} 415262306a36Sopenharmony_ci 415362306a36Sopenharmony_ciint be_cmd_get_ext_fat_capabilites(struct be_adapter *adapter, 415462306a36Sopenharmony_ci struct be_dma_mem *cmd) 415562306a36Sopenharmony_ci{ 415662306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 415762306a36Sopenharmony_ci struct be_cmd_req_get_ext_fat_caps *req; 415862306a36Sopenharmony_ci int status; 415962306a36Sopenharmony_ci 416062306a36Sopenharmony_ci if (!be_cmd_allowed(adapter, OPCODE_COMMON_GET_EXT_FAT_CAPABILITIES, 416162306a36Sopenharmony_ci CMD_SUBSYSTEM_COMMON)) 416262306a36Sopenharmony_ci return -EPERM; 416362306a36Sopenharmony_ci 416462306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 416562306a36Sopenharmony_ci return -1; 416662306a36Sopenharmony_ci 416762306a36Sopenharmony_ci wrb = wrb_from_mbox(adapter); 416862306a36Sopenharmony_ci if (!wrb) { 416962306a36Sopenharmony_ci status = -EBUSY; 417062306a36Sopenharmony_ci goto err; 417162306a36Sopenharmony_ci } 417262306a36Sopenharmony_ci 417362306a36Sopenharmony_ci req = cmd->va; 417462306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 417562306a36Sopenharmony_ci OPCODE_COMMON_GET_EXT_FAT_CAPABILITIES, 417662306a36Sopenharmony_ci cmd->size, wrb, cmd); 417762306a36Sopenharmony_ci req->parameter_type = cpu_to_le32(1); 417862306a36Sopenharmony_ci 417962306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 418062306a36Sopenharmony_cierr: 418162306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 418262306a36Sopenharmony_ci return status; 418362306a36Sopenharmony_ci} 418462306a36Sopenharmony_ci 418562306a36Sopenharmony_ciint be_cmd_set_ext_fat_capabilites(struct be_adapter *adapter, 418662306a36Sopenharmony_ci struct be_dma_mem *cmd, 418762306a36Sopenharmony_ci struct be_fat_conf_params *configs) 418862306a36Sopenharmony_ci{ 418962306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 419062306a36Sopenharmony_ci struct be_cmd_req_set_ext_fat_caps *req; 419162306a36Sopenharmony_ci int status; 419262306a36Sopenharmony_ci 419362306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 419462306a36Sopenharmony_ci 419562306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 419662306a36Sopenharmony_ci if (!wrb) { 419762306a36Sopenharmony_ci status = -EBUSY; 419862306a36Sopenharmony_ci goto err; 419962306a36Sopenharmony_ci } 420062306a36Sopenharmony_ci 420162306a36Sopenharmony_ci req = cmd->va; 420262306a36Sopenharmony_ci memcpy(&req->set_params, configs, sizeof(struct be_fat_conf_params)); 420362306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 420462306a36Sopenharmony_ci OPCODE_COMMON_SET_EXT_FAT_CAPABILITIES, 420562306a36Sopenharmony_ci cmd->size, wrb, cmd); 420662306a36Sopenharmony_ci 420762306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 420862306a36Sopenharmony_cierr: 420962306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 421062306a36Sopenharmony_ci return status; 421162306a36Sopenharmony_ci} 421262306a36Sopenharmony_ci 421362306a36Sopenharmony_ciint be_cmd_query_port_name(struct be_adapter *adapter) 421462306a36Sopenharmony_ci{ 421562306a36Sopenharmony_ci struct be_cmd_req_get_port_name *req; 421662306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 421762306a36Sopenharmony_ci int status; 421862306a36Sopenharmony_ci 421962306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 422062306a36Sopenharmony_ci return -1; 422162306a36Sopenharmony_ci 422262306a36Sopenharmony_ci wrb = wrb_from_mbox(adapter); 422362306a36Sopenharmony_ci req = embedded_payload(wrb); 422462306a36Sopenharmony_ci 422562306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 422662306a36Sopenharmony_ci OPCODE_COMMON_GET_PORT_NAME, sizeof(*req), wrb, 422762306a36Sopenharmony_ci NULL); 422862306a36Sopenharmony_ci if (!BEx_chip(adapter)) 422962306a36Sopenharmony_ci req->hdr.version = 1; 423062306a36Sopenharmony_ci 423162306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 423262306a36Sopenharmony_ci if (!status) { 423362306a36Sopenharmony_ci struct be_cmd_resp_get_port_name *resp = embedded_payload(wrb); 423462306a36Sopenharmony_ci 423562306a36Sopenharmony_ci adapter->port_name = resp->port_name[adapter->hba_port_num]; 423662306a36Sopenharmony_ci } else { 423762306a36Sopenharmony_ci adapter->port_name = adapter->hba_port_num + '0'; 423862306a36Sopenharmony_ci } 423962306a36Sopenharmony_ci 424062306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 424162306a36Sopenharmony_ci return status; 424262306a36Sopenharmony_ci} 424362306a36Sopenharmony_ci 424462306a36Sopenharmony_ci/* When more than 1 NIC descriptor is present in the descriptor list, 424562306a36Sopenharmony_ci * the caller must specify the pf_num to obtain the NIC descriptor 424662306a36Sopenharmony_ci * corresponding to its pci function. 424762306a36Sopenharmony_ci * get_vft must be true when the caller wants the VF-template desc of the 424862306a36Sopenharmony_ci * PF-pool. 424962306a36Sopenharmony_ci * The pf_num should be set to PF_NUM_IGNORE when the caller knows 425062306a36Sopenharmony_ci * that only it's NIC descriptor is present in the descriptor list. 425162306a36Sopenharmony_ci */ 425262306a36Sopenharmony_cistatic struct be_nic_res_desc *be_get_nic_desc(u8 *buf, u32 desc_count, 425362306a36Sopenharmony_ci bool get_vft, u8 pf_num) 425462306a36Sopenharmony_ci{ 425562306a36Sopenharmony_ci struct be_res_desc_hdr *hdr = (struct be_res_desc_hdr *)buf; 425662306a36Sopenharmony_ci struct be_nic_res_desc *nic; 425762306a36Sopenharmony_ci int i; 425862306a36Sopenharmony_ci 425962306a36Sopenharmony_ci for (i = 0; i < desc_count; i++) { 426062306a36Sopenharmony_ci if (hdr->desc_type == NIC_RESOURCE_DESC_TYPE_V0 || 426162306a36Sopenharmony_ci hdr->desc_type == NIC_RESOURCE_DESC_TYPE_V1) { 426262306a36Sopenharmony_ci nic = (struct be_nic_res_desc *)hdr; 426362306a36Sopenharmony_ci 426462306a36Sopenharmony_ci if ((pf_num == PF_NUM_IGNORE || 426562306a36Sopenharmony_ci nic->pf_num == pf_num) && 426662306a36Sopenharmony_ci (!get_vft || nic->flags & BIT(VFT_SHIFT))) 426762306a36Sopenharmony_ci return nic; 426862306a36Sopenharmony_ci } 426962306a36Sopenharmony_ci hdr->desc_len = hdr->desc_len ? : RESOURCE_DESC_SIZE_V0; 427062306a36Sopenharmony_ci hdr = (void *)hdr + hdr->desc_len; 427162306a36Sopenharmony_ci } 427262306a36Sopenharmony_ci return NULL; 427362306a36Sopenharmony_ci} 427462306a36Sopenharmony_ci 427562306a36Sopenharmony_cistatic struct be_nic_res_desc *be_get_vft_desc(u8 *buf, u32 desc_count, 427662306a36Sopenharmony_ci u8 pf_num) 427762306a36Sopenharmony_ci{ 427862306a36Sopenharmony_ci return be_get_nic_desc(buf, desc_count, true, pf_num); 427962306a36Sopenharmony_ci} 428062306a36Sopenharmony_ci 428162306a36Sopenharmony_cistatic struct be_nic_res_desc *be_get_func_nic_desc(u8 *buf, u32 desc_count, 428262306a36Sopenharmony_ci u8 pf_num) 428362306a36Sopenharmony_ci{ 428462306a36Sopenharmony_ci return be_get_nic_desc(buf, desc_count, false, pf_num); 428562306a36Sopenharmony_ci} 428662306a36Sopenharmony_ci 428762306a36Sopenharmony_cistatic struct be_pcie_res_desc *be_get_pcie_desc(u8 *buf, u32 desc_count, 428862306a36Sopenharmony_ci u8 pf_num) 428962306a36Sopenharmony_ci{ 429062306a36Sopenharmony_ci struct be_res_desc_hdr *hdr = (struct be_res_desc_hdr *)buf; 429162306a36Sopenharmony_ci struct be_pcie_res_desc *pcie; 429262306a36Sopenharmony_ci int i; 429362306a36Sopenharmony_ci 429462306a36Sopenharmony_ci for (i = 0; i < desc_count; i++) { 429562306a36Sopenharmony_ci if (hdr->desc_type == PCIE_RESOURCE_DESC_TYPE_V0 || 429662306a36Sopenharmony_ci hdr->desc_type == PCIE_RESOURCE_DESC_TYPE_V1) { 429762306a36Sopenharmony_ci pcie = (struct be_pcie_res_desc *)hdr; 429862306a36Sopenharmony_ci if (pcie->pf_num == pf_num) 429962306a36Sopenharmony_ci return pcie; 430062306a36Sopenharmony_ci } 430162306a36Sopenharmony_ci 430262306a36Sopenharmony_ci hdr->desc_len = hdr->desc_len ? : RESOURCE_DESC_SIZE_V0; 430362306a36Sopenharmony_ci hdr = (void *)hdr + hdr->desc_len; 430462306a36Sopenharmony_ci } 430562306a36Sopenharmony_ci return NULL; 430662306a36Sopenharmony_ci} 430762306a36Sopenharmony_ci 430862306a36Sopenharmony_cistatic struct be_port_res_desc *be_get_port_desc(u8 *buf, u32 desc_count) 430962306a36Sopenharmony_ci{ 431062306a36Sopenharmony_ci struct be_res_desc_hdr *hdr = (struct be_res_desc_hdr *)buf; 431162306a36Sopenharmony_ci int i; 431262306a36Sopenharmony_ci 431362306a36Sopenharmony_ci for (i = 0; i < desc_count; i++) { 431462306a36Sopenharmony_ci if (hdr->desc_type == PORT_RESOURCE_DESC_TYPE_V1) 431562306a36Sopenharmony_ci return (struct be_port_res_desc *)hdr; 431662306a36Sopenharmony_ci 431762306a36Sopenharmony_ci hdr->desc_len = hdr->desc_len ? : RESOURCE_DESC_SIZE_V0; 431862306a36Sopenharmony_ci hdr = (void *)hdr + hdr->desc_len; 431962306a36Sopenharmony_ci } 432062306a36Sopenharmony_ci return NULL; 432162306a36Sopenharmony_ci} 432262306a36Sopenharmony_ci 432362306a36Sopenharmony_cistatic void be_copy_nic_desc(struct be_resources *res, 432462306a36Sopenharmony_ci struct be_nic_res_desc *desc) 432562306a36Sopenharmony_ci{ 432662306a36Sopenharmony_ci res->max_uc_mac = le16_to_cpu(desc->unicast_mac_count); 432762306a36Sopenharmony_ci res->max_vlans = le16_to_cpu(desc->vlan_count); 432862306a36Sopenharmony_ci res->max_mcast_mac = le16_to_cpu(desc->mcast_mac_count); 432962306a36Sopenharmony_ci res->max_tx_qs = le16_to_cpu(desc->txq_count); 433062306a36Sopenharmony_ci res->max_rss_qs = le16_to_cpu(desc->rssq_count); 433162306a36Sopenharmony_ci res->max_rx_qs = le16_to_cpu(desc->rq_count); 433262306a36Sopenharmony_ci res->max_evt_qs = le16_to_cpu(desc->eq_count); 433362306a36Sopenharmony_ci res->max_cq_count = le16_to_cpu(desc->cq_count); 433462306a36Sopenharmony_ci res->max_iface_count = le16_to_cpu(desc->iface_count); 433562306a36Sopenharmony_ci res->max_mcc_count = le16_to_cpu(desc->mcc_count); 433662306a36Sopenharmony_ci /* Clear flags that driver is not interested in */ 433762306a36Sopenharmony_ci res->if_cap_flags = le32_to_cpu(desc->cap_flags) & 433862306a36Sopenharmony_ci BE_IF_CAP_FLAGS_WANT; 433962306a36Sopenharmony_ci} 434062306a36Sopenharmony_ci 434162306a36Sopenharmony_ci/* Uses Mbox */ 434262306a36Sopenharmony_ciint be_cmd_get_func_config(struct be_adapter *adapter, struct be_resources *res) 434362306a36Sopenharmony_ci{ 434462306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 434562306a36Sopenharmony_ci struct be_cmd_req_get_func_config *req; 434662306a36Sopenharmony_ci int status; 434762306a36Sopenharmony_ci struct be_dma_mem cmd; 434862306a36Sopenharmony_ci 434962306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 435062306a36Sopenharmony_ci return -1; 435162306a36Sopenharmony_ci 435262306a36Sopenharmony_ci memset(&cmd, 0, sizeof(struct be_dma_mem)); 435362306a36Sopenharmony_ci cmd.size = sizeof(struct be_cmd_resp_get_func_config); 435462306a36Sopenharmony_ci cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, 435562306a36Sopenharmony_ci GFP_ATOMIC); 435662306a36Sopenharmony_ci if (!cmd.va) { 435762306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Memory alloc failure\n"); 435862306a36Sopenharmony_ci status = -ENOMEM; 435962306a36Sopenharmony_ci goto err; 436062306a36Sopenharmony_ci } 436162306a36Sopenharmony_ci 436262306a36Sopenharmony_ci wrb = wrb_from_mbox(adapter); 436362306a36Sopenharmony_ci if (!wrb) { 436462306a36Sopenharmony_ci status = -EBUSY; 436562306a36Sopenharmony_ci goto err; 436662306a36Sopenharmony_ci } 436762306a36Sopenharmony_ci 436862306a36Sopenharmony_ci req = cmd.va; 436962306a36Sopenharmony_ci 437062306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 437162306a36Sopenharmony_ci OPCODE_COMMON_GET_FUNC_CONFIG, 437262306a36Sopenharmony_ci cmd.size, wrb, &cmd); 437362306a36Sopenharmony_ci 437462306a36Sopenharmony_ci if (skyhawk_chip(adapter)) 437562306a36Sopenharmony_ci req->hdr.version = 1; 437662306a36Sopenharmony_ci 437762306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 437862306a36Sopenharmony_ci if (!status) { 437962306a36Sopenharmony_ci struct be_cmd_resp_get_func_config *resp = cmd.va; 438062306a36Sopenharmony_ci u32 desc_count = le32_to_cpu(resp->desc_count); 438162306a36Sopenharmony_ci struct be_nic_res_desc *desc; 438262306a36Sopenharmony_ci 438362306a36Sopenharmony_ci /* GET_FUNC_CONFIG returns resource descriptors of the 438462306a36Sopenharmony_ci * current function only. So, pf_num should be set to 438562306a36Sopenharmony_ci * PF_NUM_IGNORE. 438662306a36Sopenharmony_ci */ 438762306a36Sopenharmony_ci desc = be_get_func_nic_desc(resp->func_param, desc_count, 438862306a36Sopenharmony_ci PF_NUM_IGNORE); 438962306a36Sopenharmony_ci if (!desc) { 439062306a36Sopenharmony_ci status = -EINVAL; 439162306a36Sopenharmony_ci goto err; 439262306a36Sopenharmony_ci } 439362306a36Sopenharmony_ci 439462306a36Sopenharmony_ci /* Store pf_num & vf_num for later use in GET_PROFILE_CONFIG */ 439562306a36Sopenharmony_ci adapter->pf_num = desc->pf_num; 439662306a36Sopenharmony_ci adapter->vf_num = desc->vf_num; 439762306a36Sopenharmony_ci 439862306a36Sopenharmony_ci if (res) 439962306a36Sopenharmony_ci be_copy_nic_desc(res, desc); 440062306a36Sopenharmony_ci } 440162306a36Sopenharmony_cierr: 440262306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 440362306a36Sopenharmony_ci if (cmd.va) 440462306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, 440562306a36Sopenharmony_ci cmd.dma); 440662306a36Sopenharmony_ci return status; 440762306a36Sopenharmony_ci} 440862306a36Sopenharmony_ci 440962306a36Sopenharmony_ci/* This routine returns a list of all the NIC PF_nums in the adapter */ 441062306a36Sopenharmony_cistatic u16 be_get_nic_pf_num_list(u8 *buf, u32 desc_count, u16 *nic_pf_nums) 441162306a36Sopenharmony_ci{ 441262306a36Sopenharmony_ci struct be_res_desc_hdr *hdr = (struct be_res_desc_hdr *)buf; 441362306a36Sopenharmony_ci struct be_pcie_res_desc *pcie = NULL; 441462306a36Sopenharmony_ci int i; 441562306a36Sopenharmony_ci u16 nic_pf_count = 0; 441662306a36Sopenharmony_ci 441762306a36Sopenharmony_ci for (i = 0; i < desc_count; i++) { 441862306a36Sopenharmony_ci if (hdr->desc_type == PCIE_RESOURCE_DESC_TYPE_V0 || 441962306a36Sopenharmony_ci hdr->desc_type == PCIE_RESOURCE_DESC_TYPE_V1) { 442062306a36Sopenharmony_ci pcie = (struct be_pcie_res_desc *)hdr; 442162306a36Sopenharmony_ci if (pcie->pf_state && (pcie->pf_type == MISSION_NIC || 442262306a36Sopenharmony_ci pcie->pf_type == MISSION_RDMA)) { 442362306a36Sopenharmony_ci nic_pf_nums[nic_pf_count++] = pcie->pf_num; 442462306a36Sopenharmony_ci } 442562306a36Sopenharmony_ci } 442662306a36Sopenharmony_ci 442762306a36Sopenharmony_ci hdr->desc_len = hdr->desc_len ? : RESOURCE_DESC_SIZE_V0; 442862306a36Sopenharmony_ci hdr = (void *)hdr + hdr->desc_len; 442962306a36Sopenharmony_ci } 443062306a36Sopenharmony_ci return nic_pf_count; 443162306a36Sopenharmony_ci} 443262306a36Sopenharmony_ci 443362306a36Sopenharmony_ci/* Will use MBOX only if MCCQ has not been created */ 443462306a36Sopenharmony_ciint be_cmd_get_profile_config(struct be_adapter *adapter, 443562306a36Sopenharmony_ci struct be_resources *res, 443662306a36Sopenharmony_ci struct be_port_resources *port_res, 443762306a36Sopenharmony_ci u8 profile_type, u8 query, u8 domain) 443862306a36Sopenharmony_ci{ 443962306a36Sopenharmony_ci struct be_cmd_resp_get_profile_config *resp; 444062306a36Sopenharmony_ci struct be_cmd_req_get_profile_config *req; 444162306a36Sopenharmony_ci struct be_nic_res_desc *vf_res; 444262306a36Sopenharmony_ci struct be_pcie_res_desc *pcie; 444362306a36Sopenharmony_ci struct be_port_res_desc *port; 444462306a36Sopenharmony_ci struct be_nic_res_desc *nic; 444562306a36Sopenharmony_ci struct be_mcc_wrb wrb = {0}; 444662306a36Sopenharmony_ci struct be_dma_mem cmd; 444762306a36Sopenharmony_ci u16 desc_count; 444862306a36Sopenharmony_ci int status; 444962306a36Sopenharmony_ci 445062306a36Sopenharmony_ci memset(&cmd, 0, sizeof(struct be_dma_mem)); 445162306a36Sopenharmony_ci cmd.size = sizeof(struct be_cmd_resp_get_profile_config); 445262306a36Sopenharmony_ci cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, 445362306a36Sopenharmony_ci GFP_ATOMIC); 445462306a36Sopenharmony_ci if (!cmd.va) 445562306a36Sopenharmony_ci return -ENOMEM; 445662306a36Sopenharmony_ci 445762306a36Sopenharmony_ci req = cmd.va; 445862306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 445962306a36Sopenharmony_ci OPCODE_COMMON_GET_PROFILE_CONFIG, 446062306a36Sopenharmony_ci cmd.size, &wrb, &cmd); 446162306a36Sopenharmony_ci 446262306a36Sopenharmony_ci if (!lancer_chip(adapter)) 446362306a36Sopenharmony_ci req->hdr.version = 1; 446462306a36Sopenharmony_ci req->type = profile_type; 446562306a36Sopenharmony_ci req->hdr.domain = domain; 446662306a36Sopenharmony_ci 446762306a36Sopenharmony_ci /* When QUERY_MODIFIABLE_FIELDS_TYPE bit is set, cmd returns the 446862306a36Sopenharmony_ci * descriptors with all bits set to "1" for the fields which can be 446962306a36Sopenharmony_ci * modified using SET_PROFILE_CONFIG cmd. 447062306a36Sopenharmony_ci */ 447162306a36Sopenharmony_ci if (query == RESOURCE_MODIFIABLE) 447262306a36Sopenharmony_ci req->type |= QUERY_MODIFIABLE_FIELDS_TYPE; 447362306a36Sopenharmony_ci 447462306a36Sopenharmony_ci status = be_cmd_notify_wait(adapter, &wrb); 447562306a36Sopenharmony_ci if (status) 447662306a36Sopenharmony_ci goto err; 447762306a36Sopenharmony_ci 447862306a36Sopenharmony_ci resp = cmd.va; 447962306a36Sopenharmony_ci desc_count = le16_to_cpu(resp->desc_count); 448062306a36Sopenharmony_ci 448162306a36Sopenharmony_ci if (port_res) { 448262306a36Sopenharmony_ci u16 nic_pf_cnt = 0, i; 448362306a36Sopenharmony_ci u16 nic_pf_num_list[MAX_NIC_FUNCS]; 448462306a36Sopenharmony_ci 448562306a36Sopenharmony_ci nic_pf_cnt = be_get_nic_pf_num_list(resp->func_param, 448662306a36Sopenharmony_ci desc_count, 448762306a36Sopenharmony_ci nic_pf_num_list); 448862306a36Sopenharmony_ci 448962306a36Sopenharmony_ci for (i = 0; i < nic_pf_cnt; i++) { 449062306a36Sopenharmony_ci nic = be_get_func_nic_desc(resp->func_param, desc_count, 449162306a36Sopenharmony_ci nic_pf_num_list[i]); 449262306a36Sopenharmony_ci if (nic->link_param == adapter->port_num) { 449362306a36Sopenharmony_ci port_res->nic_pfs++; 449462306a36Sopenharmony_ci pcie = be_get_pcie_desc(resp->func_param, 449562306a36Sopenharmony_ci desc_count, 449662306a36Sopenharmony_ci nic_pf_num_list[i]); 449762306a36Sopenharmony_ci port_res->max_vfs += le16_to_cpu(pcie->num_vfs); 449862306a36Sopenharmony_ci } 449962306a36Sopenharmony_ci } 450062306a36Sopenharmony_ci goto err; 450162306a36Sopenharmony_ci } 450262306a36Sopenharmony_ci 450362306a36Sopenharmony_ci pcie = be_get_pcie_desc(resp->func_param, desc_count, 450462306a36Sopenharmony_ci adapter->pf_num); 450562306a36Sopenharmony_ci if (pcie) 450662306a36Sopenharmony_ci res->max_vfs = le16_to_cpu(pcie->num_vfs); 450762306a36Sopenharmony_ci 450862306a36Sopenharmony_ci port = be_get_port_desc(resp->func_param, desc_count); 450962306a36Sopenharmony_ci if (port) 451062306a36Sopenharmony_ci adapter->mc_type = port->mc_type; 451162306a36Sopenharmony_ci 451262306a36Sopenharmony_ci nic = be_get_func_nic_desc(resp->func_param, desc_count, 451362306a36Sopenharmony_ci adapter->pf_num); 451462306a36Sopenharmony_ci if (nic) 451562306a36Sopenharmony_ci be_copy_nic_desc(res, nic); 451662306a36Sopenharmony_ci 451762306a36Sopenharmony_ci vf_res = be_get_vft_desc(resp->func_param, desc_count, 451862306a36Sopenharmony_ci adapter->pf_num); 451962306a36Sopenharmony_ci if (vf_res) 452062306a36Sopenharmony_ci res->vf_if_cap_flags = vf_res->cap_flags; 452162306a36Sopenharmony_cierr: 452262306a36Sopenharmony_ci if (cmd.va) 452362306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, 452462306a36Sopenharmony_ci cmd.dma); 452562306a36Sopenharmony_ci return status; 452662306a36Sopenharmony_ci} 452762306a36Sopenharmony_ci 452862306a36Sopenharmony_ci/* Will use MBOX only if MCCQ has not been created */ 452962306a36Sopenharmony_cistatic int be_cmd_set_profile_config(struct be_adapter *adapter, void *desc, 453062306a36Sopenharmony_ci int size, int count, u8 version, u8 domain) 453162306a36Sopenharmony_ci{ 453262306a36Sopenharmony_ci struct be_cmd_req_set_profile_config *req; 453362306a36Sopenharmony_ci struct be_mcc_wrb wrb = {0}; 453462306a36Sopenharmony_ci struct be_dma_mem cmd; 453562306a36Sopenharmony_ci int status; 453662306a36Sopenharmony_ci 453762306a36Sopenharmony_ci memset(&cmd, 0, sizeof(struct be_dma_mem)); 453862306a36Sopenharmony_ci cmd.size = sizeof(struct be_cmd_req_set_profile_config); 453962306a36Sopenharmony_ci cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, 454062306a36Sopenharmony_ci GFP_ATOMIC); 454162306a36Sopenharmony_ci if (!cmd.va) 454262306a36Sopenharmony_ci return -ENOMEM; 454362306a36Sopenharmony_ci 454462306a36Sopenharmony_ci req = cmd.va; 454562306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 454662306a36Sopenharmony_ci OPCODE_COMMON_SET_PROFILE_CONFIG, cmd.size, 454762306a36Sopenharmony_ci &wrb, &cmd); 454862306a36Sopenharmony_ci req->hdr.version = version; 454962306a36Sopenharmony_ci req->hdr.domain = domain; 455062306a36Sopenharmony_ci req->desc_count = cpu_to_le32(count); 455162306a36Sopenharmony_ci memcpy(req->desc, desc, size); 455262306a36Sopenharmony_ci 455362306a36Sopenharmony_ci status = be_cmd_notify_wait(adapter, &wrb); 455462306a36Sopenharmony_ci 455562306a36Sopenharmony_ci if (cmd.va) 455662306a36Sopenharmony_ci dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, 455762306a36Sopenharmony_ci cmd.dma); 455862306a36Sopenharmony_ci return status; 455962306a36Sopenharmony_ci} 456062306a36Sopenharmony_ci 456162306a36Sopenharmony_ci/* Mark all fields invalid */ 456262306a36Sopenharmony_cistatic void be_reset_nic_desc(struct be_nic_res_desc *nic) 456362306a36Sopenharmony_ci{ 456462306a36Sopenharmony_ci memset(nic, 0, sizeof(*nic)); 456562306a36Sopenharmony_ci nic->unicast_mac_count = 0xFFFF; 456662306a36Sopenharmony_ci nic->mcc_count = 0xFFFF; 456762306a36Sopenharmony_ci nic->vlan_count = 0xFFFF; 456862306a36Sopenharmony_ci nic->mcast_mac_count = 0xFFFF; 456962306a36Sopenharmony_ci nic->txq_count = 0xFFFF; 457062306a36Sopenharmony_ci nic->rq_count = 0xFFFF; 457162306a36Sopenharmony_ci nic->rssq_count = 0xFFFF; 457262306a36Sopenharmony_ci nic->lro_count = 0xFFFF; 457362306a36Sopenharmony_ci nic->cq_count = 0xFFFF; 457462306a36Sopenharmony_ci nic->toe_conn_count = 0xFFFF; 457562306a36Sopenharmony_ci nic->eq_count = 0xFFFF; 457662306a36Sopenharmony_ci nic->iface_count = 0xFFFF; 457762306a36Sopenharmony_ci nic->link_param = 0xFF; 457862306a36Sopenharmony_ci nic->channel_id_param = cpu_to_le16(0xF000); 457962306a36Sopenharmony_ci nic->acpi_params = 0xFF; 458062306a36Sopenharmony_ci nic->wol_param = 0x0F; 458162306a36Sopenharmony_ci nic->tunnel_iface_count = 0xFFFF; 458262306a36Sopenharmony_ci nic->direct_tenant_iface_count = 0xFFFF; 458362306a36Sopenharmony_ci nic->bw_min = 0xFFFFFFFF; 458462306a36Sopenharmony_ci nic->bw_max = 0xFFFFFFFF; 458562306a36Sopenharmony_ci} 458662306a36Sopenharmony_ci 458762306a36Sopenharmony_ci/* Mark all fields invalid */ 458862306a36Sopenharmony_cistatic void be_reset_pcie_desc(struct be_pcie_res_desc *pcie) 458962306a36Sopenharmony_ci{ 459062306a36Sopenharmony_ci memset(pcie, 0, sizeof(*pcie)); 459162306a36Sopenharmony_ci pcie->sriov_state = 0xFF; 459262306a36Sopenharmony_ci pcie->pf_state = 0xFF; 459362306a36Sopenharmony_ci pcie->pf_type = 0xFF; 459462306a36Sopenharmony_ci pcie->num_vfs = 0xFFFF; 459562306a36Sopenharmony_ci} 459662306a36Sopenharmony_ci 459762306a36Sopenharmony_ciint be_cmd_config_qos(struct be_adapter *adapter, u32 max_rate, u16 link_speed, 459862306a36Sopenharmony_ci u8 domain) 459962306a36Sopenharmony_ci{ 460062306a36Sopenharmony_ci struct be_nic_res_desc nic_desc; 460162306a36Sopenharmony_ci u32 bw_percent; 460262306a36Sopenharmony_ci u16 version = 0; 460362306a36Sopenharmony_ci 460462306a36Sopenharmony_ci if (BE3_chip(adapter)) 460562306a36Sopenharmony_ci return be_cmd_set_qos(adapter, max_rate / 10, domain); 460662306a36Sopenharmony_ci 460762306a36Sopenharmony_ci be_reset_nic_desc(&nic_desc); 460862306a36Sopenharmony_ci nic_desc.pf_num = adapter->pf_num; 460962306a36Sopenharmony_ci nic_desc.vf_num = domain; 461062306a36Sopenharmony_ci nic_desc.bw_min = 0; 461162306a36Sopenharmony_ci if (lancer_chip(adapter)) { 461262306a36Sopenharmony_ci nic_desc.hdr.desc_type = NIC_RESOURCE_DESC_TYPE_V0; 461362306a36Sopenharmony_ci nic_desc.hdr.desc_len = RESOURCE_DESC_SIZE_V0; 461462306a36Sopenharmony_ci nic_desc.flags = (1 << QUN_SHIFT) | (1 << IMM_SHIFT) | 461562306a36Sopenharmony_ci (1 << NOSV_SHIFT); 461662306a36Sopenharmony_ci nic_desc.bw_max = cpu_to_le32(max_rate / 10); 461762306a36Sopenharmony_ci } else { 461862306a36Sopenharmony_ci version = 1; 461962306a36Sopenharmony_ci nic_desc.hdr.desc_type = NIC_RESOURCE_DESC_TYPE_V1; 462062306a36Sopenharmony_ci nic_desc.hdr.desc_len = RESOURCE_DESC_SIZE_V1; 462162306a36Sopenharmony_ci nic_desc.flags = (1 << IMM_SHIFT) | (1 << NOSV_SHIFT); 462262306a36Sopenharmony_ci bw_percent = max_rate ? (max_rate * 100) / link_speed : 100; 462362306a36Sopenharmony_ci nic_desc.bw_max = cpu_to_le32(bw_percent); 462462306a36Sopenharmony_ci } 462562306a36Sopenharmony_ci 462662306a36Sopenharmony_ci return be_cmd_set_profile_config(adapter, &nic_desc, 462762306a36Sopenharmony_ci nic_desc.hdr.desc_len, 462862306a36Sopenharmony_ci 1, version, domain); 462962306a36Sopenharmony_ci} 463062306a36Sopenharmony_ci 463162306a36Sopenharmony_ciint be_cmd_set_sriov_config(struct be_adapter *adapter, 463262306a36Sopenharmony_ci struct be_resources pool_res, u16 num_vfs, 463362306a36Sopenharmony_ci struct be_resources *vft_res) 463462306a36Sopenharmony_ci{ 463562306a36Sopenharmony_ci struct { 463662306a36Sopenharmony_ci struct be_pcie_res_desc pcie; 463762306a36Sopenharmony_ci struct be_nic_res_desc nic_vft; 463862306a36Sopenharmony_ci } __packed desc; 463962306a36Sopenharmony_ci 464062306a36Sopenharmony_ci /* PF PCIE descriptor */ 464162306a36Sopenharmony_ci be_reset_pcie_desc(&desc.pcie); 464262306a36Sopenharmony_ci desc.pcie.hdr.desc_type = PCIE_RESOURCE_DESC_TYPE_V1; 464362306a36Sopenharmony_ci desc.pcie.hdr.desc_len = RESOURCE_DESC_SIZE_V1; 464462306a36Sopenharmony_ci desc.pcie.flags = BIT(IMM_SHIFT) | BIT(NOSV_SHIFT); 464562306a36Sopenharmony_ci desc.pcie.pf_num = adapter->pdev->devfn; 464662306a36Sopenharmony_ci desc.pcie.sriov_state = num_vfs ? 1 : 0; 464762306a36Sopenharmony_ci desc.pcie.num_vfs = cpu_to_le16(num_vfs); 464862306a36Sopenharmony_ci 464962306a36Sopenharmony_ci /* VF NIC Template descriptor */ 465062306a36Sopenharmony_ci be_reset_nic_desc(&desc.nic_vft); 465162306a36Sopenharmony_ci desc.nic_vft.hdr.desc_type = NIC_RESOURCE_DESC_TYPE_V1; 465262306a36Sopenharmony_ci desc.nic_vft.hdr.desc_len = RESOURCE_DESC_SIZE_V1; 465362306a36Sopenharmony_ci desc.nic_vft.flags = vft_res->flags | BIT(VFT_SHIFT) | 465462306a36Sopenharmony_ci BIT(IMM_SHIFT) | BIT(NOSV_SHIFT); 465562306a36Sopenharmony_ci desc.nic_vft.pf_num = adapter->pdev->devfn; 465662306a36Sopenharmony_ci desc.nic_vft.vf_num = 0; 465762306a36Sopenharmony_ci desc.nic_vft.cap_flags = cpu_to_le32(vft_res->vf_if_cap_flags); 465862306a36Sopenharmony_ci desc.nic_vft.rq_count = cpu_to_le16(vft_res->max_rx_qs); 465962306a36Sopenharmony_ci desc.nic_vft.txq_count = cpu_to_le16(vft_res->max_tx_qs); 466062306a36Sopenharmony_ci desc.nic_vft.rssq_count = cpu_to_le16(vft_res->max_rss_qs); 466162306a36Sopenharmony_ci desc.nic_vft.cq_count = cpu_to_le16(vft_res->max_cq_count); 466262306a36Sopenharmony_ci 466362306a36Sopenharmony_ci if (vft_res->max_uc_mac) 466462306a36Sopenharmony_ci desc.nic_vft.unicast_mac_count = 466562306a36Sopenharmony_ci cpu_to_le16(vft_res->max_uc_mac); 466662306a36Sopenharmony_ci if (vft_res->max_vlans) 466762306a36Sopenharmony_ci desc.nic_vft.vlan_count = cpu_to_le16(vft_res->max_vlans); 466862306a36Sopenharmony_ci if (vft_res->max_iface_count) 466962306a36Sopenharmony_ci desc.nic_vft.iface_count = 467062306a36Sopenharmony_ci cpu_to_le16(vft_res->max_iface_count); 467162306a36Sopenharmony_ci if (vft_res->max_mcc_count) 467262306a36Sopenharmony_ci desc.nic_vft.mcc_count = cpu_to_le16(vft_res->max_mcc_count); 467362306a36Sopenharmony_ci 467462306a36Sopenharmony_ci return be_cmd_set_profile_config(adapter, &desc, 467562306a36Sopenharmony_ci 2 * RESOURCE_DESC_SIZE_V1, 2, 1, 0); 467662306a36Sopenharmony_ci} 467762306a36Sopenharmony_ci 467862306a36Sopenharmony_ciint be_cmd_manage_iface(struct be_adapter *adapter, u32 iface, u8 op) 467962306a36Sopenharmony_ci{ 468062306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 468162306a36Sopenharmony_ci struct be_cmd_req_manage_iface_filters *req; 468262306a36Sopenharmony_ci int status; 468362306a36Sopenharmony_ci 468462306a36Sopenharmony_ci if (iface == 0xFFFFFFFF) 468562306a36Sopenharmony_ci return -1; 468662306a36Sopenharmony_ci 468762306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 468862306a36Sopenharmony_ci 468962306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 469062306a36Sopenharmony_ci if (!wrb) { 469162306a36Sopenharmony_ci status = -EBUSY; 469262306a36Sopenharmony_ci goto err; 469362306a36Sopenharmony_ci } 469462306a36Sopenharmony_ci req = embedded_payload(wrb); 469562306a36Sopenharmony_ci 469662306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 469762306a36Sopenharmony_ci OPCODE_COMMON_MANAGE_IFACE_FILTERS, sizeof(*req), 469862306a36Sopenharmony_ci wrb, NULL); 469962306a36Sopenharmony_ci req->op = op; 470062306a36Sopenharmony_ci req->target_iface_id = cpu_to_le32(iface); 470162306a36Sopenharmony_ci 470262306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 470362306a36Sopenharmony_cierr: 470462306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 470562306a36Sopenharmony_ci return status; 470662306a36Sopenharmony_ci} 470762306a36Sopenharmony_ci 470862306a36Sopenharmony_ciint be_cmd_set_vxlan_port(struct be_adapter *adapter, __be16 port) 470962306a36Sopenharmony_ci{ 471062306a36Sopenharmony_ci struct be_port_res_desc port_desc; 471162306a36Sopenharmony_ci 471262306a36Sopenharmony_ci memset(&port_desc, 0, sizeof(port_desc)); 471362306a36Sopenharmony_ci port_desc.hdr.desc_type = PORT_RESOURCE_DESC_TYPE_V1; 471462306a36Sopenharmony_ci port_desc.hdr.desc_len = RESOURCE_DESC_SIZE_V1; 471562306a36Sopenharmony_ci port_desc.flags = (1 << IMM_SHIFT) | (1 << NOSV_SHIFT); 471662306a36Sopenharmony_ci port_desc.link_num = adapter->hba_port_num; 471762306a36Sopenharmony_ci if (port) { 471862306a36Sopenharmony_ci port_desc.nv_flags = NV_TYPE_VXLAN | (1 << SOCVID_SHIFT) | 471962306a36Sopenharmony_ci (1 << RCVID_SHIFT); 472062306a36Sopenharmony_ci port_desc.nv_port = swab16(port); 472162306a36Sopenharmony_ci } else { 472262306a36Sopenharmony_ci port_desc.nv_flags = NV_TYPE_DISABLED; 472362306a36Sopenharmony_ci port_desc.nv_port = 0; 472462306a36Sopenharmony_ci } 472562306a36Sopenharmony_ci 472662306a36Sopenharmony_ci return be_cmd_set_profile_config(adapter, &port_desc, 472762306a36Sopenharmony_ci RESOURCE_DESC_SIZE_V1, 1, 1, 0); 472862306a36Sopenharmony_ci} 472962306a36Sopenharmony_ci 473062306a36Sopenharmony_ciint be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg, 473162306a36Sopenharmony_ci int vf_num) 473262306a36Sopenharmony_ci{ 473362306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 473462306a36Sopenharmony_ci struct be_cmd_req_get_iface_list *req; 473562306a36Sopenharmony_ci struct be_cmd_resp_get_iface_list *resp; 473662306a36Sopenharmony_ci int status; 473762306a36Sopenharmony_ci 473862306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 473962306a36Sopenharmony_ci 474062306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 474162306a36Sopenharmony_ci if (!wrb) { 474262306a36Sopenharmony_ci status = -EBUSY; 474362306a36Sopenharmony_ci goto err; 474462306a36Sopenharmony_ci } 474562306a36Sopenharmony_ci req = embedded_payload(wrb); 474662306a36Sopenharmony_ci 474762306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 474862306a36Sopenharmony_ci OPCODE_COMMON_GET_IFACE_LIST, sizeof(*resp), 474962306a36Sopenharmony_ci wrb, NULL); 475062306a36Sopenharmony_ci req->hdr.domain = vf_num + 1; 475162306a36Sopenharmony_ci 475262306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 475362306a36Sopenharmony_ci if (!status) { 475462306a36Sopenharmony_ci resp = (struct be_cmd_resp_get_iface_list *)req; 475562306a36Sopenharmony_ci vf_cfg->if_handle = le32_to_cpu(resp->if_desc.if_id); 475662306a36Sopenharmony_ci } 475762306a36Sopenharmony_ci 475862306a36Sopenharmony_cierr: 475962306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 476062306a36Sopenharmony_ci return status; 476162306a36Sopenharmony_ci} 476262306a36Sopenharmony_ci 476362306a36Sopenharmony_cistatic int lancer_wait_idle(struct be_adapter *adapter) 476462306a36Sopenharmony_ci{ 476562306a36Sopenharmony_ci#define SLIPORT_IDLE_TIMEOUT 30 476662306a36Sopenharmony_ci u32 reg_val; 476762306a36Sopenharmony_ci int status = 0, i; 476862306a36Sopenharmony_ci 476962306a36Sopenharmony_ci for (i = 0; i < SLIPORT_IDLE_TIMEOUT; i++) { 477062306a36Sopenharmony_ci reg_val = ioread32(adapter->db + PHYSDEV_CONTROL_OFFSET); 477162306a36Sopenharmony_ci if ((reg_val & PHYSDEV_CONTROL_INP_MASK) == 0) 477262306a36Sopenharmony_ci break; 477362306a36Sopenharmony_ci 477462306a36Sopenharmony_ci ssleep(1); 477562306a36Sopenharmony_ci } 477662306a36Sopenharmony_ci 477762306a36Sopenharmony_ci if (i == SLIPORT_IDLE_TIMEOUT) 477862306a36Sopenharmony_ci status = -1; 477962306a36Sopenharmony_ci 478062306a36Sopenharmony_ci return status; 478162306a36Sopenharmony_ci} 478262306a36Sopenharmony_ci 478362306a36Sopenharmony_ciint lancer_physdev_ctrl(struct be_adapter *adapter, u32 mask) 478462306a36Sopenharmony_ci{ 478562306a36Sopenharmony_ci int status = 0; 478662306a36Sopenharmony_ci 478762306a36Sopenharmony_ci status = lancer_wait_idle(adapter); 478862306a36Sopenharmony_ci if (status) 478962306a36Sopenharmony_ci return status; 479062306a36Sopenharmony_ci 479162306a36Sopenharmony_ci iowrite32(mask, adapter->db + PHYSDEV_CONTROL_OFFSET); 479262306a36Sopenharmony_ci 479362306a36Sopenharmony_ci return status; 479462306a36Sopenharmony_ci} 479562306a36Sopenharmony_ci 479662306a36Sopenharmony_ci/* Routine to check whether dump image is present or not */ 479762306a36Sopenharmony_cibool dump_present(struct be_adapter *adapter) 479862306a36Sopenharmony_ci{ 479962306a36Sopenharmony_ci u32 sliport_status = 0; 480062306a36Sopenharmony_ci 480162306a36Sopenharmony_ci sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); 480262306a36Sopenharmony_ci return !!(sliport_status & SLIPORT_STATUS_DIP_MASK); 480362306a36Sopenharmony_ci} 480462306a36Sopenharmony_ci 480562306a36Sopenharmony_ciint lancer_initiate_dump(struct be_adapter *adapter) 480662306a36Sopenharmony_ci{ 480762306a36Sopenharmony_ci struct device *dev = &adapter->pdev->dev; 480862306a36Sopenharmony_ci int status; 480962306a36Sopenharmony_ci 481062306a36Sopenharmony_ci if (dump_present(adapter)) { 481162306a36Sopenharmony_ci dev_info(dev, "Previous dump not cleared, not forcing dump\n"); 481262306a36Sopenharmony_ci return -EEXIST; 481362306a36Sopenharmony_ci } 481462306a36Sopenharmony_ci 481562306a36Sopenharmony_ci /* give firmware reset and diagnostic dump */ 481662306a36Sopenharmony_ci status = lancer_physdev_ctrl(adapter, PHYSDEV_CONTROL_FW_RESET_MASK | 481762306a36Sopenharmony_ci PHYSDEV_CONTROL_DD_MASK); 481862306a36Sopenharmony_ci if (status < 0) { 481962306a36Sopenharmony_ci dev_err(dev, "FW reset failed\n"); 482062306a36Sopenharmony_ci return status; 482162306a36Sopenharmony_ci } 482262306a36Sopenharmony_ci 482362306a36Sopenharmony_ci status = lancer_wait_idle(adapter); 482462306a36Sopenharmony_ci if (status) 482562306a36Sopenharmony_ci return status; 482662306a36Sopenharmony_ci 482762306a36Sopenharmony_ci if (!dump_present(adapter)) { 482862306a36Sopenharmony_ci dev_err(dev, "FW dump not generated\n"); 482962306a36Sopenharmony_ci return -EIO; 483062306a36Sopenharmony_ci } 483162306a36Sopenharmony_ci 483262306a36Sopenharmony_ci return 0; 483362306a36Sopenharmony_ci} 483462306a36Sopenharmony_ci 483562306a36Sopenharmony_ciint lancer_delete_dump(struct be_adapter *adapter) 483662306a36Sopenharmony_ci{ 483762306a36Sopenharmony_ci int status; 483862306a36Sopenharmony_ci 483962306a36Sopenharmony_ci status = lancer_cmd_delete_object(adapter, LANCER_FW_DUMP_FILE); 484062306a36Sopenharmony_ci return be_cmd_status(status); 484162306a36Sopenharmony_ci} 484262306a36Sopenharmony_ci 484362306a36Sopenharmony_ci/* Uses sync mcc */ 484462306a36Sopenharmony_ciint be_cmd_enable_vf(struct be_adapter *adapter, u8 domain) 484562306a36Sopenharmony_ci{ 484662306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 484762306a36Sopenharmony_ci struct be_cmd_enable_disable_vf *req; 484862306a36Sopenharmony_ci int status; 484962306a36Sopenharmony_ci 485062306a36Sopenharmony_ci if (BEx_chip(adapter)) 485162306a36Sopenharmony_ci return 0; 485262306a36Sopenharmony_ci 485362306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 485462306a36Sopenharmony_ci 485562306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 485662306a36Sopenharmony_ci if (!wrb) { 485762306a36Sopenharmony_ci status = -EBUSY; 485862306a36Sopenharmony_ci goto err; 485962306a36Sopenharmony_ci } 486062306a36Sopenharmony_ci 486162306a36Sopenharmony_ci req = embedded_payload(wrb); 486262306a36Sopenharmony_ci 486362306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 486462306a36Sopenharmony_ci OPCODE_COMMON_ENABLE_DISABLE_VF, sizeof(*req), 486562306a36Sopenharmony_ci wrb, NULL); 486662306a36Sopenharmony_ci 486762306a36Sopenharmony_ci req->hdr.domain = domain; 486862306a36Sopenharmony_ci req->enable = 1; 486962306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 487062306a36Sopenharmony_cierr: 487162306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 487262306a36Sopenharmony_ci return status; 487362306a36Sopenharmony_ci} 487462306a36Sopenharmony_ci 487562306a36Sopenharmony_ciint be_cmd_intr_set(struct be_adapter *adapter, bool intr_enable) 487662306a36Sopenharmony_ci{ 487762306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 487862306a36Sopenharmony_ci struct be_cmd_req_intr_set *req; 487962306a36Sopenharmony_ci int status; 488062306a36Sopenharmony_ci 488162306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 488262306a36Sopenharmony_ci return -1; 488362306a36Sopenharmony_ci 488462306a36Sopenharmony_ci wrb = wrb_from_mbox(adapter); 488562306a36Sopenharmony_ci 488662306a36Sopenharmony_ci req = embedded_payload(wrb); 488762306a36Sopenharmony_ci 488862306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 488962306a36Sopenharmony_ci OPCODE_COMMON_SET_INTERRUPT_ENABLE, sizeof(*req), 489062306a36Sopenharmony_ci wrb, NULL); 489162306a36Sopenharmony_ci 489262306a36Sopenharmony_ci req->intr_enabled = intr_enable; 489362306a36Sopenharmony_ci 489462306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 489562306a36Sopenharmony_ci 489662306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 489762306a36Sopenharmony_ci return status; 489862306a36Sopenharmony_ci} 489962306a36Sopenharmony_ci 490062306a36Sopenharmony_ci/* Uses MBOX */ 490162306a36Sopenharmony_ciint be_cmd_get_active_profile(struct be_adapter *adapter, u16 *profile_id) 490262306a36Sopenharmony_ci{ 490362306a36Sopenharmony_ci struct be_cmd_req_get_active_profile *req; 490462306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 490562306a36Sopenharmony_ci int status; 490662306a36Sopenharmony_ci 490762306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mbox_lock)) 490862306a36Sopenharmony_ci return -1; 490962306a36Sopenharmony_ci 491062306a36Sopenharmony_ci wrb = wrb_from_mbox(adapter); 491162306a36Sopenharmony_ci if (!wrb) { 491262306a36Sopenharmony_ci status = -EBUSY; 491362306a36Sopenharmony_ci goto err; 491462306a36Sopenharmony_ci } 491562306a36Sopenharmony_ci 491662306a36Sopenharmony_ci req = embedded_payload(wrb); 491762306a36Sopenharmony_ci 491862306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 491962306a36Sopenharmony_ci OPCODE_COMMON_GET_ACTIVE_PROFILE, sizeof(*req), 492062306a36Sopenharmony_ci wrb, NULL); 492162306a36Sopenharmony_ci 492262306a36Sopenharmony_ci status = be_mbox_notify_wait(adapter); 492362306a36Sopenharmony_ci if (!status) { 492462306a36Sopenharmony_ci struct be_cmd_resp_get_active_profile *resp = 492562306a36Sopenharmony_ci embedded_payload(wrb); 492662306a36Sopenharmony_ci 492762306a36Sopenharmony_ci *profile_id = le16_to_cpu(resp->active_profile_id); 492862306a36Sopenharmony_ci } 492962306a36Sopenharmony_ci 493062306a36Sopenharmony_cierr: 493162306a36Sopenharmony_ci mutex_unlock(&adapter->mbox_lock); 493262306a36Sopenharmony_ci return status; 493362306a36Sopenharmony_ci} 493462306a36Sopenharmony_ci 493562306a36Sopenharmony_cistatic int 493662306a36Sopenharmony_ci__be_cmd_set_logical_link_config(struct be_adapter *adapter, 493762306a36Sopenharmony_ci int link_state, int version, u8 domain) 493862306a36Sopenharmony_ci{ 493962306a36Sopenharmony_ci struct be_cmd_req_set_ll_link *req; 494062306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 494162306a36Sopenharmony_ci u32 link_config = 0; 494262306a36Sopenharmony_ci int status; 494362306a36Sopenharmony_ci 494462306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 494562306a36Sopenharmony_ci 494662306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 494762306a36Sopenharmony_ci if (!wrb) { 494862306a36Sopenharmony_ci status = -EBUSY; 494962306a36Sopenharmony_ci goto err; 495062306a36Sopenharmony_ci } 495162306a36Sopenharmony_ci 495262306a36Sopenharmony_ci req = embedded_payload(wrb); 495362306a36Sopenharmony_ci 495462306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 495562306a36Sopenharmony_ci OPCODE_COMMON_SET_LOGICAL_LINK_CONFIG, 495662306a36Sopenharmony_ci sizeof(*req), wrb, NULL); 495762306a36Sopenharmony_ci 495862306a36Sopenharmony_ci req->hdr.version = version; 495962306a36Sopenharmony_ci req->hdr.domain = domain; 496062306a36Sopenharmony_ci 496162306a36Sopenharmony_ci if (link_state == IFLA_VF_LINK_STATE_ENABLE || 496262306a36Sopenharmony_ci link_state == IFLA_VF_LINK_STATE_AUTO) 496362306a36Sopenharmony_ci link_config |= PLINK_ENABLE; 496462306a36Sopenharmony_ci 496562306a36Sopenharmony_ci if (link_state == IFLA_VF_LINK_STATE_AUTO) 496662306a36Sopenharmony_ci link_config |= PLINK_TRACK; 496762306a36Sopenharmony_ci 496862306a36Sopenharmony_ci req->link_config = cpu_to_le32(link_config); 496962306a36Sopenharmony_ci 497062306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 497162306a36Sopenharmony_cierr: 497262306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 497362306a36Sopenharmony_ci return status; 497462306a36Sopenharmony_ci} 497562306a36Sopenharmony_ci 497662306a36Sopenharmony_ciint be_cmd_set_logical_link_config(struct be_adapter *adapter, 497762306a36Sopenharmony_ci int link_state, u8 domain) 497862306a36Sopenharmony_ci{ 497962306a36Sopenharmony_ci int status; 498062306a36Sopenharmony_ci 498162306a36Sopenharmony_ci if (BE2_chip(adapter)) 498262306a36Sopenharmony_ci return -EOPNOTSUPP; 498362306a36Sopenharmony_ci 498462306a36Sopenharmony_ci status = __be_cmd_set_logical_link_config(adapter, link_state, 498562306a36Sopenharmony_ci 2, domain); 498662306a36Sopenharmony_ci 498762306a36Sopenharmony_ci /* Version 2 of the command will not be recognized by older FW. 498862306a36Sopenharmony_ci * On such a failure issue version 1 of the command. 498962306a36Sopenharmony_ci */ 499062306a36Sopenharmony_ci if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST) 499162306a36Sopenharmony_ci status = __be_cmd_set_logical_link_config(adapter, link_state, 499262306a36Sopenharmony_ci 1, domain); 499362306a36Sopenharmony_ci return status; 499462306a36Sopenharmony_ci} 499562306a36Sopenharmony_ci 499662306a36Sopenharmony_ciint be_cmd_set_features(struct be_adapter *adapter) 499762306a36Sopenharmony_ci{ 499862306a36Sopenharmony_ci struct be_cmd_resp_set_features *resp; 499962306a36Sopenharmony_ci struct be_cmd_req_set_features *req; 500062306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 500162306a36Sopenharmony_ci int status; 500262306a36Sopenharmony_ci 500362306a36Sopenharmony_ci if (mutex_lock_interruptible(&adapter->mcc_lock)) 500462306a36Sopenharmony_ci return -1; 500562306a36Sopenharmony_ci 500662306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 500762306a36Sopenharmony_ci if (!wrb) { 500862306a36Sopenharmony_ci status = -EBUSY; 500962306a36Sopenharmony_ci goto err; 501062306a36Sopenharmony_ci } 501162306a36Sopenharmony_ci 501262306a36Sopenharmony_ci req = embedded_payload(wrb); 501362306a36Sopenharmony_ci 501462306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 501562306a36Sopenharmony_ci OPCODE_COMMON_SET_FEATURES, 501662306a36Sopenharmony_ci sizeof(*req), wrb, NULL); 501762306a36Sopenharmony_ci 501862306a36Sopenharmony_ci req->features = cpu_to_le32(BE_FEATURE_UE_RECOVERY); 501962306a36Sopenharmony_ci req->parameter_len = cpu_to_le32(sizeof(struct be_req_ue_recovery)); 502062306a36Sopenharmony_ci req->parameter.req.uer = cpu_to_le32(BE_UE_RECOVERY_UER_MASK); 502162306a36Sopenharmony_ci 502262306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 502362306a36Sopenharmony_ci if (status) 502462306a36Sopenharmony_ci goto err; 502562306a36Sopenharmony_ci 502662306a36Sopenharmony_ci resp = embedded_payload(wrb); 502762306a36Sopenharmony_ci 502862306a36Sopenharmony_ci adapter->error_recovery.ue_to_poll_time = 502962306a36Sopenharmony_ci le16_to_cpu(resp->parameter.resp.ue2rp); 503062306a36Sopenharmony_ci adapter->error_recovery.ue_to_reset_time = 503162306a36Sopenharmony_ci le16_to_cpu(resp->parameter.resp.ue2sr); 503262306a36Sopenharmony_ci adapter->error_recovery.recovery_supported = true; 503362306a36Sopenharmony_cierr: 503462306a36Sopenharmony_ci /* Checking "MCC_STATUS_INVALID_LENGTH" for SKH as FW 503562306a36Sopenharmony_ci * returns this error in older firmware versions 503662306a36Sopenharmony_ci */ 503762306a36Sopenharmony_ci if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST || 503862306a36Sopenharmony_ci base_status(status) == MCC_STATUS_INVALID_LENGTH) 503962306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, 504062306a36Sopenharmony_ci "Adapter does not support HW error recovery\n"); 504162306a36Sopenharmony_ci 504262306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 504362306a36Sopenharmony_ci return status; 504462306a36Sopenharmony_ci} 504562306a36Sopenharmony_ci 504662306a36Sopenharmony_ciint be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload, 504762306a36Sopenharmony_ci int wrb_payload_size, u16 *cmd_status, u16 *ext_status) 504862306a36Sopenharmony_ci{ 504962306a36Sopenharmony_ci struct be_adapter *adapter = netdev_priv(netdev_handle); 505062306a36Sopenharmony_ci struct be_mcc_wrb *wrb; 505162306a36Sopenharmony_ci struct be_cmd_req_hdr *hdr = (struct be_cmd_req_hdr *)wrb_payload; 505262306a36Sopenharmony_ci struct be_cmd_req_hdr *req; 505362306a36Sopenharmony_ci struct be_cmd_resp_hdr *resp; 505462306a36Sopenharmony_ci int status; 505562306a36Sopenharmony_ci 505662306a36Sopenharmony_ci mutex_lock(&adapter->mcc_lock); 505762306a36Sopenharmony_ci 505862306a36Sopenharmony_ci wrb = wrb_from_mccq(adapter); 505962306a36Sopenharmony_ci if (!wrb) { 506062306a36Sopenharmony_ci status = -EBUSY; 506162306a36Sopenharmony_ci goto err; 506262306a36Sopenharmony_ci } 506362306a36Sopenharmony_ci req = embedded_payload(wrb); 506462306a36Sopenharmony_ci resp = embedded_payload(wrb); 506562306a36Sopenharmony_ci 506662306a36Sopenharmony_ci be_wrb_cmd_hdr_prepare(req, hdr->subsystem, 506762306a36Sopenharmony_ci hdr->opcode, wrb_payload_size, wrb, NULL); 506862306a36Sopenharmony_ci memcpy(req, wrb_payload, wrb_payload_size); 506962306a36Sopenharmony_ci be_dws_cpu_to_le(req, wrb_payload_size); 507062306a36Sopenharmony_ci 507162306a36Sopenharmony_ci status = be_mcc_notify_wait(adapter); 507262306a36Sopenharmony_ci if (cmd_status) 507362306a36Sopenharmony_ci *cmd_status = (status & 0xffff); 507462306a36Sopenharmony_ci if (ext_status) 507562306a36Sopenharmony_ci *ext_status = 0; 507662306a36Sopenharmony_ci memcpy(wrb_payload, resp, sizeof(*resp) + resp->response_length); 507762306a36Sopenharmony_ci be_dws_le_to_cpu(wrb_payload, sizeof(*resp) + resp->response_length); 507862306a36Sopenharmony_cierr: 507962306a36Sopenharmony_ci mutex_unlock(&adapter->mcc_lock); 508062306a36Sopenharmony_ci return status; 508162306a36Sopenharmony_ci} 508262306a36Sopenharmony_ciEXPORT_SYMBOL(be_roce_mcc_cmd); 5083