constchar * const be_misconfig_evt_port_state[] = { "Physical Link is functional", "Optics faulted/incorrectly installed/not installed - Reseat optics. If issue not resolved, replace.", "Optics of two types installed – Remove one optic or install matching pair of optics.", "Incompatible optics – Replace with compatible optics for card to function.", "Unqualified optics – Replace with Avago optics for Warranty and Technical Support.", "Uncertified optics – Replace with Avago-certified optics to enable link operation."
};
staticbool be_cmd_allowed(struct be_adapter *adapter, u8 opcode, u8 subsystem)
{ int i; int num_entries = ARRAY_SIZE(cmd_priv_map);
u32 cmd_privileges = adapter->cmd_privileges;
for (i = 0; i < num_entries; i++) if (opcode == cmd_priv_map[i].opcode &&
subsystem == cmd_priv_map[i].subsystem) if (!(cmd_privileges & cmd_priv_map[i].priv_mask)) returnfalse;
/* To check if valid bit is set, check the entire word as we don't know * the endianness of the data (old entry is host endian while a new entry is * little endian)
*/ staticinlinebool be_mcc_compl_is_new(struct be_mcc_compl *compl)
{
u32 flags;
/* Place holder for all the async MCC cmds wherein the caller is not in a busy * loop (has not issued be_mcc_notify_wait())
*/ staticvoid be_async_cmd_process(struct be_adapter *adapter, struct be_mcc_compl *compl, struct be_cmd_resp_hdr *resp_hdr)
{ enum mcc_base_status base_status = base_status(compl->status);
u8 opcode = 0, subsystem = 0;
if (resp_hdr) {
opcode = resp_hdr->opcode;
subsystem = resp_hdr->subsystem;
}
if (base_status != MCC_STATUS_SUCCESS &&
!be_skip_err_log(opcode, base_status, addl_status)) { if (base_status == MCC_STATUS_UNAUTHORIZED_REQUEST ||
addl_status == MCC_ADDL_STATUS_INSUFFICIENT_PRIVILEGES) {
dev_warn(&adapter->pdev->dev, "VF is not privileged to issue opcode %d-%d\n",
opcode, subsystem);
} else {
dev_err(&adapter->pdev->dev, "opcode %d-%d failed:status %d-%d\n",
opcode, subsystem, base_status, addl_status);
}
} return compl->status;
}
/* Link state evt is a string of bytes; no need for endian swapping */ staticvoid be_async_link_state_process(struct be_adapter *adapter, struct be_mcc_compl *compl)
{ struct be_async_event_link_state *evt =
(struct be_async_event_link_state *)compl;
/* When link status changes, link speed must be re-queried from FW */
adapter->phy.link_speed = -1;
/* On BEx the FW does not send a separate link status * notification for physical and logical link. * On other chips just process the logical link * status notification
*/ if (!BEx_chip(adapter) &&
!(evt->port_link_status & LOGICAL_LINK_STATUS_MASK)) return;
/* For the initial link status do not rely on the ASYNC event as * it may not be received in some cases.
*/ if (adapter->flags & BE_FLAGS_LINK_STATUS_INIT)
be_link_status_update(adapter,
evt->port_link_status & LINK_STATUS_MASK);
}
if (be_phy_unqualified(new_phy_state))
phy_oper_state = (phy_state_info & PHY_STATE_OPER);
}
log_message: /* Log an error message that would allow a user to determine * whether the SFPs have an issue
*/ if (be_phy_state_unknown(new_phy_state))
dev_printk(be_port_misconfig_evt_severity[msg_severity], dev, "Port %c: Unrecognized Optics state: 0x%x. %s",
adapter->port_name,
new_phy_state,
phy_state_oper_desc[phy_oper_state]); else
dev_printk(be_port_misconfig_evt_severity[msg_severity], dev, "Port %c: %s %s",
adapter->port_name,
be_misconfig_evt_port_state[new_phy_state],
phy_state_oper_desc[phy_oper_state]);
/* Log Vendor name and part no. if a misconfigured SFP is detected */ if (be_phy_misconfigured(new_phy_state))
adapter->flags |= BE_FLAGS_PHY_MISCONFIGURED;
}
/* Wait till no more pending mcc requests are present */ staticint be_mcc_wait_compl(struct be_adapter *adapter)
{ #define mcc_timeout 120000 /* 12s timeout */ int i, status = 0; struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
for (i = 0; i < mcc_timeout; i++) { if (be_check_error(adapter, BE_ERROR_ANY)) return -EIO;
local_bh_disable();
status = be_process_mcc(adapter);
local_bh_enable();
if (atomic_read(&mcc_obj->q.used) == 0) break;
udelay(100);
} if (i == mcc_timeout) {
dev_err(&adapter->pdev->dev, "FW not responding\n");
be_set_error(adapter, BE_ERROR_FW); return -EIO;
} return status;
}
/* Notify MCC requests and wait for completion */ staticint be_mcc_notify_wait(struct be_adapter *adapter)
{ int status; struct be_mcc_wrb *wrb; struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
u32 index = mcc_obj->q.head; struct be_cmd_resp_hdr *resp;
do { if (be_check_error(adapter, BE_ERROR_ANY)) return -EIO;
ready = ioread32(db); if (ready == 0xffffffff) return -1;
ready &= MPU_MAILBOX_DB_RDY_MASK; if (ready) break;
if (msecs > 4000) {
dev_err(&adapter->pdev->dev, "FW not responding\n");
be_set_error(adapter, BE_ERROR_FW);
be_detect_error(adapter); return -1;
}
msleep(1);
msecs++;
} while (true);
return 0;
}
/* Insert the mailbox address into the doorbell in two steps * Polls on the mbox doorbell till a command completion (or a timeout) occurs
*/ staticint be_mbox_notify_wait(struct be_adapter *adapter)
{ int status;
u32 val = 0; void __iomem *db = adapter->db + MPU_MAILBOX_DB_OFFSET; struct be_dma_mem *mbox_mem = &adapter->mbox_mem; struct be_mcc_mailbox *mbox = mbox_mem->va; struct be_mcc_compl *compl = &mbox->compl;
/* wait for ready to be set */
status = be_mbox_db_ready_wait(adapter, db); if (status != 0) return status;
val |= MPU_MAILBOX_DB_HI_MASK; /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */
val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2;
iowrite32(val, db);
/* wait for ready to be set */
status = be_mbox_db_ready_wait(adapter, db); if (status != 0) return status;
val = 0; /* at bits 2 - 31 place mbox dma addr lsb bits 4 - 33 */
val |= (u32)(mbox_mem->dma >> 4) << 2;
iowrite32(val, db);
status = be_mbox_db_ready_wait(adapter, db); if (status != 0) return status;
/* A cq entry has been made now */ if (be_mcc_compl_is_new(compl)) {
status = be_mcc_compl_process(adapter, &mbox->compl);
be_mcc_compl_use(compl); if (status) return status;
} else {
dev_err(&adapter->pdev->dev, "invalid mailbox completion\n"); return -1;
} return 0;
}
for (i = 0; i < SLIPORT_READY_TIMEOUT; i++) {
sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); if (sliport_status & SLIPORT_STATUS_RDY_MASK) return 0;
if (sliport_status & SLIPORT_STATUS_ERR_MASK &&
!(sliport_status & SLIPORT_STATUS_RN_MASK)) return -EIO;
msleep(1000);
}
return sliport_status ? : -1;
}
int be_fw_wait_ready(struct be_adapter *adapter)
{
u16 stage; int status, timeout = 0; struct device *dev = &adapter->pdev->dev;
if (lancer_chip(adapter)) {
status = lancer_wait_ready(adapter); if (status) {
stage = status; goto err;
} return 0;
}
do { /* There's no means to poll POST state on BE2/3 VFs */ if (BEx_chip(adapter) && be_virtfn(adapter)) return 0;
stage = be_POST_stage_get(adapter); if (stage == POST_STAGE_ARMFW_RDY) return 0;
dev_info(dev, "Waiting for POST, %ds elapsed\n", timeout); if (msleep_interruptible(2000)) {
dev_err(dev, "Waiting for POST aborted\n"); return -EINTR;
}
timeout += 2;
} while (timeout < 60);
/* Must be used only in process context */ staticint be_cmd_lock(struct be_adapter *adapter)
{ if (use_mcc(adapter)) {
spin_lock_bh(&adapter->mcc_lock); return 0;
} else { return mutex_lock_interruptible(&adapter->mbox_lock);
}
}
/* Must be used only in process context */ staticvoid be_cmd_unlock(struct be_adapter *adapter)
{ if (use_mcc(adapter)) return spin_unlock_bh(&adapter->mcc_lock); else return mutex_unlock(&adapter->mbox_lock);
}
if (use_mcc(adapter)) {
dest_wrb = wrb_from_mccq(adapter); if (!dest_wrb) return NULL;
} else {
dest_wrb = wrb_from_mbox(adapter);
}
memcpy(dest_wrb, wrb, sizeof(*wrb)); if (wrb->embedded & cpu_to_le32(MCC_WRB_EMBEDDED_MASK))
fill_wrb_tags(dest_wrb, (ulong)embedded_payload(wrb));
return dest_wrb;
}
/* Must be used only in process context */ staticint be_cmd_notify_wait(struct be_adapter *adapter, struct be_mcc_wrb *wrb)
{ struct be_mcc_wrb *dest_wrb; int status;
status = be_cmd_lock(adapter); if (status) return status;
dest_wrb = be_cmd_copy(adapter, wrb); if (!dest_wrb) {
status = -EBUSY; goto unlock;
}
if (use_mcc(adapter))
status = be_mcc_notify_wait(adapter); else
status = be_mbox_notify_wait(adapter);
if (!status)
memcpy(wrb, dest_wrb, sizeof(*wrb));
unlock:
be_cmd_unlock(adapter); return status;
}
/* Tell fw we're about to start firing cmds by writing a * special pattern across the wrb hdr; uses mbox
*/ int be_cmd_fw_init(struct be_adapter *adapter)
{
u8 *wrb; int status;
if (lancer_chip(adapter)) return 0;
if (mutex_lock_interruptible(&adapter->mbox_lock)) return -1;
/* Tell fw we're done with firing cmds by writing a * special pattern across the wrb hdr; uses mbox
*/ int be_cmd_fw_clean(struct be_adapter *adapter)
{
u8 *wrb; int status;
if (lancer_chip(adapter)) return 0;
if (mutex_lock_interruptible(&adapter->mbox_lock)) return -1;
/* coalesce-wm field in this cmd is not relevant to Lancer. * Lancer uses COMMON_MODIFY_CQ to set this field
*/ if (!lancer_chip(adapter))
AMAP_SET_BITS(struct amap_cq_context_v2, coalescwm,
ctxt, coalesce_wm);
AMAP_SET_BITS(struct amap_cq_context_v2, nodelay, ctxt,
no_delay);
AMAP_SET_BITS(struct amap_cq_context_v2, count, ctxt,
__ilog2_u32(cq->len / 256));
AMAP_SET_BITS(struct amap_cq_context_v2, valid, ctxt, 1);
AMAP_SET_BITS(struct amap_cq_context_v2, eventable, ctxt, 1);
AMAP_SET_BITS(struct amap_cq_context_v2, eqid, ctxt, eq->id);
}
int be_cmd_mccq_create(struct be_adapter *adapter, struct be_queue_info *mccq, struct be_queue_info *cq)
{ int status;
status = be_cmd_mccq_ext_create(adapter, mccq, cq); if (status && BEx_chip(adapter)) {
dev_warn(&adapter->pdev->dev, "Upgrade to F/W ver 2.102.235.0 " "or newer to avoid conflicting priorities between NIC " "and FCoE traffic");
status = be_cmd_mccq_org_create(adapter, mccq, cq);
} return status;
}
/* Create an rx filtering policy configuration on an i/f * Will use MBOX only if MCCQ has not been created.
*/ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
u32 *if_handle, u32 domain)
{ struct be_mcc_wrb wrb = {0}; struct be_cmd_req_if_create *req; int status;
status = be_cmd_notify_wait(adapter, &wrb); return status;
}
/* Get stats is a non embedded command: the request is not embedded inside * WRB but is a separate dma memory block * Uses asynchronous MCC
*/ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd)
{ struct be_mcc_wrb *wrb; struct be_cmd_req_hdr *hdr; int status = 0;
spin_lock_bh(&adapter->mcc_lock);
wrb = wrb_from_mccq(adapter); if (!wrb) {
status = -EBUSY; goto err;
}
hdr = nonemb_cmd->va;
/* version 1 of the cmd is not supported only by BE2 */ if (BE2_chip(adapter))
hdr->version = 0; elseif (BE3_chip(adapter) || lancer_chip(adapter))
hdr->version = 1; else
hdr->version = 2;
status = be_mcc_notify(adapter); if (status) goto err;
/* set the EQ delay interval of an EQ to specified value * Uses async mcc
*/ staticint __be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *set_eqd, int num)
{ struct be_mcc_wrb *wrb; struct be_cmd_req_modify_eq_delay *req; int status = 0, i;
spin_lock_bh(&adapter->mcc_lock);
wrb = wrb_from_mccq(adapter); if (!wrb) {
status = -EBUSY; goto err;
}
req = embedded_payload(wrb);
/* Reset mcast promisc mode if already set by setting mask * and not setting flags field
*/
req->if_flags_mask |=
cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS &
be_if_cap_flags(adapter));
req->mcast_num = cpu_to_le32(adapter->mc_count); for (i = 0; i < adapter->mc_count; i++)
ether_addr_copy(req->mcast_mac[i].byte,
adapter->mc_list[i].mac);
}
status = be_mcc_notify_wait(adapter);
err:
spin_unlock_bh(&adapter->mcc_lock); return status;
}
/* Uses mbox */ int be_cmd_reset_function(struct be_adapter *adapter)
{ struct be_mcc_wrb *wrb; struct be_cmd_req_hdr *req; int status;
if (lancer_chip(adapter)) {
iowrite32(SLI_PORT_CONTROL_IP_MASK,
adapter->db + SLIPORT_CONTROL_OFFSET);
status = lancer_wait_ready(adapter); if (status)
dev_err(&adapter->pdev->dev, "Adapter in non recoverable error\n"); return status;
}
if (mutex_lock_interruptible(&adapter->mbox_lock)) return -1;
/* * Since the cookie is text, add a parsing-skipped space to keep it from * ever being matched on storage holding this source file.
*/ staticconstchar flash_cookie[32] __nonstring = "*** SE FLAS""H DIRECTORY *** ";
staticbool is_comp_in_ufi(struct be_adapter *adapter, struct flash_section_info *fsec, int type)
{ int i = 0, img_type = 0; struct flash_section_info_g2 *fsec_g2 = NULL;
if (BE2_chip(adapter))
fsec_g2 = (struct flash_section_info_g2 *)fsec;
for (i = 0; i < MAX_FLASH_COMP; i++) { if (fsec_g2)
img_type = le32_to_cpu(fsec_g2->fsec_entry[i].type); else
img_type = le32_to_cpu(fsec->fsec_entry[i].type);
if (img_type == type) returntrue;
} returnfalse;
}
#define NCSI_UPDATE_LOG "NCSI section update is not supported in FW ver %s\n" staticbool be_fw_ncsi_supported(char *ver)
{ int v1[4] = {3, 102, 148, 0}; /* Min ver that supports NCSI FW */ int v2[4]; int i;
if (sscanf(ver, "%d.%d.%d.%d", &v2[0], &v2[1], &v2[2], &v2[3]) != 4) returnfalse;
for (i = 0; i < 4; i++) { if (v1[i] < v2[i]) returntrue; elseif (v1[i] > v2[i]) returnfalse;
}
returntrue;
}
/* For BE2, BE3 and BE3-R */ staticint be_flash_BEx(struct be_adapter *adapter, conststruct firmware *fw, struct be_dma_mem *flash_cmd, int num_of_images)
{ int img_hdrs_size = (num_of_images * sizeof(struct image_hdr)); struct device *dev = &adapter->pdev->dev; struct flash_section_info *fsec = NULL; int status, i, filehdr_size, num_comp; conststruct flash_comp *pflashcomp; bool crc_match; const u8 *p;
/* Get flash section info*/
fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw); if (!fsec) {
dev_err(dev, "Invalid Cookie. FW image may be corrupted\n"); return -1;
} for (i = 0; i < num_comp; i++) { if (!is_comp_in_ufi(adapter, fsec, pflashcomp[i].img_type)) continue;
if (pflashcomp[i].optype == OPTYPE_PHY_FW &&
!phy_flashing_required(adapter)) continue;
if (pflashcomp[i].optype == OPTYPE_REDBOOT) {
status = be_check_flash_crc(adapter, fw->data,
pflashcomp[i].offset,
pflashcomp[i].size,
filehdr_size +
img_hdrs_size,
OPTYPE_REDBOOT, &crc_match); if (status) {
dev_err(dev, "Could not get CRC for 0x%x region\n",
pflashcomp[i].optype); continue;
}
if (crc_match) continue;
}
p = fw->data + filehdr_size + pflashcomp[i].offset +
img_hdrs_size; if (p + pflashcomp[i].size > fw->data + fw->size) return -1;
status = be_flash(adapter, p, flash_cmd, pflashcomp[i].optype,
pflashcomp[i].size, 0); if (status) {
dev_err(dev, "Flashing section type 0x%x failed\n",
pflashcomp[i].img_type); return status;
}
} return 0;
}
filehdr_size = sizeof(struct flash_file_hdr_g3);
fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw); if (!fsec) {
dev_err(dev, "Invalid Cookie. FW image may be corrupted\n"); return -EINVAL;
}
retry_flash: for (i = 0; i < le32_to_cpu(fsec->fsec_hdr.num_images); i++) {
img_offset = le32_to_cpu(fsec->fsec_entry[i].offset);
img_size = le32_to_cpu(fsec->fsec_entry[i].pad_size);
img_type = le32_to_cpu(fsec->fsec_entry[i].type);
img_optype = be_get_img_optype(fsec->fsec_entry[i]);
old_fw_img = fsec->fsec_entry[i].optype == 0xFFFF;
if (img_optype == 0xFFFF) continue;
if (flash_offset_support)
flash_optype = OPTYPE_OFFSET_SPECIFIED; else
flash_optype = img_optype;
/* Don't bother verifying CRC if an old FW image is being * flashed
*/ if (old_fw_img) goto flash;
status = be_check_flash_crc(adapter, fw->data, img_offset,
img_size, filehdr_size +
img_hdrs_size, flash_optype,
&crc_match); if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST ||
base_status(status) == MCC_STATUS_ILLEGAL_FIELD) { /* The current FW image on the card does not support * OFFSET based flashing. Retry using older mechanism * of OPTYPE based flashing
*/ if (flash_optype == OPTYPE_OFFSET_SPECIFIED) {
flash_offset_support = false; goto retry_flash;
}
/* The current FW image on the card does not recognize * the new FLASH op_type. The FW download is partially * complete. Reboot the server now to enable FW image * to recognize the new FLASH op_type. To complete the * remaining process, download the same FW again after * the reboot.
*/
dev_err(dev, "Flash incomplete. Reset the server\n");
dev_err(dev, "Download FW image again after reset\n"); return -EAGAIN;
} elseif (status) {
dev_err(dev, "Could not get CRC for 0x%x region\n",
img_optype); return -EFAULT;
}
if (crc_match) continue;
flash:
p = fw->data + filehdr_size + img_offset + img_hdrs_size; if (p + img_size > fw->data + fw->size) return -1;
status = be_flash(adapter, p, flash_cmd, flash_optype, img_size,
img_offset);
/* The current FW image on the card does not support OFFSET * based flashing. Retry using older mechanism of OPTYPE based * flashing
*/ if (base_status(status) == MCC_STATUS_ILLEGAL_FIELD &&
flash_optype == OPTYPE_OFFSET_SPECIFIED) {
flash_offset_support = false; goto retry_flash;
}
/* For old FW images ignore ILLEGAL_FIELD error or errors on * UFI_DIR region
*/ if (old_fw_img &&
(base_status(status) == MCC_STATUS_ILLEGAL_FIELD ||
(img_optype == OPTYPE_UFI_DIR &&
base_status(status) == MCC_STATUS_FAILED))) { continue;
} elseif (status) {
dev_err(dev, "Flashing section type 0x%x failed\n",
img_type);
switch (addl_status(status)) { case MCC_ADDL_STATUS_MISSING_SIGNATURE:
dev_err(dev, "Digital signature missing in FW\n"); return -EINVAL; case MCC_ADDL_STATUS_INVALID_SIGNATURE:
dev_err(dev, "Invalid digital signature in FW\n"); return -EINVAL; default: return -EFAULT;
}
}
} return 0;
}
if (!status) { /* Commit the FW written */
status = lancer_cmd_write_object(adapter, &flash_cmd,
0, offset,
LANCER_FW_DOWNLOAD_LOCATION,
&data_written, &change_status,
&add_status);
}
if (change_status == LANCER_FW_RESET_NEEDED) {
dev_info(dev, "Resetting adapter to activate new FW\n");
status = lancer_physdev_ctrl(adapter,
PHYSDEV_CONTROL_FW_RESET_MASK); if (status) {
dev_err(dev, "Adapter busy, could not reset FW\n");
dev_err(dev, "Reboot server to activate new FW\n");
}
} elseif (change_status != LANCER_NO_RESET_NEEDED) {
dev_info(dev, "Reboot server to activate new FW\n");
}
return 0;
}
/* Check if the flash image file is compatible with the adapter that * is being flashed.
*/ staticbool be_check_ufi_compatibility(struct be_adapter *adapter, struct flash_file_hdr_g3 *fhdr)
{ if (!fhdr) {
dev_err(&adapter->pdev->dev, "Invalid FW UFI file"); returnfalse;
}
/* First letter of the build version is used to identify * which chip this image file is meant for.
*/ switch (fhdr->build[0]) { case BLD_STR_UFI_TYPE_SH: if (!skyhawk_chip(adapter)) returnfalse; break; case BLD_STR_UFI_TYPE_BE3: if (!BE3_chip(adapter)) returnfalse; break; case BLD_STR_UFI_TYPE_BE2: if (!BE2_chip(adapter)) returnfalse; break; default: returnfalse;
}
/* In BE3 FW images the "asic_type_rev" field doesn't track the * asic_rev of the chips it is compatible with. * When asic_type_rev is 0 the image is compatible only with * pre-BE3-R chips (asic_rev < 0x10)
*/ if (BEx_chip(adapter) && fhdr->asic_type_rev == 0) return adapter->asic_rev < 0x10; else return (fhdr->asic_type_rev >= adapter->asic_rev);
}
int be_fw_download(struct be_adapter *adapter, conststruct firmware *fw)
{ struct device *dev = &adapter->pdev->dev; struct flash_file_hdr_g3 *fhdr3; struct image_hdr *img_hdr_ptr; int status = 0, i, num_imgs; struct be_dma_mem flash_cmd;
fhdr3 = (struct flash_file_hdr_g3 *)fw->data; if (!be_check_ufi_compatibility(adapter, fhdr3)) {
dev_err(dev, "Flash image is not compatible with adapter\n"); return -EINVAL;
}
status = be_mbox_notify_wait(adapter); if (!status) {
attribs = attribs_cmd.va + sizeof(struct be_cmd_resp_hdr);
adapter->hba_port_num = attribs->hba_attribs.phy_port;
serial_num = attribs->hba_attribs.controller_serial_number; for (i = 0; i < CNTL_SERIAL_NUM_WORDS; i++)
adapter->serial_num[i] = le32_to_cpu(serial_num[i]) &
(BIT_MASK(16) - 1); /* For BEx, since GET_FUNC_CONFIG command is not * supported, we read funcnum here as a workaround.
*/ if (BEx_chip(adapter))
adapter->pf_num = attribs->hba_attribs.pci_funcnum;
}
status = be_mbox_notify_wait(adapter); if (!status) { struct be_cmd_resp_set_func_cap *resp = embedded_payload(wrb);
adapter->be3_native = le32_to_cpu(resp->cap_flags) &
CAPABILITY_BE3_NATIVE_ERX_API; if (!adapter->be3_native)
dev_warn(&adapter->pdev->dev, "adapter not in advanced mode\n");
}
err:
mutex_unlock(&adapter->mbox_lock); return status;
}
/* Get privilege(s) for a function */ int be_cmd_get_fn_privileges(struct be_adapter *adapter, u32 *privilege,
u32 domain)
{ struct be_mcc_wrb *wrb; struct be_cmd_req_get_fn_privileges *req; int status;
spin_lock_bh(&adapter->mcc_lock);
wrb = wrb_from_mccq(adapter); if (!wrb) {
status = -EBUSY; goto err;
}
status = be_mcc_notify_wait(adapter); if (!status) { struct be_cmd_resp_get_fn_privileges *resp =
embedded_payload(wrb);
*privilege = le32_to_cpu(resp->privilege_mask);
/* In UMC mode FW does not return right privileges. * Override with correct privilege equivalent to PF.
*/ if (BEx_chip(adapter) && be_is_mc(adapter) &&
be_physfn(adapter))
*privilege = MAX_PRIVILEGES;
}
/* Set privilege(s) for a function */ int be_cmd_set_fn_privileges(struct be_adapter *adapter, u32 privileges,
u32 domain)
{ struct be_mcc_wrb *wrb; struct be_cmd_req_set_fn_privileges *req; int status;
spin_lock_bh(&adapter->mcc_lock);
wrb = wrb_from_mccq(adapter); if (!wrb) {
status = -EBUSY; goto err;
}
status = be_mcc_notify_wait(adapter);
err:
spin_unlock_bh(&adapter->mcc_lock); return status;
}
/* pmac_id_valid: true => pmac_id is supplied and MAC address is requested. * pmac_id_valid: false => pmac_id or MAC address is requested. * If pmac_id is returned, pmac_id_valid is returned as true
*/ int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac, bool *pmac_id_valid, u32 *pmac_id, u32 if_handle,
u8 domain)
{ struct be_mcc_wrb *wrb; struct be_cmd_req_get_mac_list *req; int status; int mac_count; struct be_dma_mem get_mac_list_cmd; int i;
status = be_mcc_notify_wait(adapter); if (!status) { struct be_cmd_resp_get_mac_list *resp =
get_mac_list_cmd.va;
if (*pmac_id_valid) {
memcpy(mac, resp->macid_macaddr.mac_addr_id.macaddr,
ETH_ALEN); goto out;
}
mac_count = resp->true_mac_count + resp->pseudo_mac_count; /* Mac list returned could contain one or more active mac_ids * or one or more true or pseudo permanent mac addresses. * If an active mac_id is present, return first active mac_id * found.
*/ for (i = 0; i < mac_count; i++) { struct get_list_macaddr *mac_entry;
u16 mac_addr_size;
u32 mac_id;
mac_entry = &resp->macaddr_list[i];
mac_addr_size = le16_to_cpu(mac_entry->mac_addr_size); /* mac_id is a 32 bit value and mac_addr size * is 6 bytes
*/ if (mac_addr_size == sizeof(u32)) {
*pmac_id_valid = true;
mac_id = mac_entry->mac_addr_id.s_mac_id.mac_id;
*pmac_id = le32_to_cpu(mac_id); goto out;
}
} /* If no active mac_id found, return first mac addr */
*pmac_id_valid = false;
memcpy(mac, resp->macaddr_list[0].mac_addr_id.macaddr,
ETH_ALEN);
}
/* Wrapper to delete any active MACs and provision the new mac. * Changes to MAC_LIST are allowed iff none of the MAC addresses in the * current list are active.
*/ int be_cmd_set_mac(struct be_adapter *adapter, u8 *mac, int if_id, u32 dom)
{ bool active_mac = false;
u8 old_mac[ETH_ALEN];
u32 pmac_id; int status;
status = be_cmd_get_mac_from_list(adapter, old_mac, &active_mac,
&pmac_id, if_id, dom);
if (!status && active_mac)
be_cmd_pmac_del(adapter, if_id, pmac_id, dom);
return be_cmd_set_mac_list(adapter, mac, mac ? 1 : 0, dom);
}
switch (pdev->subsystem_device) { case OC_SUBSYS_DEVICE_ID1: case OC_SUBSYS_DEVICE_ID2: case OC_SUBSYS_DEVICE_ID3: case OC_SUBSYS_DEVICE_ID4: returntrue; default: returnfalse;
}
}
int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter)
{ struct be_mcc_wrb *wrb; struct be_cmd_req_acpi_wol_magic_config_v1 *req; int status = 0; struct be_dma_mem cmd;
if (!be_cmd_allowed(adapter, OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG,
CMD_SUBSYSTEM_ETH)) return -EPERM;
if (be_is_wol_excluded(adapter)) return status;
if (mutex_lock_interruptible(&adapter->mbox_lock)) return -1;
/* Non-zero macaddr indicates WOL is enabled */ if (adapter->wol_cap & BE_WOL_CAP &&
!is_zero_ether_addr(resp->magic_mac))
adapter->wol_en = true;
}
err:
mutex_unlock(&adapter->mbox_lock); if (cmd.va)
dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va,
cmd.dma); return status;
}
int be_cmd_set_fw_log_level(struct be_adapter *adapter, u32 level)
{ struct be_dma_mem extfat_cmd; struct be_fat_conf_params *cfgs; int status; int i, j;
/* When more than 1 NIC descriptor is present in the descriptor list, * the caller must specify the pf_num to obtain the NIC descriptor * corresponding to its pci function. * get_vft must be true when the caller wants the VF-template desc of the * PF-pool. * The pf_num should be set to PF_NUM_IGNORE when the caller knows * that only it's NIC descriptor is present in the descriptor list.
*/ staticstruct be_nic_res_desc *be_get_nic_desc(u8 *buf, u32 desc_count, bool get_vft, u8 pf_num)
{ struct be_res_desc_hdr *hdr = (struct be_res_desc_hdr *)buf; struct be_nic_res_desc *nic; int i;
for (i = 0; i < desc_count; i++) { if (hdr->desc_type == NIC_RESOURCE_DESC_TYPE_V0 ||
hdr->desc_type == NIC_RESOURCE_DESC_TYPE_V1) {
nic = (struct be_nic_res_desc *)hdr;
status = be_mbox_notify_wait(adapter); if (!status) { struct be_cmd_resp_get_func_config *resp = cmd.va;
u32 desc_count = le32_to_cpu(resp->desc_count); struct be_nic_res_desc *desc;
/* GET_FUNC_CONFIG returns resource descriptors of the * current function only. So, pf_num should be set to * PF_NUM_IGNORE.
*/
desc = be_get_func_nic_desc(resp->func_param, desc_count,
PF_NUM_IGNORE); if (!desc) {
status = -EINVAL; goto err;
}
/* Store pf_num & vf_num for later use in GET_PROFILE_CONFIG */
adapter->pf_num = desc->pf_num;
adapter->vf_num = desc->vf_num;
if (res)
be_copy_nic_desc(res, desc);
}
err:
mutex_unlock(&adapter->mbox_lock); if (cmd.va)
dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va,
cmd.dma); return status;
}
/* This routine returns a list of all the NIC PF_nums in the adapter */ static u16 be_get_nic_pf_num_list(u8 *buf, u32 desc_count, u16 *nic_pf_nums)
{ struct be_res_desc_hdr *hdr = (struct be_res_desc_hdr *)buf; struct be_pcie_res_desc *pcie = NULL; int i;
u16 nic_pf_count = 0;
for (i = 0; i < desc_count; i++) { if (hdr->desc_type == PCIE_RESOURCE_DESC_TYPE_V0 ||
hdr->desc_type == PCIE_RESOURCE_DESC_TYPE_V1) {
pcie = (struct be_pcie_res_desc *)hdr; if (pcie->pf_state && (pcie->pf_type == MISSION_NIC ||
pcie->pf_type == MISSION_RDMA)) {
nic_pf_nums[nic_pf_count++] = pcie->pf_num;
}
}
/* When QUERY_MODIFIABLE_FIELDS_TYPE bit is set, cmd returns the * descriptors with all bits set to "1" for the fields which can be * modified using SET_PROFILE_CONFIG cmd.
*/ if (query == RESOURCE_MODIFIABLE)
req->type |= QUERY_MODIFIABLE_FIELDS_TYPE;
status = be_cmd_notify_wait(adapter, &wrb); if (status) goto err;
for (i = 0; i < nic_pf_cnt; i++) {
nic = be_get_func_nic_desc(resp->func_param, desc_count,
nic_pf_num_list[i]); if (nic->link_param == adapter->port_num) {
port_res->nic_pfs++;
pcie = be_get_pcie_desc(resp->func_param,
desc_count,
nic_pf_num_list[i]);
port_res->max_vfs += le16_to_cpu(pcie->num_vfs);
}
} goto err;
}
pcie = be_get_pcie_desc(resp->func_param, desc_count,
adapter->pf_num); if (pcie)
res->max_vfs = le16_to_cpu(pcie->num_vfs);
port = be_get_port_desc(resp->func_param, desc_count); if (port)
adapter->mc_type = port->mc_type;
nic = be_get_func_nic_desc(resp->func_param, desc_count,
adapter->pf_num); if (nic)
be_copy_nic_desc(res, nic);
vf_res = be_get_vft_desc(resp->func_param, desc_count,
adapter->pf_num); if (vf_res)
res->vf_if_cap_flags = vf_res->cap_flags;
err: if (cmd.va)
dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va,
cmd.dma); return status;
}
/* Will use MBOX only if MCCQ has not been created */ staticint be_cmd_set_profile_config(struct be_adapter *adapter, void *desc, int size, int count, u8 version, u8 domain)
{ struct be_cmd_req_set_profile_config *req; struct be_mcc_wrb wrb = {0}; struct be_dma_mem cmd; int status;
if (vft_res->max_uc_mac)
desc.nic_vft.unicast_mac_count =
cpu_to_le16(vft_res->max_uc_mac); if (vft_res->max_vlans)
desc.nic_vft.vlan_count = cpu_to_le16(vft_res->max_vlans); if (vft_res->max_iface_count)
desc.nic_vft.iface_count =
cpu_to_le16(vft_res->max_iface_count); if (vft_res->max_mcc_count)
desc.nic_vft.mcc_count = cpu_to_le16(vft_res->max_mcc_count);
if (link_state == IFLA_VF_LINK_STATE_AUTO)
link_config |= PLINK_TRACK;
req->link_config = cpu_to_le32(link_config);
status = be_mcc_notify_wait(adapter);
err:
spin_unlock_bh(&adapter->mcc_lock); return status;
}
int be_cmd_set_logical_link_config(struct be_adapter *adapter, int link_state, u8 domain)
{ int status;
if (BE2_chip(adapter)) return -EOPNOTSUPP;
status = __be_cmd_set_logical_link_config(adapter, link_state,
2, domain);
/* Version 2 of the command will not be recognized by older FW. * On such a failure issue version 1 of the command.
*/ if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST)
status = __be_cmd_set_logical_link_config(adapter, link_state,
1, domain); return status;
}
int be_cmd_set_features(struct be_adapter *adapter)
{ struct be_cmd_resp_set_features *resp; struct be_cmd_req_set_features *req; struct be_mcc_wrb *wrb; int status;
spin_lock_bh(&adapter->mcc_lock);
wrb = wrb_from_mccq(adapter); if (!wrb) {
status = -EBUSY; goto err;
}
status = be_mcc_notify_wait(adapter); if (cmd_status)
*cmd_status = (status & 0xffff); if (ext_status)
*ext_status = 0;
memcpy(wrb_payload, resp, sizeof(*resp) + resp->response_length);
be_dws_le_to_cpu(wrb_payload, sizeof(*resp) + resp->response_length);
err:
spin_unlock_bh(&adapter->mcc_lock); return status;
}
EXPORT_SYMBOL(be_roce_mcc_cmd);
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.109Bemerkung:
(vorverarbeitet am 2026-04-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.