162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is part of the Chelsio T4 Ethernet driver for Linux. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2003-2016 Chelsio Communications, Inc. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This software is available to you under a choice of one of two 762306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1062306a36Sopenharmony_ci * OpenIB.org BSD license below: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1362306a36Sopenharmony_ci * without modification, are permitted provided that the following 1462306a36Sopenharmony_ci * conditions are met: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1762306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1862306a36Sopenharmony_ci * disclaimer. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2162306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2262306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2362306a36Sopenharmony_ci * provided with the distribution. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3262306a36Sopenharmony_ci * SOFTWARE. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <linux/delay.h> 3662306a36Sopenharmony_ci#include "cxgb4.h" 3762306a36Sopenharmony_ci#include "t4_regs.h" 3862306a36Sopenharmony_ci#include "t4_values.h" 3962306a36Sopenharmony_ci#include "t4fw_api.h" 4062306a36Sopenharmony_ci#include "t4fw_version.h" 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/** 4362306a36Sopenharmony_ci * t4_wait_op_done_val - wait until an operation is completed 4462306a36Sopenharmony_ci * @adapter: the adapter performing the operation 4562306a36Sopenharmony_ci * @reg: the register to check for completion 4662306a36Sopenharmony_ci * @mask: a single-bit field within @reg that indicates completion 4762306a36Sopenharmony_ci * @polarity: the value of the field when the operation is completed 4862306a36Sopenharmony_ci * @attempts: number of check iterations 4962306a36Sopenharmony_ci * @delay: delay in usecs between iterations 5062306a36Sopenharmony_ci * @valp: where to store the value of the register at completion time 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * Wait until an operation is completed by checking a bit in a register 5362306a36Sopenharmony_ci * up to @attempts times. If @valp is not NULL the value of the register 5462306a36Sopenharmony_ci * at the time it indicated completion is stored there. Returns 0 if the 5562306a36Sopenharmony_ci * operation completes and -EAGAIN otherwise. 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_cistatic int t4_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, 5862306a36Sopenharmony_ci int polarity, int attempts, int delay, u32 *valp) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci while (1) { 6162306a36Sopenharmony_ci u32 val = t4_read_reg(adapter, reg); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (!!(val & mask) == polarity) { 6462306a36Sopenharmony_ci if (valp) 6562306a36Sopenharmony_ci *valp = val; 6662306a36Sopenharmony_ci return 0; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci if (--attempts == 0) 6962306a36Sopenharmony_ci return -EAGAIN; 7062306a36Sopenharmony_ci if (delay) 7162306a36Sopenharmony_ci udelay(delay); 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic inline int t4_wait_op_done(struct adapter *adapter, int reg, u32 mask, 7662306a36Sopenharmony_ci int polarity, int attempts, int delay) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci return t4_wait_op_done_val(adapter, reg, mask, polarity, attempts, 7962306a36Sopenharmony_ci delay, NULL); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/** 8362306a36Sopenharmony_ci * t4_set_reg_field - set a register field to a value 8462306a36Sopenharmony_ci * @adapter: the adapter to program 8562306a36Sopenharmony_ci * @addr: the register address 8662306a36Sopenharmony_ci * @mask: specifies the portion of the register to modify 8762306a36Sopenharmony_ci * @val: the new value for the register field 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * Sets a register field specified by the supplied mask to the 9062306a36Sopenharmony_ci * given value. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_civoid t4_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask, 9362306a36Sopenharmony_ci u32 val) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci u32 v = t4_read_reg(adapter, addr) & ~mask; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci t4_write_reg(adapter, addr, v | val); 9862306a36Sopenharmony_ci (void) t4_read_reg(adapter, addr); /* flush */ 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/** 10262306a36Sopenharmony_ci * t4_read_indirect - read indirectly addressed registers 10362306a36Sopenharmony_ci * @adap: the adapter 10462306a36Sopenharmony_ci * @addr_reg: register holding the indirect address 10562306a36Sopenharmony_ci * @data_reg: register holding the value of the indirect register 10662306a36Sopenharmony_ci * @vals: where the read register values are stored 10762306a36Sopenharmony_ci * @nregs: how many indirect registers to read 10862306a36Sopenharmony_ci * @start_idx: index of first indirect register to read 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * Reads registers that are accessed indirectly through an address/data 11162306a36Sopenharmony_ci * register pair. 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_civoid t4_read_indirect(struct adapter *adap, unsigned int addr_reg, 11462306a36Sopenharmony_ci unsigned int data_reg, u32 *vals, 11562306a36Sopenharmony_ci unsigned int nregs, unsigned int start_idx) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci while (nregs--) { 11862306a36Sopenharmony_ci t4_write_reg(adap, addr_reg, start_idx); 11962306a36Sopenharmony_ci *vals++ = t4_read_reg(adap, data_reg); 12062306a36Sopenharmony_ci start_idx++; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/** 12562306a36Sopenharmony_ci * t4_write_indirect - write indirectly addressed registers 12662306a36Sopenharmony_ci * @adap: the adapter 12762306a36Sopenharmony_ci * @addr_reg: register holding the indirect addresses 12862306a36Sopenharmony_ci * @data_reg: register holding the value for the indirect registers 12962306a36Sopenharmony_ci * @vals: values to write 13062306a36Sopenharmony_ci * @nregs: how many indirect registers to write 13162306a36Sopenharmony_ci * @start_idx: address of first indirect register to write 13262306a36Sopenharmony_ci * 13362306a36Sopenharmony_ci * Writes a sequential block of registers that are accessed indirectly 13462306a36Sopenharmony_ci * through an address/data register pair. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_civoid t4_write_indirect(struct adapter *adap, unsigned int addr_reg, 13762306a36Sopenharmony_ci unsigned int data_reg, const u32 *vals, 13862306a36Sopenharmony_ci unsigned int nregs, unsigned int start_idx) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci while (nregs--) { 14162306a36Sopenharmony_ci t4_write_reg(adap, addr_reg, start_idx++); 14262306a36Sopenharmony_ci t4_write_reg(adap, data_reg, *vals++); 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* 14762306a36Sopenharmony_ci * Read a 32-bit PCI Configuration Space register via the PCI-E backdoor 14862306a36Sopenharmony_ci * mechanism. This guarantees that we get the real value even if we're 14962306a36Sopenharmony_ci * operating within a Virtual Machine and the Hypervisor is trapping our 15062306a36Sopenharmony_ci * Configuration Space accesses. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_civoid t4_hw_pci_read_cfg4(struct adapter *adap, int reg, u32 *val) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci u32 req = FUNCTION_V(adap->pf) | REGISTER_V(reg); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5) 15762306a36Sopenharmony_ci req |= ENABLE_F; 15862306a36Sopenharmony_ci else 15962306a36Sopenharmony_ci req |= T6_ENABLE_F; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (is_t4(adap->params.chip)) 16262306a36Sopenharmony_ci req |= LOCALCFG_F; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci t4_write_reg(adap, PCIE_CFG_SPACE_REQ_A, req); 16562306a36Sopenharmony_ci *val = t4_read_reg(adap, PCIE_CFG_SPACE_DATA_A); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* Reset ENABLE to 0 so reads of PCIE_CFG_SPACE_DATA won't cause a 16862306a36Sopenharmony_ci * Configuration Space read. (None of the other fields matter when 16962306a36Sopenharmony_ci * ENABLE is 0 so a simple register write is easier than a 17062306a36Sopenharmony_ci * read-modify-write via t4_set_reg_field().) 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_ci t4_write_reg(adap, PCIE_CFG_SPACE_REQ_A, 0); 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/* 17662306a36Sopenharmony_ci * t4_report_fw_error - report firmware error 17762306a36Sopenharmony_ci * @adap: the adapter 17862306a36Sopenharmony_ci * 17962306a36Sopenharmony_ci * The adapter firmware can indicate error conditions to the host. 18062306a36Sopenharmony_ci * If the firmware has indicated an error, print out the reason for 18162306a36Sopenharmony_ci * the firmware error. 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_cistatic void t4_report_fw_error(struct adapter *adap) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci static const char *const reason[] = { 18662306a36Sopenharmony_ci "Crash", /* PCIE_FW_EVAL_CRASH */ 18762306a36Sopenharmony_ci "During Device Preparation", /* PCIE_FW_EVAL_PREP */ 18862306a36Sopenharmony_ci "During Device Configuration", /* PCIE_FW_EVAL_CONF */ 18962306a36Sopenharmony_ci "During Device Initialization", /* PCIE_FW_EVAL_INIT */ 19062306a36Sopenharmony_ci "Unexpected Event", /* PCIE_FW_EVAL_UNEXPECTEDEVENT */ 19162306a36Sopenharmony_ci "Insufficient Airflow", /* PCIE_FW_EVAL_OVERHEAT */ 19262306a36Sopenharmony_ci "Device Shutdown", /* PCIE_FW_EVAL_DEVICESHUTDOWN */ 19362306a36Sopenharmony_ci "Reserved", /* reserved */ 19462306a36Sopenharmony_ci }; 19562306a36Sopenharmony_ci u32 pcie_fw; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci pcie_fw = t4_read_reg(adap, PCIE_FW_A); 19862306a36Sopenharmony_ci if (pcie_fw & PCIE_FW_ERR_F) { 19962306a36Sopenharmony_ci dev_err(adap->pdev_dev, "Firmware reports adapter error: %s\n", 20062306a36Sopenharmony_ci reason[PCIE_FW_EVAL_G(pcie_fw)]); 20162306a36Sopenharmony_ci adap->flags &= ~CXGB4_FW_OK; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/* 20662306a36Sopenharmony_ci * Get the reply to a mailbox command and store it in @rpl in big-endian order. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_cistatic void get_mbox_rpl(struct adapter *adap, __be64 *rpl, int nflit, 20962306a36Sopenharmony_ci u32 mbox_addr) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci for ( ; nflit; nflit--, mbox_addr += 8) 21262306a36Sopenharmony_ci *rpl++ = cpu_to_be64(t4_read_reg64(adap, mbox_addr)); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci/* 21662306a36Sopenharmony_ci * Handle a FW assertion reported in a mailbox. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_cistatic void fw_asrt(struct adapter *adap, u32 mbox_addr) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci struct fw_debug_cmd asrt; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci get_mbox_rpl(adap, (__be64 *)&asrt, sizeof(asrt) / 8, mbox_addr); 22362306a36Sopenharmony_ci dev_alert(adap->pdev_dev, 22462306a36Sopenharmony_ci "FW assertion at %.16s:%u, val0 %#x, val1 %#x\n", 22562306a36Sopenharmony_ci asrt.u.assert.filename_0_7, be32_to_cpu(asrt.u.assert.line), 22662306a36Sopenharmony_ci be32_to_cpu(asrt.u.assert.x), be32_to_cpu(asrt.u.assert.y)); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/** 23062306a36Sopenharmony_ci * t4_record_mbox - record a Firmware Mailbox Command/Reply in the log 23162306a36Sopenharmony_ci * @adapter: the adapter 23262306a36Sopenharmony_ci * @cmd: the Firmware Mailbox Command or Reply 23362306a36Sopenharmony_ci * @size: command length in bytes 23462306a36Sopenharmony_ci * @access: the time (ms) needed to access the Firmware Mailbox 23562306a36Sopenharmony_ci * @execute: the time (ms) the command spent being executed 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_cistatic void t4_record_mbox(struct adapter *adapter, 23862306a36Sopenharmony_ci const __be64 *cmd, unsigned int size, 23962306a36Sopenharmony_ci int access, int execute) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct mbox_cmd_log *log = adapter->mbox_log; 24262306a36Sopenharmony_ci struct mbox_cmd *entry; 24362306a36Sopenharmony_ci int i; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci entry = mbox_cmd_log_entry(log, log->cursor++); 24662306a36Sopenharmony_ci if (log->cursor == log->size) 24762306a36Sopenharmony_ci log->cursor = 0; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci for (i = 0; i < size / 8; i++) 25062306a36Sopenharmony_ci entry->cmd[i] = be64_to_cpu(cmd[i]); 25162306a36Sopenharmony_ci while (i < MBOX_LEN / 8) 25262306a36Sopenharmony_ci entry->cmd[i++] = 0; 25362306a36Sopenharmony_ci entry->timestamp = jiffies; 25462306a36Sopenharmony_ci entry->seqno = log->seqno++; 25562306a36Sopenharmony_ci entry->access = access; 25662306a36Sopenharmony_ci entry->execute = execute; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci/** 26062306a36Sopenharmony_ci * t4_wr_mbox_meat_timeout - send a command to FW through the given mailbox 26162306a36Sopenharmony_ci * @adap: the adapter 26262306a36Sopenharmony_ci * @mbox: index of the mailbox to use 26362306a36Sopenharmony_ci * @cmd: the command to write 26462306a36Sopenharmony_ci * @size: command length in bytes 26562306a36Sopenharmony_ci * @rpl: where to optionally store the reply 26662306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 26762306a36Sopenharmony_ci * @timeout: time to wait for command to finish before timing out 26862306a36Sopenharmony_ci * 26962306a36Sopenharmony_ci * Sends the given command to FW through the selected mailbox and waits 27062306a36Sopenharmony_ci * for the FW to execute the command. If @rpl is not %NULL it is used to 27162306a36Sopenharmony_ci * store the FW's reply to the command. The command and its optional 27262306a36Sopenharmony_ci * reply are of the same length. FW can take up to %FW_CMD_MAX_TIMEOUT ms 27362306a36Sopenharmony_ci * to respond. @sleep_ok determines whether we may sleep while awaiting 27462306a36Sopenharmony_ci * the response. If sleeping is allowed we use progressive backoff 27562306a36Sopenharmony_ci * otherwise we spin. 27662306a36Sopenharmony_ci * 27762306a36Sopenharmony_ci * The return value is 0 on success or a negative errno on failure. A 27862306a36Sopenharmony_ci * failure can happen either because we are not able to execute the 27962306a36Sopenharmony_ci * command or FW executes it but signals an error. In the latter case 28062306a36Sopenharmony_ci * the return value is the error code indicated by FW (negated). 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_ciint t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox, const void *cmd, 28362306a36Sopenharmony_ci int size, void *rpl, bool sleep_ok, int timeout) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci static const int delay[] = { 28662306a36Sopenharmony_ci 1, 1, 3, 5, 10, 10, 20, 50, 100, 200 28762306a36Sopenharmony_ci }; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci struct mbox_list entry; 29062306a36Sopenharmony_ci u16 access = 0; 29162306a36Sopenharmony_ci u16 execute = 0; 29262306a36Sopenharmony_ci u32 v; 29362306a36Sopenharmony_ci u64 res; 29462306a36Sopenharmony_ci int i, ms, delay_idx, ret; 29562306a36Sopenharmony_ci const __be64 *p = cmd; 29662306a36Sopenharmony_ci u32 data_reg = PF_REG(mbox, CIM_PF_MAILBOX_DATA_A); 29762306a36Sopenharmony_ci u32 ctl_reg = PF_REG(mbox, CIM_PF_MAILBOX_CTRL_A); 29862306a36Sopenharmony_ci __be64 cmd_rpl[MBOX_LEN / 8]; 29962306a36Sopenharmony_ci u32 pcie_fw; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if ((size & 15) || size > MBOX_LEN) 30262306a36Sopenharmony_ci return -EINVAL; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* 30562306a36Sopenharmony_ci * If the device is off-line, as in EEH, commands will time out. 30662306a36Sopenharmony_ci * Fail them early so we don't waste time waiting. 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_ci if (adap->pdev->error_state != pci_channel_io_normal) 30962306a36Sopenharmony_ci return -EIO; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* If we have a negative timeout, that implies that we can't sleep. */ 31262306a36Sopenharmony_ci if (timeout < 0) { 31362306a36Sopenharmony_ci sleep_ok = false; 31462306a36Sopenharmony_ci timeout = -timeout; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* Queue ourselves onto the mailbox access list. When our entry is at 31862306a36Sopenharmony_ci * the front of the list, we have rights to access the mailbox. So we 31962306a36Sopenharmony_ci * wait [for a while] till we're at the front [or bail out with an 32062306a36Sopenharmony_ci * EBUSY] ... 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_ci spin_lock_bh(&adap->mbox_lock); 32362306a36Sopenharmony_ci list_add_tail(&entry.list, &adap->mlist.list); 32462306a36Sopenharmony_ci spin_unlock_bh(&adap->mbox_lock); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci delay_idx = 0; 32762306a36Sopenharmony_ci ms = delay[0]; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci for (i = 0; ; i += ms) { 33062306a36Sopenharmony_ci /* If we've waited too long, return a busy indication. This 33162306a36Sopenharmony_ci * really ought to be based on our initial position in the 33262306a36Sopenharmony_ci * mailbox access list but this is a start. We very rarely 33362306a36Sopenharmony_ci * contend on access to the mailbox ... 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_ci pcie_fw = t4_read_reg(adap, PCIE_FW_A); 33662306a36Sopenharmony_ci if (i > FW_CMD_MAX_TIMEOUT || (pcie_fw & PCIE_FW_ERR_F)) { 33762306a36Sopenharmony_ci spin_lock_bh(&adap->mbox_lock); 33862306a36Sopenharmony_ci list_del(&entry.list); 33962306a36Sopenharmony_ci spin_unlock_bh(&adap->mbox_lock); 34062306a36Sopenharmony_ci ret = (pcie_fw & PCIE_FW_ERR_F) ? -ENXIO : -EBUSY; 34162306a36Sopenharmony_ci t4_record_mbox(adap, cmd, size, access, ret); 34262306a36Sopenharmony_ci return ret; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* If we're at the head, break out and start the mailbox 34662306a36Sopenharmony_ci * protocol. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci if (list_first_entry(&adap->mlist.list, struct mbox_list, 34962306a36Sopenharmony_ci list) == &entry) 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* Delay for a bit before checking again ... */ 35362306a36Sopenharmony_ci if (sleep_ok) { 35462306a36Sopenharmony_ci ms = delay[delay_idx]; /* last element may repeat */ 35562306a36Sopenharmony_ci if (delay_idx < ARRAY_SIZE(delay) - 1) 35662306a36Sopenharmony_ci delay_idx++; 35762306a36Sopenharmony_ci msleep(ms); 35862306a36Sopenharmony_ci } else { 35962306a36Sopenharmony_ci mdelay(ms); 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* Loop trying to get ownership of the mailbox. Return an error 36462306a36Sopenharmony_ci * if we can't gain ownership. 36562306a36Sopenharmony_ci */ 36662306a36Sopenharmony_ci v = MBOWNER_G(t4_read_reg(adap, ctl_reg)); 36762306a36Sopenharmony_ci for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++) 36862306a36Sopenharmony_ci v = MBOWNER_G(t4_read_reg(adap, ctl_reg)); 36962306a36Sopenharmony_ci if (v != MBOX_OWNER_DRV) { 37062306a36Sopenharmony_ci spin_lock_bh(&adap->mbox_lock); 37162306a36Sopenharmony_ci list_del(&entry.list); 37262306a36Sopenharmony_ci spin_unlock_bh(&adap->mbox_lock); 37362306a36Sopenharmony_ci ret = (v == MBOX_OWNER_FW) ? -EBUSY : -ETIMEDOUT; 37462306a36Sopenharmony_ci t4_record_mbox(adap, cmd, size, access, ret); 37562306a36Sopenharmony_ci return ret; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* Copy in the new mailbox command and send it on its way ... */ 37962306a36Sopenharmony_ci t4_record_mbox(adap, cmd, size, access, 0); 38062306a36Sopenharmony_ci for (i = 0; i < size; i += 8) 38162306a36Sopenharmony_ci t4_write_reg64(adap, data_reg + i, be64_to_cpu(*p++)); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci t4_write_reg(adap, ctl_reg, MBMSGVALID_F | MBOWNER_V(MBOX_OWNER_FW)); 38462306a36Sopenharmony_ci t4_read_reg(adap, ctl_reg); /* flush write */ 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci delay_idx = 0; 38762306a36Sopenharmony_ci ms = delay[0]; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci for (i = 0; 39062306a36Sopenharmony_ci !((pcie_fw = t4_read_reg(adap, PCIE_FW_A)) & PCIE_FW_ERR_F) && 39162306a36Sopenharmony_ci i < timeout; 39262306a36Sopenharmony_ci i += ms) { 39362306a36Sopenharmony_ci if (sleep_ok) { 39462306a36Sopenharmony_ci ms = delay[delay_idx]; /* last element may repeat */ 39562306a36Sopenharmony_ci if (delay_idx < ARRAY_SIZE(delay) - 1) 39662306a36Sopenharmony_ci delay_idx++; 39762306a36Sopenharmony_ci msleep(ms); 39862306a36Sopenharmony_ci } else 39962306a36Sopenharmony_ci mdelay(ms); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci v = t4_read_reg(adap, ctl_reg); 40262306a36Sopenharmony_ci if (MBOWNER_G(v) == MBOX_OWNER_DRV) { 40362306a36Sopenharmony_ci if (!(v & MBMSGVALID_F)) { 40462306a36Sopenharmony_ci t4_write_reg(adap, ctl_reg, 0); 40562306a36Sopenharmony_ci continue; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci get_mbox_rpl(adap, cmd_rpl, MBOX_LEN / 8, data_reg); 40962306a36Sopenharmony_ci res = be64_to_cpu(cmd_rpl[0]); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (FW_CMD_OP_G(res >> 32) == FW_DEBUG_CMD) { 41262306a36Sopenharmony_ci fw_asrt(adap, data_reg); 41362306a36Sopenharmony_ci res = FW_CMD_RETVAL_V(EIO); 41462306a36Sopenharmony_ci } else if (rpl) { 41562306a36Sopenharmony_ci memcpy(rpl, cmd_rpl, size); 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci t4_write_reg(adap, ctl_reg, 0); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci execute = i + ms; 42162306a36Sopenharmony_ci t4_record_mbox(adap, cmd_rpl, 42262306a36Sopenharmony_ci MBOX_LEN, access, execute); 42362306a36Sopenharmony_ci spin_lock_bh(&adap->mbox_lock); 42462306a36Sopenharmony_ci list_del(&entry.list); 42562306a36Sopenharmony_ci spin_unlock_bh(&adap->mbox_lock); 42662306a36Sopenharmony_ci return -FW_CMD_RETVAL_G((int)res); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci ret = (pcie_fw & PCIE_FW_ERR_F) ? -ENXIO : -ETIMEDOUT; 43162306a36Sopenharmony_ci t4_record_mbox(adap, cmd, size, access, ret); 43262306a36Sopenharmony_ci dev_err(adap->pdev_dev, "command %#x in mailbox %d timed out\n", 43362306a36Sopenharmony_ci *(const u8 *)cmd, mbox); 43462306a36Sopenharmony_ci t4_report_fw_error(adap); 43562306a36Sopenharmony_ci spin_lock_bh(&adap->mbox_lock); 43662306a36Sopenharmony_ci list_del(&entry.list); 43762306a36Sopenharmony_ci spin_unlock_bh(&adap->mbox_lock); 43862306a36Sopenharmony_ci t4_fatal_err(adap); 43962306a36Sopenharmony_ci return ret; 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ciint t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, 44362306a36Sopenharmony_ci void *rpl, bool sleep_ok) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci return t4_wr_mbox_meat_timeout(adap, mbox, cmd, size, rpl, sleep_ok, 44662306a36Sopenharmony_ci FW_CMD_MAX_TIMEOUT); 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic int t4_edc_err_read(struct adapter *adap, int idx) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci u32 edc_ecc_err_addr_reg; 45262306a36Sopenharmony_ci u32 rdata_reg; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (is_t4(adap->params.chip)) { 45562306a36Sopenharmony_ci CH_WARN(adap, "%s: T4 NOT supported.\n", __func__); 45662306a36Sopenharmony_ci return 0; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci if (idx != 0 && idx != 1) { 45962306a36Sopenharmony_ci CH_WARN(adap, "%s: idx %d NOT supported.\n", __func__, idx); 46062306a36Sopenharmony_ci return 0; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci edc_ecc_err_addr_reg = EDC_T5_REG(EDC_H_ECC_ERR_ADDR_A, idx); 46462306a36Sopenharmony_ci rdata_reg = EDC_T5_REG(EDC_H_BIST_STATUS_RDATA_A, idx); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci CH_WARN(adap, 46762306a36Sopenharmony_ci "edc%d err addr 0x%x: 0x%x.\n", 46862306a36Sopenharmony_ci idx, edc_ecc_err_addr_reg, 46962306a36Sopenharmony_ci t4_read_reg(adap, edc_ecc_err_addr_reg)); 47062306a36Sopenharmony_ci CH_WARN(adap, 47162306a36Sopenharmony_ci "bist: 0x%x, status %llx %llx %llx %llx %llx %llx %llx %llx %llx.\n", 47262306a36Sopenharmony_ci rdata_reg, 47362306a36Sopenharmony_ci (unsigned long long)t4_read_reg64(adap, rdata_reg), 47462306a36Sopenharmony_ci (unsigned long long)t4_read_reg64(adap, rdata_reg + 8), 47562306a36Sopenharmony_ci (unsigned long long)t4_read_reg64(adap, rdata_reg + 16), 47662306a36Sopenharmony_ci (unsigned long long)t4_read_reg64(adap, rdata_reg + 24), 47762306a36Sopenharmony_ci (unsigned long long)t4_read_reg64(adap, rdata_reg + 32), 47862306a36Sopenharmony_ci (unsigned long long)t4_read_reg64(adap, rdata_reg + 40), 47962306a36Sopenharmony_ci (unsigned long long)t4_read_reg64(adap, rdata_reg + 48), 48062306a36Sopenharmony_ci (unsigned long long)t4_read_reg64(adap, rdata_reg + 56), 48162306a36Sopenharmony_ci (unsigned long long)t4_read_reg64(adap, rdata_reg + 64)); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci return 0; 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci/** 48762306a36Sopenharmony_ci * t4_memory_rw_init - Get memory window relative offset, base, and size. 48862306a36Sopenharmony_ci * @adap: the adapter 48962306a36Sopenharmony_ci * @win: PCI-E Memory Window to use 49062306a36Sopenharmony_ci * @mtype: memory type: MEM_EDC0, MEM_EDC1, MEM_HMA or MEM_MC 49162306a36Sopenharmony_ci * @mem_off: memory relative offset with respect to @mtype. 49262306a36Sopenharmony_ci * @mem_base: configured memory base address. 49362306a36Sopenharmony_ci * @mem_aperture: configured memory window aperture. 49462306a36Sopenharmony_ci * 49562306a36Sopenharmony_ci * Get the configured memory window's relative offset, base, and size. 49662306a36Sopenharmony_ci */ 49762306a36Sopenharmony_ciint t4_memory_rw_init(struct adapter *adap, int win, int mtype, u32 *mem_off, 49862306a36Sopenharmony_ci u32 *mem_base, u32 *mem_aperture) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci u32 edc_size, mc_size, mem_reg; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* Offset into the region of memory which is being accessed 50362306a36Sopenharmony_ci * MEM_EDC0 = 0 50462306a36Sopenharmony_ci * MEM_EDC1 = 1 50562306a36Sopenharmony_ci * MEM_MC = 2 -- MEM_MC for chips with only 1 memory controller 50662306a36Sopenharmony_ci * MEM_MC1 = 3 -- for chips with 2 memory controllers (e.g. T5) 50762306a36Sopenharmony_ci * MEM_HMA = 4 50862306a36Sopenharmony_ci */ 50962306a36Sopenharmony_ci edc_size = EDRAM0_SIZE_G(t4_read_reg(adap, MA_EDRAM0_BAR_A)); 51062306a36Sopenharmony_ci if (mtype == MEM_HMA) { 51162306a36Sopenharmony_ci *mem_off = 2 * (edc_size * 1024 * 1024); 51262306a36Sopenharmony_ci } else if (mtype != MEM_MC1) { 51362306a36Sopenharmony_ci *mem_off = (mtype * (edc_size * 1024 * 1024)); 51462306a36Sopenharmony_ci } else { 51562306a36Sopenharmony_ci mc_size = EXT_MEM0_SIZE_G(t4_read_reg(adap, 51662306a36Sopenharmony_ci MA_EXT_MEMORY0_BAR_A)); 51762306a36Sopenharmony_ci *mem_off = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* Each PCI-E Memory Window is programmed with a window size -- or 52162306a36Sopenharmony_ci * "aperture" -- which controls the granularity of its mapping onto 52262306a36Sopenharmony_ci * adapter memory. We need to grab that aperture in order to know 52362306a36Sopenharmony_ci * how to use the specified window. The window is also programmed 52462306a36Sopenharmony_ci * with the base address of the Memory Window in BAR0's address 52562306a36Sopenharmony_ci * space. For T4 this is an absolute PCI-E Bus Address. For T5 52662306a36Sopenharmony_ci * the address is relative to BAR0. 52762306a36Sopenharmony_ci */ 52862306a36Sopenharmony_ci mem_reg = t4_read_reg(adap, 52962306a36Sopenharmony_ci PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 53062306a36Sopenharmony_ci win)); 53162306a36Sopenharmony_ci /* a dead adapter will return 0xffffffff for PIO reads */ 53262306a36Sopenharmony_ci if (mem_reg == 0xffffffff) 53362306a36Sopenharmony_ci return -ENXIO; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci *mem_aperture = 1 << (WINDOW_G(mem_reg) + WINDOW_SHIFT_X); 53662306a36Sopenharmony_ci *mem_base = PCIEOFST_G(mem_reg) << PCIEOFST_SHIFT_X; 53762306a36Sopenharmony_ci if (is_t4(adap->params.chip)) 53862306a36Sopenharmony_ci *mem_base -= adap->t4_bar0; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci return 0; 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci/** 54462306a36Sopenharmony_ci * t4_memory_update_win - Move memory window to specified address. 54562306a36Sopenharmony_ci * @adap: the adapter 54662306a36Sopenharmony_ci * @win: PCI-E Memory Window to use 54762306a36Sopenharmony_ci * @addr: location to move. 54862306a36Sopenharmony_ci * 54962306a36Sopenharmony_ci * Move memory window to specified address. 55062306a36Sopenharmony_ci */ 55162306a36Sopenharmony_civoid t4_memory_update_win(struct adapter *adap, int win, u32 addr) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci t4_write_reg(adap, 55462306a36Sopenharmony_ci PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win), 55562306a36Sopenharmony_ci addr); 55662306a36Sopenharmony_ci /* Read it back to ensure that changes propagate before we 55762306a36Sopenharmony_ci * attempt to use the new value. 55862306a36Sopenharmony_ci */ 55962306a36Sopenharmony_ci t4_read_reg(adap, 56062306a36Sopenharmony_ci PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win)); 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci/** 56462306a36Sopenharmony_ci * t4_memory_rw_residual - Read/Write residual data. 56562306a36Sopenharmony_ci * @adap: the adapter 56662306a36Sopenharmony_ci * @off: relative offset within residual to start read/write. 56762306a36Sopenharmony_ci * @addr: address within indicated memory type. 56862306a36Sopenharmony_ci * @buf: host memory buffer 56962306a36Sopenharmony_ci * @dir: direction of transfer T4_MEMORY_READ (1) or T4_MEMORY_WRITE (0) 57062306a36Sopenharmony_ci * 57162306a36Sopenharmony_ci * Read/Write residual data less than 32-bits. 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_civoid t4_memory_rw_residual(struct adapter *adap, u32 off, u32 addr, u8 *buf, 57462306a36Sopenharmony_ci int dir) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci union { 57762306a36Sopenharmony_ci u32 word; 57862306a36Sopenharmony_ci char byte[4]; 57962306a36Sopenharmony_ci } last; 58062306a36Sopenharmony_ci unsigned char *bp; 58162306a36Sopenharmony_ci int i; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci if (dir == T4_MEMORY_READ) { 58462306a36Sopenharmony_ci last.word = le32_to_cpu((__force __le32) 58562306a36Sopenharmony_ci t4_read_reg(adap, addr)); 58662306a36Sopenharmony_ci for (bp = (unsigned char *)buf, i = off; i < 4; i++) 58762306a36Sopenharmony_ci bp[i] = last.byte[i]; 58862306a36Sopenharmony_ci } else { 58962306a36Sopenharmony_ci last.word = *buf; 59062306a36Sopenharmony_ci for (i = off; i < 4; i++) 59162306a36Sopenharmony_ci last.byte[i] = 0; 59262306a36Sopenharmony_ci t4_write_reg(adap, addr, 59362306a36Sopenharmony_ci (__force u32)cpu_to_le32(last.word)); 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci} 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci/** 59862306a36Sopenharmony_ci * t4_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window 59962306a36Sopenharmony_ci * @adap: the adapter 60062306a36Sopenharmony_ci * @win: PCI-E Memory Window to use 60162306a36Sopenharmony_ci * @mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC 60262306a36Sopenharmony_ci * @addr: address within indicated memory type 60362306a36Sopenharmony_ci * @len: amount of memory to transfer 60462306a36Sopenharmony_ci * @hbuf: host memory buffer 60562306a36Sopenharmony_ci * @dir: direction of transfer T4_MEMORY_READ (1) or T4_MEMORY_WRITE (0) 60662306a36Sopenharmony_ci * 60762306a36Sopenharmony_ci * Reads/writes an [almost] arbitrary memory region in the firmware: the 60862306a36Sopenharmony_ci * firmware memory address and host buffer must be aligned on 32-bit 60962306a36Sopenharmony_ci * boundaries; the length may be arbitrary. The memory is transferred as 61062306a36Sopenharmony_ci * a raw byte sequence from/to the firmware's memory. If this memory 61162306a36Sopenharmony_ci * contains data structures which contain multi-byte integers, it's the 61262306a36Sopenharmony_ci * caller's responsibility to perform appropriate byte order conversions. 61362306a36Sopenharmony_ci */ 61462306a36Sopenharmony_ciint t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr, 61562306a36Sopenharmony_ci u32 len, void *hbuf, int dir) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci u32 pos, offset, resid, memoffset; 61862306a36Sopenharmony_ci u32 win_pf, mem_aperture, mem_base; 61962306a36Sopenharmony_ci u32 *buf; 62062306a36Sopenharmony_ci int ret; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* Argument sanity checks ... 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_ci if (addr & 0x3 || (uintptr_t)hbuf & 0x3) 62562306a36Sopenharmony_ci return -EINVAL; 62662306a36Sopenharmony_ci buf = (u32 *)hbuf; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci /* It's convenient to be able to handle lengths which aren't a 62962306a36Sopenharmony_ci * multiple of 32-bits because we often end up transferring files to 63062306a36Sopenharmony_ci * the firmware. So we'll handle that by normalizing the length here 63162306a36Sopenharmony_ci * and then handling any residual transfer at the end. 63262306a36Sopenharmony_ci */ 63362306a36Sopenharmony_ci resid = len & 0x3; 63462306a36Sopenharmony_ci len -= resid; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci ret = t4_memory_rw_init(adap, win, mtype, &memoffset, &mem_base, 63762306a36Sopenharmony_ci &mem_aperture); 63862306a36Sopenharmony_ci if (ret) 63962306a36Sopenharmony_ci return ret; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci /* Determine the PCIE_MEM_ACCESS_OFFSET */ 64262306a36Sopenharmony_ci addr = addr + memoffset; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci win_pf = is_t4(adap->params.chip) ? 0 : PFNUM_V(adap->pf); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* Calculate our initial PCI-E Memory Window Position and Offset into 64762306a36Sopenharmony_ci * that Window. 64862306a36Sopenharmony_ci */ 64962306a36Sopenharmony_ci pos = addr & ~(mem_aperture - 1); 65062306a36Sopenharmony_ci offset = addr - pos; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci /* Set up initial PCI-E Memory Window to cover the start of our 65362306a36Sopenharmony_ci * transfer. 65462306a36Sopenharmony_ci */ 65562306a36Sopenharmony_ci t4_memory_update_win(adap, win, pos | win_pf); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Transfer data to/from the adapter as long as there's an integral 65862306a36Sopenharmony_ci * number of 32-bit transfers to complete. 65962306a36Sopenharmony_ci * 66062306a36Sopenharmony_ci * A note on Endianness issues: 66162306a36Sopenharmony_ci * 66262306a36Sopenharmony_ci * The "register" reads and writes below from/to the PCI-E Memory 66362306a36Sopenharmony_ci * Window invoke the standard adapter Big-Endian to PCI-E Link 66462306a36Sopenharmony_ci * Little-Endian "swizzel." As a result, if we have the following 66562306a36Sopenharmony_ci * data in adapter memory: 66662306a36Sopenharmony_ci * 66762306a36Sopenharmony_ci * Memory: ... | b0 | b1 | b2 | b3 | ... 66862306a36Sopenharmony_ci * Address: i+0 i+1 i+2 i+3 66962306a36Sopenharmony_ci * 67062306a36Sopenharmony_ci * Then a read of the adapter memory via the PCI-E Memory Window 67162306a36Sopenharmony_ci * will yield: 67262306a36Sopenharmony_ci * 67362306a36Sopenharmony_ci * x = readl(i) 67462306a36Sopenharmony_ci * 31 0 67562306a36Sopenharmony_ci * [ b3 | b2 | b1 | b0 ] 67662306a36Sopenharmony_ci * 67762306a36Sopenharmony_ci * If this value is stored into local memory on a Little-Endian system 67862306a36Sopenharmony_ci * it will show up correctly in local memory as: 67962306a36Sopenharmony_ci * 68062306a36Sopenharmony_ci * ( ..., b0, b1, b2, b3, ... ) 68162306a36Sopenharmony_ci * 68262306a36Sopenharmony_ci * But on a Big-Endian system, the store will show up in memory 68362306a36Sopenharmony_ci * incorrectly swizzled as: 68462306a36Sopenharmony_ci * 68562306a36Sopenharmony_ci * ( ..., b3, b2, b1, b0, ... ) 68662306a36Sopenharmony_ci * 68762306a36Sopenharmony_ci * So we need to account for this in the reads and writes to the 68862306a36Sopenharmony_ci * PCI-E Memory Window below by undoing the register read/write 68962306a36Sopenharmony_ci * swizzels. 69062306a36Sopenharmony_ci */ 69162306a36Sopenharmony_ci while (len > 0) { 69262306a36Sopenharmony_ci if (dir == T4_MEMORY_READ) 69362306a36Sopenharmony_ci *buf++ = le32_to_cpu((__force __le32)t4_read_reg(adap, 69462306a36Sopenharmony_ci mem_base + offset)); 69562306a36Sopenharmony_ci else 69662306a36Sopenharmony_ci t4_write_reg(adap, mem_base + offset, 69762306a36Sopenharmony_ci (__force u32)cpu_to_le32(*buf++)); 69862306a36Sopenharmony_ci offset += sizeof(__be32); 69962306a36Sopenharmony_ci len -= sizeof(__be32); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci /* If we've reached the end of our current window aperture, 70262306a36Sopenharmony_ci * move the PCI-E Memory Window on to the next. Note that 70362306a36Sopenharmony_ci * doing this here after "len" may be 0 allows us to set up 70462306a36Sopenharmony_ci * the PCI-E Memory Window for a possible final residual 70562306a36Sopenharmony_ci * transfer below ... 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_ci if (offset == mem_aperture) { 70862306a36Sopenharmony_ci pos += mem_aperture; 70962306a36Sopenharmony_ci offset = 0; 71062306a36Sopenharmony_ci t4_memory_update_win(adap, win, pos | win_pf); 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci /* If the original transfer had a length which wasn't a multiple of 71562306a36Sopenharmony_ci * 32-bits, now's where we need to finish off the transfer of the 71662306a36Sopenharmony_ci * residual amount. The PCI-E Memory Window has already been moved 71762306a36Sopenharmony_ci * above (if necessary) to cover this final transfer. 71862306a36Sopenharmony_ci */ 71962306a36Sopenharmony_ci if (resid) 72062306a36Sopenharmony_ci t4_memory_rw_residual(adap, resid, mem_base + offset, 72162306a36Sopenharmony_ci (u8 *)buf, dir); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci return 0; 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci/* Return the specified PCI-E Configuration Space register from our Physical 72762306a36Sopenharmony_ci * Function. We try first via a Firmware LDST Command since we prefer to let 72862306a36Sopenharmony_ci * the firmware own all of these registers, but if that fails we go for it 72962306a36Sopenharmony_ci * directly ourselves. 73062306a36Sopenharmony_ci */ 73162306a36Sopenharmony_ciu32 t4_read_pcie_cfg4(struct adapter *adap, int reg) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci u32 val, ldst_addrspace; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci /* If fw_attach != 0, construct and send the Firmware LDST Command to 73662306a36Sopenharmony_ci * retrieve the specified PCI-E Configuration Space register. 73762306a36Sopenharmony_ci */ 73862306a36Sopenharmony_ci struct fw_ldst_cmd ldst_cmd; 73962306a36Sopenharmony_ci int ret; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci memset(&ldst_cmd, 0, sizeof(ldst_cmd)); 74262306a36Sopenharmony_ci ldst_addrspace = FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_FUNC_PCIE); 74362306a36Sopenharmony_ci ldst_cmd.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) | 74462306a36Sopenharmony_ci FW_CMD_REQUEST_F | 74562306a36Sopenharmony_ci FW_CMD_READ_F | 74662306a36Sopenharmony_ci ldst_addrspace); 74762306a36Sopenharmony_ci ldst_cmd.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst_cmd)); 74862306a36Sopenharmony_ci ldst_cmd.u.pcie.select_naccess = FW_LDST_CMD_NACCESS_V(1); 74962306a36Sopenharmony_ci ldst_cmd.u.pcie.ctrl_to_fn = 75062306a36Sopenharmony_ci (FW_LDST_CMD_LC_F | FW_LDST_CMD_FN_V(adap->pf)); 75162306a36Sopenharmony_ci ldst_cmd.u.pcie.r = reg; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci /* If the LDST Command succeeds, return the result, otherwise 75462306a36Sopenharmony_ci * fall through to reading it directly ourselves ... 75562306a36Sopenharmony_ci */ 75662306a36Sopenharmony_ci ret = t4_wr_mbox(adap, adap->mbox, &ldst_cmd, sizeof(ldst_cmd), 75762306a36Sopenharmony_ci &ldst_cmd); 75862306a36Sopenharmony_ci if (ret == 0) 75962306a36Sopenharmony_ci val = be32_to_cpu(ldst_cmd.u.pcie.data[0]); 76062306a36Sopenharmony_ci else 76162306a36Sopenharmony_ci /* Read the desired Configuration Space register via the PCI-E 76262306a36Sopenharmony_ci * Backdoor mechanism. 76362306a36Sopenharmony_ci */ 76462306a36Sopenharmony_ci t4_hw_pci_read_cfg4(adap, reg, &val); 76562306a36Sopenharmony_ci return val; 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci/* Get the window based on base passed to it. 76962306a36Sopenharmony_ci * Window aperture is currently unhandled, but there is no use case for it 77062306a36Sopenharmony_ci * right now 77162306a36Sopenharmony_ci */ 77262306a36Sopenharmony_cistatic u32 t4_get_window(struct adapter *adap, u32 pci_base, u64 pci_mask, 77362306a36Sopenharmony_ci u32 memwin_base) 77462306a36Sopenharmony_ci{ 77562306a36Sopenharmony_ci u32 ret; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (is_t4(adap->params.chip)) { 77862306a36Sopenharmony_ci u32 bar0; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci /* Truncation intentional: we only read the bottom 32-bits of 78162306a36Sopenharmony_ci * the 64-bit BAR0/BAR1 ... We use the hardware backdoor 78262306a36Sopenharmony_ci * mechanism to read BAR0 instead of using 78362306a36Sopenharmony_ci * pci_resource_start() because we could be operating from 78462306a36Sopenharmony_ci * within a Virtual Machine which is trapping our accesses to 78562306a36Sopenharmony_ci * our Configuration Space and we need to set up the PCI-E 78662306a36Sopenharmony_ci * Memory Window decoders with the actual addresses which will 78762306a36Sopenharmony_ci * be coming across the PCI-E link. 78862306a36Sopenharmony_ci */ 78962306a36Sopenharmony_ci bar0 = t4_read_pcie_cfg4(adap, pci_base); 79062306a36Sopenharmony_ci bar0 &= pci_mask; 79162306a36Sopenharmony_ci adap->t4_bar0 = bar0; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci ret = bar0 + memwin_base; 79462306a36Sopenharmony_ci } else { 79562306a36Sopenharmony_ci /* For T5, only relative offset inside the PCIe BAR is passed */ 79662306a36Sopenharmony_ci ret = memwin_base; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci return ret; 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci/* Get the default utility window (win0) used by everyone */ 80262306a36Sopenharmony_ciu32 t4_get_util_window(struct adapter *adap) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci return t4_get_window(adap, PCI_BASE_ADDRESS_0, 80562306a36Sopenharmony_ci PCI_BASE_ADDRESS_MEM_MASK, MEMWIN0_BASE); 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci/* Set up memory window for accessing adapter memory ranges. (Read 80962306a36Sopenharmony_ci * back MA register to ensure that changes propagate before we attempt 81062306a36Sopenharmony_ci * to use the new values.) 81162306a36Sopenharmony_ci */ 81262306a36Sopenharmony_civoid t4_setup_memwin(struct adapter *adap, u32 memwin_base, u32 window) 81362306a36Sopenharmony_ci{ 81462306a36Sopenharmony_ci t4_write_reg(adap, 81562306a36Sopenharmony_ci PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, window), 81662306a36Sopenharmony_ci memwin_base | BIR_V(0) | 81762306a36Sopenharmony_ci WINDOW_V(ilog2(MEMWIN0_APERTURE) - WINDOW_SHIFT_X)); 81862306a36Sopenharmony_ci t4_read_reg(adap, 81962306a36Sopenharmony_ci PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, window)); 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci/** 82362306a36Sopenharmony_ci * t4_get_regs_len - return the size of the chips register set 82462306a36Sopenharmony_ci * @adapter: the adapter 82562306a36Sopenharmony_ci * 82662306a36Sopenharmony_ci * Returns the size of the chip's BAR0 register space. 82762306a36Sopenharmony_ci */ 82862306a36Sopenharmony_ciunsigned int t4_get_regs_len(struct adapter *adapter) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci unsigned int chip_version = CHELSIO_CHIP_VERSION(adapter->params.chip); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci switch (chip_version) { 83362306a36Sopenharmony_ci case CHELSIO_T4: 83462306a36Sopenharmony_ci return T4_REGMAP_SIZE; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci case CHELSIO_T5: 83762306a36Sopenharmony_ci case CHELSIO_T6: 83862306a36Sopenharmony_ci return T5_REGMAP_SIZE; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 84262306a36Sopenharmony_ci "Unsupported chip version %d\n", chip_version); 84362306a36Sopenharmony_ci return 0; 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci/** 84762306a36Sopenharmony_ci * t4_get_regs - read chip registers into provided buffer 84862306a36Sopenharmony_ci * @adap: the adapter 84962306a36Sopenharmony_ci * @buf: register buffer 85062306a36Sopenharmony_ci * @buf_size: size (in bytes) of register buffer 85162306a36Sopenharmony_ci * 85262306a36Sopenharmony_ci * If the provided register buffer isn't large enough for the chip's 85362306a36Sopenharmony_ci * full register range, the register dump will be truncated to the 85462306a36Sopenharmony_ci * register buffer's size. 85562306a36Sopenharmony_ci */ 85662306a36Sopenharmony_civoid t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) 85762306a36Sopenharmony_ci{ 85862306a36Sopenharmony_ci static const unsigned int t4_reg_ranges[] = { 85962306a36Sopenharmony_ci 0x1008, 0x1108, 86062306a36Sopenharmony_ci 0x1180, 0x1184, 86162306a36Sopenharmony_ci 0x1190, 0x1194, 86262306a36Sopenharmony_ci 0x11a0, 0x11a4, 86362306a36Sopenharmony_ci 0x11b0, 0x11b4, 86462306a36Sopenharmony_ci 0x11fc, 0x123c, 86562306a36Sopenharmony_ci 0x1300, 0x173c, 86662306a36Sopenharmony_ci 0x1800, 0x18fc, 86762306a36Sopenharmony_ci 0x3000, 0x30d8, 86862306a36Sopenharmony_ci 0x30e0, 0x30e4, 86962306a36Sopenharmony_ci 0x30ec, 0x5910, 87062306a36Sopenharmony_ci 0x5920, 0x5924, 87162306a36Sopenharmony_ci 0x5960, 0x5960, 87262306a36Sopenharmony_ci 0x5968, 0x5968, 87362306a36Sopenharmony_ci 0x5970, 0x5970, 87462306a36Sopenharmony_ci 0x5978, 0x5978, 87562306a36Sopenharmony_ci 0x5980, 0x5980, 87662306a36Sopenharmony_ci 0x5988, 0x5988, 87762306a36Sopenharmony_ci 0x5990, 0x5990, 87862306a36Sopenharmony_ci 0x5998, 0x5998, 87962306a36Sopenharmony_ci 0x59a0, 0x59d4, 88062306a36Sopenharmony_ci 0x5a00, 0x5ae0, 88162306a36Sopenharmony_ci 0x5ae8, 0x5ae8, 88262306a36Sopenharmony_ci 0x5af0, 0x5af0, 88362306a36Sopenharmony_ci 0x5af8, 0x5af8, 88462306a36Sopenharmony_ci 0x6000, 0x6098, 88562306a36Sopenharmony_ci 0x6100, 0x6150, 88662306a36Sopenharmony_ci 0x6200, 0x6208, 88762306a36Sopenharmony_ci 0x6240, 0x6248, 88862306a36Sopenharmony_ci 0x6280, 0x62b0, 88962306a36Sopenharmony_ci 0x62c0, 0x6338, 89062306a36Sopenharmony_ci 0x6370, 0x638c, 89162306a36Sopenharmony_ci 0x6400, 0x643c, 89262306a36Sopenharmony_ci 0x6500, 0x6524, 89362306a36Sopenharmony_ci 0x6a00, 0x6a04, 89462306a36Sopenharmony_ci 0x6a14, 0x6a38, 89562306a36Sopenharmony_ci 0x6a60, 0x6a70, 89662306a36Sopenharmony_ci 0x6a78, 0x6a78, 89762306a36Sopenharmony_ci 0x6b00, 0x6b0c, 89862306a36Sopenharmony_ci 0x6b1c, 0x6b84, 89962306a36Sopenharmony_ci 0x6bf0, 0x6bf8, 90062306a36Sopenharmony_ci 0x6c00, 0x6c0c, 90162306a36Sopenharmony_ci 0x6c1c, 0x6c84, 90262306a36Sopenharmony_ci 0x6cf0, 0x6cf8, 90362306a36Sopenharmony_ci 0x6d00, 0x6d0c, 90462306a36Sopenharmony_ci 0x6d1c, 0x6d84, 90562306a36Sopenharmony_ci 0x6df0, 0x6df8, 90662306a36Sopenharmony_ci 0x6e00, 0x6e0c, 90762306a36Sopenharmony_ci 0x6e1c, 0x6e84, 90862306a36Sopenharmony_ci 0x6ef0, 0x6ef8, 90962306a36Sopenharmony_ci 0x6f00, 0x6f0c, 91062306a36Sopenharmony_ci 0x6f1c, 0x6f84, 91162306a36Sopenharmony_ci 0x6ff0, 0x6ff8, 91262306a36Sopenharmony_ci 0x7000, 0x700c, 91362306a36Sopenharmony_ci 0x701c, 0x7084, 91462306a36Sopenharmony_ci 0x70f0, 0x70f8, 91562306a36Sopenharmony_ci 0x7100, 0x710c, 91662306a36Sopenharmony_ci 0x711c, 0x7184, 91762306a36Sopenharmony_ci 0x71f0, 0x71f8, 91862306a36Sopenharmony_ci 0x7200, 0x720c, 91962306a36Sopenharmony_ci 0x721c, 0x7284, 92062306a36Sopenharmony_ci 0x72f0, 0x72f8, 92162306a36Sopenharmony_ci 0x7300, 0x730c, 92262306a36Sopenharmony_ci 0x731c, 0x7384, 92362306a36Sopenharmony_ci 0x73f0, 0x73f8, 92462306a36Sopenharmony_ci 0x7400, 0x7450, 92562306a36Sopenharmony_ci 0x7500, 0x7530, 92662306a36Sopenharmony_ci 0x7600, 0x760c, 92762306a36Sopenharmony_ci 0x7614, 0x761c, 92862306a36Sopenharmony_ci 0x7680, 0x76cc, 92962306a36Sopenharmony_ci 0x7700, 0x7798, 93062306a36Sopenharmony_ci 0x77c0, 0x77fc, 93162306a36Sopenharmony_ci 0x7900, 0x79fc, 93262306a36Sopenharmony_ci 0x7b00, 0x7b58, 93362306a36Sopenharmony_ci 0x7b60, 0x7b84, 93462306a36Sopenharmony_ci 0x7b8c, 0x7c38, 93562306a36Sopenharmony_ci 0x7d00, 0x7d38, 93662306a36Sopenharmony_ci 0x7d40, 0x7d80, 93762306a36Sopenharmony_ci 0x7d8c, 0x7ddc, 93862306a36Sopenharmony_ci 0x7de4, 0x7e04, 93962306a36Sopenharmony_ci 0x7e10, 0x7e1c, 94062306a36Sopenharmony_ci 0x7e24, 0x7e38, 94162306a36Sopenharmony_ci 0x7e40, 0x7e44, 94262306a36Sopenharmony_ci 0x7e4c, 0x7e78, 94362306a36Sopenharmony_ci 0x7e80, 0x7ea4, 94462306a36Sopenharmony_ci 0x7eac, 0x7edc, 94562306a36Sopenharmony_ci 0x7ee8, 0x7efc, 94662306a36Sopenharmony_ci 0x8dc0, 0x8e04, 94762306a36Sopenharmony_ci 0x8e10, 0x8e1c, 94862306a36Sopenharmony_ci 0x8e30, 0x8e78, 94962306a36Sopenharmony_ci 0x8ea0, 0x8eb8, 95062306a36Sopenharmony_ci 0x8ec0, 0x8f6c, 95162306a36Sopenharmony_ci 0x8fc0, 0x9008, 95262306a36Sopenharmony_ci 0x9010, 0x9058, 95362306a36Sopenharmony_ci 0x9060, 0x9060, 95462306a36Sopenharmony_ci 0x9068, 0x9074, 95562306a36Sopenharmony_ci 0x90fc, 0x90fc, 95662306a36Sopenharmony_ci 0x9400, 0x9408, 95762306a36Sopenharmony_ci 0x9410, 0x9458, 95862306a36Sopenharmony_ci 0x9600, 0x9600, 95962306a36Sopenharmony_ci 0x9608, 0x9638, 96062306a36Sopenharmony_ci 0x9640, 0x96bc, 96162306a36Sopenharmony_ci 0x9800, 0x9808, 96262306a36Sopenharmony_ci 0x9820, 0x983c, 96362306a36Sopenharmony_ci 0x9850, 0x9864, 96462306a36Sopenharmony_ci 0x9c00, 0x9c6c, 96562306a36Sopenharmony_ci 0x9c80, 0x9cec, 96662306a36Sopenharmony_ci 0x9d00, 0x9d6c, 96762306a36Sopenharmony_ci 0x9d80, 0x9dec, 96862306a36Sopenharmony_ci 0x9e00, 0x9e6c, 96962306a36Sopenharmony_ci 0x9e80, 0x9eec, 97062306a36Sopenharmony_ci 0x9f00, 0x9f6c, 97162306a36Sopenharmony_ci 0x9f80, 0x9fec, 97262306a36Sopenharmony_ci 0xd004, 0xd004, 97362306a36Sopenharmony_ci 0xd010, 0xd03c, 97462306a36Sopenharmony_ci 0xdfc0, 0xdfe0, 97562306a36Sopenharmony_ci 0xe000, 0xea7c, 97662306a36Sopenharmony_ci 0xf000, 0x11110, 97762306a36Sopenharmony_ci 0x11118, 0x11190, 97862306a36Sopenharmony_ci 0x19040, 0x1906c, 97962306a36Sopenharmony_ci 0x19078, 0x19080, 98062306a36Sopenharmony_ci 0x1908c, 0x190e4, 98162306a36Sopenharmony_ci 0x190f0, 0x190f8, 98262306a36Sopenharmony_ci 0x19100, 0x19110, 98362306a36Sopenharmony_ci 0x19120, 0x19124, 98462306a36Sopenharmony_ci 0x19150, 0x19194, 98562306a36Sopenharmony_ci 0x1919c, 0x191b0, 98662306a36Sopenharmony_ci 0x191d0, 0x191e8, 98762306a36Sopenharmony_ci 0x19238, 0x1924c, 98862306a36Sopenharmony_ci 0x193f8, 0x1943c, 98962306a36Sopenharmony_ci 0x1944c, 0x19474, 99062306a36Sopenharmony_ci 0x19490, 0x194e0, 99162306a36Sopenharmony_ci 0x194f0, 0x194f8, 99262306a36Sopenharmony_ci 0x19800, 0x19c08, 99362306a36Sopenharmony_ci 0x19c10, 0x19c90, 99462306a36Sopenharmony_ci 0x19ca0, 0x19ce4, 99562306a36Sopenharmony_ci 0x19cf0, 0x19d40, 99662306a36Sopenharmony_ci 0x19d50, 0x19d94, 99762306a36Sopenharmony_ci 0x19da0, 0x19de8, 99862306a36Sopenharmony_ci 0x19df0, 0x19e40, 99962306a36Sopenharmony_ci 0x19e50, 0x19e90, 100062306a36Sopenharmony_ci 0x19ea0, 0x19f4c, 100162306a36Sopenharmony_ci 0x1a000, 0x1a004, 100262306a36Sopenharmony_ci 0x1a010, 0x1a06c, 100362306a36Sopenharmony_ci 0x1a0b0, 0x1a0e4, 100462306a36Sopenharmony_ci 0x1a0ec, 0x1a0f4, 100562306a36Sopenharmony_ci 0x1a100, 0x1a108, 100662306a36Sopenharmony_ci 0x1a114, 0x1a120, 100762306a36Sopenharmony_ci 0x1a128, 0x1a130, 100862306a36Sopenharmony_ci 0x1a138, 0x1a138, 100962306a36Sopenharmony_ci 0x1a190, 0x1a1c4, 101062306a36Sopenharmony_ci 0x1a1fc, 0x1a1fc, 101162306a36Sopenharmony_ci 0x1e040, 0x1e04c, 101262306a36Sopenharmony_ci 0x1e284, 0x1e28c, 101362306a36Sopenharmony_ci 0x1e2c0, 0x1e2c0, 101462306a36Sopenharmony_ci 0x1e2e0, 0x1e2e0, 101562306a36Sopenharmony_ci 0x1e300, 0x1e384, 101662306a36Sopenharmony_ci 0x1e3c0, 0x1e3c8, 101762306a36Sopenharmony_ci 0x1e440, 0x1e44c, 101862306a36Sopenharmony_ci 0x1e684, 0x1e68c, 101962306a36Sopenharmony_ci 0x1e6c0, 0x1e6c0, 102062306a36Sopenharmony_ci 0x1e6e0, 0x1e6e0, 102162306a36Sopenharmony_ci 0x1e700, 0x1e784, 102262306a36Sopenharmony_ci 0x1e7c0, 0x1e7c8, 102362306a36Sopenharmony_ci 0x1e840, 0x1e84c, 102462306a36Sopenharmony_ci 0x1ea84, 0x1ea8c, 102562306a36Sopenharmony_ci 0x1eac0, 0x1eac0, 102662306a36Sopenharmony_ci 0x1eae0, 0x1eae0, 102762306a36Sopenharmony_ci 0x1eb00, 0x1eb84, 102862306a36Sopenharmony_ci 0x1ebc0, 0x1ebc8, 102962306a36Sopenharmony_ci 0x1ec40, 0x1ec4c, 103062306a36Sopenharmony_ci 0x1ee84, 0x1ee8c, 103162306a36Sopenharmony_ci 0x1eec0, 0x1eec0, 103262306a36Sopenharmony_ci 0x1eee0, 0x1eee0, 103362306a36Sopenharmony_ci 0x1ef00, 0x1ef84, 103462306a36Sopenharmony_ci 0x1efc0, 0x1efc8, 103562306a36Sopenharmony_ci 0x1f040, 0x1f04c, 103662306a36Sopenharmony_ci 0x1f284, 0x1f28c, 103762306a36Sopenharmony_ci 0x1f2c0, 0x1f2c0, 103862306a36Sopenharmony_ci 0x1f2e0, 0x1f2e0, 103962306a36Sopenharmony_ci 0x1f300, 0x1f384, 104062306a36Sopenharmony_ci 0x1f3c0, 0x1f3c8, 104162306a36Sopenharmony_ci 0x1f440, 0x1f44c, 104262306a36Sopenharmony_ci 0x1f684, 0x1f68c, 104362306a36Sopenharmony_ci 0x1f6c0, 0x1f6c0, 104462306a36Sopenharmony_ci 0x1f6e0, 0x1f6e0, 104562306a36Sopenharmony_ci 0x1f700, 0x1f784, 104662306a36Sopenharmony_ci 0x1f7c0, 0x1f7c8, 104762306a36Sopenharmony_ci 0x1f840, 0x1f84c, 104862306a36Sopenharmony_ci 0x1fa84, 0x1fa8c, 104962306a36Sopenharmony_ci 0x1fac0, 0x1fac0, 105062306a36Sopenharmony_ci 0x1fae0, 0x1fae0, 105162306a36Sopenharmony_ci 0x1fb00, 0x1fb84, 105262306a36Sopenharmony_ci 0x1fbc0, 0x1fbc8, 105362306a36Sopenharmony_ci 0x1fc40, 0x1fc4c, 105462306a36Sopenharmony_ci 0x1fe84, 0x1fe8c, 105562306a36Sopenharmony_ci 0x1fec0, 0x1fec0, 105662306a36Sopenharmony_ci 0x1fee0, 0x1fee0, 105762306a36Sopenharmony_ci 0x1ff00, 0x1ff84, 105862306a36Sopenharmony_ci 0x1ffc0, 0x1ffc8, 105962306a36Sopenharmony_ci 0x20000, 0x2002c, 106062306a36Sopenharmony_ci 0x20100, 0x2013c, 106162306a36Sopenharmony_ci 0x20190, 0x201a0, 106262306a36Sopenharmony_ci 0x201a8, 0x201b8, 106362306a36Sopenharmony_ci 0x201c4, 0x201c8, 106462306a36Sopenharmony_ci 0x20200, 0x20318, 106562306a36Sopenharmony_ci 0x20400, 0x204b4, 106662306a36Sopenharmony_ci 0x204c0, 0x20528, 106762306a36Sopenharmony_ci 0x20540, 0x20614, 106862306a36Sopenharmony_ci 0x21000, 0x21040, 106962306a36Sopenharmony_ci 0x2104c, 0x21060, 107062306a36Sopenharmony_ci 0x210c0, 0x210ec, 107162306a36Sopenharmony_ci 0x21200, 0x21268, 107262306a36Sopenharmony_ci 0x21270, 0x21284, 107362306a36Sopenharmony_ci 0x212fc, 0x21388, 107462306a36Sopenharmony_ci 0x21400, 0x21404, 107562306a36Sopenharmony_ci 0x21500, 0x21500, 107662306a36Sopenharmony_ci 0x21510, 0x21518, 107762306a36Sopenharmony_ci 0x2152c, 0x21530, 107862306a36Sopenharmony_ci 0x2153c, 0x2153c, 107962306a36Sopenharmony_ci 0x21550, 0x21554, 108062306a36Sopenharmony_ci 0x21600, 0x21600, 108162306a36Sopenharmony_ci 0x21608, 0x2161c, 108262306a36Sopenharmony_ci 0x21624, 0x21628, 108362306a36Sopenharmony_ci 0x21630, 0x21634, 108462306a36Sopenharmony_ci 0x2163c, 0x2163c, 108562306a36Sopenharmony_ci 0x21700, 0x2171c, 108662306a36Sopenharmony_ci 0x21780, 0x2178c, 108762306a36Sopenharmony_ci 0x21800, 0x21818, 108862306a36Sopenharmony_ci 0x21820, 0x21828, 108962306a36Sopenharmony_ci 0x21830, 0x21848, 109062306a36Sopenharmony_ci 0x21850, 0x21854, 109162306a36Sopenharmony_ci 0x21860, 0x21868, 109262306a36Sopenharmony_ci 0x21870, 0x21870, 109362306a36Sopenharmony_ci 0x21878, 0x21898, 109462306a36Sopenharmony_ci 0x218a0, 0x218a8, 109562306a36Sopenharmony_ci 0x218b0, 0x218c8, 109662306a36Sopenharmony_ci 0x218d0, 0x218d4, 109762306a36Sopenharmony_ci 0x218e0, 0x218e8, 109862306a36Sopenharmony_ci 0x218f0, 0x218f0, 109962306a36Sopenharmony_ci 0x218f8, 0x21a18, 110062306a36Sopenharmony_ci 0x21a20, 0x21a28, 110162306a36Sopenharmony_ci 0x21a30, 0x21a48, 110262306a36Sopenharmony_ci 0x21a50, 0x21a54, 110362306a36Sopenharmony_ci 0x21a60, 0x21a68, 110462306a36Sopenharmony_ci 0x21a70, 0x21a70, 110562306a36Sopenharmony_ci 0x21a78, 0x21a98, 110662306a36Sopenharmony_ci 0x21aa0, 0x21aa8, 110762306a36Sopenharmony_ci 0x21ab0, 0x21ac8, 110862306a36Sopenharmony_ci 0x21ad0, 0x21ad4, 110962306a36Sopenharmony_ci 0x21ae0, 0x21ae8, 111062306a36Sopenharmony_ci 0x21af0, 0x21af0, 111162306a36Sopenharmony_ci 0x21af8, 0x21c18, 111262306a36Sopenharmony_ci 0x21c20, 0x21c20, 111362306a36Sopenharmony_ci 0x21c28, 0x21c30, 111462306a36Sopenharmony_ci 0x21c38, 0x21c38, 111562306a36Sopenharmony_ci 0x21c80, 0x21c98, 111662306a36Sopenharmony_ci 0x21ca0, 0x21ca8, 111762306a36Sopenharmony_ci 0x21cb0, 0x21cc8, 111862306a36Sopenharmony_ci 0x21cd0, 0x21cd4, 111962306a36Sopenharmony_ci 0x21ce0, 0x21ce8, 112062306a36Sopenharmony_ci 0x21cf0, 0x21cf0, 112162306a36Sopenharmony_ci 0x21cf8, 0x21d7c, 112262306a36Sopenharmony_ci 0x21e00, 0x21e04, 112362306a36Sopenharmony_ci 0x22000, 0x2202c, 112462306a36Sopenharmony_ci 0x22100, 0x2213c, 112562306a36Sopenharmony_ci 0x22190, 0x221a0, 112662306a36Sopenharmony_ci 0x221a8, 0x221b8, 112762306a36Sopenharmony_ci 0x221c4, 0x221c8, 112862306a36Sopenharmony_ci 0x22200, 0x22318, 112962306a36Sopenharmony_ci 0x22400, 0x224b4, 113062306a36Sopenharmony_ci 0x224c0, 0x22528, 113162306a36Sopenharmony_ci 0x22540, 0x22614, 113262306a36Sopenharmony_ci 0x23000, 0x23040, 113362306a36Sopenharmony_ci 0x2304c, 0x23060, 113462306a36Sopenharmony_ci 0x230c0, 0x230ec, 113562306a36Sopenharmony_ci 0x23200, 0x23268, 113662306a36Sopenharmony_ci 0x23270, 0x23284, 113762306a36Sopenharmony_ci 0x232fc, 0x23388, 113862306a36Sopenharmony_ci 0x23400, 0x23404, 113962306a36Sopenharmony_ci 0x23500, 0x23500, 114062306a36Sopenharmony_ci 0x23510, 0x23518, 114162306a36Sopenharmony_ci 0x2352c, 0x23530, 114262306a36Sopenharmony_ci 0x2353c, 0x2353c, 114362306a36Sopenharmony_ci 0x23550, 0x23554, 114462306a36Sopenharmony_ci 0x23600, 0x23600, 114562306a36Sopenharmony_ci 0x23608, 0x2361c, 114662306a36Sopenharmony_ci 0x23624, 0x23628, 114762306a36Sopenharmony_ci 0x23630, 0x23634, 114862306a36Sopenharmony_ci 0x2363c, 0x2363c, 114962306a36Sopenharmony_ci 0x23700, 0x2371c, 115062306a36Sopenharmony_ci 0x23780, 0x2378c, 115162306a36Sopenharmony_ci 0x23800, 0x23818, 115262306a36Sopenharmony_ci 0x23820, 0x23828, 115362306a36Sopenharmony_ci 0x23830, 0x23848, 115462306a36Sopenharmony_ci 0x23850, 0x23854, 115562306a36Sopenharmony_ci 0x23860, 0x23868, 115662306a36Sopenharmony_ci 0x23870, 0x23870, 115762306a36Sopenharmony_ci 0x23878, 0x23898, 115862306a36Sopenharmony_ci 0x238a0, 0x238a8, 115962306a36Sopenharmony_ci 0x238b0, 0x238c8, 116062306a36Sopenharmony_ci 0x238d0, 0x238d4, 116162306a36Sopenharmony_ci 0x238e0, 0x238e8, 116262306a36Sopenharmony_ci 0x238f0, 0x238f0, 116362306a36Sopenharmony_ci 0x238f8, 0x23a18, 116462306a36Sopenharmony_ci 0x23a20, 0x23a28, 116562306a36Sopenharmony_ci 0x23a30, 0x23a48, 116662306a36Sopenharmony_ci 0x23a50, 0x23a54, 116762306a36Sopenharmony_ci 0x23a60, 0x23a68, 116862306a36Sopenharmony_ci 0x23a70, 0x23a70, 116962306a36Sopenharmony_ci 0x23a78, 0x23a98, 117062306a36Sopenharmony_ci 0x23aa0, 0x23aa8, 117162306a36Sopenharmony_ci 0x23ab0, 0x23ac8, 117262306a36Sopenharmony_ci 0x23ad0, 0x23ad4, 117362306a36Sopenharmony_ci 0x23ae0, 0x23ae8, 117462306a36Sopenharmony_ci 0x23af0, 0x23af0, 117562306a36Sopenharmony_ci 0x23af8, 0x23c18, 117662306a36Sopenharmony_ci 0x23c20, 0x23c20, 117762306a36Sopenharmony_ci 0x23c28, 0x23c30, 117862306a36Sopenharmony_ci 0x23c38, 0x23c38, 117962306a36Sopenharmony_ci 0x23c80, 0x23c98, 118062306a36Sopenharmony_ci 0x23ca0, 0x23ca8, 118162306a36Sopenharmony_ci 0x23cb0, 0x23cc8, 118262306a36Sopenharmony_ci 0x23cd0, 0x23cd4, 118362306a36Sopenharmony_ci 0x23ce0, 0x23ce8, 118462306a36Sopenharmony_ci 0x23cf0, 0x23cf0, 118562306a36Sopenharmony_ci 0x23cf8, 0x23d7c, 118662306a36Sopenharmony_ci 0x23e00, 0x23e04, 118762306a36Sopenharmony_ci 0x24000, 0x2402c, 118862306a36Sopenharmony_ci 0x24100, 0x2413c, 118962306a36Sopenharmony_ci 0x24190, 0x241a0, 119062306a36Sopenharmony_ci 0x241a8, 0x241b8, 119162306a36Sopenharmony_ci 0x241c4, 0x241c8, 119262306a36Sopenharmony_ci 0x24200, 0x24318, 119362306a36Sopenharmony_ci 0x24400, 0x244b4, 119462306a36Sopenharmony_ci 0x244c0, 0x24528, 119562306a36Sopenharmony_ci 0x24540, 0x24614, 119662306a36Sopenharmony_ci 0x25000, 0x25040, 119762306a36Sopenharmony_ci 0x2504c, 0x25060, 119862306a36Sopenharmony_ci 0x250c0, 0x250ec, 119962306a36Sopenharmony_ci 0x25200, 0x25268, 120062306a36Sopenharmony_ci 0x25270, 0x25284, 120162306a36Sopenharmony_ci 0x252fc, 0x25388, 120262306a36Sopenharmony_ci 0x25400, 0x25404, 120362306a36Sopenharmony_ci 0x25500, 0x25500, 120462306a36Sopenharmony_ci 0x25510, 0x25518, 120562306a36Sopenharmony_ci 0x2552c, 0x25530, 120662306a36Sopenharmony_ci 0x2553c, 0x2553c, 120762306a36Sopenharmony_ci 0x25550, 0x25554, 120862306a36Sopenharmony_ci 0x25600, 0x25600, 120962306a36Sopenharmony_ci 0x25608, 0x2561c, 121062306a36Sopenharmony_ci 0x25624, 0x25628, 121162306a36Sopenharmony_ci 0x25630, 0x25634, 121262306a36Sopenharmony_ci 0x2563c, 0x2563c, 121362306a36Sopenharmony_ci 0x25700, 0x2571c, 121462306a36Sopenharmony_ci 0x25780, 0x2578c, 121562306a36Sopenharmony_ci 0x25800, 0x25818, 121662306a36Sopenharmony_ci 0x25820, 0x25828, 121762306a36Sopenharmony_ci 0x25830, 0x25848, 121862306a36Sopenharmony_ci 0x25850, 0x25854, 121962306a36Sopenharmony_ci 0x25860, 0x25868, 122062306a36Sopenharmony_ci 0x25870, 0x25870, 122162306a36Sopenharmony_ci 0x25878, 0x25898, 122262306a36Sopenharmony_ci 0x258a0, 0x258a8, 122362306a36Sopenharmony_ci 0x258b0, 0x258c8, 122462306a36Sopenharmony_ci 0x258d0, 0x258d4, 122562306a36Sopenharmony_ci 0x258e0, 0x258e8, 122662306a36Sopenharmony_ci 0x258f0, 0x258f0, 122762306a36Sopenharmony_ci 0x258f8, 0x25a18, 122862306a36Sopenharmony_ci 0x25a20, 0x25a28, 122962306a36Sopenharmony_ci 0x25a30, 0x25a48, 123062306a36Sopenharmony_ci 0x25a50, 0x25a54, 123162306a36Sopenharmony_ci 0x25a60, 0x25a68, 123262306a36Sopenharmony_ci 0x25a70, 0x25a70, 123362306a36Sopenharmony_ci 0x25a78, 0x25a98, 123462306a36Sopenharmony_ci 0x25aa0, 0x25aa8, 123562306a36Sopenharmony_ci 0x25ab0, 0x25ac8, 123662306a36Sopenharmony_ci 0x25ad0, 0x25ad4, 123762306a36Sopenharmony_ci 0x25ae0, 0x25ae8, 123862306a36Sopenharmony_ci 0x25af0, 0x25af0, 123962306a36Sopenharmony_ci 0x25af8, 0x25c18, 124062306a36Sopenharmony_ci 0x25c20, 0x25c20, 124162306a36Sopenharmony_ci 0x25c28, 0x25c30, 124262306a36Sopenharmony_ci 0x25c38, 0x25c38, 124362306a36Sopenharmony_ci 0x25c80, 0x25c98, 124462306a36Sopenharmony_ci 0x25ca0, 0x25ca8, 124562306a36Sopenharmony_ci 0x25cb0, 0x25cc8, 124662306a36Sopenharmony_ci 0x25cd0, 0x25cd4, 124762306a36Sopenharmony_ci 0x25ce0, 0x25ce8, 124862306a36Sopenharmony_ci 0x25cf0, 0x25cf0, 124962306a36Sopenharmony_ci 0x25cf8, 0x25d7c, 125062306a36Sopenharmony_ci 0x25e00, 0x25e04, 125162306a36Sopenharmony_ci 0x26000, 0x2602c, 125262306a36Sopenharmony_ci 0x26100, 0x2613c, 125362306a36Sopenharmony_ci 0x26190, 0x261a0, 125462306a36Sopenharmony_ci 0x261a8, 0x261b8, 125562306a36Sopenharmony_ci 0x261c4, 0x261c8, 125662306a36Sopenharmony_ci 0x26200, 0x26318, 125762306a36Sopenharmony_ci 0x26400, 0x264b4, 125862306a36Sopenharmony_ci 0x264c0, 0x26528, 125962306a36Sopenharmony_ci 0x26540, 0x26614, 126062306a36Sopenharmony_ci 0x27000, 0x27040, 126162306a36Sopenharmony_ci 0x2704c, 0x27060, 126262306a36Sopenharmony_ci 0x270c0, 0x270ec, 126362306a36Sopenharmony_ci 0x27200, 0x27268, 126462306a36Sopenharmony_ci 0x27270, 0x27284, 126562306a36Sopenharmony_ci 0x272fc, 0x27388, 126662306a36Sopenharmony_ci 0x27400, 0x27404, 126762306a36Sopenharmony_ci 0x27500, 0x27500, 126862306a36Sopenharmony_ci 0x27510, 0x27518, 126962306a36Sopenharmony_ci 0x2752c, 0x27530, 127062306a36Sopenharmony_ci 0x2753c, 0x2753c, 127162306a36Sopenharmony_ci 0x27550, 0x27554, 127262306a36Sopenharmony_ci 0x27600, 0x27600, 127362306a36Sopenharmony_ci 0x27608, 0x2761c, 127462306a36Sopenharmony_ci 0x27624, 0x27628, 127562306a36Sopenharmony_ci 0x27630, 0x27634, 127662306a36Sopenharmony_ci 0x2763c, 0x2763c, 127762306a36Sopenharmony_ci 0x27700, 0x2771c, 127862306a36Sopenharmony_ci 0x27780, 0x2778c, 127962306a36Sopenharmony_ci 0x27800, 0x27818, 128062306a36Sopenharmony_ci 0x27820, 0x27828, 128162306a36Sopenharmony_ci 0x27830, 0x27848, 128262306a36Sopenharmony_ci 0x27850, 0x27854, 128362306a36Sopenharmony_ci 0x27860, 0x27868, 128462306a36Sopenharmony_ci 0x27870, 0x27870, 128562306a36Sopenharmony_ci 0x27878, 0x27898, 128662306a36Sopenharmony_ci 0x278a0, 0x278a8, 128762306a36Sopenharmony_ci 0x278b0, 0x278c8, 128862306a36Sopenharmony_ci 0x278d0, 0x278d4, 128962306a36Sopenharmony_ci 0x278e0, 0x278e8, 129062306a36Sopenharmony_ci 0x278f0, 0x278f0, 129162306a36Sopenharmony_ci 0x278f8, 0x27a18, 129262306a36Sopenharmony_ci 0x27a20, 0x27a28, 129362306a36Sopenharmony_ci 0x27a30, 0x27a48, 129462306a36Sopenharmony_ci 0x27a50, 0x27a54, 129562306a36Sopenharmony_ci 0x27a60, 0x27a68, 129662306a36Sopenharmony_ci 0x27a70, 0x27a70, 129762306a36Sopenharmony_ci 0x27a78, 0x27a98, 129862306a36Sopenharmony_ci 0x27aa0, 0x27aa8, 129962306a36Sopenharmony_ci 0x27ab0, 0x27ac8, 130062306a36Sopenharmony_ci 0x27ad0, 0x27ad4, 130162306a36Sopenharmony_ci 0x27ae0, 0x27ae8, 130262306a36Sopenharmony_ci 0x27af0, 0x27af0, 130362306a36Sopenharmony_ci 0x27af8, 0x27c18, 130462306a36Sopenharmony_ci 0x27c20, 0x27c20, 130562306a36Sopenharmony_ci 0x27c28, 0x27c30, 130662306a36Sopenharmony_ci 0x27c38, 0x27c38, 130762306a36Sopenharmony_ci 0x27c80, 0x27c98, 130862306a36Sopenharmony_ci 0x27ca0, 0x27ca8, 130962306a36Sopenharmony_ci 0x27cb0, 0x27cc8, 131062306a36Sopenharmony_ci 0x27cd0, 0x27cd4, 131162306a36Sopenharmony_ci 0x27ce0, 0x27ce8, 131262306a36Sopenharmony_ci 0x27cf0, 0x27cf0, 131362306a36Sopenharmony_ci 0x27cf8, 0x27d7c, 131462306a36Sopenharmony_ci 0x27e00, 0x27e04, 131562306a36Sopenharmony_ci }; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci static const unsigned int t5_reg_ranges[] = { 131862306a36Sopenharmony_ci 0x1008, 0x10c0, 131962306a36Sopenharmony_ci 0x10cc, 0x10f8, 132062306a36Sopenharmony_ci 0x1100, 0x1100, 132162306a36Sopenharmony_ci 0x110c, 0x1148, 132262306a36Sopenharmony_ci 0x1180, 0x1184, 132362306a36Sopenharmony_ci 0x1190, 0x1194, 132462306a36Sopenharmony_ci 0x11a0, 0x11a4, 132562306a36Sopenharmony_ci 0x11b0, 0x11b4, 132662306a36Sopenharmony_ci 0x11fc, 0x123c, 132762306a36Sopenharmony_ci 0x1280, 0x173c, 132862306a36Sopenharmony_ci 0x1800, 0x18fc, 132962306a36Sopenharmony_ci 0x3000, 0x3028, 133062306a36Sopenharmony_ci 0x3060, 0x30b0, 133162306a36Sopenharmony_ci 0x30b8, 0x30d8, 133262306a36Sopenharmony_ci 0x30e0, 0x30fc, 133362306a36Sopenharmony_ci 0x3140, 0x357c, 133462306a36Sopenharmony_ci 0x35a8, 0x35cc, 133562306a36Sopenharmony_ci 0x35ec, 0x35ec, 133662306a36Sopenharmony_ci 0x3600, 0x5624, 133762306a36Sopenharmony_ci 0x56cc, 0x56ec, 133862306a36Sopenharmony_ci 0x56f4, 0x5720, 133962306a36Sopenharmony_ci 0x5728, 0x575c, 134062306a36Sopenharmony_ci 0x580c, 0x5814, 134162306a36Sopenharmony_ci 0x5890, 0x589c, 134262306a36Sopenharmony_ci 0x58a4, 0x58ac, 134362306a36Sopenharmony_ci 0x58b8, 0x58bc, 134462306a36Sopenharmony_ci 0x5940, 0x59c8, 134562306a36Sopenharmony_ci 0x59d0, 0x59dc, 134662306a36Sopenharmony_ci 0x59fc, 0x5a18, 134762306a36Sopenharmony_ci 0x5a60, 0x5a70, 134862306a36Sopenharmony_ci 0x5a80, 0x5a9c, 134962306a36Sopenharmony_ci 0x5b94, 0x5bfc, 135062306a36Sopenharmony_ci 0x6000, 0x6020, 135162306a36Sopenharmony_ci 0x6028, 0x6040, 135262306a36Sopenharmony_ci 0x6058, 0x609c, 135362306a36Sopenharmony_ci 0x60a8, 0x614c, 135462306a36Sopenharmony_ci 0x7700, 0x7798, 135562306a36Sopenharmony_ci 0x77c0, 0x78fc, 135662306a36Sopenharmony_ci 0x7b00, 0x7b58, 135762306a36Sopenharmony_ci 0x7b60, 0x7b84, 135862306a36Sopenharmony_ci 0x7b8c, 0x7c54, 135962306a36Sopenharmony_ci 0x7d00, 0x7d38, 136062306a36Sopenharmony_ci 0x7d40, 0x7d80, 136162306a36Sopenharmony_ci 0x7d8c, 0x7ddc, 136262306a36Sopenharmony_ci 0x7de4, 0x7e04, 136362306a36Sopenharmony_ci 0x7e10, 0x7e1c, 136462306a36Sopenharmony_ci 0x7e24, 0x7e38, 136562306a36Sopenharmony_ci 0x7e40, 0x7e44, 136662306a36Sopenharmony_ci 0x7e4c, 0x7e78, 136762306a36Sopenharmony_ci 0x7e80, 0x7edc, 136862306a36Sopenharmony_ci 0x7ee8, 0x7efc, 136962306a36Sopenharmony_ci 0x8dc0, 0x8de0, 137062306a36Sopenharmony_ci 0x8df8, 0x8e04, 137162306a36Sopenharmony_ci 0x8e10, 0x8e84, 137262306a36Sopenharmony_ci 0x8ea0, 0x8f84, 137362306a36Sopenharmony_ci 0x8fc0, 0x9058, 137462306a36Sopenharmony_ci 0x9060, 0x9060, 137562306a36Sopenharmony_ci 0x9068, 0x90f8, 137662306a36Sopenharmony_ci 0x9400, 0x9408, 137762306a36Sopenharmony_ci 0x9410, 0x9470, 137862306a36Sopenharmony_ci 0x9600, 0x9600, 137962306a36Sopenharmony_ci 0x9608, 0x9638, 138062306a36Sopenharmony_ci 0x9640, 0x96f4, 138162306a36Sopenharmony_ci 0x9800, 0x9808, 138262306a36Sopenharmony_ci 0x9810, 0x9864, 138362306a36Sopenharmony_ci 0x9c00, 0x9c6c, 138462306a36Sopenharmony_ci 0x9c80, 0x9cec, 138562306a36Sopenharmony_ci 0x9d00, 0x9d6c, 138662306a36Sopenharmony_ci 0x9d80, 0x9dec, 138762306a36Sopenharmony_ci 0x9e00, 0x9e6c, 138862306a36Sopenharmony_ci 0x9e80, 0x9eec, 138962306a36Sopenharmony_ci 0x9f00, 0x9f6c, 139062306a36Sopenharmony_ci 0x9f80, 0xa020, 139162306a36Sopenharmony_ci 0xd000, 0xd004, 139262306a36Sopenharmony_ci 0xd010, 0xd03c, 139362306a36Sopenharmony_ci 0xdfc0, 0xdfe0, 139462306a36Sopenharmony_ci 0xe000, 0x1106c, 139562306a36Sopenharmony_ci 0x11074, 0x11088, 139662306a36Sopenharmony_ci 0x1109c, 0x1117c, 139762306a36Sopenharmony_ci 0x11190, 0x11204, 139862306a36Sopenharmony_ci 0x19040, 0x1906c, 139962306a36Sopenharmony_ci 0x19078, 0x19080, 140062306a36Sopenharmony_ci 0x1908c, 0x190e8, 140162306a36Sopenharmony_ci 0x190f0, 0x190f8, 140262306a36Sopenharmony_ci 0x19100, 0x19110, 140362306a36Sopenharmony_ci 0x19120, 0x19124, 140462306a36Sopenharmony_ci 0x19150, 0x19194, 140562306a36Sopenharmony_ci 0x1919c, 0x191b0, 140662306a36Sopenharmony_ci 0x191d0, 0x191e8, 140762306a36Sopenharmony_ci 0x19238, 0x19290, 140862306a36Sopenharmony_ci 0x193f8, 0x19428, 140962306a36Sopenharmony_ci 0x19430, 0x19444, 141062306a36Sopenharmony_ci 0x1944c, 0x1946c, 141162306a36Sopenharmony_ci 0x19474, 0x19474, 141262306a36Sopenharmony_ci 0x19490, 0x194cc, 141362306a36Sopenharmony_ci 0x194f0, 0x194f8, 141462306a36Sopenharmony_ci 0x19c00, 0x19c08, 141562306a36Sopenharmony_ci 0x19c10, 0x19c60, 141662306a36Sopenharmony_ci 0x19c94, 0x19ce4, 141762306a36Sopenharmony_ci 0x19cf0, 0x19d40, 141862306a36Sopenharmony_ci 0x19d50, 0x19d94, 141962306a36Sopenharmony_ci 0x19da0, 0x19de8, 142062306a36Sopenharmony_ci 0x19df0, 0x19e10, 142162306a36Sopenharmony_ci 0x19e50, 0x19e90, 142262306a36Sopenharmony_ci 0x19ea0, 0x19f24, 142362306a36Sopenharmony_ci 0x19f34, 0x19f34, 142462306a36Sopenharmony_ci 0x19f40, 0x19f50, 142562306a36Sopenharmony_ci 0x19f90, 0x19fb4, 142662306a36Sopenharmony_ci 0x19fc4, 0x19fe4, 142762306a36Sopenharmony_ci 0x1a000, 0x1a004, 142862306a36Sopenharmony_ci 0x1a010, 0x1a06c, 142962306a36Sopenharmony_ci 0x1a0b0, 0x1a0e4, 143062306a36Sopenharmony_ci 0x1a0ec, 0x1a0f8, 143162306a36Sopenharmony_ci 0x1a100, 0x1a108, 143262306a36Sopenharmony_ci 0x1a114, 0x1a130, 143362306a36Sopenharmony_ci 0x1a138, 0x1a1c4, 143462306a36Sopenharmony_ci 0x1a1fc, 0x1a1fc, 143562306a36Sopenharmony_ci 0x1e008, 0x1e00c, 143662306a36Sopenharmony_ci 0x1e040, 0x1e044, 143762306a36Sopenharmony_ci 0x1e04c, 0x1e04c, 143862306a36Sopenharmony_ci 0x1e284, 0x1e290, 143962306a36Sopenharmony_ci 0x1e2c0, 0x1e2c0, 144062306a36Sopenharmony_ci 0x1e2e0, 0x1e2e0, 144162306a36Sopenharmony_ci 0x1e300, 0x1e384, 144262306a36Sopenharmony_ci 0x1e3c0, 0x1e3c8, 144362306a36Sopenharmony_ci 0x1e408, 0x1e40c, 144462306a36Sopenharmony_ci 0x1e440, 0x1e444, 144562306a36Sopenharmony_ci 0x1e44c, 0x1e44c, 144662306a36Sopenharmony_ci 0x1e684, 0x1e690, 144762306a36Sopenharmony_ci 0x1e6c0, 0x1e6c0, 144862306a36Sopenharmony_ci 0x1e6e0, 0x1e6e0, 144962306a36Sopenharmony_ci 0x1e700, 0x1e784, 145062306a36Sopenharmony_ci 0x1e7c0, 0x1e7c8, 145162306a36Sopenharmony_ci 0x1e808, 0x1e80c, 145262306a36Sopenharmony_ci 0x1e840, 0x1e844, 145362306a36Sopenharmony_ci 0x1e84c, 0x1e84c, 145462306a36Sopenharmony_ci 0x1ea84, 0x1ea90, 145562306a36Sopenharmony_ci 0x1eac0, 0x1eac0, 145662306a36Sopenharmony_ci 0x1eae0, 0x1eae0, 145762306a36Sopenharmony_ci 0x1eb00, 0x1eb84, 145862306a36Sopenharmony_ci 0x1ebc0, 0x1ebc8, 145962306a36Sopenharmony_ci 0x1ec08, 0x1ec0c, 146062306a36Sopenharmony_ci 0x1ec40, 0x1ec44, 146162306a36Sopenharmony_ci 0x1ec4c, 0x1ec4c, 146262306a36Sopenharmony_ci 0x1ee84, 0x1ee90, 146362306a36Sopenharmony_ci 0x1eec0, 0x1eec0, 146462306a36Sopenharmony_ci 0x1eee0, 0x1eee0, 146562306a36Sopenharmony_ci 0x1ef00, 0x1ef84, 146662306a36Sopenharmony_ci 0x1efc0, 0x1efc8, 146762306a36Sopenharmony_ci 0x1f008, 0x1f00c, 146862306a36Sopenharmony_ci 0x1f040, 0x1f044, 146962306a36Sopenharmony_ci 0x1f04c, 0x1f04c, 147062306a36Sopenharmony_ci 0x1f284, 0x1f290, 147162306a36Sopenharmony_ci 0x1f2c0, 0x1f2c0, 147262306a36Sopenharmony_ci 0x1f2e0, 0x1f2e0, 147362306a36Sopenharmony_ci 0x1f300, 0x1f384, 147462306a36Sopenharmony_ci 0x1f3c0, 0x1f3c8, 147562306a36Sopenharmony_ci 0x1f408, 0x1f40c, 147662306a36Sopenharmony_ci 0x1f440, 0x1f444, 147762306a36Sopenharmony_ci 0x1f44c, 0x1f44c, 147862306a36Sopenharmony_ci 0x1f684, 0x1f690, 147962306a36Sopenharmony_ci 0x1f6c0, 0x1f6c0, 148062306a36Sopenharmony_ci 0x1f6e0, 0x1f6e0, 148162306a36Sopenharmony_ci 0x1f700, 0x1f784, 148262306a36Sopenharmony_ci 0x1f7c0, 0x1f7c8, 148362306a36Sopenharmony_ci 0x1f808, 0x1f80c, 148462306a36Sopenharmony_ci 0x1f840, 0x1f844, 148562306a36Sopenharmony_ci 0x1f84c, 0x1f84c, 148662306a36Sopenharmony_ci 0x1fa84, 0x1fa90, 148762306a36Sopenharmony_ci 0x1fac0, 0x1fac0, 148862306a36Sopenharmony_ci 0x1fae0, 0x1fae0, 148962306a36Sopenharmony_ci 0x1fb00, 0x1fb84, 149062306a36Sopenharmony_ci 0x1fbc0, 0x1fbc8, 149162306a36Sopenharmony_ci 0x1fc08, 0x1fc0c, 149262306a36Sopenharmony_ci 0x1fc40, 0x1fc44, 149362306a36Sopenharmony_ci 0x1fc4c, 0x1fc4c, 149462306a36Sopenharmony_ci 0x1fe84, 0x1fe90, 149562306a36Sopenharmony_ci 0x1fec0, 0x1fec0, 149662306a36Sopenharmony_ci 0x1fee0, 0x1fee0, 149762306a36Sopenharmony_ci 0x1ff00, 0x1ff84, 149862306a36Sopenharmony_ci 0x1ffc0, 0x1ffc8, 149962306a36Sopenharmony_ci 0x30000, 0x30030, 150062306a36Sopenharmony_ci 0x30100, 0x30144, 150162306a36Sopenharmony_ci 0x30190, 0x301a0, 150262306a36Sopenharmony_ci 0x301a8, 0x301b8, 150362306a36Sopenharmony_ci 0x301c4, 0x301c8, 150462306a36Sopenharmony_ci 0x301d0, 0x301d0, 150562306a36Sopenharmony_ci 0x30200, 0x30318, 150662306a36Sopenharmony_ci 0x30400, 0x304b4, 150762306a36Sopenharmony_ci 0x304c0, 0x3052c, 150862306a36Sopenharmony_ci 0x30540, 0x3061c, 150962306a36Sopenharmony_ci 0x30800, 0x30828, 151062306a36Sopenharmony_ci 0x30834, 0x30834, 151162306a36Sopenharmony_ci 0x308c0, 0x30908, 151262306a36Sopenharmony_ci 0x30910, 0x309ac, 151362306a36Sopenharmony_ci 0x30a00, 0x30a14, 151462306a36Sopenharmony_ci 0x30a1c, 0x30a2c, 151562306a36Sopenharmony_ci 0x30a44, 0x30a50, 151662306a36Sopenharmony_ci 0x30a74, 0x30a74, 151762306a36Sopenharmony_ci 0x30a7c, 0x30afc, 151862306a36Sopenharmony_ci 0x30b08, 0x30c24, 151962306a36Sopenharmony_ci 0x30d00, 0x30d00, 152062306a36Sopenharmony_ci 0x30d08, 0x30d14, 152162306a36Sopenharmony_ci 0x30d1c, 0x30d20, 152262306a36Sopenharmony_ci 0x30d3c, 0x30d3c, 152362306a36Sopenharmony_ci 0x30d48, 0x30d50, 152462306a36Sopenharmony_ci 0x31200, 0x3120c, 152562306a36Sopenharmony_ci 0x31220, 0x31220, 152662306a36Sopenharmony_ci 0x31240, 0x31240, 152762306a36Sopenharmony_ci 0x31600, 0x3160c, 152862306a36Sopenharmony_ci 0x31a00, 0x31a1c, 152962306a36Sopenharmony_ci 0x31e00, 0x31e20, 153062306a36Sopenharmony_ci 0x31e38, 0x31e3c, 153162306a36Sopenharmony_ci 0x31e80, 0x31e80, 153262306a36Sopenharmony_ci 0x31e88, 0x31ea8, 153362306a36Sopenharmony_ci 0x31eb0, 0x31eb4, 153462306a36Sopenharmony_ci 0x31ec8, 0x31ed4, 153562306a36Sopenharmony_ci 0x31fb8, 0x32004, 153662306a36Sopenharmony_ci 0x32200, 0x32200, 153762306a36Sopenharmony_ci 0x32208, 0x32240, 153862306a36Sopenharmony_ci 0x32248, 0x32280, 153962306a36Sopenharmony_ci 0x32288, 0x322c0, 154062306a36Sopenharmony_ci 0x322c8, 0x322fc, 154162306a36Sopenharmony_ci 0x32600, 0x32630, 154262306a36Sopenharmony_ci 0x32a00, 0x32abc, 154362306a36Sopenharmony_ci 0x32b00, 0x32b10, 154462306a36Sopenharmony_ci 0x32b20, 0x32b30, 154562306a36Sopenharmony_ci 0x32b40, 0x32b50, 154662306a36Sopenharmony_ci 0x32b60, 0x32b70, 154762306a36Sopenharmony_ci 0x33000, 0x33028, 154862306a36Sopenharmony_ci 0x33030, 0x33048, 154962306a36Sopenharmony_ci 0x33060, 0x33068, 155062306a36Sopenharmony_ci 0x33070, 0x3309c, 155162306a36Sopenharmony_ci 0x330f0, 0x33128, 155262306a36Sopenharmony_ci 0x33130, 0x33148, 155362306a36Sopenharmony_ci 0x33160, 0x33168, 155462306a36Sopenharmony_ci 0x33170, 0x3319c, 155562306a36Sopenharmony_ci 0x331f0, 0x33238, 155662306a36Sopenharmony_ci 0x33240, 0x33240, 155762306a36Sopenharmony_ci 0x33248, 0x33250, 155862306a36Sopenharmony_ci 0x3325c, 0x33264, 155962306a36Sopenharmony_ci 0x33270, 0x332b8, 156062306a36Sopenharmony_ci 0x332c0, 0x332e4, 156162306a36Sopenharmony_ci 0x332f8, 0x33338, 156262306a36Sopenharmony_ci 0x33340, 0x33340, 156362306a36Sopenharmony_ci 0x33348, 0x33350, 156462306a36Sopenharmony_ci 0x3335c, 0x33364, 156562306a36Sopenharmony_ci 0x33370, 0x333b8, 156662306a36Sopenharmony_ci 0x333c0, 0x333e4, 156762306a36Sopenharmony_ci 0x333f8, 0x33428, 156862306a36Sopenharmony_ci 0x33430, 0x33448, 156962306a36Sopenharmony_ci 0x33460, 0x33468, 157062306a36Sopenharmony_ci 0x33470, 0x3349c, 157162306a36Sopenharmony_ci 0x334f0, 0x33528, 157262306a36Sopenharmony_ci 0x33530, 0x33548, 157362306a36Sopenharmony_ci 0x33560, 0x33568, 157462306a36Sopenharmony_ci 0x33570, 0x3359c, 157562306a36Sopenharmony_ci 0x335f0, 0x33638, 157662306a36Sopenharmony_ci 0x33640, 0x33640, 157762306a36Sopenharmony_ci 0x33648, 0x33650, 157862306a36Sopenharmony_ci 0x3365c, 0x33664, 157962306a36Sopenharmony_ci 0x33670, 0x336b8, 158062306a36Sopenharmony_ci 0x336c0, 0x336e4, 158162306a36Sopenharmony_ci 0x336f8, 0x33738, 158262306a36Sopenharmony_ci 0x33740, 0x33740, 158362306a36Sopenharmony_ci 0x33748, 0x33750, 158462306a36Sopenharmony_ci 0x3375c, 0x33764, 158562306a36Sopenharmony_ci 0x33770, 0x337b8, 158662306a36Sopenharmony_ci 0x337c0, 0x337e4, 158762306a36Sopenharmony_ci 0x337f8, 0x337fc, 158862306a36Sopenharmony_ci 0x33814, 0x33814, 158962306a36Sopenharmony_ci 0x3382c, 0x3382c, 159062306a36Sopenharmony_ci 0x33880, 0x3388c, 159162306a36Sopenharmony_ci 0x338e8, 0x338ec, 159262306a36Sopenharmony_ci 0x33900, 0x33928, 159362306a36Sopenharmony_ci 0x33930, 0x33948, 159462306a36Sopenharmony_ci 0x33960, 0x33968, 159562306a36Sopenharmony_ci 0x33970, 0x3399c, 159662306a36Sopenharmony_ci 0x339f0, 0x33a38, 159762306a36Sopenharmony_ci 0x33a40, 0x33a40, 159862306a36Sopenharmony_ci 0x33a48, 0x33a50, 159962306a36Sopenharmony_ci 0x33a5c, 0x33a64, 160062306a36Sopenharmony_ci 0x33a70, 0x33ab8, 160162306a36Sopenharmony_ci 0x33ac0, 0x33ae4, 160262306a36Sopenharmony_ci 0x33af8, 0x33b10, 160362306a36Sopenharmony_ci 0x33b28, 0x33b28, 160462306a36Sopenharmony_ci 0x33b3c, 0x33b50, 160562306a36Sopenharmony_ci 0x33bf0, 0x33c10, 160662306a36Sopenharmony_ci 0x33c28, 0x33c28, 160762306a36Sopenharmony_ci 0x33c3c, 0x33c50, 160862306a36Sopenharmony_ci 0x33cf0, 0x33cfc, 160962306a36Sopenharmony_ci 0x34000, 0x34030, 161062306a36Sopenharmony_ci 0x34100, 0x34144, 161162306a36Sopenharmony_ci 0x34190, 0x341a0, 161262306a36Sopenharmony_ci 0x341a8, 0x341b8, 161362306a36Sopenharmony_ci 0x341c4, 0x341c8, 161462306a36Sopenharmony_ci 0x341d0, 0x341d0, 161562306a36Sopenharmony_ci 0x34200, 0x34318, 161662306a36Sopenharmony_ci 0x34400, 0x344b4, 161762306a36Sopenharmony_ci 0x344c0, 0x3452c, 161862306a36Sopenharmony_ci 0x34540, 0x3461c, 161962306a36Sopenharmony_ci 0x34800, 0x34828, 162062306a36Sopenharmony_ci 0x34834, 0x34834, 162162306a36Sopenharmony_ci 0x348c0, 0x34908, 162262306a36Sopenharmony_ci 0x34910, 0x349ac, 162362306a36Sopenharmony_ci 0x34a00, 0x34a14, 162462306a36Sopenharmony_ci 0x34a1c, 0x34a2c, 162562306a36Sopenharmony_ci 0x34a44, 0x34a50, 162662306a36Sopenharmony_ci 0x34a74, 0x34a74, 162762306a36Sopenharmony_ci 0x34a7c, 0x34afc, 162862306a36Sopenharmony_ci 0x34b08, 0x34c24, 162962306a36Sopenharmony_ci 0x34d00, 0x34d00, 163062306a36Sopenharmony_ci 0x34d08, 0x34d14, 163162306a36Sopenharmony_ci 0x34d1c, 0x34d20, 163262306a36Sopenharmony_ci 0x34d3c, 0x34d3c, 163362306a36Sopenharmony_ci 0x34d48, 0x34d50, 163462306a36Sopenharmony_ci 0x35200, 0x3520c, 163562306a36Sopenharmony_ci 0x35220, 0x35220, 163662306a36Sopenharmony_ci 0x35240, 0x35240, 163762306a36Sopenharmony_ci 0x35600, 0x3560c, 163862306a36Sopenharmony_ci 0x35a00, 0x35a1c, 163962306a36Sopenharmony_ci 0x35e00, 0x35e20, 164062306a36Sopenharmony_ci 0x35e38, 0x35e3c, 164162306a36Sopenharmony_ci 0x35e80, 0x35e80, 164262306a36Sopenharmony_ci 0x35e88, 0x35ea8, 164362306a36Sopenharmony_ci 0x35eb0, 0x35eb4, 164462306a36Sopenharmony_ci 0x35ec8, 0x35ed4, 164562306a36Sopenharmony_ci 0x35fb8, 0x36004, 164662306a36Sopenharmony_ci 0x36200, 0x36200, 164762306a36Sopenharmony_ci 0x36208, 0x36240, 164862306a36Sopenharmony_ci 0x36248, 0x36280, 164962306a36Sopenharmony_ci 0x36288, 0x362c0, 165062306a36Sopenharmony_ci 0x362c8, 0x362fc, 165162306a36Sopenharmony_ci 0x36600, 0x36630, 165262306a36Sopenharmony_ci 0x36a00, 0x36abc, 165362306a36Sopenharmony_ci 0x36b00, 0x36b10, 165462306a36Sopenharmony_ci 0x36b20, 0x36b30, 165562306a36Sopenharmony_ci 0x36b40, 0x36b50, 165662306a36Sopenharmony_ci 0x36b60, 0x36b70, 165762306a36Sopenharmony_ci 0x37000, 0x37028, 165862306a36Sopenharmony_ci 0x37030, 0x37048, 165962306a36Sopenharmony_ci 0x37060, 0x37068, 166062306a36Sopenharmony_ci 0x37070, 0x3709c, 166162306a36Sopenharmony_ci 0x370f0, 0x37128, 166262306a36Sopenharmony_ci 0x37130, 0x37148, 166362306a36Sopenharmony_ci 0x37160, 0x37168, 166462306a36Sopenharmony_ci 0x37170, 0x3719c, 166562306a36Sopenharmony_ci 0x371f0, 0x37238, 166662306a36Sopenharmony_ci 0x37240, 0x37240, 166762306a36Sopenharmony_ci 0x37248, 0x37250, 166862306a36Sopenharmony_ci 0x3725c, 0x37264, 166962306a36Sopenharmony_ci 0x37270, 0x372b8, 167062306a36Sopenharmony_ci 0x372c0, 0x372e4, 167162306a36Sopenharmony_ci 0x372f8, 0x37338, 167262306a36Sopenharmony_ci 0x37340, 0x37340, 167362306a36Sopenharmony_ci 0x37348, 0x37350, 167462306a36Sopenharmony_ci 0x3735c, 0x37364, 167562306a36Sopenharmony_ci 0x37370, 0x373b8, 167662306a36Sopenharmony_ci 0x373c0, 0x373e4, 167762306a36Sopenharmony_ci 0x373f8, 0x37428, 167862306a36Sopenharmony_ci 0x37430, 0x37448, 167962306a36Sopenharmony_ci 0x37460, 0x37468, 168062306a36Sopenharmony_ci 0x37470, 0x3749c, 168162306a36Sopenharmony_ci 0x374f0, 0x37528, 168262306a36Sopenharmony_ci 0x37530, 0x37548, 168362306a36Sopenharmony_ci 0x37560, 0x37568, 168462306a36Sopenharmony_ci 0x37570, 0x3759c, 168562306a36Sopenharmony_ci 0x375f0, 0x37638, 168662306a36Sopenharmony_ci 0x37640, 0x37640, 168762306a36Sopenharmony_ci 0x37648, 0x37650, 168862306a36Sopenharmony_ci 0x3765c, 0x37664, 168962306a36Sopenharmony_ci 0x37670, 0x376b8, 169062306a36Sopenharmony_ci 0x376c0, 0x376e4, 169162306a36Sopenharmony_ci 0x376f8, 0x37738, 169262306a36Sopenharmony_ci 0x37740, 0x37740, 169362306a36Sopenharmony_ci 0x37748, 0x37750, 169462306a36Sopenharmony_ci 0x3775c, 0x37764, 169562306a36Sopenharmony_ci 0x37770, 0x377b8, 169662306a36Sopenharmony_ci 0x377c0, 0x377e4, 169762306a36Sopenharmony_ci 0x377f8, 0x377fc, 169862306a36Sopenharmony_ci 0x37814, 0x37814, 169962306a36Sopenharmony_ci 0x3782c, 0x3782c, 170062306a36Sopenharmony_ci 0x37880, 0x3788c, 170162306a36Sopenharmony_ci 0x378e8, 0x378ec, 170262306a36Sopenharmony_ci 0x37900, 0x37928, 170362306a36Sopenharmony_ci 0x37930, 0x37948, 170462306a36Sopenharmony_ci 0x37960, 0x37968, 170562306a36Sopenharmony_ci 0x37970, 0x3799c, 170662306a36Sopenharmony_ci 0x379f0, 0x37a38, 170762306a36Sopenharmony_ci 0x37a40, 0x37a40, 170862306a36Sopenharmony_ci 0x37a48, 0x37a50, 170962306a36Sopenharmony_ci 0x37a5c, 0x37a64, 171062306a36Sopenharmony_ci 0x37a70, 0x37ab8, 171162306a36Sopenharmony_ci 0x37ac0, 0x37ae4, 171262306a36Sopenharmony_ci 0x37af8, 0x37b10, 171362306a36Sopenharmony_ci 0x37b28, 0x37b28, 171462306a36Sopenharmony_ci 0x37b3c, 0x37b50, 171562306a36Sopenharmony_ci 0x37bf0, 0x37c10, 171662306a36Sopenharmony_ci 0x37c28, 0x37c28, 171762306a36Sopenharmony_ci 0x37c3c, 0x37c50, 171862306a36Sopenharmony_ci 0x37cf0, 0x37cfc, 171962306a36Sopenharmony_ci 0x38000, 0x38030, 172062306a36Sopenharmony_ci 0x38100, 0x38144, 172162306a36Sopenharmony_ci 0x38190, 0x381a0, 172262306a36Sopenharmony_ci 0x381a8, 0x381b8, 172362306a36Sopenharmony_ci 0x381c4, 0x381c8, 172462306a36Sopenharmony_ci 0x381d0, 0x381d0, 172562306a36Sopenharmony_ci 0x38200, 0x38318, 172662306a36Sopenharmony_ci 0x38400, 0x384b4, 172762306a36Sopenharmony_ci 0x384c0, 0x3852c, 172862306a36Sopenharmony_ci 0x38540, 0x3861c, 172962306a36Sopenharmony_ci 0x38800, 0x38828, 173062306a36Sopenharmony_ci 0x38834, 0x38834, 173162306a36Sopenharmony_ci 0x388c0, 0x38908, 173262306a36Sopenharmony_ci 0x38910, 0x389ac, 173362306a36Sopenharmony_ci 0x38a00, 0x38a14, 173462306a36Sopenharmony_ci 0x38a1c, 0x38a2c, 173562306a36Sopenharmony_ci 0x38a44, 0x38a50, 173662306a36Sopenharmony_ci 0x38a74, 0x38a74, 173762306a36Sopenharmony_ci 0x38a7c, 0x38afc, 173862306a36Sopenharmony_ci 0x38b08, 0x38c24, 173962306a36Sopenharmony_ci 0x38d00, 0x38d00, 174062306a36Sopenharmony_ci 0x38d08, 0x38d14, 174162306a36Sopenharmony_ci 0x38d1c, 0x38d20, 174262306a36Sopenharmony_ci 0x38d3c, 0x38d3c, 174362306a36Sopenharmony_ci 0x38d48, 0x38d50, 174462306a36Sopenharmony_ci 0x39200, 0x3920c, 174562306a36Sopenharmony_ci 0x39220, 0x39220, 174662306a36Sopenharmony_ci 0x39240, 0x39240, 174762306a36Sopenharmony_ci 0x39600, 0x3960c, 174862306a36Sopenharmony_ci 0x39a00, 0x39a1c, 174962306a36Sopenharmony_ci 0x39e00, 0x39e20, 175062306a36Sopenharmony_ci 0x39e38, 0x39e3c, 175162306a36Sopenharmony_ci 0x39e80, 0x39e80, 175262306a36Sopenharmony_ci 0x39e88, 0x39ea8, 175362306a36Sopenharmony_ci 0x39eb0, 0x39eb4, 175462306a36Sopenharmony_ci 0x39ec8, 0x39ed4, 175562306a36Sopenharmony_ci 0x39fb8, 0x3a004, 175662306a36Sopenharmony_ci 0x3a200, 0x3a200, 175762306a36Sopenharmony_ci 0x3a208, 0x3a240, 175862306a36Sopenharmony_ci 0x3a248, 0x3a280, 175962306a36Sopenharmony_ci 0x3a288, 0x3a2c0, 176062306a36Sopenharmony_ci 0x3a2c8, 0x3a2fc, 176162306a36Sopenharmony_ci 0x3a600, 0x3a630, 176262306a36Sopenharmony_ci 0x3aa00, 0x3aabc, 176362306a36Sopenharmony_ci 0x3ab00, 0x3ab10, 176462306a36Sopenharmony_ci 0x3ab20, 0x3ab30, 176562306a36Sopenharmony_ci 0x3ab40, 0x3ab50, 176662306a36Sopenharmony_ci 0x3ab60, 0x3ab70, 176762306a36Sopenharmony_ci 0x3b000, 0x3b028, 176862306a36Sopenharmony_ci 0x3b030, 0x3b048, 176962306a36Sopenharmony_ci 0x3b060, 0x3b068, 177062306a36Sopenharmony_ci 0x3b070, 0x3b09c, 177162306a36Sopenharmony_ci 0x3b0f0, 0x3b128, 177262306a36Sopenharmony_ci 0x3b130, 0x3b148, 177362306a36Sopenharmony_ci 0x3b160, 0x3b168, 177462306a36Sopenharmony_ci 0x3b170, 0x3b19c, 177562306a36Sopenharmony_ci 0x3b1f0, 0x3b238, 177662306a36Sopenharmony_ci 0x3b240, 0x3b240, 177762306a36Sopenharmony_ci 0x3b248, 0x3b250, 177862306a36Sopenharmony_ci 0x3b25c, 0x3b264, 177962306a36Sopenharmony_ci 0x3b270, 0x3b2b8, 178062306a36Sopenharmony_ci 0x3b2c0, 0x3b2e4, 178162306a36Sopenharmony_ci 0x3b2f8, 0x3b338, 178262306a36Sopenharmony_ci 0x3b340, 0x3b340, 178362306a36Sopenharmony_ci 0x3b348, 0x3b350, 178462306a36Sopenharmony_ci 0x3b35c, 0x3b364, 178562306a36Sopenharmony_ci 0x3b370, 0x3b3b8, 178662306a36Sopenharmony_ci 0x3b3c0, 0x3b3e4, 178762306a36Sopenharmony_ci 0x3b3f8, 0x3b428, 178862306a36Sopenharmony_ci 0x3b430, 0x3b448, 178962306a36Sopenharmony_ci 0x3b460, 0x3b468, 179062306a36Sopenharmony_ci 0x3b470, 0x3b49c, 179162306a36Sopenharmony_ci 0x3b4f0, 0x3b528, 179262306a36Sopenharmony_ci 0x3b530, 0x3b548, 179362306a36Sopenharmony_ci 0x3b560, 0x3b568, 179462306a36Sopenharmony_ci 0x3b570, 0x3b59c, 179562306a36Sopenharmony_ci 0x3b5f0, 0x3b638, 179662306a36Sopenharmony_ci 0x3b640, 0x3b640, 179762306a36Sopenharmony_ci 0x3b648, 0x3b650, 179862306a36Sopenharmony_ci 0x3b65c, 0x3b664, 179962306a36Sopenharmony_ci 0x3b670, 0x3b6b8, 180062306a36Sopenharmony_ci 0x3b6c0, 0x3b6e4, 180162306a36Sopenharmony_ci 0x3b6f8, 0x3b738, 180262306a36Sopenharmony_ci 0x3b740, 0x3b740, 180362306a36Sopenharmony_ci 0x3b748, 0x3b750, 180462306a36Sopenharmony_ci 0x3b75c, 0x3b764, 180562306a36Sopenharmony_ci 0x3b770, 0x3b7b8, 180662306a36Sopenharmony_ci 0x3b7c0, 0x3b7e4, 180762306a36Sopenharmony_ci 0x3b7f8, 0x3b7fc, 180862306a36Sopenharmony_ci 0x3b814, 0x3b814, 180962306a36Sopenharmony_ci 0x3b82c, 0x3b82c, 181062306a36Sopenharmony_ci 0x3b880, 0x3b88c, 181162306a36Sopenharmony_ci 0x3b8e8, 0x3b8ec, 181262306a36Sopenharmony_ci 0x3b900, 0x3b928, 181362306a36Sopenharmony_ci 0x3b930, 0x3b948, 181462306a36Sopenharmony_ci 0x3b960, 0x3b968, 181562306a36Sopenharmony_ci 0x3b970, 0x3b99c, 181662306a36Sopenharmony_ci 0x3b9f0, 0x3ba38, 181762306a36Sopenharmony_ci 0x3ba40, 0x3ba40, 181862306a36Sopenharmony_ci 0x3ba48, 0x3ba50, 181962306a36Sopenharmony_ci 0x3ba5c, 0x3ba64, 182062306a36Sopenharmony_ci 0x3ba70, 0x3bab8, 182162306a36Sopenharmony_ci 0x3bac0, 0x3bae4, 182262306a36Sopenharmony_ci 0x3baf8, 0x3bb10, 182362306a36Sopenharmony_ci 0x3bb28, 0x3bb28, 182462306a36Sopenharmony_ci 0x3bb3c, 0x3bb50, 182562306a36Sopenharmony_ci 0x3bbf0, 0x3bc10, 182662306a36Sopenharmony_ci 0x3bc28, 0x3bc28, 182762306a36Sopenharmony_ci 0x3bc3c, 0x3bc50, 182862306a36Sopenharmony_ci 0x3bcf0, 0x3bcfc, 182962306a36Sopenharmony_ci 0x3c000, 0x3c030, 183062306a36Sopenharmony_ci 0x3c100, 0x3c144, 183162306a36Sopenharmony_ci 0x3c190, 0x3c1a0, 183262306a36Sopenharmony_ci 0x3c1a8, 0x3c1b8, 183362306a36Sopenharmony_ci 0x3c1c4, 0x3c1c8, 183462306a36Sopenharmony_ci 0x3c1d0, 0x3c1d0, 183562306a36Sopenharmony_ci 0x3c200, 0x3c318, 183662306a36Sopenharmony_ci 0x3c400, 0x3c4b4, 183762306a36Sopenharmony_ci 0x3c4c0, 0x3c52c, 183862306a36Sopenharmony_ci 0x3c540, 0x3c61c, 183962306a36Sopenharmony_ci 0x3c800, 0x3c828, 184062306a36Sopenharmony_ci 0x3c834, 0x3c834, 184162306a36Sopenharmony_ci 0x3c8c0, 0x3c908, 184262306a36Sopenharmony_ci 0x3c910, 0x3c9ac, 184362306a36Sopenharmony_ci 0x3ca00, 0x3ca14, 184462306a36Sopenharmony_ci 0x3ca1c, 0x3ca2c, 184562306a36Sopenharmony_ci 0x3ca44, 0x3ca50, 184662306a36Sopenharmony_ci 0x3ca74, 0x3ca74, 184762306a36Sopenharmony_ci 0x3ca7c, 0x3cafc, 184862306a36Sopenharmony_ci 0x3cb08, 0x3cc24, 184962306a36Sopenharmony_ci 0x3cd00, 0x3cd00, 185062306a36Sopenharmony_ci 0x3cd08, 0x3cd14, 185162306a36Sopenharmony_ci 0x3cd1c, 0x3cd20, 185262306a36Sopenharmony_ci 0x3cd3c, 0x3cd3c, 185362306a36Sopenharmony_ci 0x3cd48, 0x3cd50, 185462306a36Sopenharmony_ci 0x3d200, 0x3d20c, 185562306a36Sopenharmony_ci 0x3d220, 0x3d220, 185662306a36Sopenharmony_ci 0x3d240, 0x3d240, 185762306a36Sopenharmony_ci 0x3d600, 0x3d60c, 185862306a36Sopenharmony_ci 0x3da00, 0x3da1c, 185962306a36Sopenharmony_ci 0x3de00, 0x3de20, 186062306a36Sopenharmony_ci 0x3de38, 0x3de3c, 186162306a36Sopenharmony_ci 0x3de80, 0x3de80, 186262306a36Sopenharmony_ci 0x3de88, 0x3dea8, 186362306a36Sopenharmony_ci 0x3deb0, 0x3deb4, 186462306a36Sopenharmony_ci 0x3dec8, 0x3ded4, 186562306a36Sopenharmony_ci 0x3dfb8, 0x3e004, 186662306a36Sopenharmony_ci 0x3e200, 0x3e200, 186762306a36Sopenharmony_ci 0x3e208, 0x3e240, 186862306a36Sopenharmony_ci 0x3e248, 0x3e280, 186962306a36Sopenharmony_ci 0x3e288, 0x3e2c0, 187062306a36Sopenharmony_ci 0x3e2c8, 0x3e2fc, 187162306a36Sopenharmony_ci 0x3e600, 0x3e630, 187262306a36Sopenharmony_ci 0x3ea00, 0x3eabc, 187362306a36Sopenharmony_ci 0x3eb00, 0x3eb10, 187462306a36Sopenharmony_ci 0x3eb20, 0x3eb30, 187562306a36Sopenharmony_ci 0x3eb40, 0x3eb50, 187662306a36Sopenharmony_ci 0x3eb60, 0x3eb70, 187762306a36Sopenharmony_ci 0x3f000, 0x3f028, 187862306a36Sopenharmony_ci 0x3f030, 0x3f048, 187962306a36Sopenharmony_ci 0x3f060, 0x3f068, 188062306a36Sopenharmony_ci 0x3f070, 0x3f09c, 188162306a36Sopenharmony_ci 0x3f0f0, 0x3f128, 188262306a36Sopenharmony_ci 0x3f130, 0x3f148, 188362306a36Sopenharmony_ci 0x3f160, 0x3f168, 188462306a36Sopenharmony_ci 0x3f170, 0x3f19c, 188562306a36Sopenharmony_ci 0x3f1f0, 0x3f238, 188662306a36Sopenharmony_ci 0x3f240, 0x3f240, 188762306a36Sopenharmony_ci 0x3f248, 0x3f250, 188862306a36Sopenharmony_ci 0x3f25c, 0x3f264, 188962306a36Sopenharmony_ci 0x3f270, 0x3f2b8, 189062306a36Sopenharmony_ci 0x3f2c0, 0x3f2e4, 189162306a36Sopenharmony_ci 0x3f2f8, 0x3f338, 189262306a36Sopenharmony_ci 0x3f340, 0x3f340, 189362306a36Sopenharmony_ci 0x3f348, 0x3f350, 189462306a36Sopenharmony_ci 0x3f35c, 0x3f364, 189562306a36Sopenharmony_ci 0x3f370, 0x3f3b8, 189662306a36Sopenharmony_ci 0x3f3c0, 0x3f3e4, 189762306a36Sopenharmony_ci 0x3f3f8, 0x3f428, 189862306a36Sopenharmony_ci 0x3f430, 0x3f448, 189962306a36Sopenharmony_ci 0x3f460, 0x3f468, 190062306a36Sopenharmony_ci 0x3f470, 0x3f49c, 190162306a36Sopenharmony_ci 0x3f4f0, 0x3f528, 190262306a36Sopenharmony_ci 0x3f530, 0x3f548, 190362306a36Sopenharmony_ci 0x3f560, 0x3f568, 190462306a36Sopenharmony_ci 0x3f570, 0x3f59c, 190562306a36Sopenharmony_ci 0x3f5f0, 0x3f638, 190662306a36Sopenharmony_ci 0x3f640, 0x3f640, 190762306a36Sopenharmony_ci 0x3f648, 0x3f650, 190862306a36Sopenharmony_ci 0x3f65c, 0x3f664, 190962306a36Sopenharmony_ci 0x3f670, 0x3f6b8, 191062306a36Sopenharmony_ci 0x3f6c0, 0x3f6e4, 191162306a36Sopenharmony_ci 0x3f6f8, 0x3f738, 191262306a36Sopenharmony_ci 0x3f740, 0x3f740, 191362306a36Sopenharmony_ci 0x3f748, 0x3f750, 191462306a36Sopenharmony_ci 0x3f75c, 0x3f764, 191562306a36Sopenharmony_ci 0x3f770, 0x3f7b8, 191662306a36Sopenharmony_ci 0x3f7c0, 0x3f7e4, 191762306a36Sopenharmony_ci 0x3f7f8, 0x3f7fc, 191862306a36Sopenharmony_ci 0x3f814, 0x3f814, 191962306a36Sopenharmony_ci 0x3f82c, 0x3f82c, 192062306a36Sopenharmony_ci 0x3f880, 0x3f88c, 192162306a36Sopenharmony_ci 0x3f8e8, 0x3f8ec, 192262306a36Sopenharmony_ci 0x3f900, 0x3f928, 192362306a36Sopenharmony_ci 0x3f930, 0x3f948, 192462306a36Sopenharmony_ci 0x3f960, 0x3f968, 192562306a36Sopenharmony_ci 0x3f970, 0x3f99c, 192662306a36Sopenharmony_ci 0x3f9f0, 0x3fa38, 192762306a36Sopenharmony_ci 0x3fa40, 0x3fa40, 192862306a36Sopenharmony_ci 0x3fa48, 0x3fa50, 192962306a36Sopenharmony_ci 0x3fa5c, 0x3fa64, 193062306a36Sopenharmony_ci 0x3fa70, 0x3fab8, 193162306a36Sopenharmony_ci 0x3fac0, 0x3fae4, 193262306a36Sopenharmony_ci 0x3faf8, 0x3fb10, 193362306a36Sopenharmony_ci 0x3fb28, 0x3fb28, 193462306a36Sopenharmony_ci 0x3fb3c, 0x3fb50, 193562306a36Sopenharmony_ci 0x3fbf0, 0x3fc10, 193662306a36Sopenharmony_ci 0x3fc28, 0x3fc28, 193762306a36Sopenharmony_ci 0x3fc3c, 0x3fc50, 193862306a36Sopenharmony_ci 0x3fcf0, 0x3fcfc, 193962306a36Sopenharmony_ci 0x40000, 0x4000c, 194062306a36Sopenharmony_ci 0x40040, 0x40050, 194162306a36Sopenharmony_ci 0x40060, 0x40068, 194262306a36Sopenharmony_ci 0x4007c, 0x4008c, 194362306a36Sopenharmony_ci 0x40094, 0x400b0, 194462306a36Sopenharmony_ci 0x400c0, 0x40144, 194562306a36Sopenharmony_ci 0x40180, 0x4018c, 194662306a36Sopenharmony_ci 0x40200, 0x40254, 194762306a36Sopenharmony_ci 0x40260, 0x40264, 194862306a36Sopenharmony_ci 0x40270, 0x40288, 194962306a36Sopenharmony_ci 0x40290, 0x40298, 195062306a36Sopenharmony_ci 0x402ac, 0x402c8, 195162306a36Sopenharmony_ci 0x402d0, 0x402e0, 195262306a36Sopenharmony_ci 0x402f0, 0x402f0, 195362306a36Sopenharmony_ci 0x40300, 0x4033c, 195462306a36Sopenharmony_ci 0x403f8, 0x403fc, 195562306a36Sopenharmony_ci 0x41304, 0x413c4, 195662306a36Sopenharmony_ci 0x41400, 0x4140c, 195762306a36Sopenharmony_ci 0x41414, 0x4141c, 195862306a36Sopenharmony_ci 0x41480, 0x414d0, 195962306a36Sopenharmony_ci 0x44000, 0x44054, 196062306a36Sopenharmony_ci 0x4405c, 0x44078, 196162306a36Sopenharmony_ci 0x440c0, 0x44174, 196262306a36Sopenharmony_ci 0x44180, 0x441ac, 196362306a36Sopenharmony_ci 0x441b4, 0x441b8, 196462306a36Sopenharmony_ci 0x441c0, 0x44254, 196562306a36Sopenharmony_ci 0x4425c, 0x44278, 196662306a36Sopenharmony_ci 0x442c0, 0x44374, 196762306a36Sopenharmony_ci 0x44380, 0x443ac, 196862306a36Sopenharmony_ci 0x443b4, 0x443b8, 196962306a36Sopenharmony_ci 0x443c0, 0x44454, 197062306a36Sopenharmony_ci 0x4445c, 0x44478, 197162306a36Sopenharmony_ci 0x444c0, 0x44574, 197262306a36Sopenharmony_ci 0x44580, 0x445ac, 197362306a36Sopenharmony_ci 0x445b4, 0x445b8, 197462306a36Sopenharmony_ci 0x445c0, 0x44654, 197562306a36Sopenharmony_ci 0x4465c, 0x44678, 197662306a36Sopenharmony_ci 0x446c0, 0x44774, 197762306a36Sopenharmony_ci 0x44780, 0x447ac, 197862306a36Sopenharmony_ci 0x447b4, 0x447b8, 197962306a36Sopenharmony_ci 0x447c0, 0x44854, 198062306a36Sopenharmony_ci 0x4485c, 0x44878, 198162306a36Sopenharmony_ci 0x448c0, 0x44974, 198262306a36Sopenharmony_ci 0x44980, 0x449ac, 198362306a36Sopenharmony_ci 0x449b4, 0x449b8, 198462306a36Sopenharmony_ci 0x449c0, 0x449fc, 198562306a36Sopenharmony_ci 0x45000, 0x45004, 198662306a36Sopenharmony_ci 0x45010, 0x45030, 198762306a36Sopenharmony_ci 0x45040, 0x45060, 198862306a36Sopenharmony_ci 0x45068, 0x45068, 198962306a36Sopenharmony_ci 0x45080, 0x45084, 199062306a36Sopenharmony_ci 0x450a0, 0x450b0, 199162306a36Sopenharmony_ci 0x45200, 0x45204, 199262306a36Sopenharmony_ci 0x45210, 0x45230, 199362306a36Sopenharmony_ci 0x45240, 0x45260, 199462306a36Sopenharmony_ci 0x45268, 0x45268, 199562306a36Sopenharmony_ci 0x45280, 0x45284, 199662306a36Sopenharmony_ci 0x452a0, 0x452b0, 199762306a36Sopenharmony_ci 0x460c0, 0x460e4, 199862306a36Sopenharmony_ci 0x47000, 0x4703c, 199962306a36Sopenharmony_ci 0x47044, 0x4708c, 200062306a36Sopenharmony_ci 0x47200, 0x47250, 200162306a36Sopenharmony_ci 0x47400, 0x47408, 200262306a36Sopenharmony_ci 0x47414, 0x47420, 200362306a36Sopenharmony_ci 0x47600, 0x47618, 200462306a36Sopenharmony_ci 0x47800, 0x47814, 200562306a36Sopenharmony_ci 0x48000, 0x4800c, 200662306a36Sopenharmony_ci 0x48040, 0x48050, 200762306a36Sopenharmony_ci 0x48060, 0x48068, 200862306a36Sopenharmony_ci 0x4807c, 0x4808c, 200962306a36Sopenharmony_ci 0x48094, 0x480b0, 201062306a36Sopenharmony_ci 0x480c0, 0x48144, 201162306a36Sopenharmony_ci 0x48180, 0x4818c, 201262306a36Sopenharmony_ci 0x48200, 0x48254, 201362306a36Sopenharmony_ci 0x48260, 0x48264, 201462306a36Sopenharmony_ci 0x48270, 0x48288, 201562306a36Sopenharmony_ci 0x48290, 0x48298, 201662306a36Sopenharmony_ci 0x482ac, 0x482c8, 201762306a36Sopenharmony_ci 0x482d0, 0x482e0, 201862306a36Sopenharmony_ci 0x482f0, 0x482f0, 201962306a36Sopenharmony_ci 0x48300, 0x4833c, 202062306a36Sopenharmony_ci 0x483f8, 0x483fc, 202162306a36Sopenharmony_ci 0x49304, 0x493c4, 202262306a36Sopenharmony_ci 0x49400, 0x4940c, 202362306a36Sopenharmony_ci 0x49414, 0x4941c, 202462306a36Sopenharmony_ci 0x49480, 0x494d0, 202562306a36Sopenharmony_ci 0x4c000, 0x4c054, 202662306a36Sopenharmony_ci 0x4c05c, 0x4c078, 202762306a36Sopenharmony_ci 0x4c0c0, 0x4c174, 202862306a36Sopenharmony_ci 0x4c180, 0x4c1ac, 202962306a36Sopenharmony_ci 0x4c1b4, 0x4c1b8, 203062306a36Sopenharmony_ci 0x4c1c0, 0x4c254, 203162306a36Sopenharmony_ci 0x4c25c, 0x4c278, 203262306a36Sopenharmony_ci 0x4c2c0, 0x4c374, 203362306a36Sopenharmony_ci 0x4c380, 0x4c3ac, 203462306a36Sopenharmony_ci 0x4c3b4, 0x4c3b8, 203562306a36Sopenharmony_ci 0x4c3c0, 0x4c454, 203662306a36Sopenharmony_ci 0x4c45c, 0x4c478, 203762306a36Sopenharmony_ci 0x4c4c0, 0x4c574, 203862306a36Sopenharmony_ci 0x4c580, 0x4c5ac, 203962306a36Sopenharmony_ci 0x4c5b4, 0x4c5b8, 204062306a36Sopenharmony_ci 0x4c5c0, 0x4c654, 204162306a36Sopenharmony_ci 0x4c65c, 0x4c678, 204262306a36Sopenharmony_ci 0x4c6c0, 0x4c774, 204362306a36Sopenharmony_ci 0x4c780, 0x4c7ac, 204462306a36Sopenharmony_ci 0x4c7b4, 0x4c7b8, 204562306a36Sopenharmony_ci 0x4c7c0, 0x4c854, 204662306a36Sopenharmony_ci 0x4c85c, 0x4c878, 204762306a36Sopenharmony_ci 0x4c8c0, 0x4c974, 204862306a36Sopenharmony_ci 0x4c980, 0x4c9ac, 204962306a36Sopenharmony_ci 0x4c9b4, 0x4c9b8, 205062306a36Sopenharmony_ci 0x4c9c0, 0x4c9fc, 205162306a36Sopenharmony_ci 0x4d000, 0x4d004, 205262306a36Sopenharmony_ci 0x4d010, 0x4d030, 205362306a36Sopenharmony_ci 0x4d040, 0x4d060, 205462306a36Sopenharmony_ci 0x4d068, 0x4d068, 205562306a36Sopenharmony_ci 0x4d080, 0x4d084, 205662306a36Sopenharmony_ci 0x4d0a0, 0x4d0b0, 205762306a36Sopenharmony_ci 0x4d200, 0x4d204, 205862306a36Sopenharmony_ci 0x4d210, 0x4d230, 205962306a36Sopenharmony_ci 0x4d240, 0x4d260, 206062306a36Sopenharmony_ci 0x4d268, 0x4d268, 206162306a36Sopenharmony_ci 0x4d280, 0x4d284, 206262306a36Sopenharmony_ci 0x4d2a0, 0x4d2b0, 206362306a36Sopenharmony_ci 0x4e0c0, 0x4e0e4, 206462306a36Sopenharmony_ci 0x4f000, 0x4f03c, 206562306a36Sopenharmony_ci 0x4f044, 0x4f08c, 206662306a36Sopenharmony_ci 0x4f200, 0x4f250, 206762306a36Sopenharmony_ci 0x4f400, 0x4f408, 206862306a36Sopenharmony_ci 0x4f414, 0x4f420, 206962306a36Sopenharmony_ci 0x4f600, 0x4f618, 207062306a36Sopenharmony_ci 0x4f800, 0x4f814, 207162306a36Sopenharmony_ci 0x50000, 0x50084, 207262306a36Sopenharmony_ci 0x50090, 0x500cc, 207362306a36Sopenharmony_ci 0x50400, 0x50400, 207462306a36Sopenharmony_ci 0x50800, 0x50884, 207562306a36Sopenharmony_ci 0x50890, 0x508cc, 207662306a36Sopenharmony_ci 0x50c00, 0x50c00, 207762306a36Sopenharmony_ci 0x51000, 0x5101c, 207862306a36Sopenharmony_ci 0x51300, 0x51308, 207962306a36Sopenharmony_ci }; 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci static const unsigned int t6_reg_ranges[] = { 208262306a36Sopenharmony_ci 0x1008, 0x101c, 208362306a36Sopenharmony_ci 0x1024, 0x10a8, 208462306a36Sopenharmony_ci 0x10b4, 0x10f8, 208562306a36Sopenharmony_ci 0x1100, 0x1114, 208662306a36Sopenharmony_ci 0x111c, 0x112c, 208762306a36Sopenharmony_ci 0x1138, 0x113c, 208862306a36Sopenharmony_ci 0x1144, 0x114c, 208962306a36Sopenharmony_ci 0x1180, 0x1184, 209062306a36Sopenharmony_ci 0x1190, 0x1194, 209162306a36Sopenharmony_ci 0x11a0, 0x11a4, 209262306a36Sopenharmony_ci 0x11b0, 0x11b4, 209362306a36Sopenharmony_ci 0x11fc, 0x123c, 209462306a36Sopenharmony_ci 0x1254, 0x1274, 209562306a36Sopenharmony_ci 0x1280, 0x133c, 209662306a36Sopenharmony_ci 0x1800, 0x18fc, 209762306a36Sopenharmony_ci 0x3000, 0x302c, 209862306a36Sopenharmony_ci 0x3060, 0x30b0, 209962306a36Sopenharmony_ci 0x30b8, 0x30d8, 210062306a36Sopenharmony_ci 0x30e0, 0x30fc, 210162306a36Sopenharmony_ci 0x3140, 0x357c, 210262306a36Sopenharmony_ci 0x35a8, 0x35cc, 210362306a36Sopenharmony_ci 0x35ec, 0x35ec, 210462306a36Sopenharmony_ci 0x3600, 0x5624, 210562306a36Sopenharmony_ci 0x56cc, 0x56ec, 210662306a36Sopenharmony_ci 0x56f4, 0x5720, 210762306a36Sopenharmony_ci 0x5728, 0x575c, 210862306a36Sopenharmony_ci 0x580c, 0x5814, 210962306a36Sopenharmony_ci 0x5890, 0x589c, 211062306a36Sopenharmony_ci 0x58a4, 0x58ac, 211162306a36Sopenharmony_ci 0x58b8, 0x58bc, 211262306a36Sopenharmony_ci 0x5940, 0x595c, 211362306a36Sopenharmony_ci 0x5980, 0x598c, 211462306a36Sopenharmony_ci 0x59b0, 0x59c8, 211562306a36Sopenharmony_ci 0x59d0, 0x59dc, 211662306a36Sopenharmony_ci 0x59fc, 0x5a18, 211762306a36Sopenharmony_ci 0x5a60, 0x5a6c, 211862306a36Sopenharmony_ci 0x5a80, 0x5a8c, 211962306a36Sopenharmony_ci 0x5a94, 0x5a9c, 212062306a36Sopenharmony_ci 0x5b94, 0x5bfc, 212162306a36Sopenharmony_ci 0x5c10, 0x5e48, 212262306a36Sopenharmony_ci 0x5e50, 0x5e94, 212362306a36Sopenharmony_ci 0x5ea0, 0x5eb0, 212462306a36Sopenharmony_ci 0x5ec0, 0x5ec0, 212562306a36Sopenharmony_ci 0x5ec8, 0x5ed0, 212662306a36Sopenharmony_ci 0x5ee0, 0x5ee0, 212762306a36Sopenharmony_ci 0x5ef0, 0x5ef0, 212862306a36Sopenharmony_ci 0x5f00, 0x5f00, 212962306a36Sopenharmony_ci 0x6000, 0x6020, 213062306a36Sopenharmony_ci 0x6028, 0x6040, 213162306a36Sopenharmony_ci 0x6058, 0x609c, 213262306a36Sopenharmony_ci 0x60a8, 0x619c, 213362306a36Sopenharmony_ci 0x7700, 0x7798, 213462306a36Sopenharmony_ci 0x77c0, 0x7880, 213562306a36Sopenharmony_ci 0x78cc, 0x78fc, 213662306a36Sopenharmony_ci 0x7b00, 0x7b58, 213762306a36Sopenharmony_ci 0x7b60, 0x7b84, 213862306a36Sopenharmony_ci 0x7b8c, 0x7c54, 213962306a36Sopenharmony_ci 0x7d00, 0x7d38, 214062306a36Sopenharmony_ci 0x7d40, 0x7d84, 214162306a36Sopenharmony_ci 0x7d8c, 0x7ddc, 214262306a36Sopenharmony_ci 0x7de4, 0x7e04, 214362306a36Sopenharmony_ci 0x7e10, 0x7e1c, 214462306a36Sopenharmony_ci 0x7e24, 0x7e38, 214562306a36Sopenharmony_ci 0x7e40, 0x7e44, 214662306a36Sopenharmony_ci 0x7e4c, 0x7e78, 214762306a36Sopenharmony_ci 0x7e80, 0x7edc, 214862306a36Sopenharmony_ci 0x7ee8, 0x7efc, 214962306a36Sopenharmony_ci 0x8dc0, 0x8de4, 215062306a36Sopenharmony_ci 0x8df8, 0x8e04, 215162306a36Sopenharmony_ci 0x8e10, 0x8e84, 215262306a36Sopenharmony_ci 0x8ea0, 0x8f88, 215362306a36Sopenharmony_ci 0x8fb8, 0x9058, 215462306a36Sopenharmony_ci 0x9060, 0x9060, 215562306a36Sopenharmony_ci 0x9068, 0x90f8, 215662306a36Sopenharmony_ci 0x9100, 0x9124, 215762306a36Sopenharmony_ci 0x9400, 0x9470, 215862306a36Sopenharmony_ci 0x9600, 0x9600, 215962306a36Sopenharmony_ci 0x9608, 0x9638, 216062306a36Sopenharmony_ci 0x9640, 0x9704, 216162306a36Sopenharmony_ci 0x9710, 0x971c, 216262306a36Sopenharmony_ci 0x9800, 0x9808, 216362306a36Sopenharmony_ci 0x9810, 0x9864, 216462306a36Sopenharmony_ci 0x9c00, 0x9c6c, 216562306a36Sopenharmony_ci 0x9c80, 0x9cec, 216662306a36Sopenharmony_ci 0x9d00, 0x9d6c, 216762306a36Sopenharmony_ci 0x9d80, 0x9dec, 216862306a36Sopenharmony_ci 0x9e00, 0x9e6c, 216962306a36Sopenharmony_ci 0x9e80, 0x9eec, 217062306a36Sopenharmony_ci 0x9f00, 0x9f6c, 217162306a36Sopenharmony_ci 0x9f80, 0xa020, 217262306a36Sopenharmony_ci 0xd000, 0xd03c, 217362306a36Sopenharmony_ci 0xd100, 0xd118, 217462306a36Sopenharmony_ci 0xd200, 0xd214, 217562306a36Sopenharmony_ci 0xd220, 0xd234, 217662306a36Sopenharmony_ci 0xd240, 0xd254, 217762306a36Sopenharmony_ci 0xd260, 0xd274, 217862306a36Sopenharmony_ci 0xd280, 0xd294, 217962306a36Sopenharmony_ci 0xd2a0, 0xd2b4, 218062306a36Sopenharmony_ci 0xd2c0, 0xd2d4, 218162306a36Sopenharmony_ci 0xd2e0, 0xd2f4, 218262306a36Sopenharmony_ci 0xd300, 0xd31c, 218362306a36Sopenharmony_ci 0xdfc0, 0xdfe0, 218462306a36Sopenharmony_ci 0xe000, 0xf008, 218562306a36Sopenharmony_ci 0xf010, 0xf018, 218662306a36Sopenharmony_ci 0xf020, 0xf028, 218762306a36Sopenharmony_ci 0x11000, 0x11014, 218862306a36Sopenharmony_ci 0x11048, 0x1106c, 218962306a36Sopenharmony_ci 0x11074, 0x11088, 219062306a36Sopenharmony_ci 0x11098, 0x11120, 219162306a36Sopenharmony_ci 0x1112c, 0x1117c, 219262306a36Sopenharmony_ci 0x11190, 0x112e0, 219362306a36Sopenharmony_ci 0x11300, 0x1130c, 219462306a36Sopenharmony_ci 0x12000, 0x1206c, 219562306a36Sopenharmony_ci 0x19040, 0x1906c, 219662306a36Sopenharmony_ci 0x19078, 0x19080, 219762306a36Sopenharmony_ci 0x1908c, 0x190e8, 219862306a36Sopenharmony_ci 0x190f0, 0x190f8, 219962306a36Sopenharmony_ci 0x19100, 0x19110, 220062306a36Sopenharmony_ci 0x19120, 0x19124, 220162306a36Sopenharmony_ci 0x19150, 0x19194, 220262306a36Sopenharmony_ci 0x1919c, 0x191b0, 220362306a36Sopenharmony_ci 0x191d0, 0x191e8, 220462306a36Sopenharmony_ci 0x19238, 0x19290, 220562306a36Sopenharmony_ci 0x192a4, 0x192b0, 220662306a36Sopenharmony_ci 0x192bc, 0x192bc, 220762306a36Sopenharmony_ci 0x19348, 0x1934c, 220862306a36Sopenharmony_ci 0x193f8, 0x19418, 220962306a36Sopenharmony_ci 0x19420, 0x19428, 221062306a36Sopenharmony_ci 0x19430, 0x19444, 221162306a36Sopenharmony_ci 0x1944c, 0x1946c, 221262306a36Sopenharmony_ci 0x19474, 0x19474, 221362306a36Sopenharmony_ci 0x19490, 0x194cc, 221462306a36Sopenharmony_ci 0x194f0, 0x194f8, 221562306a36Sopenharmony_ci 0x19c00, 0x19c48, 221662306a36Sopenharmony_ci 0x19c50, 0x19c80, 221762306a36Sopenharmony_ci 0x19c94, 0x19c98, 221862306a36Sopenharmony_ci 0x19ca0, 0x19cbc, 221962306a36Sopenharmony_ci 0x19ce4, 0x19ce4, 222062306a36Sopenharmony_ci 0x19cf0, 0x19cf8, 222162306a36Sopenharmony_ci 0x19d00, 0x19d28, 222262306a36Sopenharmony_ci 0x19d50, 0x19d78, 222362306a36Sopenharmony_ci 0x19d94, 0x19d98, 222462306a36Sopenharmony_ci 0x19da0, 0x19dc8, 222562306a36Sopenharmony_ci 0x19df0, 0x19e10, 222662306a36Sopenharmony_ci 0x19e50, 0x19e6c, 222762306a36Sopenharmony_ci 0x19ea0, 0x19ebc, 222862306a36Sopenharmony_ci 0x19ec4, 0x19ef4, 222962306a36Sopenharmony_ci 0x19f04, 0x19f2c, 223062306a36Sopenharmony_ci 0x19f34, 0x19f34, 223162306a36Sopenharmony_ci 0x19f40, 0x19f50, 223262306a36Sopenharmony_ci 0x19f90, 0x19fac, 223362306a36Sopenharmony_ci 0x19fc4, 0x19fc8, 223462306a36Sopenharmony_ci 0x19fd0, 0x19fe4, 223562306a36Sopenharmony_ci 0x1a000, 0x1a004, 223662306a36Sopenharmony_ci 0x1a010, 0x1a06c, 223762306a36Sopenharmony_ci 0x1a0b0, 0x1a0e4, 223862306a36Sopenharmony_ci 0x1a0ec, 0x1a0f8, 223962306a36Sopenharmony_ci 0x1a100, 0x1a108, 224062306a36Sopenharmony_ci 0x1a114, 0x1a130, 224162306a36Sopenharmony_ci 0x1a138, 0x1a1c4, 224262306a36Sopenharmony_ci 0x1a1fc, 0x1a1fc, 224362306a36Sopenharmony_ci 0x1e008, 0x1e00c, 224462306a36Sopenharmony_ci 0x1e040, 0x1e044, 224562306a36Sopenharmony_ci 0x1e04c, 0x1e04c, 224662306a36Sopenharmony_ci 0x1e284, 0x1e290, 224762306a36Sopenharmony_ci 0x1e2c0, 0x1e2c0, 224862306a36Sopenharmony_ci 0x1e2e0, 0x1e2e0, 224962306a36Sopenharmony_ci 0x1e300, 0x1e384, 225062306a36Sopenharmony_ci 0x1e3c0, 0x1e3c8, 225162306a36Sopenharmony_ci 0x1e408, 0x1e40c, 225262306a36Sopenharmony_ci 0x1e440, 0x1e444, 225362306a36Sopenharmony_ci 0x1e44c, 0x1e44c, 225462306a36Sopenharmony_ci 0x1e684, 0x1e690, 225562306a36Sopenharmony_ci 0x1e6c0, 0x1e6c0, 225662306a36Sopenharmony_ci 0x1e6e0, 0x1e6e0, 225762306a36Sopenharmony_ci 0x1e700, 0x1e784, 225862306a36Sopenharmony_ci 0x1e7c0, 0x1e7c8, 225962306a36Sopenharmony_ci 0x1e808, 0x1e80c, 226062306a36Sopenharmony_ci 0x1e840, 0x1e844, 226162306a36Sopenharmony_ci 0x1e84c, 0x1e84c, 226262306a36Sopenharmony_ci 0x1ea84, 0x1ea90, 226362306a36Sopenharmony_ci 0x1eac0, 0x1eac0, 226462306a36Sopenharmony_ci 0x1eae0, 0x1eae0, 226562306a36Sopenharmony_ci 0x1eb00, 0x1eb84, 226662306a36Sopenharmony_ci 0x1ebc0, 0x1ebc8, 226762306a36Sopenharmony_ci 0x1ec08, 0x1ec0c, 226862306a36Sopenharmony_ci 0x1ec40, 0x1ec44, 226962306a36Sopenharmony_ci 0x1ec4c, 0x1ec4c, 227062306a36Sopenharmony_ci 0x1ee84, 0x1ee90, 227162306a36Sopenharmony_ci 0x1eec0, 0x1eec0, 227262306a36Sopenharmony_ci 0x1eee0, 0x1eee0, 227362306a36Sopenharmony_ci 0x1ef00, 0x1ef84, 227462306a36Sopenharmony_ci 0x1efc0, 0x1efc8, 227562306a36Sopenharmony_ci 0x1f008, 0x1f00c, 227662306a36Sopenharmony_ci 0x1f040, 0x1f044, 227762306a36Sopenharmony_ci 0x1f04c, 0x1f04c, 227862306a36Sopenharmony_ci 0x1f284, 0x1f290, 227962306a36Sopenharmony_ci 0x1f2c0, 0x1f2c0, 228062306a36Sopenharmony_ci 0x1f2e0, 0x1f2e0, 228162306a36Sopenharmony_ci 0x1f300, 0x1f384, 228262306a36Sopenharmony_ci 0x1f3c0, 0x1f3c8, 228362306a36Sopenharmony_ci 0x1f408, 0x1f40c, 228462306a36Sopenharmony_ci 0x1f440, 0x1f444, 228562306a36Sopenharmony_ci 0x1f44c, 0x1f44c, 228662306a36Sopenharmony_ci 0x1f684, 0x1f690, 228762306a36Sopenharmony_ci 0x1f6c0, 0x1f6c0, 228862306a36Sopenharmony_ci 0x1f6e0, 0x1f6e0, 228962306a36Sopenharmony_ci 0x1f700, 0x1f784, 229062306a36Sopenharmony_ci 0x1f7c0, 0x1f7c8, 229162306a36Sopenharmony_ci 0x1f808, 0x1f80c, 229262306a36Sopenharmony_ci 0x1f840, 0x1f844, 229362306a36Sopenharmony_ci 0x1f84c, 0x1f84c, 229462306a36Sopenharmony_ci 0x1fa84, 0x1fa90, 229562306a36Sopenharmony_ci 0x1fac0, 0x1fac0, 229662306a36Sopenharmony_ci 0x1fae0, 0x1fae0, 229762306a36Sopenharmony_ci 0x1fb00, 0x1fb84, 229862306a36Sopenharmony_ci 0x1fbc0, 0x1fbc8, 229962306a36Sopenharmony_ci 0x1fc08, 0x1fc0c, 230062306a36Sopenharmony_ci 0x1fc40, 0x1fc44, 230162306a36Sopenharmony_ci 0x1fc4c, 0x1fc4c, 230262306a36Sopenharmony_ci 0x1fe84, 0x1fe90, 230362306a36Sopenharmony_ci 0x1fec0, 0x1fec0, 230462306a36Sopenharmony_ci 0x1fee0, 0x1fee0, 230562306a36Sopenharmony_ci 0x1ff00, 0x1ff84, 230662306a36Sopenharmony_ci 0x1ffc0, 0x1ffc8, 230762306a36Sopenharmony_ci 0x30000, 0x30030, 230862306a36Sopenharmony_ci 0x30100, 0x30168, 230962306a36Sopenharmony_ci 0x30190, 0x301a0, 231062306a36Sopenharmony_ci 0x301a8, 0x301b8, 231162306a36Sopenharmony_ci 0x301c4, 0x301c8, 231262306a36Sopenharmony_ci 0x301d0, 0x301d0, 231362306a36Sopenharmony_ci 0x30200, 0x30320, 231462306a36Sopenharmony_ci 0x30400, 0x304b4, 231562306a36Sopenharmony_ci 0x304c0, 0x3052c, 231662306a36Sopenharmony_ci 0x30540, 0x3061c, 231762306a36Sopenharmony_ci 0x30800, 0x308a0, 231862306a36Sopenharmony_ci 0x308c0, 0x30908, 231962306a36Sopenharmony_ci 0x30910, 0x309b8, 232062306a36Sopenharmony_ci 0x30a00, 0x30a04, 232162306a36Sopenharmony_ci 0x30a0c, 0x30a14, 232262306a36Sopenharmony_ci 0x30a1c, 0x30a2c, 232362306a36Sopenharmony_ci 0x30a44, 0x30a50, 232462306a36Sopenharmony_ci 0x30a74, 0x30a74, 232562306a36Sopenharmony_ci 0x30a7c, 0x30afc, 232662306a36Sopenharmony_ci 0x30b08, 0x30c24, 232762306a36Sopenharmony_ci 0x30d00, 0x30d14, 232862306a36Sopenharmony_ci 0x30d1c, 0x30d3c, 232962306a36Sopenharmony_ci 0x30d44, 0x30d4c, 233062306a36Sopenharmony_ci 0x30d54, 0x30d74, 233162306a36Sopenharmony_ci 0x30d7c, 0x30d7c, 233262306a36Sopenharmony_ci 0x30de0, 0x30de0, 233362306a36Sopenharmony_ci 0x30e00, 0x30ed4, 233462306a36Sopenharmony_ci 0x30f00, 0x30fa4, 233562306a36Sopenharmony_ci 0x30fc0, 0x30fc4, 233662306a36Sopenharmony_ci 0x31000, 0x31004, 233762306a36Sopenharmony_ci 0x31080, 0x310fc, 233862306a36Sopenharmony_ci 0x31208, 0x31220, 233962306a36Sopenharmony_ci 0x3123c, 0x31254, 234062306a36Sopenharmony_ci 0x31300, 0x31300, 234162306a36Sopenharmony_ci 0x31308, 0x3131c, 234262306a36Sopenharmony_ci 0x31338, 0x3133c, 234362306a36Sopenharmony_ci 0x31380, 0x31380, 234462306a36Sopenharmony_ci 0x31388, 0x313a8, 234562306a36Sopenharmony_ci 0x313b4, 0x313b4, 234662306a36Sopenharmony_ci 0x31400, 0x31420, 234762306a36Sopenharmony_ci 0x31438, 0x3143c, 234862306a36Sopenharmony_ci 0x31480, 0x31480, 234962306a36Sopenharmony_ci 0x314a8, 0x314a8, 235062306a36Sopenharmony_ci 0x314b0, 0x314b4, 235162306a36Sopenharmony_ci 0x314c8, 0x314d4, 235262306a36Sopenharmony_ci 0x31a40, 0x31a4c, 235362306a36Sopenharmony_ci 0x31af0, 0x31b20, 235462306a36Sopenharmony_ci 0x31b38, 0x31b3c, 235562306a36Sopenharmony_ci 0x31b80, 0x31b80, 235662306a36Sopenharmony_ci 0x31ba8, 0x31ba8, 235762306a36Sopenharmony_ci 0x31bb0, 0x31bb4, 235862306a36Sopenharmony_ci 0x31bc8, 0x31bd4, 235962306a36Sopenharmony_ci 0x32140, 0x3218c, 236062306a36Sopenharmony_ci 0x321f0, 0x321f4, 236162306a36Sopenharmony_ci 0x32200, 0x32200, 236262306a36Sopenharmony_ci 0x32218, 0x32218, 236362306a36Sopenharmony_ci 0x32400, 0x32400, 236462306a36Sopenharmony_ci 0x32408, 0x3241c, 236562306a36Sopenharmony_ci 0x32618, 0x32620, 236662306a36Sopenharmony_ci 0x32664, 0x32664, 236762306a36Sopenharmony_ci 0x326a8, 0x326a8, 236862306a36Sopenharmony_ci 0x326ec, 0x326ec, 236962306a36Sopenharmony_ci 0x32a00, 0x32abc, 237062306a36Sopenharmony_ci 0x32b00, 0x32b18, 237162306a36Sopenharmony_ci 0x32b20, 0x32b38, 237262306a36Sopenharmony_ci 0x32b40, 0x32b58, 237362306a36Sopenharmony_ci 0x32b60, 0x32b78, 237462306a36Sopenharmony_ci 0x32c00, 0x32c00, 237562306a36Sopenharmony_ci 0x32c08, 0x32c3c, 237662306a36Sopenharmony_ci 0x33000, 0x3302c, 237762306a36Sopenharmony_ci 0x33034, 0x33050, 237862306a36Sopenharmony_ci 0x33058, 0x33058, 237962306a36Sopenharmony_ci 0x33060, 0x3308c, 238062306a36Sopenharmony_ci 0x3309c, 0x330ac, 238162306a36Sopenharmony_ci 0x330c0, 0x330c0, 238262306a36Sopenharmony_ci 0x330c8, 0x330d0, 238362306a36Sopenharmony_ci 0x330d8, 0x330e0, 238462306a36Sopenharmony_ci 0x330ec, 0x3312c, 238562306a36Sopenharmony_ci 0x33134, 0x33150, 238662306a36Sopenharmony_ci 0x33158, 0x33158, 238762306a36Sopenharmony_ci 0x33160, 0x3318c, 238862306a36Sopenharmony_ci 0x3319c, 0x331ac, 238962306a36Sopenharmony_ci 0x331c0, 0x331c0, 239062306a36Sopenharmony_ci 0x331c8, 0x331d0, 239162306a36Sopenharmony_ci 0x331d8, 0x331e0, 239262306a36Sopenharmony_ci 0x331ec, 0x33290, 239362306a36Sopenharmony_ci 0x33298, 0x332c4, 239462306a36Sopenharmony_ci 0x332e4, 0x33390, 239562306a36Sopenharmony_ci 0x33398, 0x333c4, 239662306a36Sopenharmony_ci 0x333e4, 0x3342c, 239762306a36Sopenharmony_ci 0x33434, 0x33450, 239862306a36Sopenharmony_ci 0x33458, 0x33458, 239962306a36Sopenharmony_ci 0x33460, 0x3348c, 240062306a36Sopenharmony_ci 0x3349c, 0x334ac, 240162306a36Sopenharmony_ci 0x334c0, 0x334c0, 240262306a36Sopenharmony_ci 0x334c8, 0x334d0, 240362306a36Sopenharmony_ci 0x334d8, 0x334e0, 240462306a36Sopenharmony_ci 0x334ec, 0x3352c, 240562306a36Sopenharmony_ci 0x33534, 0x33550, 240662306a36Sopenharmony_ci 0x33558, 0x33558, 240762306a36Sopenharmony_ci 0x33560, 0x3358c, 240862306a36Sopenharmony_ci 0x3359c, 0x335ac, 240962306a36Sopenharmony_ci 0x335c0, 0x335c0, 241062306a36Sopenharmony_ci 0x335c8, 0x335d0, 241162306a36Sopenharmony_ci 0x335d8, 0x335e0, 241262306a36Sopenharmony_ci 0x335ec, 0x33690, 241362306a36Sopenharmony_ci 0x33698, 0x336c4, 241462306a36Sopenharmony_ci 0x336e4, 0x33790, 241562306a36Sopenharmony_ci 0x33798, 0x337c4, 241662306a36Sopenharmony_ci 0x337e4, 0x337fc, 241762306a36Sopenharmony_ci 0x33814, 0x33814, 241862306a36Sopenharmony_ci 0x33854, 0x33868, 241962306a36Sopenharmony_ci 0x33880, 0x3388c, 242062306a36Sopenharmony_ci 0x338c0, 0x338d0, 242162306a36Sopenharmony_ci 0x338e8, 0x338ec, 242262306a36Sopenharmony_ci 0x33900, 0x3392c, 242362306a36Sopenharmony_ci 0x33934, 0x33950, 242462306a36Sopenharmony_ci 0x33958, 0x33958, 242562306a36Sopenharmony_ci 0x33960, 0x3398c, 242662306a36Sopenharmony_ci 0x3399c, 0x339ac, 242762306a36Sopenharmony_ci 0x339c0, 0x339c0, 242862306a36Sopenharmony_ci 0x339c8, 0x339d0, 242962306a36Sopenharmony_ci 0x339d8, 0x339e0, 243062306a36Sopenharmony_ci 0x339ec, 0x33a90, 243162306a36Sopenharmony_ci 0x33a98, 0x33ac4, 243262306a36Sopenharmony_ci 0x33ae4, 0x33b10, 243362306a36Sopenharmony_ci 0x33b24, 0x33b28, 243462306a36Sopenharmony_ci 0x33b38, 0x33b50, 243562306a36Sopenharmony_ci 0x33bf0, 0x33c10, 243662306a36Sopenharmony_ci 0x33c24, 0x33c28, 243762306a36Sopenharmony_ci 0x33c38, 0x33c50, 243862306a36Sopenharmony_ci 0x33cf0, 0x33cfc, 243962306a36Sopenharmony_ci 0x34000, 0x34030, 244062306a36Sopenharmony_ci 0x34100, 0x34168, 244162306a36Sopenharmony_ci 0x34190, 0x341a0, 244262306a36Sopenharmony_ci 0x341a8, 0x341b8, 244362306a36Sopenharmony_ci 0x341c4, 0x341c8, 244462306a36Sopenharmony_ci 0x341d0, 0x341d0, 244562306a36Sopenharmony_ci 0x34200, 0x34320, 244662306a36Sopenharmony_ci 0x34400, 0x344b4, 244762306a36Sopenharmony_ci 0x344c0, 0x3452c, 244862306a36Sopenharmony_ci 0x34540, 0x3461c, 244962306a36Sopenharmony_ci 0x34800, 0x348a0, 245062306a36Sopenharmony_ci 0x348c0, 0x34908, 245162306a36Sopenharmony_ci 0x34910, 0x349b8, 245262306a36Sopenharmony_ci 0x34a00, 0x34a04, 245362306a36Sopenharmony_ci 0x34a0c, 0x34a14, 245462306a36Sopenharmony_ci 0x34a1c, 0x34a2c, 245562306a36Sopenharmony_ci 0x34a44, 0x34a50, 245662306a36Sopenharmony_ci 0x34a74, 0x34a74, 245762306a36Sopenharmony_ci 0x34a7c, 0x34afc, 245862306a36Sopenharmony_ci 0x34b08, 0x34c24, 245962306a36Sopenharmony_ci 0x34d00, 0x34d14, 246062306a36Sopenharmony_ci 0x34d1c, 0x34d3c, 246162306a36Sopenharmony_ci 0x34d44, 0x34d4c, 246262306a36Sopenharmony_ci 0x34d54, 0x34d74, 246362306a36Sopenharmony_ci 0x34d7c, 0x34d7c, 246462306a36Sopenharmony_ci 0x34de0, 0x34de0, 246562306a36Sopenharmony_ci 0x34e00, 0x34ed4, 246662306a36Sopenharmony_ci 0x34f00, 0x34fa4, 246762306a36Sopenharmony_ci 0x34fc0, 0x34fc4, 246862306a36Sopenharmony_ci 0x35000, 0x35004, 246962306a36Sopenharmony_ci 0x35080, 0x350fc, 247062306a36Sopenharmony_ci 0x35208, 0x35220, 247162306a36Sopenharmony_ci 0x3523c, 0x35254, 247262306a36Sopenharmony_ci 0x35300, 0x35300, 247362306a36Sopenharmony_ci 0x35308, 0x3531c, 247462306a36Sopenharmony_ci 0x35338, 0x3533c, 247562306a36Sopenharmony_ci 0x35380, 0x35380, 247662306a36Sopenharmony_ci 0x35388, 0x353a8, 247762306a36Sopenharmony_ci 0x353b4, 0x353b4, 247862306a36Sopenharmony_ci 0x35400, 0x35420, 247962306a36Sopenharmony_ci 0x35438, 0x3543c, 248062306a36Sopenharmony_ci 0x35480, 0x35480, 248162306a36Sopenharmony_ci 0x354a8, 0x354a8, 248262306a36Sopenharmony_ci 0x354b0, 0x354b4, 248362306a36Sopenharmony_ci 0x354c8, 0x354d4, 248462306a36Sopenharmony_ci 0x35a40, 0x35a4c, 248562306a36Sopenharmony_ci 0x35af0, 0x35b20, 248662306a36Sopenharmony_ci 0x35b38, 0x35b3c, 248762306a36Sopenharmony_ci 0x35b80, 0x35b80, 248862306a36Sopenharmony_ci 0x35ba8, 0x35ba8, 248962306a36Sopenharmony_ci 0x35bb0, 0x35bb4, 249062306a36Sopenharmony_ci 0x35bc8, 0x35bd4, 249162306a36Sopenharmony_ci 0x36140, 0x3618c, 249262306a36Sopenharmony_ci 0x361f0, 0x361f4, 249362306a36Sopenharmony_ci 0x36200, 0x36200, 249462306a36Sopenharmony_ci 0x36218, 0x36218, 249562306a36Sopenharmony_ci 0x36400, 0x36400, 249662306a36Sopenharmony_ci 0x36408, 0x3641c, 249762306a36Sopenharmony_ci 0x36618, 0x36620, 249862306a36Sopenharmony_ci 0x36664, 0x36664, 249962306a36Sopenharmony_ci 0x366a8, 0x366a8, 250062306a36Sopenharmony_ci 0x366ec, 0x366ec, 250162306a36Sopenharmony_ci 0x36a00, 0x36abc, 250262306a36Sopenharmony_ci 0x36b00, 0x36b18, 250362306a36Sopenharmony_ci 0x36b20, 0x36b38, 250462306a36Sopenharmony_ci 0x36b40, 0x36b58, 250562306a36Sopenharmony_ci 0x36b60, 0x36b78, 250662306a36Sopenharmony_ci 0x36c00, 0x36c00, 250762306a36Sopenharmony_ci 0x36c08, 0x36c3c, 250862306a36Sopenharmony_ci 0x37000, 0x3702c, 250962306a36Sopenharmony_ci 0x37034, 0x37050, 251062306a36Sopenharmony_ci 0x37058, 0x37058, 251162306a36Sopenharmony_ci 0x37060, 0x3708c, 251262306a36Sopenharmony_ci 0x3709c, 0x370ac, 251362306a36Sopenharmony_ci 0x370c0, 0x370c0, 251462306a36Sopenharmony_ci 0x370c8, 0x370d0, 251562306a36Sopenharmony_ci 0x370d8, 0x370e0, 251662306a36Sopenharmony_ci 0x370ec, 0x3712c, 251762306a36Sopenharmony_ci 0x37134, 0x37150, 251862306a36Sopenharmony_ci 0x37158, 0x37158, 251962306a36Sopenharmony_ci 0x37160, 0x3718c, 252062306a36Sopenharmony_ci 0x3719c, 0x371ac, 252162306a36Sopenharmony_ci 0x371c0, 0x371c0, 252262306a36Sopenharmony_ci 0x371c8, 0x371d0, 252362306a36Sopenharmony_ci 0x371d8, 0x371e0, 252462306a36Sopenharmony_ci 0x371ec, 0x37290, 252562306a36Sopenharmony_ci 0x37298, 0x372c4, 252662306a36Sopenharmony_ci 0x372e4, 0x37390, 252762306a36Sopenharmony_ci 0x37398, 0x373c4, 252862306a36Sopenharmony_ci 0x373e4, 0x3742c, 252962306a36Sopenharmony_ci 0x37434, 0x37450, 253062306a36Sopenharmony_ci 0x37458, 0x37458, 253162306a36Sopenharmony_ci 0x37460, 0x3748c, 253262306a36Sopenharmony_ci 0x3749c, 0x374ac, 253362306a36Sopenharmony_ci 0x374c0, 0x374c0, 253462306a36Sopenharmony_ci 0x374c8, 0x374d0, 253562306a36Sopenharmony_ci 0x374d8, 0x374e0, 253662306a36Sopenharmony_ci 0x374ec, 0x3752c, 253762306a36Sopenharmony_ci 0x37534, 0x37550, 253862306a36Sopenharmony_ci 0x37558, 0x37558, 253962306a36Sopenharmony_ci 0x37560, 0x3758c, 254062306a36Sopenharmony_ci 0x3759c, 0x375ac, 254162306a36Sopenharmony_ci 0x375c0, 0x375c0, 254262306a36Sopenharmony_ci 0x375c8, 0x375d0, 254362306a36Sopenharmony_ci 0x375d8, 0x375e0, 254462306a36Sopenharmony_ci 0x375ec, 0x37690, 254562306a36Sopenharmony_ci 0x37698, 0x376c4, 254662306a36Sopenharmony_ci 0x376e4, 0x37790, 254762306a36Sopenharmony_ci 0x37798, 0x377c4, 254862306a36Sopenharmony_ci 0x377e4, 0x377fc, 254962306a36Sopenharmony_ci 0x37814, 0x37814, 255062306a36Sopenharmony_ci 0x37854, 0x37868, 255162306a36Sopenharmony_ci 0x37880, 0x3788c, 255262306a36Sopenharmony_ci 0x378c0, 0x378d0, 255362306a36Sopenharmony_ci 0x378e8, 0x378ec, 255462306a36Sopenharmony_ci 0x37900, 0x3792c, 255562306a36Sopenharmony_ci 0x37934, 0x37950, 255662306a36Sopenharmony_ci 0x37958, 0x37958, 255762306a36Sopenharmony_ci 0x37960, 0x3798c, 255862306a36Sopenharmony_ci 0x3799c, 0x379ac, 255962306a36Sopenharmony_ci 0x379c0, 0x379c0, 256062306a36Sopenharmony_ci 0x379c8, 0x379d0, 256162306a36Sopenharmony_ci 0x379d8, 0x379e0, 256262306a36Sopenharmony_ci 0x379ec, 0x37a90, 256362306a36Sopenharmony_ci 0x37a98, 0x37ac4, 256462306a36Sopenharmony_ci 0x37ae4, 0x37b10, 256562306a36Sopenharmony_ci 0x37b24, 0x37b28, 256662306a36Sopenharmony_ci 0x37b38, 0x37b50, 256762306a36Sopenharmony_ci 0x37bf0, 0x37c10, 256862306a36Sopenharmony_ci 0x37c24, 0x37c28, 256962306a36Sopenharmony_ci 0x37c38, 0x37c50, 257062306a36Sopenharmony_ci 0x37cf0, 0x37cfc, 257162306a36Sopenharmony_ci 0x40040, 0x40040, 257262306a36Sopenharmony_ci 0x40080, 0x40084, 257362306a36Sopenharmony_ci 0x40100, 0x40100, 257462306a36Sopenharmony_ci 0x40140, 0x401bc, 257562306a36Sopenharmony_ci 0x40200, 0x40214, 257662306a36Sopenharmony_ci 0x40228, 0x40228, 257762306a36Sopenharmony_ci 0x40240, 0x40258, 257862306a36Sopenharmony_ci 0x40280, 0x40280, 257962306a36Sopenharmony_ci 0x40304, 0x40304, 258062306a36Sopenharmony_ci 0x40330, 0x4033c, 258162306a36Sopenharmony_ci 0x41304, 0x413c8, 258262306a36Sopenharmony_ci 0x413d0, 0x413dc, 258362306a36Sopenharmony_ci 0x413f0, 0x413f0, 258462306a36Sopenharmony_ci 0x41400, 0x4140c, 258562306a36Sopenharmony_ci 0x41414, 0x4141c, 258662306a36Sopenharmony_ci 0x41480, 0x414d0, 258762306a36Sopenharmony_ci 0x44000, 0x4407c, 258862306a36Sopenharmony_ci 0x440c0, 0x441ac, 258962306a36Sopenharmony_ci 0x441b4, 0x4427c, 259062306a36Sopenharmony_ci 0x442c0, 0x443ac, 259162306a36Sopenharmony_ci 0x443b4, 0x4447c, 259262306a36Sopenharmony_ci 0x444c0, 0x445ac, 259362306a36Sopenharmony_ci 0x445b4, 0x4467c, 259462306a36Sopenharmony_ci 0x446c0, 0x447ac, 259562306a36Sopenharmony_ci 0x447b4, 0x4487c, 259662306a36Sopenharmony_ci 0x448c0, 0x449ac, 259762306a36Sopenharmony_ci 0x449b4, 0x44a7c, 259862306a36Sopenharmony_ci 0x44ac0, 0x44bac, 259962306a36Sopenharmony_ci 0x44bb4, 0x44c7c, 260062306a36Sopenharmony_ci 0x44cc0, 0x44dac, 260162306a36Sopenharmony_ci 0x44db4, 0x44e7c, 260262306a36Sopenharmony_ci 0x44ec0, 0x44fac, 260362306a36Sopenharmony_ci 0x44fb4, 0x4507c, 260462306a36Sopenharmony_ci 0x450c0, 0x451ac, 260562306a36Sopenharmony_ci 0x451b4, 0x451fc, 260662306a36Sopenharmony_ci 0x45800, 0x45804, 260762306a36Sopenharmony_ci 0x45810, 0x45830, 260862306a36Sopenharmony_ci 0x45840, 0x45860, 260962306a36Sopenharmony_ci 0x45868, 0x45868, 261062306a36Sopenharmony_ci 0x45880, 0x45884, 261162306a36Sopenharmony_ci 0x458a0, 0x458b0, 261262306a36Sopenharmony_ci 0x45a00, 0x45a04, 261362306a36Sopenharmony_ci 0x45a10, 0x45a30, 261462306a36Sopenharmony_ci 0x45a40, 0x45a60, 261562306a36Sopenharmony_ci 0x45a68, 0x45a68, 261662306a36Sopenharmony_ci 0x45a80, 0x45a84, 261762306a36Sopenharmony_ci 0x45aa0, 0x45ab0, 261862306a36Sopenharmony_ci 0x460c0, 0x460e4, 261962306a36Sopenharmony_ci 0x47000, 0x4703c, 262062306a36Sopenharmony_ci 0x47044, 0x4708c, 262162306a36Sopenharmony_ci 0x47200, 0x47250, 262262306a36Sopenharmony_ci 0x47400, 0x47408, 262362306a36Sopenharmony_ci 0x47414, 0x47420, 262462306a36Sopenharmony_ci 0x47600, 0x47618, 262562306a36Sopenharmony_ci 0x47800, 0x47814, 262662306a36Sopenharmony_ci 0x47820, 0x4782c, 262762306a36Sopenharmony_ci 0x50000, 0x50084, 262862306a36Sopenharmony_ci 0x50090, 0x500cc, 262962306a36Sopenharmony_ci 0x50300, 0x50384, 263062306a36Sopenharmony_ci 0x50400, 0x50400, 263162306a36Sopenharmony_ci 0x50800, 0x50884, 263262306a36Sopenharmony_ci 0x50890, 0x508cc, 263362306a36Sopenharmony_ci 0x50b00, 0x50b84, 263462306a36Sopenharmony_ci 0x50c00, 0x50c00, 263562306a36Sopenharmony_ci 0x51000, 0x51020, 263662306a36Sopenharmony_ci 0x51028, 0x510b0, 263762306a36Sopenharmony_ci 0x51300, 0x51324, 263862306a36Sopenharmony_ci }; 263962306a36Sopenharmony_ci 264062306a36Sopenharmony_ci u32 *buf_end = (u32 *)((char *)buf + buf_size); 264162306a36Sopenharmony_ci const unsigned int *reg_ranges; 264262306a36Sopenharmony_ci int reg_ranges_size, range; 264362306a36Sopenharmony_ci unsigned int chip_version = CHELSIO_CHIP_VERSION(adap->params.chip); 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci /* Select the right set of register ranges to dump depending on the 264662306a36Sopenharmony_ci * adapter chip type. 264762306a36Sopenharmony_ci */ 264862306a36Sopenharmony_ci switch (chip_version) { 264962306a36Sopenharmony_ci case CHELSIO_T4: 265062306a36Sopenharmony_ci reg_ranges = t4_reg_ranges; 265162306a36Sopenharmony_ci reg_ranges_size = ARRAY_SIZE(t4_reg_ranges); 265262306a36Sopenharmony_ci break; 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci case CHELSIO_T5: 265562306a36Sopenharmony_ci reg_ranges = t5_reg_ranges; 265662306a36Sopenharmony_ci reg_ranges_size = ARRAY_SIZE(t5_reg_ranges); 265762306a36Sopenharmony_ci break; 265862306a36Sopenharmony_ci 265962306a36Sopenharmony_ci case CHELSIO_T6: 266062306a36Sopenharmony_ci reg_ranges = t6_reg_ranges; 266162306a36Sopenharmony_ci reg_ranges_size = ARRAY_SIZE(t6_reg_ranges); 266262306a36Sopenharmony_ci break; 266362306a36Sopenharmony_ci 266462306a36Sopenharmony_ci default: 266562306a36Sopenharmony_ci dev_err(adap->pdev_dev, 266662306a36Sopenharmony_ci "Unsupported chip version %d\n", chip_version); 266762306a36Sopenharmony_ci return; 266862306a36Sopenharmony_ci } 266962306a36Sopenharmony_ci 267062306a36Sopenharmony_ci /* Clear the register buffer and insert the appropriate register 267162306a36Sopenharmony_ci * values selected by the above register ranges. 267262306a36Sopenharmony_ci */ 267362306a36Sopenharmony_ci memset(buf, 0, buf_size); 267462306a36Sopenharmony_ci for (range = 0; range < reg_ranges_size; range += 2) { 267562306a36Sopenharmony_ci unsigned int reg = reg_ranges[range]; 267662306a36Sopenharmony_ci unsigned int last_reg = reg_ranges[range + 1]; 267762306a36Sopenharmony_ci u32 *bufp = (u32 *)((char *)buf + reg); 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci /* Iterate across the register range filling in the register 268062306a36Sopenharmony_ci * buffer but don't write past the end of the register buffer. 268162306a36Sopenharmony_ci */ 268262306a36Sopenharmony_ci while (reg <= last_reg && bufp < buf_end) { 268362306a36Sopenharmony_ci *bufp++ = t4_read_reg(adap, reg); 268462306a36Sopenharmony_ci reg += sizeof(u32); 268562306a36Sopenharmony_ci } 268662306a36Sopenharmony_ci } 268762306a36Sopenharmony_ci} 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_ci#define EEPROM_STAT_ADDR 0x7bfc 269062306a36Sopenharmony_ci#define VPD_BASE 0x400 269162306a36Sopenharmony_ci#define VPD_BASE_OLD 0 269262306a36Sopenharmony_ci#define VPD_LEN 1024 269362306a36Sopenharmony_ci 269462306a36Sopenharmony_ci/** 269562306a36Sopenharmony_ci * t4_eeprom_ptov - translate a physical EEPROM address to virtual 269662306a36Sopenharmony_ci * @phys_addr: the physical EEPROM address 269762306a36Sopenharmony_ci * @fn: the PCI function number 269862306a36Sopenharmony_ci * @sz: size of function-specific area 269962306a36Sopenharmony_ci * 270062306a36Sopenharmony_ci * Translate a physical EEPROM address to virtual. The first 1K is 270162306a36Sopenharmony_ci * accessed through virtual addresses starting at 31K, the rest is 270262306a36Sopenharmony_ci * accessed through virtual addresses starting at 0. 270362306a36Sopenharmony_ci * 270462306a36Sopenharmony_ci * The mapping is as follows: 270562306a36Sopenharmony_ci * [0..1K) -> [31K..32K) 270662306a36Sopenharmony_ci * [1K..1K+A) -> [31K-A..31K) 270762306a36Sopenharmony_ci * [1K+A..ES) -> [0..ES-A-1K) 270862306a36Sopenharmony_ci * 270962306a36Sopenharmony_ci * where A = @fn * @sz, and ES = EEPROM size. 271062306a36Sopenharmony_ci */ 271162306a36Sopenharmony_ciint t4_eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz) 271262306a36Sopenharmony_ci{ 271362306a36Sopenharmony_ci fn *= sz; 271462306a36Sopenharmony_ci if (phys_addr < 1024) 271562306a36Sopenharmony_ci return phys_addr + (31 << 10); 271662306a36Sopenharmony_ci if (phys_addr < 1024 + fn) 271762306a36Sopenharmony_ci return 31744 - fn + phys_addr - 1024; 271862306a36Sopenharmony_ci if (phys_addr < EEPROMSIZE) 271962306a36Sopenharmony_ci return phys_addr - 1024 - fn; 272062306a36Sopenharmony_ci return -EINVAL; 272162306a36Sopenharmony_ci} 272262306a36Sopenharmony_ci 272362306a36Sopenharmony_ci/** 272462306a36Sopenharmony_ci * t4_seeprom_wp - enable/disable EEPROM write protection 272562306a36Sopenharmony_ci * @adapter: the adapter 272662306a36Sopenharmony_ci * @enable: whether to enable or disable write protection 272762306a36Sopenharmony_ci * 272862306a36Sopenharmony_ci * Enables or disables write protection on the serial EEPROM. 272962306a36Sopenharmony_ci */ 273062306a36Sopenharmony_ciint t4_seeprom_wp(struct adapter *adapter, bool enable) 273162306a36Sopenharmony_ci{ 273262306a36Sopenharmony_ci unsigned int v = enable ? 0xc : 0; 273362306a36Sopenharmony_ci int ret = pci_write_vpd(adapter->pdev, EEPROM_STAT_ADDR, 4, &v); 273462306a36Sopenharmony_ci return ret < 0 ? ret : 0; 273562306a36Sopenharmony_ci} 273662306a36Sopenharmony_ci 273762306a36Sopenharmony_ci/** 273862306a36Sopenharmony_ci * t4_get_raw_vpd_params - read VPD parameters from VPD EEPROM 273962306a36Sopenharmony_ci * @adapter: adapter to read 274062306a36Sopenharmony_ci * @p: where to store the parameters 274162306a36Sopenharmony_ci * 274262306a36Sopenharmony_ci * Reads card parameters stored in VPD EEPROM. 274362306a36Sopenharmony_ci */ 274462306a36Sopenharmony_ciint t4_get_raw_vpd_params(struct adapter *adapter, struct vpd_params *p) 274562306a36Sopenharmony_ci{ 274662306a36Sopenharmony_ci unsigned int id_len, pn_len, sn_len, na_len; 274762306a36Sopenharmony_ci int id, sn, pn, na, addr, ret = 0; 274862306a36Sopenharmony_ci u8 *vpd, base_val = 0; 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_ci vpd = vmalloc(VPD_LEN); 275162306a36Sopenharmony_ci if (!vpd) 275262306a36Sopenharmony_ci return -ENOMEM; 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_ci /* Card information normally starts at VPD_BASE but early cards had 275562306a36Sopenharmony_ci * it at 0. 275662306a36Sopenharmony_ci */ 275762306a36Sopenharmony_ci ret = pci_read_vpd(adapter->pdev, VPD_BASE, 1, &base_val); 275862306a36Sopenharmony_ci if (ret < 0) 275962306a36Sopenharmony_ci goto out; 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci addr = base_val == PCI_VPD_LRDT_ID_STRING ? VPD_BASE : VPD_BASE_OLD; 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_ci ret = pci_read_vpd(adapter->pdev, addr, VPD_LEN, vpd); 276462306a36Sopenharmony_ci if (ret < 0) 276562306a36Sopenharmony_ci goto out; 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci ret = pci_vpd_find_id_string(vpd, VPD_LEN, &id_len); 276862306a36Sopenharmony_ci if (ret < 0) 276962306a36Sopenharmony_ci goto out; 277062306a36Sopenharmony_ci id = ret; 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ci ret = pci_vpd_check_csum(vpd, VPD_LEN); 277362306a36Sopenharmony_ci if (ret) { 277462306a36Sopenharmony_ci dev_err(adapter->pdev_dev, "VPD checksum incorrect or missing\n"); 277562306a36Sopenharmony_ci ret = -EINVAL; 277662306a36Sopenharmony_ci goto out; 277762306a36Sopenharmony_ci } 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci ret = pci_vpd_find_ro_info_keyword(vpd, VPD_LEN, 278062306a36Sopenharmony_ci PCI_VPD_RO_KEYWORD_SERIALNO, &sn_len); 278162306a36Sopenharmony_ci if (ret < 0) 278262306a36Sopenharmony_ci goto out; 278362306a36Sopenharmony_ci sn = ret; 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_ci ret = pci_vpd_find_ro_info_keyword(vpd, VPD_LEN, 278662306a36Sopenharmony_ci PCI_VPD_RO_KEYWORD_PARTNO, &pn_len); 278762306a36Sopenharmony_ci if (ret < 0) 278862306a36Sopenharmony_ci goto out; 278962306a36Sopenharmony_ci pn = ret; 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci ret = pci_vpd_find_ro_info_keyword(vpd, VPD_LEN, "NA", &na_len); 279262306a36Sopenharmony_ci if (ret < 0) 279362306a36Sopenharmony_ci goto out; 279462306a36Sopenharmony_ci na = ret; 279562306a36Sopenharmony_ci 279662306a36Sopenharmony_ci memcpy(p->id, vpd + id, min_t(unsigned int, id_len, ID_LEN)); 279762306a36Sopenharmony_ci strim(p->id); 279862306a36Sopenharmony_ci memcpy(p->sn, vpd + sn, min_t(unsigned int, sn_len, SERNUM_LEN)); 279962306a36Sopenharmony_ci strim(p->sn); 280062306a36Sopenharmony_ci memcpy(p->pn, vpd + pn, min_t(unsigned int, pn_len, PN_LEN)); 280162306a36Sopenharmony_ci strim(p->pn); 280262306a36Sopenharmony_ci memcpy(p->na, vpd + na, min_t(unsigned int, na_len, MACADDR_LEN)); 280362306a36Sopenharmony_ci strim(p->na); 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_ciout: 280662306a36Sopenharmony_ci vfree(vpd); 280762306a36Sopenharmony_ci if (ret < 0) { 280862306a36Sopenharmony_ci dev_err(adapter->pdev_dev, "error reading VPD\n"); 280962306a36Sopenharmony_ci return ret; 281062306a36Sopenharmony_ci } 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci return 0; 281362306a36Sopenharmony_ci} 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci/** 281662306a36Sopenharmony_ci * t4_get_vpd_params - read VPD parameters & retrieve Core Clock 281762306a36Sopenharmony_ci * @adapter: adapter to read 281862306a36Sopenharmony_ci * @p: where to store the parameters 281962306a36Sopenharmony_ci * 282062306a36Sopenharmony_ci * Reads card parameters stored in VPD EEPROM and retrieves the Core 282162306a36Sopenharmony_ci * Clock. This can only be called after a connection to the firmware 282262306a36Sopenharmony_ci * is established. 282362306a36Sopenharmony_ci */ 282462306a36Sopenharmony_ciint t4_get_vpd_params(struct adapter *adapter, struct vpd_params *p) 282562306a36Sopenharmony_ci{ 282662306a36Sopenharmony_ci u32 cclk_param, cclk_val; 282762306a36Sopenharmony_ci int ret; 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ci /* Grab the raw VPD parameters. 283062306a36Sopenharmony_ci */ 283162306a36Sopenharmony_ci ret = t4_get_raw_vpd_params(adapter, p); 283262306a36Sopenharmony_ci if (ret) 283362306a36Sopenharmony_ci return ret; 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ci /* Ask firmware for the Core Clock since it knows how to translate the 283662306a36Sopenharmony_ci * Reference Clock ('V2') VPD field into a Core Clock value ... 283762306a36Sopenharmony_ci */ 283862306a36Sopenharmony_ci cclk_param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 283962306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CCLK)); 284062306a36Sopenharmony_ci ret = t4_query_params(adapter, adapter->mbox, adapter->pf, 0, 284162306a36Sopenharmony_ci 1, &cclk_param, &cclk_val); 284262306a36Sopenharmony_ci 284362306a36Sopenharmony_ci if (ret) 284462306a36Sopenharmony_ci return ret; 284562306a36Sopenharmony_ci p->cclk = cclk_val; 284662306a36Sopenharmony_ci 284762306a36Sopenharmony_ci return 0; 284862306a36Sopenharmony_ci} 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci/** 285162306a36Sopenharmony_ci * t4_get_pfres - retrieve VF resource limits 285262306a36Sopenharmony_ci * @adapter: the adapter 285362306a36Sopenharmony_ci * 285462306a36Sopenharmony_ci * Retrieves configured resource limits and capabilities for a physical 285562306a36Sopenharmony_ci * function. The results are stored in @adapter->pfres. 285662306a36Sopenharmony_ci */ 285762306a36Sopenharmony_ciint t4_get_pfres(struct adapter *adapter) 285862306a36Sopenharmony_ci{ 285962306a36Sopenharmony_ci struct pf_resources *pfres = &adapter->params.pfres; 286062306a36Sopenharmony_ci struct fw_pfvf_cmd cmd, rpl; 286162306a36Sopenharmony_ci int v; 286262306a36Sopenharmony_ci u32 word; 286362306a36Sopenharmony_ci 286462306a36Sopenharmony_ci /* Execute PFVF Read command to get VF resource limits; bail out early 286562306a36Sopenharmony_ci * with error on command failure. 286662306a36Sopenharmony_ci */ 286762306a36Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 286862306a36Sopenharmony_ci cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PFVF_CMD) | 286962306a36Sopenharmony_ci FW_CMD_REQUEST_F | 287062306a36Sopenharmony_ci FW_CMD_READ_F | 287162306a36Sopenharmony_ci FW_PFVF_CMD_PFN_V(adapter->pf) | 287262306a36Sopenharmony_ci FW_PFVF_CMD_VFN_V(0)); 287362306a36Sopenharmony_ci cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); 287462306a36Sopenharmony_ci v = t4_wr_mbox(adapter, adapter->mbox, &cmd, sizeof(cmd), &rpl); 287562306a36Sopenharmony_ci if (v != FW_SUCCESS) 287662306a36Sopenharmony_ci return v; 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_ci /* Extract PF resource limits and return success. 287962306a36Sopenharmony_ci */ 288062306a36Sopenharmony_ci word = be32_to_cpu(rpl.niqflint_niq); 288162306a36Sopenharmony_ci pfres->niqflint = FW_PFVF_CMD_NIQFLINT_G(word); 288262306a36Sopenharmony_ci pfres->niq = FW_PFVF_CMD_NIQ_G(word); 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci word = be32_to_cpu(rpl.type_to_neq); 288562306a36Sopenharmony_ci pfres->neq = FW_PFVF_CMD_NEQ_G(word); 288662306a36Sopenharmony_ci pfres->pmask = FW_PFVF_CMD_PMASK_G(word); 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_ci word = be32_to_cpu(rpl.tc_to_nexactf); 288962306a36Sopenharmony_ci pfres->tc = FW_PFVF_CMD_TC_G(word); 289062306a36Sopenharmony_ci pfres->nvi = FW_PFVF_CMD_NVI_G(word); 289162306a36Sopenharmony_ci pfres->nexactf = FW_PFVF_CMD_NEXACTF_G(word); 289262306a36Sopenharmony_ci 289362306a36Sopenharmony_ci word = be32_to_cpu(rpl.r_caps_to_nethctrl); 289462306a36Sopenharmony_ci pfres->r_caps = FW_PFVF_CMD_R_CAPS_G(word); 289562306a36Sopenharmony_ci pfres->wx_caps = FW_PFVF_CMD_WX_CAPS_G(word); 289662306a36Sopenharmony_ci pfres->nethctrl = FW_PFVF_CMD_NETHCTRL_G(word); 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci return 0; 289962306a36Sopenharmony_ci} 290062306a36Sopenharmony_ci 290162306a36Sopenharmony_ci/* serial flash and firmware constants */ 290262306a36Sopenharmony_cienum { 290362306a36Sopenharmony_ci SF_ATTEMPTS = 10, /* max retries for SF operations */ 290462306a36Sopenharmony_ci 290562306a36Sopenharmony_ci /* flash command opcodes */ 290662306a36Sopenharmony_ci SF_PROG_PAGE = 2, /* program page */ 290762306a36Sopenharmony_ci SF_WR_DISABLE = 4, /* disable writes */ 290862306a36Sopenharmony_ci SF_RD_STATUS = 5, /* read status register */ 290962306a36Sopenharmony_ci SF_WR_ENABLE = 6, /* enable writes */ 291062306a36Sopenharmony_ci SF_RD_DATA_FAST = 0xb, /* read flash */ 291162306a36Sopenharmony_ci SF_RD_ID = 0x9f, /* read ID */ 291262306a36Sopenharmony_ci SF_ERASE_SECTOR = 0xd8, /* erase sector */ 291362306a36Sopenharmony_ci}; 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci/** 291662306a36Sopenharmony_ci * sf1_read - read data from the serial flash 291762306a36Sopenharmony_ci * @adapter: the adapter 291862306a36Sopenharmony_ci * @byte_cnt: number of bytes to read 291962306a36Sopenharmony_ci * @cont: whether another operation will be chained 292062306a36Sopenharmony_ci * @lock: whether to lock SF for PL access only 292162306a36Sopenharmony_ci * @valp: where to store the read data 292262306a36Sopenharmony_ci * 292362306a36Sopenharmony_ci * Reads up to 4 bytes of data from the serial flash. The location of 292462306a36Sopenharmony_ci * the read needs to be specified prior to calling this by issuing the 292562306a36Sopenharmony_ci * appropriate commands to the serial flash. 292662306a36Sopenharmony_ci */ 292762306a36Sopenharmony_cistatic int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont, 292862306a36Sopenharmony_ci int lock, u32 *valp) 292962306a36Sopenharmony_ci{ 293062306a36Sopenharmony_ci int ret; 293162306a36Sopenharmony_ci 293262306a36Sopenharmony_ci if (!byte_cnt || byte_cnt > 4) 293362306a36Sopenharmony_ci return -EINVAL; 293462306a36Sopenharmony_ci if (t4_read_reg(adapter, SF_OP_A) & SF_BUSY_F) 293562306a36Sopenharmony_ci return -EBUSY; 293662306a36Sopenharmony_ci t4_write_reg(adapter, SF_OP_A, SF_LOCK_V(lock) | 293762306a36Sopenharmony_ci SF_CONT_V(cont) | BYTECNT_V(byte_cnt - 1)); 293862306a36Sopenharmony_ci ret = t4_wait_op_done(adapter, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS, 5); 293962306a36Sopenharmony_ci if (!ret) 294062306a36Sopenharmony_ci *valp = t4_read_reg(adapter, SF_DATA_A); 294162306a36Sopenharmony_ci return ret; 294262306a36Sopenharmony_ci} 294362306a36Sopenharmony_ci 294462306a36Sopenharmony_ci/** 294562306a36Sopenharmony_ci * sf1_write - write data to the serial flash 294662306a36Sopenharmony_ci * @adapter: the adapter 294762306a36Sopenharmony_ci * @byte_cnt: number of bytes to write 294862306a36Sopenharmony_ci * @cont: whether another operation will be chained 294962306a36Sopenharmony_ci * @lock: whether to lock SF for PL access only 295062306a36Sopenharmony_ci * @val: value to write 295162306a36Sopenharmony_ci * 295262306a36Sopenharmony_ci * Writes up to 4 bytes of data to the serial flash. The location of 295362306a36Sopenharmony_ci * the write needs to be specified prior to calling this by issuing the 295462306a36Sopenharmony_ci * appropriate commands to the serial flash. 295562306a36Sopenharmony_ci */ 295662306a36Sopenharmony_cistatic int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont, 295762306a36Sopenharmony_ci int lock, u32 val) 295862306a36Sopenharmony_ci{ 295962306a36Sopenharmony_ci if (!byte_cnt || byte_cnt > 4) 296062306a36Sopenharmony_ci return -EINVAL; 296162306a36Sopenharmony_ci if (t4_read_reg(adapter, SF_OP_A) & SF_BUSY_F) 296262306a36Sopenharmony_ci return -EBUSY; 296362306a36Sopenharmony_ci t4_write_reg(adapter, SF_DATA_A, val); 296462306a36Sopenharmony_ci t4_write_reg(adapter, SF_OP_A, SF_LOCK_V(lock) | 296562306a36Sopenharmony_ci SF_CONT_V(cont) | BYTECNT_V(byte_cnt - 1) | OP_V(1)); 296662306a36Sopenharmony_ci return t4_wait_op_done(adapter, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS, 5); 296762306a36Sopenharmony_ci} 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_ci/** 297062306a36Sopenharmony_ci * flash_wait_op - wait for a flash operation to complete 297162306a36Sopenharmony_ci * @adapter: the adapter 297262306a36Sopenharmony_ci * @attempts: max number of polls of the status register 297362306a36Sopenharmony_ci * @delay: delay between polls in ms 297462306a36Sopenharmony_ci * 297562306a36Sopenharmony_ci * Wait for a flash operation to complete by polling the status register. 297662306a36Sopenharmony_ci */ 297762306a36Sopenharmony_cistatic int flash_wait_op(struct adapter *adapter, int attempts, int delay) 297862306a36Sopenharmony_ci{ 297962306a36Sopenharmony_ci int ret; 298062306a36Sopenharmony_ci u32 status; 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci while (1) { 298362306a36Sopenharmony_ci if ((ret = sf1_write(adapter, 1, 1, 1, SF_RD_STATUS)) != 0 || 298462306a36Sopenharmony_ci (ret = sf1_read(adapter, 1, 0, 1, &status)) != 0) 298562306a36Sopenharmony_ci return ret; 298662306a36Sopenharmony_ci if (!(status & 1)) 298762306a36Sopenharmony_ci return 0; 298862306a36Sopenharmony_ci if (--attempts == 0) 298962306a36Sopenharmony_ci return -EAGAIN; 299062306a36Sopenharmony_ci if (delay) 299162306a36Sopenharmony_ci msleep(delay); 299262306a36Sopenharmony_ci } 299362306a36Sopenharmony_ci} 299462306a36Sopenharmony_ci 299562306a36Sopenharmony_ci/** 299662306a36Sopenharmony_ci * t4_read_flash - read words from serial flash 299762306a36Sopenharmony_ci * @adapter: the adapter 299862306a36Sopenharmony_ci * @addr: the start address for the read 299962306a36Sopenharmony_ci * @nwords: how many 32-bit words to read 300062306a36Sopenharmony_ci * @data: where to store the read data 300162306a36Sopenharmony_ci * @byte_oriented: whether to store data as bytes or as words 300262306a36Sopenharmony_ci * 300362306a36Sopenharmony_ci * Read the specified number of 32-bit words from the serial flash. 300462306a36Sopenharmony_ci * If @byte_oriented is set the read data is stored as a byte array 300562306a36Sopenharmony_ci * (i.e., big-endian), otherwise as 32-bit words in the platform's 300662306a36Sopenharmony_ci * natural endianness. 300762306a36Sopenharmony_ci */ 300862306a36Sopenharmony_ciint t4_read_flash(struct adapter *adapter, unsigned int addr, 300962306a36Sopenharmony_ci unsigned int nwords, u32 *data, int byte_oriented) 301062306a36Sopenharmony_ci{ 301162306a36Sopenharmony_ci int ret; 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci if (addr + nwords * sizeof(u32) > adapter->params.sf_size || (addr & 3)) 301462306a36Sopenharmony_ci return -EINVAL; 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_ci addr = swab32(addr) | SF_RD_DATA_FAST; 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci if ((ret = sf1_write(adapter, 4, 1, 0, addr)) != 0 || 301962306a36Sopenharmony_ci (ret = sf1_read(adapter, 1, 1, 0, data)) != 0) 302062306a36Sopenharmony_ci return ret; 302162306a36Sopenharmony_ci 302262306a36Sopenharmony_ci for ( ; nwords; nwords--, data++) { 302362306a36Sopenharmony_ci ret = sf1_read(adapter, 4, nwords > 1, nwords == 1, data); 302462306a36Sopenharmony_ci if (nwords == 1) 302562306a36Sopenharmony_ci t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */ 302662306a36Sopenharmony_ci if (ret) 302762306a36Sopenharmony_ci return ret; 302862306a36Sopenharmony_ci if (byte_oriented) 302962306a36Sopenharmony_ci *data = (__force __u32)(cpu_to_be32(*data)); 303062306a36Sopenharmony_ci } 303162306a36Sopenharmony_ci return 0; 303262306a36Sopenharmony_ci} 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_ci/** 303562306a36Sopenharmony_ci * t4_write_flash - write up to a page of data to the serial flash 303662306a36Sopenharmony_ci * @adapter: the adapter 303762306a36Sopenharmony_ci * @addr: the start address to write 303862306a36Sopenharmony_ci * @n: length of data to write in bytes 303962306a36Sopenharmony_ci * @data: the data to write 304062306a36Sopenharmony_ci * @byte_oriented: whether to store data as bytes or as words 304162306a36Sopenharmony_ci * 304262306a36Sopenharmony_ci * Writes up to a page of data (256 bytes) to the serial flash starting 304362306a36Sopenharmony_ci * at the given address. All the data must be written to the same page. 304462306a36Sopenharmony_ci * If @byte_oriented is set the write data is stored as byte stream 304562306a36Sopenharmony_ci * (i.e. matches what on disk), otherwise in big-endian. 304662306a36Sopenharmony_ci */ 304762306a36Sopenharmony_cistatic int t4_write_flash(struct adapter *adapter, unsigned int addr, 304862306a36Sopenharmony_ci unsigned int n, const u8 *data, bool byte_oriented) 304962306a36Sopenharmony_ci{ 305062306a36Sopenharmony_ci unsigned int i, c, left, val, offset = addr & 0xff; 305162306a36Sopenharmony_ci u32 buf[64]; 305262306a36Sopenharmony_ci int ret; 305362306a36Sopenharmony_ci 305462306a36Sopenharmony_ci if (addr >= adapter->params.sf_size || offset + n > SF_PAGE_SIZE) 305562306a36Sopenharmony_ci return -EINVAL; 305662306a36Sopenharmony_ci 305762306a36Sopenharmony_ci val = swab32(addr) | SF_PROG_PAGE; 305862306a36Sopenharmony_ci 305962306a36Sopenharmony_ci if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 || 306062306a36Sopenharmony_ci (ret = sf1_write(adapter, 4, 1, 1, val)) != 0) 306162306a36Sopenharmony_ci goto unlock; 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_ci for (left = n; left; left -= c, data += c) { 306462306a36Sopenharmony_ci c = min(left, 4U); 306562306a36Sopenharmony_ci for (val = 0, i = 0; i < c; ++i) { 306662306a36Sopenharmony_ci if (byte_oriented) 306762306a36Sopenharmony_ci val = (val << 8) + data[i]; 306862306a36Sopenharmony_ci else 306962306a36Sopenharmony_ci val = (val << 8) + data[c - i - 1]; 307062306a36Sopenharmony_ci } 307162306a36Sopenharmony_ci 307262306a36Sopenharmony_ci ret = sf1_write(adapter, c, c != left, 1, val); 307362306a36Sopenharmony_ci if (ret) 307462306a36Sopenharmony_ci goto unlock; 307562306a36Sopenharmony_ci } 307662306a36Sopenharmony_ci ret = flash_wait_op(adapter, 8, 1); 307762306a36Sopenharmony_ci if (ret) 307862306a36Sopenharmony_ci goto unlock; 307962306a36Sopenharmony_ci 308062306a36Sopenharmony_ci t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */ 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_ci /* Read the page to verify the write succeeded */ 308362306a36Sopenharmony_ci ret = t4_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 308462306a36Sopenharmony_ci byte_oriented); 308562306a36Sopenharmony_ci if (ret) 308662306a36Sopenharmony_ci return ret; 308762306a36Sopenharmony_ci 308862306a36Sopenharmony_ci if (memcmp(data - n, (u8 *)buf + offset, n)) { 308962306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 309062306a36Sopenharmony_ci "failed to correctly write the flash page at %#x\n", 309162306a36Sopenharmony_ci addr); 309262306a36Sopenharmony_ci return -EIO; 309362306a36Sopenharmony_ci } 309462306a36Sopenharmony_ci return 0; 309562306a36Sopenharmony_ci 309662306a36Sopenharmony_ciunlock: 309762306a36Sopenharmony_ci t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */ 309862306a36Sopenharmony_ci return ret; 309962306a36Sopenharmony_ci} 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci/** 310262306a36Sopenharmony_ci * t4_get_fw_version - read the firmware version 310362306a36Sopenharmony_ci * @adapter: the adapter 310462306a36Sopenharmony_ci * @vers: where to place the version 310562306a36Sopenharmony_ci * 310662306a36Sopenharmony_ci * Reads the FW version from flash. 310762306a36Sopenharmony_ci */ 310862306a36Sopenharmony_ciint t4_get_fw_version(struct adapter *adapter, u32 *vers) 310962306a36Sopenharmony_ci{ 311062306a36Sopenharmony_ci return t4_read_flash(adapter, FLASH_FW_START + 311162306a36Sopenharmony_ci offsetof(struct fw_hdr, fw_ver), 1, 311262306a36Sopenharmony_ci vers, 0); 311362306a36Sopenharmony_ci} 311462306a36Sopenharmony_ci 311562306a36Sopenharmony_ci/** 311662306a36Sopenharmony_ci * t4_get_bs_version - read the firmware bootstrap version 311762306a36Sopenharmony_ci * @adapter: the adapter 311862306a36Sopenharmony_ci * @vers: where to place the version 311962306a36Sopenharmony_ci * 312062306a36Sopenharmony_ci * Reads the FW Bootstrap version from flash. 312162306a36Sopenharmony_ci */ 312262306a36Sopenharmony_ciint t4_get_bs_version(struct adapter *adapter, u32 *vers) 312362306a36Sopenharmony_ci{ 312462306a36Sopenharmony_ci return t4_read_flash(adapter, FLASH_FWBOOTSTRAP_START + 312562306a36Sopenharmony_ci offsetof(struct fw_hdr, fw_ver), 1, 312662306a36Sopenharmony_ci vers, 0); 312762306a36Sopenharmony_ci} 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_ci/** 313062306a36Sopenharmony_ci * t4_get_tp_version - read the TP microcode version 313162306a36Sopenharmony_ci * @adapter: the adapter 313262306a36Sopenharmony_ci * @vers: where to place the version 313362306a36Sopenharmony_ci * 313462306a36Sopenharmony_ci * Reads the TP microcode version from flash. 313562306a36Sopenharmony_ci */ 313662306a36Sopenharmony_ciint t4_get_tp_version(struct adapter *adapter, u32 *vers) 313762306a36Sopenharmony_ci{ 313862306a36Sopenharmony_ci return t4_read_flash(adapter, FLASH_FW_START + 313962306a36Sopenharmony_ci offsetof(struct fw_hdr, tp_microcode_ver), 314062306a36Sopenharmony_ci 1, vers, 0); 314162306a36Sopenharmony_ci} 314262306a36Sopenharmony_ci 314362306a36Sopenharmony_ci/** 314462306a36Sopenharmony_ci * t4_get_exprom_version - return the Expansion ROM version (if any) 314562306a36Sopenharmony_ci * @adap: the adapter 314662306a36Sopenharmony_ci * @vers: where to place the version 314762306a36Sopenharmony_ci * 314862306a36Sopenharmony_ci * Reads the Expansion ROM header from FLASH and returns the version 314962306a36Sopenharmony_ci * number (if present) through the @vers return value pointer. We return 315062306a36Sopenharmony_ci * this in the Firmware Version Format since it's convenient. Return 315162306a36Sopenharmony_ci * 0 on success, -ENOENT if no Expansion ROM is present. 315262306a36Sopenharmony_ci */ 315362306a36Sopenharmony_ciint t4_get_exprom_version(struct adapter *adap, u32 *vers) 315462306a36Sopenharmony_ci{ 315562306a36Sopenharmony_ci struct exprom_header { 315662306a36Sopenharmony_ci unsigned char hdr_arr[16]; /* must start with 0x55aa */ 315762306a36Sopenharmony_ci unsigned char hdr_ver[4]; /* Expansion ROM version */ 315862306a36Sopenharmony_ci } *hdr; 315962306a36Sopenharmony_ci u32 exprom_header_buf[DIV_ROUND_UP(sizeof(struct exprom_header), 316062306a36Sopenharmony_ci sizeof(u32))]; 316162306a36Sopenharmony_ci int ret; 316262306a36Sopenharmony_ci 316362306a36Sopenharmony_ci ret = t4_read_flash(adap, FLASH_EXP_ROM_START, 316462306a36Sopenharmony_ci ARRAY_SIZE(exprom_header_buf), exprom_header_buf, 316562306a36Sopenharmony_ci 0); 316662306a36Sopenharmony_ci if (ret) 316762306a36Sopenharmony_ci return ret; 316862306a36Sopenharmony_ci 316962306a36Sopenharmony_ci hdr = (struct exprom_header *)exprom_header_buf; 317062306a36Sopenharmony_ci if (hdr->hdr_arr[0] != 0x55 || hdr->hdr_arr[1] != 0xaa) 317162306a36Sopenharmony_ci return -ENOENT; 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_ci *vers = (FW_HDR_FW_VER_MAJOR_V(hdr->hdr_ver[0]) | 317462306a36Sopenharmony_ci FW_HDR_FW_VER_MINOR_V(hdr->hdr_ver[1]) | 317562306a36Sopenharmony_ci FW_HDR_FW_VER_MICRO_V(hdr->hdr_ver[2]) | 317662306a36Sopenharmony_ci FW_HDR_FW_VER_BUILD_V(hdr->hdr_ver[3])); 317762306a36Sopenharmony_ci return 0; 317862306a36Sopenharmony_ci} 317962306a36Sopenharmony_ci 318062306a36Sopenharmony_ci/** 318162306a36Sopenharmony_ci * t4_get_vpd_version - return the VPD version 318262306a36Sopenharmony_ci * @adapter: the adapter 318362306a36Sopenharmony_ci * @vers: where to place the version 318462306a36Sopenharmony_ci * 318562306a36Sopenharmony_ci * Reads the VPD via the Firmware interface (thus this can only be called 318662306a36Sopenharmony_ci * once we're ready to issue Firmware commands). The format of the 318762306a36Sopenharmony_ci * VPD version is adapter specific. Returns 0 on success, an error on 318862306a36Sopenharmony_ci * failure. 318962306a36Sopenharmony_ci * 319062306a36Sopenharmony_ci * Note that early versions of the Firmware didn't include the ability 319162306a36Sopenharmony_ci * to retrieve the VPD version, so we zero-out the return-value parameter 319262306a36Sopenharmony_ci * in that case to avoid leaving it with garbage in it. 319362306a36Sopenharmony_ci * 319462306a36Sopenharmony_ci * Also note that the Firmware will return its cached copy of the VPD 319562306a36Sopenharmony_ci * Revision ID, not the actual Revision ID as written in the Serial 319662306a36Sopenharmony_ci * EEPROM. This is only an issue if a new VPD has been written and the 319762306a36Sopenharmony_ci * Firmware/Chip haven't yet gone through a RESET sequence. So it's best 319862306a36Sopenharmony_ci * to defer calling this routine till after a FW_RESET_CMD has been issued 319962306a36Sopenharmony_ci * if the Host Driver will be performing a full adapter initialization. 320062306a36Sopenharmony_ci */ 320162306a36Sopenharmony_ciint t4_get_vpd_version(struct adapter *adapter, u32 *vers) 320262306a36Sopenharmony_ci{ 320362306a36Sopenharmony_ci u32 vpdrev_param; 320462306a36Sopenharmony_ci int ret; 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ci vpdrev_param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 320762306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_VPDREV)); 320862306a36Sopenharmony_ci ret = t4_query_params(adapter, adapter->mbox, adapter->pf, 0, 320962306a36Sopenharmony_ci 1, &vpdrev_param, vers); 321062306a36Sopenharmony_ci if (ret) 321162306a36Sopenharmony_ci *vers = 0; 321262306a36Sopenharmony_ci return ret; 321362306a36Sopenharmony_ci} 321462306a36Sopenharmony_ci 321562306a36Sopenharmony_ci/** 321662306a36Sopenharmony_ci * t4_get_scfg_version - return the Serial Configuration version 321762306a36Sopenharmony_ci * @adapter: the adapter 321862306a36Sopenharmony_ci * @vers: where to place the version 321962306a36Sopenharmony_ci * 322062306a36Sopenharmony_ci * Reads the Serial Configuration Version via the Firmware interface 322162306a36Sopenharmony_ci * (thus this can only be called once we're ready to issue Firmware 322262306a36Sopenharmony_ci * commands). The format of the Serial Configuration version is 322362306a36Sopenharmony_ci * adapter specific. Returns 0 on success, an error on failure. 322462306a36Sopenharmony_ci * 322562306a36Sopenharmony_ci * Note that early versions of the Firmware didn't include the ability 322662306a36Sopenharmony_ci * to retrieve the Serial Configuration version, so we zero-out the 322762306a36Sopenharmony_ci * return-value parameter in that case to avoid leaving it with 322862306a36Sopenharmony_ci * garbage in it. 322962306a36Sopenharmony_ci * 323062306a36Sopenharmony_ci * Also note that the Firmware will return its cached copy of the Serial 323162306a36Sopenharmony_ci * Initialization Revision ID, not the actual Revision ID as written in 323262306a36Sopenharmony_ci * the Serial EEPROM. This is only an issue if a new VPD has been written 323362306a36Sopenharmony_ci * and the Firmware/Chip haven't yet gone through a RESET sequence. So 323462306a36Sopenharmony_ci * it's best to defer calling this routine till after a FW_RESET_CMD has 323562306a36Sopenharmony_ci * been issued if the Host Driver will be performing a full adapter 323662306a36Sopenharmony_ci * initialization. 323762306a36Sopenharmony_ci */ 323862306a36Sopenharmony_ciint t4_get_scfg_version(struct adapter *adapter, u32 *vers) 323962306a36Sopenharmony_ci{ 324062306a36Sopenharmony_ci u32 scfgrev_param; 324162306a36Sopenharmony_ci int ret; 324262306a36Sopenharmony_ci 324362306a36Sopenharmony_ci scfgrev_param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 324462306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_SCFGREV)); 324562306a36Sopenharmony_ci ret = t4_query_params(adapter, adapter->mbox, adapter->pf, 0, 324662306a36Sopenharmony_ci 1, &scfgrev_param, vers); 324762306a36Sopenharmony_ci if (ret) 324862306a36Sopenharmony_ci *vers = 0; 324962306a36Sopenharmony_ci return ret; 325062306a36Sopenharmony_ci} 325162306a36Sopenharmony_ci 325262306a36Sopenharmony_ci/** 325362306a36Sopenharmony_ci * t4_get_version_info - extract various chip/firmware version information 325462306a36Sopenharmony_ci * @adapter: the adapter 325562306a36Sopenharmony_ci * 325662306a36Sopenharmony_ci * Reads various chip/firmware version numbers and stores them into the 325762306a36Sopenharmony_ci * adapter Adapter Parameters structure. If any of the efforts fails 325862306a36Sopenharmony_ci * the first failure will be returned, but all of the version numbers 325962306a36Sopenharmony_ci * will be read. 326062306a36Sopenharmony_ci */ 326162306a36Sopenharmony_ciint t4_get_version_info(struct adapter *adapter) 326262306a36Sopenharmony_ci{ 326362306a36Sopenharmony_ci int ret = 0; 326462306a36Sopenharmony_ci 326562306a36Sopenharmony_ci #define FIRST_RET(__getvinfo) \ 326662306a36Sopenharmony_ci do { \ 326762306a36Sopenharmony_ci int __ret = __getvinfo; \ 326862306a36Sopenharmony_ci if (__ret && !ret) \ 326962306a36Sopenharmony_ci ret = __ret; \ 327062306a36Sopenharmony_ci } while (0) 327162306a36Sopenharmony_ci 327262306a36Sopenharmony_ci FIRST_RET(t4_get_fw_version(adapter, &adapter->params.fw_vers)); 327362306a36Sopenharmony_ci FIRST_RET(t4_get_bs_version(adapter, &adapter->params.bs_vers)); 327462306a36Sopenharmony_ci FIRST_RET(t4_get_tp_version(adapter, &adapter->params.tp_vers)); 327562306a36Sopenharmony_ci FIRST_RET(t4_get_exprom_version(adapter, &adapter->params.er_vers)); 327662306a36Sopenharmony_ci FIRST_RET(t4_get_scfg_version(adapter, &adapter->params.scfg_vers)); 327762306a36Sopenharmony_ci FIRST_RET(t4_get_vpd_version(adapter, &adapter->params.vpd_vers)); 327862306a36Sopenharmony_ci 327962306a36Sopenharmony_ci #undef FIRST_RET 328062306a36Sopenharmony_ci return ret; 328162306a36Sopenharmony_ci} 328262306a36Sopenharmony_ci 328362306a36Sopenharmony_ci/** 328462306a36Sopenharmony_ci * t4_dump_version_info - dump all of the adapter configuration IDs 328562306a36Sopenharmony_ci * @adapter: the adapter 328662306a36Sopenharmony_ci * 328762306a36Sopenharmony_ci * Dumps all of the various bits of adapter configuration version/revision 328862306a36Sopenharmony_ci * IDs information. This is typically called at some point after 328962306a36Sopenharmony_ci * t4_get_version_info() has been called. 329062306a36Sopenharmony_ci */ 329162306a36Sopenharmony_civoid t4_dump_version_info(struct adapter *adapter) 329262306a36Sopenharmony_ci{ 329362306a36Sopenharmony_ci /* Device information */ 329462306a36Sopenharmony_ci dev_info(adapter->pdev_dev, "Chelsio %s rev %d\n", 329562306a36Sopenharmony_ci adapter->params.vpd.id, 329662306a36Sopenharmony_ci CHELSIO_CHIP_RELEASE(adapter->params.chip)); 329762306a36Sopenharmony_ci dev_info(adapter->pdev_dev, "S/N: %s, P/N: %s\n", 329862306a36Sopenharmony_ci adapter->params.vpd.sn, adapter->params.vpd.pn); 329962306a36Sopenharmony_ci 330062306a36Sopenharmony_ci /* Firmware Version */ 330162306a36Sopenharmony_ci if (!adapter->params.fw_vers) 330262306a36Sopenharmony_ci dev_warn(adapter->pdev_dev, "No firmware loaded\n"); 330362306a36Sopenharmony_ci else 330462306a36Sopenharmony_ci dev_info(adapter->pdev_dev, "Firmware version: %u.%u.%u.%u\n", 330562306a36Sopenharmony_ci FW_HDR_FW_VER_MAJOR_G(adapter->params.fw_vers), 330662306a36Sopenharmony_ci FW_HDR_FW_VER_MINOR_G(adapter->params.fw_vers), 330762306a36Sopenharmony_ci FW_HDR_FW_VER_MICRO_G(adapter->params.fw_vers), 330862306a36Sopenharmony_ci FW_HDR_FW_VER_BUILD_G(adapter->params.fw_vers)); 330962306a36Sopenharmony_ci 331062306a36Sopenharmony_ci /* Bootstrap Firmware Version. (Some adapters don't have Bootstrap 331162306a36Sopenharmony_ci * Firmware, so dev_info() is more appropriate here.) 331262306a36Sopenharmony_ci */ 331362306a36Sopenharmony_ci if (!adapter->params.bs_vers) 331462306a36Sopenharmony_ci dev_info(adapter->pdev_dev, "No bootstrap loaded\n"); 331562306a36Sopenharmony_ci else 331662306a36Sopenharmony_ci dev_info(adapter->pdev_dev, "Bootstrap version: %u.%u.%u.%u\n", 331762306a36Sopenharmony_ci FW_HDR_FW_VER_MAJOR_G(adapter->params.bs_vers), 331862306a36Sopenharmony_ci FW_HDR_FW_VER_MINOR_G(adapter->params.bs_vers), 331962306a36Sopenharmony_ci FW_HDR_FW_VER_MICRO_G(adapter->params.bs_vers), 332062306a36Sopenharmony_ci FW_HDR_FW_VER_BUILD_G(adapter->params.bs_vers)); 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_ci /* TP Microcode Version */ 332362306a36Sopenharmony_ci if (!adapter->params.tp_vers) 332462306a36Sopenharmony_ci dev_warn(adapter->pdev_dev, "No TP Microcode loaded\n"); 332562306a36Sopenharmony_ci else 332662306a36Sopenharmony_ci dev_info(adapter->pdev_dev, 332762306a36Sopenharmony_ci "TP Microcode version: %u.%u.%u.%u\n", 332862306a36Sopenharmony_ci FW_HDR_FW_VER_MAJOR_G(adapter->params.tp_vers), 332962306a36Sopenharmony_ci FW_HDR_FW_VER_MINOR_G(adapter->params.tp_vers), 333062306a36Sopenharmony_ci FW_HDR_FW_VER_MICRO_G(adapter->params.tp_vers), 333162306a36Sopenharmony_ci FW_HDR_FW_VER_BUILD_G(adapter->params.tp_vers)); 333262306a36Sopenharmony_ci 333362306a36Sopenharmony_ci /* Expansion ROM version */ 333462306a36Sopenharmony_ci if (!adapter->params.er_vers) 333562306a36Sopenharmony_ci dev_info(adapter->pdev_dev, "No Expansion ROM loaded\n"); 333662306a36Sopenharmony_ci else 333762306a36Sopenharmony_ci dev_info(adapter->pdev_dev, 333862306a36Sopenharmony_ci "Expansion ROM version: %u.%u.%u.%u\n", 333962306a36Sopenharmony_ci FW_HDR_FW_VER_MAJOR_G(adapter->params.er_vers), 334062306a36Sopenharmony_ci FW_HDR_FW_VER_MINOR_G(adapter->params.er_vers), 334162306a36Sopenharmony_ci FW_HDR_FW_VER_MICRO_G(adapter->params.er_vers), 334262306a36Sopenharmony_ci FW_HDR_FW_VER_BUILD_G(adapter->params.er_vers)); 334362306a36Sopenharmony_ci 334462306a36Sopenharmony_ci /* Serial Configuration version */ 334562306a36Sopenharmony_ci dev_info(adapter->pdev_dev, "Serial Configuration version: %#x\n", 334662306a36Sopenharmony_ci adapter->params.scfg_vers); 334762306a36Sopenharmony_ci 334862306a36Sopenharmony_ci /* VPD Version */ 334962306a36Sopenharmony_ci dev_info(adapter->pdev_dev, "VPD version: %#x\n", 335062306a36Sopenharmony_ci adapter->params.vpd_vers); 335162306a36Sopenharmony_ci} 335262306a36Sopenharmony_ci 335362306a36Sopenharmony_ci/** 335462306a36Sopenharmony_ci * t4_check_fw_version - check if the FW is supported with this driver 335562306a36Sopenharmony_ci * @adap: the adapter 335662306a36Sopenharmony_ci * 335762306a36Sopenharmony_ci * Checks if an adapter's FW is compatible with the driver. Returns 0 335862306a36Sopenharmony_ci * if there's exact match, a negative error if the version could not be 335962306a36Sopenharmony_ci * read or there's a major version mismatch 336062306a36Sopenharmony_ci */ 336162306a36Sopenharmony_ciint t4_check_fw_version(struct adapter *adap) 336262306a36Sopenharmony_ci{ 336362306a36Sopenharmony_ci int i, ret, major, minor, micro; 336462306a36Sopenharmony_ci int exp_major, exp_minor, exp_micro; 336562306a36Sopenharmony_ci unsigned int chip_version = CHELSIO_CHIP_VERSION(adap->params.chip); 336662306a36Sopenharmony_ci 336762306a36Sopenharmony_ci ret = t4_get_fw_version(adap, &adap->params.fw_vers); 336862306a36Sopenharmony_ci /* Try multiple times before returning error */ 336962306a36Sopenharmony_ci for (i = 0; (ret == -EBUSY || ret == -EAGAIN) && i < 3; i++) 337062306a36Sopenharmony_ci ret = t4_get_fw_version(adap, &adap->params.fw_vers); 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci if (ret) 337362306a36Sopenharmony_ci return ret; 337462306a36Sopenharmony_ci 337562306a36Sopenharmony_ci major = FW_HDR_FW_VER_MAJOR_G(adap->params.fw_vers); 337662306a36Sopenharmony_ci minor = FW_HDR_FW_VER_MINOR_G(adap->params.fw_vers); 337762306a36Sopenharmony_ci micro = FW_HDR_FW_VER_MICRO_G(adap->params.fw_vers); 337862306a36Sopenharmony_ci 337962306a36Sopenharmony_ci switch (chip_version) { 338062306a36Sopenharmony_ci case CHELSIO_T4: 338162306a36Sopenharmony_ci exp_major = T4FW_MIN_VERSION_MAJOR; 338262306a36Sopenharmony_ci exp_minor = T4FW_MIN_VERSION_MINOR; 338362306a36Sopenharmony_ci exp_micro = T4FW_MIN_VERSION_MICRO; 338462306a36Sopenharmony_ci break; 338562306a36Sopenharmony_ci case CHELSIO_T5: 338662306a36Sopenharmony_ci exp_major = T5FW_MIN_VERSION_MAJOR; 338762306a36Sopenharmony_ci exp_minor = T5FW_MIN_VERSION_MINOR; 338862306a36Sopenharmony_ci exp_micro = T5FW_MIN_VERSION_MICRO; 338962306a36Sopenharmony_ci break; 339062306a36Sopenharmony_ci case CHELSIO_T6: 339162306a36Sopenharmony_ci exp_major = T6FW_MIN_VERSION_MAJOR; 339262306a36Sopenharmony_ci exp_minor = T6FW_MIN_VERSION_MINOR; 339362306a36Sopenharmony_ci exp_micro = T6FW_MIN_VERSION_MICRO; 339462306a36Sopenharmony_ci break; 339562306a36Sopenharmony_ci default: 339662306a36Sopenharmony_ci dev_err(adap->pdev_dev, "Unsupported chip type, %x\n", 339762306a36Sopenharmony_ci adap->chip); 339862306a36Sopenharmony_ci return -EINVAL; 339962306a36Sopenharmony_ci } 340062306a36Sopenharmony_ci 340162306a36Sopenharmony_ci if (major < exp_major || (major == exp_major && minor < exp_minor) || 340262306a36Sopenharmony_ci (major == exp_major && minor == exp_minor && micro < exp_micro)) { 340362306a36Sopenharmony_ci dev_err(adap->pdev_dev, 340462306a36Sopenharmony_ci "Card has firmware version %u.%u.%u, minimum " 340562306a36Sopenharmony_ci "supported firmware is %u.%u.%u.\n", major, minor, 340662306a36Sopenharmony_ci micro, exp_major, exp_minor, exp_micro); 340762306a36Sopenharmony_ci return -EFAULT; 340862306a36Sopenharmony_ci } 340962306a36Sopenharmony_ci return 0; 341062306a36Sopenharmony_ci} 341162306a36Sopenharmony_ci 341262306a36Sopenharmony_ci/* Is the given firmware API compatible with the one the driver was compiled 341362306a36Sopenharmony_ci * with? 341462306a36Sopenharmony_ci */ 341562306a36Sopenharmony_cistatic int fw_compatible(const struct fw_hdr *hdr1, const struct fw_hdr *hdr2) 341662306a36Sopenharmony_ci{ 341762306a36Sopenharmony_ci 341862306a36Sopenharmony_ci /* short circuit if it's the exact same firmware version */ 341962306a36Sopenharmony_ci if (hdr1->chip == hdr2->chip && hdr1->fw_ver == hdr2->fw_ver) 342062306a36Sopenharmony_ci return 1; 342162306a36Sopenharmony_ci 342262306a36Sopenharmony_ci#define SAME_INTF(x) (hdr1->intfver_##x == hdr2->intfver_##x) 342362306a36Sopenharmony_ci if (hdr1->chip == hdr2->chip && SAME_INTF(nic) && SAME_INTF(vnic) && 342462306a36Sopenharmony_ci SAME_INTF(ri) && SAME_INTF(iscsi) && SAME_INTF(fcoe)) 342562306a36Sopenharmony_ci return 1; 342662306a36Sopenharmony_ci#undef SAME_INTF 342762306a36Sopenharmony_ci 342862306a36Sopenharmony_ci return 0; 342962306a36Sopenharmony_ci} 343062306a36Sopenharmony_ci 343162306a36Sopenharmony_ci/* The firmware in the filesystem is usable, but should it be installed? 343262306a36Sopenharmony_ci * This routine explains itself in detail if it indicates the filesystem 343362306a36Sopenharmony_ci * firmware should be installed. 343462306a36Sopenharmony_ci */ 343562306a36Sopenharmony_cistatic int should_install_fs_fw(struct adapter *adap, int card_fw_usable, 343662306a36Sopenharmony_ci int k, int c) 343762306a36Sopenharmony_ci{ 343862306a36Sopenharmony_ci const char *reason; 343962306a36Sopenharmony_ci 344062306a36Sopenharmony_ci if (!card_fw_usable) { 344162306a36Sopenharmony_ci reason = "incompatible or unusable"; 344262306a36Sopenharmony_ci goto install; 344362306a36Sopenharmony_ci } 344462306a36Sopenharmony_ci 344562306a36Sopenharmony_ci if (k > c) { 344662306a36Sopenharmony_ci reason = "older than the version supported with this driver"; 344762306a36Sopenharmony_ci goto install; 344862306a36Sopenharmony_ci } 344962306a36Sopenharmony_ci 345062306a36Sopenharmony_ci return 0; 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_ciinstall: 345362306a36Sopenharmony_ci dev_err(adap->pdev_dev, "firmware on card (%u.%u.%u.%u) is %s, " 345462306a36Sopenharmony_ci "installing firmware %u.%u.%u.%u on card.\n", 345562306a36Sopenharmony_ci FW_HDR_FW_VER_MAJOR_G(c), FW_HDR_FW_VER_MINOR_G(c), 345662306a36Sopenharmony_ci FW_HDR_FW_VER_MICRO_G(c), FW_HDR_FW_VER_BUILD_G(c), reason, 345762306a36Sopenharmony_ci FW_HDR_FW_VER_MAJOR_G(k), FW_HDR_FW_VER_MINOR_G(k), 345862306a36Sopenharmony_ci FW_HDR_FW_VER_MICRO_G(k), FW_HDR_FW_VER_BUILD_G(k)); 345962306a36Sopenharmony_ci 346062306a36Sopenharmony_ci return 1; 346162306a36Sopenharmony_ci} 346262306a36Sopenharmony_ci 346362306a36Sopenharmony_ciint t4_prep_fw(struct adapter *adap, struct fw_info *fw_info, 346462306a36Sopenharmony_ci const u8 *fw_data, unsigned int fw_size, 346562306a36Sopenharmony_ci struct fw_hdr *card_fw, enum dev_state state, 346662306a36Sopenharmony_ci int *reset) 346762306a36Sopenharmony_ci{ 346862306a36Sopenharmony_ci int ret, card_fw_usable, fs_fw_usable; 346962306a36Sopenharmony_ci const struct fw_hdr *fs_fw; 347062306a36Sopenharmony_ci const struct fw_hdr *drv_fw; 347162306a36Sopenharmony_ci 347262306a36Sopenharmony_ci drv_fw = &fw_info->fw_hdr; 347362306a36Sopenharmony_ci 347462306a36Sopenharmony_ci /* Read the header of the firmware on the card */ 347562306a36Sopenharmony_ci ret = t4_read_flash(adap, FLASH_FW_START, 347662306a36Sopenharmony_ci sizeof(*card_fw) / sizeof(uint32_t), 347762306a36Sopenharmony_ci (uint32_t *)card_fw, 1); 347862306a36Sopenharmony_ci if (ret == 0) { 347962306a36Sopenharmony_ci card_fw_usable = fw_compatible(drv_fw, (const void *)card_fw); 348062306a36Sopenharmony_ci } else { 348162306a36Sopenharmony_ci dev_err(adap->pdev_dev, 348262306a36Sopenharmony_ci "Unable to read card's firmware header: %d\n", ret); 348362306a36Sopenharmony_ci card_fw_usable = 0; 348462306a36Sopenharmony_ci } 348562306a36Sopenharmony_ci 348662306a36Sopenharmony_ci if (fw_data != NULL) { 348762306a36Sopenharmony_ci fs_fw = (const void *)fw_data; 348862306a36Sopenharmony_ci fs_fw_usable = fw_compatible(drv_fw, fs_fw); 348962306a36Sopenharmony_ci } else { 349062306a36Sopenharmony_ci fs_fw = NULL; 349162306a36Sopenharmony_ci fs_fw_usable = 0; 349262306a36Sopenharmony_ci } 349362306a36Sopenharmony_ci 349462306a36Sopenharmony_ci if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver && 349562306a36Sopenharmony_ci (!fs_fw_usable || fs_fw->fw_ver == drv_fw->fw_ver)) { 349662306a36Sopenharmony_ci /* Common case: the firmware on the card is an exact match and 349762306a36Sopenharmony_ci * the filesystem one is an exact match too, or the filesystem 349862306a36Sopenharmony_ci * one is absent/incompatible. 349962306a36Sopenharmony_ci */ 350062306a36Sopenharmony_ci } else if (fs_fw_usable && state == DEV_STATE_UNINIT && 350162306a36Sopenharmony_ci should_install_fs_fw(adap, card_fw_usable, 350262306a36Sopenharmony_ci be32_to_cpu(fs_fw->fw_ver), 350362306a36Sopenharmony_ci be32_to_cpu(card_fw->fw_ver))) { 350462306a36Sopenharmony_ci ret = t4_fw_upgrade(adap, adap->mbox, fw_data, 350562306a36Sopenharmony_ci fw_size, 0); 350662306a36Sopenharmony_ci if (ret != 0) { 350762306a36Sopenharmony_ci dev_err(adap->pdev_dev, 350862306a36Sopenharmony_ci "failed to install firmware: %d\n", ret); 350962306a36Sopenharmony_ci goto bye; 351062306a36Sopenharmony_ci } 351162306a36Sopenharmony_ci 351262306a36Sopenharmony_ci /* Installed successfully, update the cached header too. */ 351362306a36Sopenharmony_ci *card_fw = *fs_fw; 351462306a36Sopenharmony_ci card_fw_usable = 1; 351562306a36Sopenharmony_ci *reset = 0; /* already reset as part of load_fw */ 351662306a36Sopenharmony_ci } 351762306a36Sopenharmony_ci 351862306a36Sopenharmony_ci if (!card_fw_usable) { 351962306a36Sopenharmony_ci uint32_t d, c, k; 352062306a36Sopenharmony_ci 352162306a36Sopenharmony_ci d = be32_to_cpu(drv_fw->fw_ver); 352262306a36Sopenharmony_ci c = be32_to_cpu(card_fw->fw_ver); 352362306a36Sopenharmony_ci k = fs_fw ? be32_to_cpu(fs_fw->fw_ver) : 0; 352462306a36Sopenharmony_ci 352562306a36Sopenharmony_ci dev_err(adap->pdev_dev, "Cannot find a usable firmware: " 352662306a36Sopenharmony_ci "chip state %d, " 352762306a36Sopenharmony_ci "driver compiled with %d.%d.%d.%d, " 352862306a36Sopenharmony_ci "card has %d.%d.%d.%d, filesystem has %d.%d.%d.%d\n", 352962306a36Sopenharmony_ci state, 353062306a36Sopenharmony_ci FW_HDR_FW_VER_MAJOR_G(d), FW_HDR_FW_VER_MINOR_G(d), 353162306a36Sopenharmony_ci FW_HDR_FW_VER_MICRO_G(d), FW_HDR_FW_VER_BUILD_G(d), 353262306a36Sopenharmony_ci FW_HDR_FW_VER_MAJOR_G(c), FW_HDR_FW_VER_MINOR_G(c), 353362306a36Sopenharmony_ci FW_HDR_FW_VER_MICRO_G(c), FW_HDR_FW_VER_BUILD_G(c), 353462306a36Sopenharmony_ci FW_HDR_FW_VER_MAJOR_G(k), FW_HDR_FW_VER_MINOR_G(k), 353562306a36Sopenharmony_ci FW_HDR_FW_VER_MICRO_G(k), FW_HDR_FW_VER_BUILD_G(k)); 353662306a36Sopenharmony_ci ret = -EINVAL; 353762306a36Sopenharmony_ci goto bye; 353862306a36Sopenharmony_ci } 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci /* We're using whatever's on the card and it's known to be good. */ 354162306a36Sopenharmony_ci adap->params.fw_vers = be32_to_cpu(card_fw->fw_ver); 354262306a36Sopenharmony_ci adap->params.tp_vers = be32_to_cpu(card_fw->tp_microcode_ver); 354362306a36Sopenharmony_ci 354462306a36Sopenharmony_cibye: 354562306a36Sopenharmony_ci return ret; 354662306a36Sopenharmony_ci} 354762306a36Sopenharmony_ci 354862306a36Sopenharmony_ci/** 354962306a36Sopenharmony_ci * t4_flash_erase_sectors - erase a range of flash sectors 355062306a36Sopenharmony_ci * @adapter: the adapter 355162306a36Sopenharmony_ci * @start: the first sector to erase 355262306a36Sopenharmony_ci * @end: the last sector to erase 355362306a36Sopenharmony_ci * 355462306a36Sopenharmony_ci * Erases the sectors in the given inclusive range. 355562306a36Sopenharmony_ci */ 355662306a36Sopenharmony_cistatic int t4_flash_erase_sectors(struct adapter *adapter, int start, int end) 355762306a36Sopenharmony_ci{ 355862306a36Sopenharmony_ci int ret = 0; 355962306a36Sopenharmony_ci 356062306a36Sopenharmony_ci if (end >= adapter->params.sf_nsec) 356162306a36Sopenharmony_ci return -EINVAL; 356262306a36Sopenharmony_ci 356362306a36Sopenharmony_ci while (start <= end) { 356462306a36Sopenharmony_ci if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 || 356562306a36Sopenharmony_ci (ret = sf1_write(adapter, 4, 0, 1, 356662306a36Sopenharmony_ci SF_ERASE_SECTOR | (start << 8))) != 0 || 356762306a36Sopenharmony_ci (ret = flash_wait_op(adapter, 14, 500)) != 0) { 356862306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 356962306a36Sopenharmony_ci "erase of flash sector %d failed, error %d\n", 357062306a36Sopenharmony_ci start, ret); 357162306a36Sopenharmony_ci break; 357262306a36Sopenharmony_ci } 357362306a36Sopenharmony_ci start++; 357462306a36Sopenharmony_ci } 357562306a36Sopenharmony_ci t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */ 357662306a36Sopenharmony_ci return ret; 357762306a36Sopenharmony_ci} 357862306a36Sopenharmony_ci 357962306a36Sopenharmony_ci/** 358062306a36Sopenharmony_ci * t4_flash_cfg_addr - return the address of the flash configuration file 358162306a36Sopenharmony_ci * @adapter: the adapter 358262306a36Sopenharmony_ci * 358362306a36Sopenharmony_ci * Return the address within the flash where the Firmware Configuration 358462306a36Sopenharmony_ci * File is stored. 358562306a36Sopenharmony_ci */ 358662306a36Sopenharmony_ciunsigned int t4_flash_cfg_addr(struct adapter *adapter) 358762306a36Sopenharmony_ci{ 358862306a36Sopenharmony_ci if (adapter->params.sf_size == 0x100000) 358962306a36Sopenharmony_ci return FLASH_FPGA_CFG_START; 359062306a36Sopenharmony_ci else 359162306a36Sopenharmony_ci return FLASH_CFG_START; 359262306a36Sopenharmony_ci} 359362306a36Sopenharmony_ci 359462306a36Sopenharmony_ci/* Return TRUE if the specified firmware matches the adapter. I.e. T4 359562306a36Sopenharmony_ci * firmware for T4 adapters, T5 firmware for T5 adapters, etc. We go ahead 359662306a36Sopenharmony_ci * and emit an error message for mismatched firmware to save our caller the 359762306a36Sopenharmony_ci * effort ... 359862306a36Sopenharmony_ci */ 359962306a36Sopenharmony_cistatic bool t4_fw_matches_chip(const struct adapter *adap, 360062306a36Sopenharmony_ci const struct fw_hdr *hdr) 360162306a36Sopenharmony_ci{ 360262306a36Sopenharmony_ci /* The expression below will return FALSE for any unsupported adapter 360362306a36Sopenharmony_ci * which will keep us "honest" in the future ... 360462306a36Sopenharmony_ci */ 360562306a36Sopenharmony_ci if ((is_t4(adap->params.chip) && hdr->chip == FW_HDR_CHIP_T4) || 360662306a36Sopenharmony_ci (is_t5(adap->params.chip) && hdr->chip == FW_HDR_CHIP_T5) || 360762306a36Sopenharmony_ci (is_t6(adap->params.chip) && hdr->chip == FW_HDR_CHIP_T6)) 360862306a36Sopenharmony_ci return true; 360962306a36Sopenharmony_ci 361062306a36Sopenharmony_ci dev_err(adap->pdev_dev, 361162306a36Sopenharmony_ci "FW image (%d) is not suitable for this adapter (%d)\n", 361262306a36Sopenharmony_ci hdr->chip, CHELSIO_CHIP_VERSION(adap->params.chip)); 361362306a36Sopenharmony_ci return false; 361462306a36Sopenharmony_ci} 361562306a36Sopenharmony_ci 361662306a36Sopenharmony_ci/** 361762306a36Sopenharmony_ci * t4_load_fw - download firmware 361862306a36Sopenharmony_ci * @adap: the adapter 361962306a36Sopenharmony_ci * @fw_data: the firmware image to write 362062306a36Sopenharmony_ci * @size: image size 362162306a36Sopenharmony_ci * 362262306a36Sopenharmony_ci * Write the supplied firmware image to the card's serial flash. 362362306a36Sopenharmony_ci */ 362462306a36Sopenharmony_ciint t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size) 362562306a36Sopenharmony_ci{ 362662306a36Sopenharmony_ci u32 csum; 362762306a36Sopenharmony_ci int ret, addr; 362862306a36Sopenharmony_ci unsigned int i; 362962306a36Sopenharmony_ci u8 first_page[SF_PAGE_SIZE]; 363062306a36Sopenharmony_ci const __be32 *p = (const __be32 *)fw_data; 363162306a36Sopenharmony_ci const struct fw_hdr *hdr = (const struct fw_hdr *)fw_data; 363262306a36Sopenharmony_ci unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; 363362306a36Sopenharmony_ci unsigned int fw_start_sec = FLASH_FW_START_SEC; 363462306a36Sopenharmony_ci unsigned int fw_size = FLASH_FW_MAX_SIZE; 363562306a36Sopenharmony_ci unsigned int fw_start = FLASH_FW_START; 363662306a36Sopenharmony_ci 363762306a36Sopenharmony_ci if (!size) { 363862306a36Sopenharmony_ci dev_err(adap->pdev_dev, "FW image has no data\n"); 363962306a36Sopenharmony_ci return -EINVAL; 364062306a36Sopenharmony_ci } 364162306a36Sopenharmony_ci if (size & 511) { 364262306a36Sopenharmony_ci dev_err(adap->pdev_dev, 364362306a36Sopenharmony_ci "FW image size not multiple of 512 bytes\n"); 364462306a36Sopenharmony_ci return -EINVAL; 364562306a36Sopenharmony_ci } 364662306a36Sopenharmony_ci if ((unsigned int)be16_to_cpu(hdr->len512) * 512 != size) { 364762306a36Sopenharmony_ci dev_err(adap->pdev_dev, 364862306a36Sopenharmony_ci "FW image size differs from size in FW header\n"); 364962306a36Sopenharmony_ci return -EINVAL; 365062306a36Sopenharmony_ci } 365162306a36Sopenharmony_ci if (size > fw_size) { 365262306a36Sopenharmony_ci dev_err(adap->pdev_dev, "FW image too large, max is %u bytes\n", 365362306a36Sopenharmony_ci fw_size); 365462306a36Sopenharmony_ci return -EFBIG; 365562306a36Sopenharmony_ci } 365662306a36Sopenharmony_ci if (!t4_fw_matches_chip(adap, hdr)) 365762306a36Sopenharmony_ci return -EINVAL; 365862306a36Sopenharmony_ci 365962306a36Sopenharmony_ci for (csum = 0, i = 0; i < size / sizeof(csum); i++) 366062306a36Sopenharmony_ci csum += be32_to_cpu(p[i]); 366162306a36Sopenharmony_ci 366262306a36Sopenharmony_ci if (csum != 0xffffffff) { 366362306a36Sopenharmony_ci dev_err(adap->pdev_dev, 366462306a36Sopenharmony_ci "corrupted firmware image, checksum %#x\n", csum); 366562306a36Sopenharmony_ci return -EINVAL; 366662306a36Sopenharmony_ci } 366762306a36Sopenharmony_ci 366862306a36Sopenharmony_ci i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */ 366962306a36Sopenharmony_ci ret = t4_flash_erase_sectors(adap, fw_start_sec, fw_start_sec + i - 1); 367062306a36Sopenharmony_ci if (ret) 367162306a36Sopenharmony_ci goto out; 367262306a36Sopenharmony_ci 367362306a36Sopenharmony_ci /* 367462306a36Sopenharmony_ci * We write the correct version at the end so the driver can see a bad 367562306a36Sopenharmony_ci * version if the FW write fails. Start by writing a copy of the 367662306a36Sopenharmony_ci * first page with a bad version. 367762306a36Sopenharmony_ci */ 367862306a36Sopenharmony_ci memcpy(first_page, fw_data, SF_PAGE_SIZE); 367962306a36Sopenharmony_ci ((struct fw_hdr *)first_page)->fw_ver = cpu_to_be32(0xffffffff); 368062306a36Sopenharmony_ci ret = t4_write_flash(adap, fw_start, SF_PAGE_SIZE, first_page, true); 368162306a36Sopenharmony_ci if (ret) 368262306a36Sopenharmony_ci goto out; 368362306a36Sopenharmony_ci 368462306a36Sopenharmony_ci addr = fw_start; 368562306a36Sopenharmony_ci for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { 368662306a36Sopenharmony_ci addr += SF_PAGE_SIZE; 368762306a36Sopenharmony_ci fw_data += SF_PAGE_SIZE; 368862306a36Sopenharmony_ci ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, fw_data, true); 368962306a36Sopenharmony_ci if (ret) 369062306a36Sopenharmony_ci goto out; 369162306a36Sopenharmony_ci } 369262306a36Sopenharmony_ci 369362306a36Sopenharmony_ci ret = t4_write_flash(adap, fw_start + offsetof(struct fw_hdr, fw_ver), 369462306a36Sopenharmony_ci sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver, 369562306a36Sopenharmony_ci true); 369662306a36Sopenharmony_ciout: 369762306a36Sopenharmony_ci if (ret) 369862306a36Sopenharmony_ci dev_err(adap->pdev_dev, "firmware download failed, error %d\n", 369962306a36Sopenharmony_ci ret); 370062306a36Sopenharmony_ci else 370162306a36Sopenharmony_ci ret = t4_get_fw_version(adap, &adap->params.fw_vers); 370262306a36Sopenharmony_ci return ret; 370362306a36Sopenharmony_ci} 370462306a36Sopenharmony_ci 370562306a36Sopenharmony_ci/** 370662306a36Sopenharmony_ci * t4_phy_fw_ver - return current PHY firmware version 370762306a36Sopenharmony_ci * @adap: the adapter 370862306a36Sopenharmony_ci * @phy_fw_ver: return value buffer for PHY firmware version 370962306a36Sopenharmony_ci * 371062306a36Sopenharmony_ci * Returns the current version of external PHY firmware on the 371162306a36Sopenharmony_ci * adapter. 371262306a36Sopenharmony_ci */ 371362306a36Sopenharmony_ciint t4_phy_fw_ver(struct adapter *adap, int *phy_fw_ver) 371462306a36Sopenharmony_ci{ 371562306a36Sopenharmony_ci u32 param, val; 371662306a36Sopenharmony_ci int ret; 371762306a36Sopenharmony_ci 371862306a36Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 371962306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PHYFW) | 372062306a36Sopenharmony_ci FW_PARAMS_PARAM_Y_V(adap->params.portvec) | 372162306a36Sopenharmony_ci FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_VERSION)); 372262306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, 372362306a36Sopenharmony_ci ¶m, &val); 372462306a36Sopenharmony_ci if (ret) 372562306a36Sopenharmony_ci return ret; 372662306a36Sopenharmony_ci *phy_fw_ver = val; 372762306a36Sopenharmony_ci return 0; 372862306a36Sopenharmony_ci} 372962306a36Sopenharmony_ci 373062306a36Sopenharmony_ci/** 373162306a36Sopenharmony_ci * t4_load_phy_fw - download port PHY firmware 373262306a36Sopenharmony_ci * @adap: the adapter 373362306a36Sopenharmony_ci * @win: the PCI-E Memory Window index to use for t4_memory_rw() 373462306a36Sopenharmony_ci * @phy_fw_version: function to check PHY firmware versions 373562306a36Sopenharmony_ci * @phy_fw_data: the PHY firmware image to write 373662306a36Sopenharmony_ci * @phy_fw_size: image size 373762306a36Sopenharmony_ci * 373862306a36Sopenharmony_ci * Transfer the specified PHY firmware to the adapter. If a non-NULL 373962306a36Sopenharmony_ci * @phy_fw_version is supplied, then it will be used to determine if 374062306a36Sopenharmony_ci * it's necessary to perform the transfer by comparing the version 374162306a36Sopenharmony_ci * of any existing adapter PHY firmware with that of the passed in 374262306a36Sopenharmony_ci * PHY firmware image. 374362306a36Sopenharmony_ci * 374462306a36Sopenharmony_ci * A negative error number will be returned if an error occurs. If 374562306a36Sopenharmony_ci * version number support is available and there's no need to upgrade 374662306a36Sopenharmony_ci * the firmware, 0 will be returned. If firmware is successfully 374762306a36Sopenharmony_ci * transferred to the adapter, 1 will be returned. 374862306a36Sopenharmony_ci * 374962306a36Sopenharmony_ci * NOTE: some adapters only have local RAM to store the PHY firmware. As 375062306a36Sopenharmony_ci * a result, a RESET of the adapter would cause that RAM to lose its 375162306a36Sopenharmony_ci * contents. Thus, loading PHY firmware on such adapters must happen 375262306a36Sopenharmony_ci * after any FW_RESET_CMDs ... 375362306a36Sopenharmony_ci */ 375462306a36Sopenharmony_ciint t4_load_phy_fw(struct adapter *adap, int win, 375562306a36Sopenharmony_ci int (*phy_fw_version)(const u8 *, size_t), 375662306a36Sopenharmony_ci const u8 *phy_fw_data, size_t phy_fw_size) 375762306a36Sopenharmony_ci{ 375862306a36Sopenharmony_ci int cur_phy_fw_ver = 0, new_phy_fw_vers = 0; 375962306a36Sopenharmony_ci unsigned long mtype = 0, maddr = 0; 376062306a36Sopenharmony_ci u32 param, val; 376162306a36Sopenharmony_ci int ret; 376262306a36Sopenharmony_ci 376362306a36Sopenharmony_ci /* If we have version number support, then check to see if the adapter 376462306a36Sopenharmony_ci * already has up-to-date PHY firmware loaded. 376562306a36Sopenharmony_ci */ 376662306a36Sopenharmony_ci if (phy_fw_version) { 376762306a36Sopenharmony_ci new_phy_fw_vers = phy_fw_version(phy_fw_data, phy_fw_size); 376862306a36Sopenharmony_ci ret = t4_phy_fw_ver(adap, &cur_phy_fw_ver); 376962306a36Sopenharmony_ci if (ret < 0) 377062306a36Sopenharmony_ci return ret; 377162306a36Sopenharmony_ci 377262306a36Sopenharmony_ci if (cur_phy_fw_ver >= new_phy_fw_vers) { 377362306a36Sopenharmony_ci CH_WARN(adap, "PHY Firmware already up-to-date, " 377462306a36Sopenharmony_ci "version %#x\n", cur_phy_fw_ver); 377562306a36Sopenharmony_ci return 0; 377662306a36Sopenharmony_ci } 377762306a36Sopenharmony_ci } 377862306a36Sopenharmony_ci 377962306a36Sopenharmony_ci /* Ask the firmware where it wants us to copy the PHY firmware image. 378062306a36Sopenharmony_ci * The size of the file requires a special version of the READ command 378162306a36Sopenharmony_ci * which will pass the file size via the values field in PARAMS_CMD and 378262306a36Sopenharmony_ci * retrieve the return value from firmware and place it in the same 378362306a36Sopenharmony_ci * buffer values 378462306a36Sopenharmony_ci */ 378562306a36Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 378662306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PHYFW) | 378762306a36Sopenharmony_ci FW_PARAMS_PARAM_Y_V(adap->params.portvec) | 378862306a36Sopenharmony_ci FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_DOWNLOAD)); 378962306a36Sopenharmony_ci val = phy_fw_size; 379062306a36Sopenharmony_ci ret = t4_query_params_rw(adap, adap->mbox, adap->pf, 0, 1, 379162306a36Sopenharmony_ci ¶m, &val, 1, true); 379262306a36Sopenharmony_ci if (ret < 0) 379362306a36Sopenharmony_ci return ret; 379462306a36Sopenharmony_ci mtype = val >> 8; 379562306a36Sopenharmony_ci maddr = (val & 0xff) << 16; 379662306a36Sopenharmony_ci 379762306a36Sopenharmony_ci /* Copy the supplied PHY Firmware image to the adapter memory location 379862306a36Sopenharmony_ci * allocated by the adapter firmware. 379962306a36Sopenharmony_ci */ 380062306a36Sopenharmony_ci spin_lock_bh(&adap->win0_lock); 380162306a36Sopenharmony_ci ret = t4_memory_rw(adap, win, mtype, maddr, 380262306a36Sopenharmony_ci phy_fw_size, (__be32 *)phy_fw_data, 380362306a36Sopenharmony_ci T4_MEMORY_WRITE); 380462306a36Sopenharmony_ci spin_unlock_bh(&adap->win0_lock); 380562306a36Sopenharmony_ci if (ret) 380662306a36Sopenharmony_ci return ret; 380762306a36Sopenharmony_ci 380862306a36Sopenharmony_ci /* Tell the firmware that the PHY firmware image has been written to 380962306a36Sopenharmony_ci * RAM and it can now start copying it over to the PHYs. The chip 381062306a36Sopenharmony_ci * firmware will RESET the affected PHYs as part of this operation 381162306a36Sopenharmony_ci * leaving them running the new PHY firmware image. 381262306a36Sopenharmony_ci */ 381362306a36Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 381462306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PHYFW) | 381562306a36Sopenharmony_ci FW_PARAMS_PARAM_Y_V(adap->params.portvec) | 381662306a36Sopenharmony_ci FW_PARAMS_PARAM_Z_V(FW_PARAMS_PARAM_DEV_PHYFW_DOWNLOAD)); 381762306a36Sopenharmony_ci ret = t4_set_params_timeout(adap, adap->mbox, adap->pf, 0, 1, 381862306a36Sopenharmony_ci ¶m, &val, 30000); 381962306a36Sopenharmony_ci if (ret) 382062306a36Sopenharmony_ci return ret; 382162306a36Sopenharmony_ci 382262306a36Sopenharmony_ci /* If we have version number support, then check to see that the new 382362306a36Sopenharmony_ci * firmware got loaded properly. 382462306a36Sopenharmony_ci */ 382562306a36Sopenharmony_ci if (phy_fw_version) { 382662306a36Sopenharmony_ci ret = t4_phy_fw_ver(adap, &cur_phy_fw_ver); 382762306a36Sopenharmony_ci if (ret < 0) 382862306a36Sopenharmony_ci return ret; 382962306a36Sopenharmony_ci 383062306a36Sopenharmony_ci if (cur_phy_fw_ver != new_phy_fw_vers) { 383162306a36Sopenharmony_ci CH_WARN(adap, "PHY Firmware did not update: " 383262306a36Sopenharmony_ci "version on adapter %#x, " 383362306a36Sopenharmony_ci "version flashed %#x\n", 383462306a36Sopenharmony_ci cur_phy_fw_ver, new_phy_fw_vers); 383562306a36Sopenharmony_ci return -ENXIO; 383662306a36Sopenharmony_ci } 383762306a36Sopenharmony_ci } 383862306a36Sopenharmony_ci 383962306a36Sopenharmony_ci return 1; 384062306a36Sopenharmony_ci} 384162306a36Sopenharmony_ci 384262306a36Sopenharmony_ci/** 384362306a36Sopenharmony_ci * t4_fwcache - firmware cache operation 384462306a36Sopenharmony_ci * @adap: the adapter 384562306a36Sopenharmony_ci * @op : the operation (flush or flush and invalidate) 384662306a36Sopenharmony_ci */ 384762306a36Sopenharmony_ciint t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op) 384862306a36Sopenharmony_ci{ 384962306a36Sopenharmony_ci struct fw_params_cmd c; 385062306a36Sopenharmony_ci 385162306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 385262306a36Sopenharmony_ci c.op_to_vfn = 385362306a36Sopenharmony_ci cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) | 385462306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F | 385562306a36Sopenharmony_ci FW_PARAMS_CMD_PFN_V(adap->pf) | 385662306a36Sopenharmony_ci FW_PARAMS_CMD_VFN_V(0)); 385762306a36Sopenharmony_ci c.retval_len16 = cpu_to_be32(FW_LEN16(c)); 385862306a36Sopenharmony_ci c.param[0].mnem = 385962306a36Sopenharmony_ci cpu_to_be32(FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 386062306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_FWCACHE)); 386162306a36Sopenharmony_ci c.param[0].val = cpu_to_be32(op); 386262306a36Sopenharmony_ci 386362306a36Sopenharmony_ci return t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), NULL); 386462306a36Sopenharmony_ci} 386562306a36Sopenharmony_ci 386662306a36Sopenharmony_civoid t4_cim_read_pif_la(struct adapter *adap, u32 *pif_req, u32 *pif_rsp, 386762306a36Sopenharmony_ci unsigned int *pif_req_wrptr, 386862306a36Sopenharmony_ci unsigned int *pif_rsp_wrptr) 386962306a36Sopenharmony_ci{ 387062306a36Sopenharmony_ci int i, j; 387162306a36Sopenharmony_ci u32 cfg, val, req, rsp; 387262306a36Sopenharmony_ci 387362306a36Sopenharmony_ci cfg = t4_read_reg(adap, CIM_DEBUGCFG_A); 387462306a36Sopenharmony_ci if (cfg & LADBGEN_F) 387562306a36Sopenharmony_ci t4_write_reg(adap, CIM_DEBUGCFG_A, cfg ^ LADBGEN_F); 387662306a36Sopenharmony_ci 387762306a36Sopenharmony_ci val = t4_read_reg(adap, CIM_DEBUGSTS_A); 387862306a36Sopenharmony_ci req = POLADBGWRPTR_G(val); 387962306a36Sopenharmony_ci rsp = PILADBGWRPTR_G(val); 388062306a36Sopenharmony_ci if (pif_req_wrptr) 388162306a36Sopenharmony_ci *pif_req_wrptr = req; 388262306a36Sopenharmony_ci if (pif_rsp_wrptr) 388362306a36Sopenharmony_ci *pif_rsp_wrptr = rsp; 388462306a36Sopenharmony_ci 388562306a36Sopenharmony_ci for (i = 0; i < CIM_PIFLA_SIZE; i++) { 388662306a36Sopenharmony_ci for (j = 0; j < 6; j++) { 388762306a36Sopenharmony_ci t4_write_reg(adap, CIM_DEBUGCFG_A, POLADBGRDPTR_V(req) | 388862306a36Sopenharmony_ci PILADBGRDPTR_V(rsp)); 388962306a36Sopenharmony_ci *pif_req++ = t4_read_reg(adap, CIM_PO_LA_DEBUGDATA_A); 389062306a36Sopenharmony_ci *pif_rsp++ = t4_read_reg(adap, CIM_PI_LA_DEBUGDATA_A); 389162306a36Sopenharmony_ci req++; 389262306a36Sopenharmony_ci rsp++; 389362306a36Sopenharmony_ci } 389462306a36Sopenharmony_ci req = (req + 2) & POLADBGRDPTR_M; 389562306a36Sopenharmony_ci rsp = (rsp + 2) & PILADBGRDPTR_M; 389662306a36Sopenharmony_ci } 389762306a36Sopenharmony_ci t4_write_reg(adap, CIM_DEBUGCFG_A, cfg); 389862306a36Sopenharmony_ci} 389962306a36Sopenharmony_ci 390062306a36Sopenharmony_civoid t4_cim_read_ma_la(struct adapter *adap, u32 *ma_req, u32 *ma_rsp) 390162306a36Sopenharmony_ci{ 390262306a36Sopenharmony_ci u32 cfg; 390362306a36Sopenharmony_ci int i, j, idx; 390462306a36Sopenharmony_ci 390562306a36Sopenharmony_ci cfg = t4_read_reg(adap, CIM_DEBUGCFG_A); 390662306a36Sopenharmony_ci if (cfg & LADBGEN_F) 390762306a36Sopenharmony_ci t4_write_reg(adap, CIM_DEBUGCFG_A, cfg ^ LADBGEN_F); 390862306a36Sopenharmony_ci 390962306a36Sopenharmony_ci for (i = 0; i < CIM_MALA_SIZE; i++) { 391062306a36Sopenharmony_ci for (j = 0; j < 5; j++) { 391162306a36Sopenharmony_ci idx = 8 * i + j; 391262306a36Sopenharmony_ci t4_write_reg(adap, CIM_DEBUGCFG_A, POLADBGRDPTR_V(idx) | 391362306a36Sopenharmony_ci PILADBGRDPTR_V(idx)); 391462306a36Sopenharmony_ci *ma_req++ = t4_read_reg(adap, CIM_PO_LA_MADEBUGDATA_A); 391562306a36Sopenharmony_ci *ma_rsp++ = t4_read_reg(adap, CIM_PI_LA_MADEBUGDATA_A); 391662306a36Sopenharmony_ci } 391762306a36Sopenharmony_ci } 391862306a36Sopenharmony_ci t4_write_reg(adap, CIM_DEBUGCFG_A, cfg); 391962306a36Sopenharmony_ci} 392062306a36Sopenharmony_ci 392162306a36Sopenharmony_civoid t4_ulprx_read_la(struct adapter *adap, u32 *la_buf) 392262306a36Sopenharmony_ci{ 392362306a36Sopenharmony_ci unsigned int i, j; 392462306a36Sopenharmony_ci 392562306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 392662306a36Sopenharmony_ci u32 *p = la_buf + i; 392762306a36Sopenharmony_ci 392862306a36Sopenharmony_ci t4_write_reg(adap, ULP_RX_LA_CTL_A, i); 392962306a36Sopenharmony_ci j = t4_read_reg(adap, ULP_RX_LA_WRPTR_A); 393062306a36Sopenharmony_ci t4_write_reg(adap, ULP_RX_LA_RDPTR_A, j); 393162306a36Sopenharmony_ci for (j = 0; j < ULPRX_LA_SIZE; j++, p += 8) 393262306a36Sopenharmony_ci *p = t4_read_reg(adap, ULP_RX_LA_RDDATA_A); 393362306a36Sopenharmony_ci } 393462306a36Sopenharmony_ci} 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_ci/* The ADVERT_MASK is used to mask out all of the Advertised Firmware Port 393762306a36Sopenharmony_ci * Capabilities which we control with separate controls -- see, for instance, 393862306a36Sopenharmony_ci * Pause Frames and Forward Error Correction. In order to determine what the 393962306a36Sopenharmony_ci * full set of Advertised Port Capabilities are, the base Advertised Port 394062306a36Sopenharmony_ci * Capabilities (masked by ADVERT_MASK) must be combined with the Advertised 394162306a36Sopenharmony_ci * Port Capabilities associated with those other controls. See 394262306a36Sopenharmony_ci * t4_link_acaps() for how this is done. 394362306a36Sopenharmony_ci */ 394462306a36Sopenharmony_ci#define ADVERT_MASK (FW_PORT_CAP32_SPEED_V(FW_PORT_CAP32_SPEED_M) | \ 394562306a36Sopenharmony_ci FW_PORT_CAP32_ANEG) 394662306a36Sopenharmony_ci 394762306a36Sopenharmony_ci/** 394862306a36Sopenharmony_ci * fwcaps16_to_caps32 - convert 16-bit Port Capabilities to 32-bits 394962306a36Sopenharmony_ci * @caps16: a 16-bit Port Capabilities value 395062306a36Sopenharmony_ci * 395162306a36Sopenharmony_ci * Returns the equivalent 32-bit Port Capabilities value. 395262306a36Sopenharmony_ci */ 395362306a36Sopenharmony_cistatic fw_port_cap32_t fwcaps16_to_caps32(fw_port_cap16_t caps16) 395462306a36Sopenharmony_ci{ 395562306a36Sopenharmony_ci fw_port_cap32_t caps32 = 0; 395662306a36Sopenharmony_ci 395762306a36Sopenharmony_ci #define CAP16_TO_CAP32(__cap) \ 395862306a36Sopenharmony_ci do { \ 395962306a36Sopenharmony_ci if (caps16 & FW_PORT_CAP_##__cap) \ 396062306a36Sopenharmony_ci caps32 |= FW_PORT_CAP32_##__cap; \ 396162306a36Sopenharmony_ci } while (0) 396262306a36Sopenharmony_ci 396362306a36Sopenharmony_ci CAP16_TO_CAP32(SPEED_100M); 396462306a36Sopenharmony_ci CAP16_TO_CAP32(SPEED_1G); 396562306a36Sopenharmony_ci CAP16_TO_CAP32(SPEED_25G); 396662306a36Sopenharmony_ci CAP16_TO_CAP32(SPEED_10G); 396762306a36Sopenharmony_ci CAP16_TO_CAP32(SPEED_40G); 396862306a36Sopenharmony_ci CAP16_TO_CAP32(SPEED_100G); 396962306a36Sopenharmony_ci CAP16_TO_CAP32(FC_RX); 397062306a36Sopenharmony_ci CAP16_TO_CAP32(FC_TX); 397162306a36Sopenharmony_ci CAP16_TO_CAP32(ANEG); 397262306a36Sopenharmony_ci CAP16_TO_CAP32(FORCE_PAUSE); 397362306a36Sopenharmony_ci CAP16_TO_CAP32(MDIAUTO); 397462306a36Sopenharmony_ci CAP16_TO_CAP32(MDISTRAIGHT); 397562306a36Sopenharmony_ci CAP16_TO_CAP32(FEC_RS); 397662306a36Sopenharmony_ci CAP16_TO_CAP32(FEC_BASER_RS); 397762306a36Sopenharmony_ci CAP16_TO_CAP32(802_3_PAUSE); 397862306a36Sopenharmony_ci CAP16_TO_CAP32(802_3_ASM_DIR); 397962306a36Sopenharmony_ci 398062306a36Sopenharmony_ci #undef CAP16_TO_CAP32 398162306a36Sopenharmony_ci 398262306a36Sopenharmony_ci return caps32; 398362306a36Sopenharmony_ci} 398462306a36Sopenharmony_ci 398562306a36Sopenharmony_ci/** 398662306a36Sopenharmony_ci * fwcaps32_to_caps16 - convert 32-bit Port Capabilities to 16-bits 398762306a36Sopenharmony_ci * @caps32: a 32-bit Port Capabilities value 398862306a36Sopenharmony_ci * 398962306a36Sopenharmony_ci * Returns the equivalent 16-bit Port Capabilities value. Note that 399062306a36Sopenharmony_ci * not all 32-bit Port Capabilities can be represented in the 16-bit 399162306a36Sopenharmony_ci * Port Capabilities and some fields/values may not make it. 399262306a36Sopenharmony_ci */ 399362306a36Sopenharmony_cistatic fw_port_cap16_t fwcaps32_to_caps16(fw_port_cap32_t caps32) 399462306a36Sopenharmony_ci{ 399562306a36Sopenharmony_ci fw_port_cap16_t caps16 = 0; 399662306a36Sopenharmony_ci 399762306a36Sopenharmony_ci #define CAP32_TO_CAP16(__cap) \ 399862306a36Sopenharmony_ci do { \ 399962306a36Sopenharmony_ci if (caps32 & FW_PORT_CAP32_##__cap) \ 400062306a36Sopenharmony_ci caps16 |= FW_PORT_CAP_##__cap; \ 400162306a36Sopenharmony_ci } while (0) 400262306a36Sopenharmony_ci 400362306a36Sopenharmony_ci CAP32_TO_CAP16(SPEED_100M); 400462306a36Sopenharmony_ci CAP32_TO_CAP16(SPEED_1G); 400562306a36Sopenharmony_ci CAP32_TO_CAP16(SPEED_10G); 400662306a36Sopenharmony_ci CAP32_TO_CAP16(SPEED_25G); 400762306a36Sopenharmony_ci CAP32_TO_CAP16(SPEED_40G); 400862306a36Sopenharmony_ci CAP32_TO_CAP16(SPEED_100G); 400962306a36Sopenharmony_ci CAP32_TO_CAP16(FC_RX); 401062306a36Sopenharmony_ci CAP32_TO_CAP16(FC_TX); 401162306a36Sopenharmony_ci CAP32_TO_CAP16(802_3_PAUSE); 401262306a36Sopenharmony_ci CAP32_TO_CAP16(802_3_ASM_DIR); 401362306a36Sopenharmony_ci CAP32_TO_CAP16(ANEG); 401462306a36Sopenharmony_ci CAP32_TO_CAP16(FORCE_PAUSE); 401562306a36Sopenharmony_ci CAP32_TO_CAP16(MDIAUTO); 401662306a36Sopenharmony_ci CAP32_TO_CAP16(MDISTRAIGHT); 401762306a36Sopenharmony_ci CAP32_TO_CAP16(FEC_RS); 401862306a36Sopenharmony_ci CAP32_TO_CAP16(FEC_BASER_RS); 401962306a36Sopenharmony_ci 402062306a36Sopenharmony_ci #undef CAP32_TO_CAP16 402162306a36Sopenharmony_ci 402262306a36Sopenharmony_ci return caps16; 402362306a36Sopenharmony_ci} 402462306a36Sopenharmony_ci 402562306a36Sopenharmony_ci/* Translate Firmware Port Capabilities Pause specification to Common Code */ 402662306a36Sopenharmony_cistatic inline enum cc_pause fwcap_to_cc_pause(fw_port_cap32_t fw_pause) 402762306a36Sopenharmony_ci{ 402862306a36Sopenharmony_ci enum cc_pause cc_pause = 0; 402962306a36Sopenharmony_ci 403062306a36Sopenharmony_ci if (fw_pause & FW_PORT_CAP32_FC_RX) 403162306a36Sopenharmony_ci cc_pause |= PAUSE_RX; 403262306a36Sopenharmony_ci if (fw_pause & FW_PORT_CAP32_FC_TX) 403362306a36Sopenharmony_ci cc_pause |= PAUSE_TX; 403462306a36Sopenharmony_ci 403562306a36Sopenharmony_ci return cc_pause; 403662306a36Sopenharmony_ci} 403762306a36Sopenharmony_ci 403862306a36Sopenharmony_ci/* Translate Common Code Pause specification into Firmware Port Capabilities */ 403962306a36Sopenharmony_cistatic inline fw_port_cap32_t cc_to_fwcap_pause(enum cc_pause cc_pause) 404062306a36Sopenharmony_ci{ 404162306a36Sopenharmony_ci /* Translate orthogonal RX/TX Pause Controls for L1 Configure 404262306a36Sopenharmony_ci * commands, etc. 404362306a36Sopenharmony_ci */ 404462306a36Sopenharmony_ci fw_port_cap32_t fw_pause = 0; 404562306a36Sopenharmony_ci 404662306a36Sopenharmony_ci if (cc_pause & PAUSE_RX) 404762306a36Sopenharmony_ci fw_pause |= FW_PORT_CAP32_FC_RX; 404862306a36Sopenharmony_ci if (cc_pause & PAUSE_TX) 404962306a36Sopenharmony_ci fw_pause |= FW_PORT_CAP32_FC_TX; 405062306a36Sopenharmony_ci if (!(cc_pause & PAUSE_AUTONEG)) 405162306a36Sopenharmony_ci fw_pause |= FW_PORT_CAP32_FORCE_PAUSE; 405262306a36Sopenharmony_ci 405362306a36Sopenharmony_ci /* Translate orthogonal Pause controls into IEEE 802.3 Pause, 405462306a36Sopenharmony_ci * Asymmetrical Pause for use in reporting to upper layer OS code, etc. 405562306a36Sopenharmony_ci * Note that these bits are ignored in L1 Configure commands. 405662306a36Sopenharmony_ci */ 405762306a36Sopenharmony_ci if (cc_pause & PAUSE_RX) { 405862306a36Sopenharmony_ci if (cc_pause & PAUSE_TX) 405962306a36Sopenharmony_ci fw_pause |= FW_PORT_CAP32_802_3_PAUSE; 406062306a36Sopenharmony_ci else 406162306a36Sopenharmony_ci fw_pause |= FW_PORT_CAP32_802_3_ASM_DIR | 406262306a36Sopenharmony_ci FW_PORT_CAP32_802_3_PAUSE; 406362306a36Sopenharmony_ci } else if (cc_pause & PAUSE_TX) { 406462306a36Sopenharmony_ci fw_pause |= FW_PORT_CAP32_802_3_ASM_DIR; 406562306a36Sopenharmony_ci } 406662306a36Sopenharmony_ci 406762306a36Sopenharmony_ci return fw_pause; 406862306a36Sopenharmony_ci} 406962306a36Sopenharmony_ci 407062306a36Sopenharmony_ci/* Translate Firmware Forward Error Correction specification to Common Code */ 407162306a36Sopenharmony_cistatic inline enum cc_fec fwcap_to_cc_fec(fw_port_cap32_t fw_fec) 407262306a36Sopenharmony_ci{ 407362306a36Sopenharmony_ci enum cc_fec cc_fec = 0; 407462306a36Sopenharmony_ci 407562306a36Sopenharmony_ci if (fw_fec & FW_PORT_CAP32_FEC_RS) 407662306a36Sopenharmony_ci cc_fec |= FEC_RS; 407762306a36Sopenharmony_ci if (fw_fec & FW_PORT_CAP32_FEC_BASER_RS) 407862306a36Sopenharmony_ci cc_fec |= FEC_BASER_RS; 407962306a36Sopenharmony_ci 408062306a36Sopenharmony_ci return cc_fec; 408162306a36Sopenharmony_ci} 408262306a36Sopenharmony_ci 408362306a36Sopenharmony_ci/* Translate Common Code Forward Error Correction specification to Firmware */ 408462306a36Sopenharmony_cistatic inline fw_port_cap32_t cc_to_fwcap_fec(enum cc_fec cc_fec) 408562306a36Sopenharmony_ci{ 408662306a36Sopenharmony_ci fw_port_cap32_t fw_fec = 0; 408762306a36Sopenharmony_ci 408862306a36Sopenharmony_ci if (cc_fec & FEC_RS) 408962306a36Sopenharmony_ci fw_fec |= FW_PORT_CAP32_FEC_RS; 409062306a36Sopenharmony_ci if (cc_fec & FEC_BASER_RS) 409162306a36Sopenharmony_ci fw_fec |= FW_PORT_CAP32_FEC_BASER_RS; 409262306a36Sopenharmony_ci 409362306a36Sopenharmony_ci return fw_fec; 409462306a36Sopenharmony_ci} 409562306a36Sopenharmony_ci 409662306a36Sopenharmony_ci/** 409762306a36Sopenharmony_ci * t4_link_acaps - compute Link Advertised Port Capabilities 409862306a36Sopenharmony_ci * @adapter: the adapter 409962306a36Sopenharmony_ci * @port: the Port ID 410062306a36Sopenharmony_ci * @lc: the Port's Link Configuration 410162306a36Sopenharmony_ci * 410262306a36Sopenharmony_ci * Synthesize the Advertised Port Capabilities we'll be using based on 410362306a36Sopenharmony_ci * the base Advertised Port Capabilities (which have been filtered by 410462306a36Sopenharmony_ci * ADVERT_MASK) plus the individual controls for things like Pause 410562306a36Sopenharmony_ci * Frames, Forward Error Correction, MDI, etc. 410662306a36Sopenharmony_ci */ 410762306a36Sopenharmony_cifw_port_cap32_t t4_link_acaps(struct adapter *adapter, unsigned int port, 410862306a36Sopenharmony_ci struct link_config *lc) 410962306a36Sopenharmony_ci{ 411062306a36Sopenharmony_ci fw_port_cap32_t fw_fc, fw_fec, acaps; 411162306a36Sopenharmony_ci unsigned int fw_mdi; 411262306a36Sopenharmony_ci char cc_fec; 411362306a36Sopenharmony_ci 411462306a36Sopenharmony_ci fw_mdi = (FW_PORT_CAP32_MDI_V(FW_PORT_CAP32_MDI_AUTO) & lc->pcaps); 411562306a36Sopenharmony_ci 411662306a36Sopenharmony_ci /* Convert driver coding of Pause Frame Flow Control settings into the 411762306a36Sopenharmony_ci * Firmware's API. 411862306a36Sopenharmony_ci */ 411962306a36Sopenharmony_ci fw_fc = cc_to_fwcap_pause(lc->requested_fc); 412062306a36Sopenharmony_ci 412162306a36Sopenharmony_ci /* Convert Common Code Forward Error Control settings into the 412262306a36Sopenharmony_ci * Firmware's API. If the current Requested FEC has "Automatic" 412362306a36Sopenharmony_ci * (IEEE 802.3) specified, then we use whatever the Firmware 412462306a36Sopenharmony_ci * sent us as part of its IEEE 802.3-based interpretation of 412562306a36Sopenharmony_ci * the Transceiver Module EPROM FEC parameters. Otherwise we 412662306a36Sopenharmony_ci * use whatever is in the current Requested FEC settings. 412762306a36Sopenharmony_ci */ 412862306a36Sopenharmony_ci if (lc->requested_fec & FEC_AUTO) 412962306a36Sopenharmony_ci cc_fec = fwcap_to_cc_fec(lc->def_acaps); 413062306a36Sopenharmony_ci else 413162306a36Sopenharmony_ci cc_fec = lc->requested_fec; 413262306a36Sopenharmony_ci fw_fec = cc_to_fwcap_fec(cc_fec); 413362306a36Sopenharmony_ci 413462306a36Sopenharmony_ci /* Figure out what our Requested Port Capabilities are going to be. 413562306a36Sopenharmony_ci * Note parallel structure in t4_handle_get_port_info() and 413662306a36Sopenharmony_ci * init_link_config(). 413762306a36Sopenharmony_ci */ 413862306a36Sopenharmony_ci if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) { 413962306a36Sopenharmony_ci acaps = lc->acaps | fw_fc | fw_fec; 414062306a36Sopenharmony_ci lc->fc = lc->requested_fc & ~PAUSE_AUTONEG; 414162306a36Sopenharmony_ci lc->fec = cc_fec; 414262306a36Sopenharmony_ci } else if (lc->autoneg == AUTONEG_DISABLE) { 414362306a36Sopenharmony_ci acaps = lc->speed_caps | fw_fc | fw_fec | fw_mdi; 414462306a36Sopenharmony_ci lc->fc = lc->requested_fc & ~PAUSE_AUTONEG; 414562306a36Sopenharmony_ci lc->fec = cc_fec; 414662306a36Sopenharmony_ci } else { 414762306a36Sopenharmony_ci acaps = lc->acaps | fw_fc | fw_fec | fw_mdi; 414862306a36Sopenharmony_ci } 414962306a36Sopenharmony_ci 415062306a36Sopenharmony_ci /* Some Requested Port Capabilities are trivially wrong if they exceed 415162306a36Sopenharmony_ci * the Physical Port Capabilities. We can check that here and provide 415262306a36Sopenharmony_ci * moderately useful feedback in the system log. 415362306a36Sopenharmony_ci * 415462306a36Sopenharmony_ci * Note that older Firmware doesn't have FW_PORT_CAP32_FORCE_PAUSE, so 415562306a36Sopenharmony_ci * we need to exclude this from this check in order to maintain 415662306a36Sopenharmony_ci * compatibility ... 415762306a36Sopenharmony_ci */ 415862306a36Sopenharmony_ci if ((acaps & ~lc->pcaps) & ~FW_PORT_CAP32_FORCE_PAUSE) { 415962306a36Sopenharmony_ci dev_err(adapter->pdev_dev, "Requested Port Capabilities %#x exceed Physical Port Capabilities %#x\n", 416062306a36Sopenharmony_ci acaps, lc->pcaps); 416162306a36Sopenharmony_ci return -EINVAL; 416262306a36Sopenharmony_ci } 416362306a36Sopenharmony_ci 416462306a36Sopenharmony_ci return acaps; 416562306a36Sopenharmony_ci} 416662306a36Sopenharmony_ci 416762306a36Sopenharmony_ci/** 416862306a36Sopenharmony_ci * t4_link_l1cfg_core - apply link configuration to MAC/PHY 416962306a36Sopenharmony_ci * @adapter: the adapter 417062306a36Sopenharmony_ci * @mbox: the Firmware Mailbox to use 417162306a36Sopenharmony_ci * @port: the Port ID 417262306a36Sopenharmony_ci * @lc: the Port's Link Configuration 417362306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 417462306a36Sopenharmony_ci * @timeout: time to wait for command to finish before timing out 417562306a36Sopenharmony_ci * (negative implies @sleep_ok=false) 417662306a36Sopenharmony_ci * 417762306a36Sopenharmony_ci * Set up a port's MAC and PHY according to a desired link configuration. 417862306a36Sopenharmony_ci * - If the PHY can auto-negotiate first decide what to advertise, then 417962306a36Sopenharmony_ci * enable/disable auto-negotiation as desired, and reset. 418062306a36Sopenharmony_ci * - If the PHY does not auto-negotiate just reset it. 418162306a36Sopenharmony_ci * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC, 418262306a36Sopenharmony_ci * otherwise do it later based on the outcome of auto-negotiation. 418362306a36Sopenharmony_ci */ 418462306a36Sopenharmony_ciint t4_link_l1cfg_core(struct adapter *adapter, unsigned int mbox, 418562306a36Sopenharmony_ci unsigned int port, struct link_config *lc, 418662306a36Sopenharmony_ci u8 sleep_ok, int timeout) 418762306a36Sopenharmony_ci{ 418862306a36Sopenharmony_ci unsigned int fw_caps = adapter->params.fw_caps_support; 418962306a36Sopenharmony_ci struct fw_port_cmd cmd; 419062306a36Sopenharmony_ci fw_port_cap32_t rcap; 419162306a36Sopenharmony_ci int ret; 419262306a36Sopenharmony_ci 419362306a36Sopenharmony_ci if (!(lc->pcaps & FW_PORT_CAP32_ANEG) && 419462306a36Sopenharmony_ci lc->autoneg == AUTONEG_ENABLE) { 419562306a36Sopenharmony_ci return -EINVAL; 419662306a36Sopenharmony_ci } 419762306a36Sopenharmony_ci 419862306a36Sopenharmony_ci /* Compute our Requested Port Capabilities and send that on to the 419962306a36Sopenharmony_ci * Firmware. 420062306a36Sopenharmony_ci */ 420162306a36Sopenharmony_ci rcap = t4_link_acaps(adapter, port, lc); 420262306a36Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 420362306a36Sopenharmony_ci cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) | 420462306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_EXEC_F | 420562306a36Sopenharmony_ci FW_PORT_CMD_PORTID_V(port)); 420662306a36Sopenharmony_ci cmd.action_to_len16 = 420762306a36Sopenharmony_ci cpu_to_be32(FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16 420862306a36Sopenharmony_ci ? FW_PORT_ACTION_L1_CFG 420962306a36Sopenharmony_ci : FW_PORT_ACTION_L1_CFG32) | 421062306a36Sopenharmony_ci FW_LEN16(cmd)); 421162306a36Sopenharmony_ci if (fw_caps == FW_CAPS16) 421262306a36Sopenharmony_ci cmd.u.l1cfg.rcap = cpu_to_be32(fwcaps32_to_caps16(rcap)); 421362306a36Sopenharmony_ci else 421462306a36Sopenharmony_ci cmd.u.l1cfg32.rcap32 = cpu_to_be32(rcap); 421562306a36Sopenharmony_ci 421662306a36Sopenharmony_ci ret = t4_wr_mbox_meat_timeout(adapter, mbox, &cmd, sizeof(cmd), NULL, 421762306a36Sopenharmony_ci sleep_ok, timeout); 421862306a36Sopenharmony_ci 421962306a36Sopenharmony_ci /* Unfortunately, even if the Requested Port Capabilities "fit" within 422062306a36Sopenharmony_ci * the Physical Port Capabilities, some combinations of features may 422162306a36Sopenharmony_ci * still not be legal. For example, 40Gb/s and Reed-Solomon Forward 422262306a36Sopenharmony_ci * Error Correction. So if the Firmware rejects the L1 Configure 422362306a36Sopenharmony_ci * request, flag that here. 422462306a36Sopenharmony_ci */ 422562306a36Sopenharmony_ci if (ret) { 422662306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 422762306a36Sopenharmony_ci "Requested Port Capabilities %#x rejected, error %d\n", 422862306a36Sopenharmony_ci rcap, -ret); 422962306a36Sopenharmony_ci return ret; 423062306a36Sopenharmony_ci } 423162306a36Sopenharmony_ci return 0; 423262306a36Sopenharmony_ci} 423362306a36Sopenharmony_ci 423462306a36Sopenharmony_ci/** 423562306a36Sopenharmony_ci * t4_restart_aneg - restart autonegotiation 423662306a36Sopenharmony_ci * @adap: the adapter 423762306a36Sopenharmony_ci * @mbox: mbox to use for the FW command 423862306a36Sopenharmony_ci * @port: the port id 423962306a36Sopenharmony_ci * 424062306a36Sopenharmony_ci * Restarts autonegotiation for the selected port. 424162306a36Sopenharmony_ci */ 424262306a36Sopenharmony_ciint t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port) 424362306a36Sopenharmony_ci{ 424462306a36Sopenharmony_ci unsigned int fw_caps = adap->params.fw_caps_support; 424562306a36Sopenharmony_ci struct fw_port_cmd c; 424662306a36Sopenharmony_ci 424762306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 424862306a36Sopenharmony_ci c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) | 424962306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_EXEC_F | 425062306a36Sopenharmony_ci FW_PORT_CMD_PORTID_V(port)); 425162306a36Sopenharmony_ci c.action_to_len16 = 425262306a36Sopenharmony_ci cpu_to_be32(FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16 425362306a36Sopenharmony_ci ? FW_PORT_ACTION_L1_CFG 425462306a36Sopenharmony_ci : FW_PORT_ACTION_L1_CFG32) | 425562306a36Sopenharmony_ci FW_LEN16(c)); 425662306a36Sopenharmony_ci if (fw_caps == FW_CAPS16) 425762306a36Sopenharmony_ci c.u.l1cfg.rcap = cpu_to_be32(FW_PORT_CAP_ANEG); 425862306a36Sopenharmony_ci else 425962306a36Sopenharmony_ci c.u.l1cfg32.rcap32 = cpu_to_be32(FW_PORT_CAP32_ANEG); 426062306a36Sopenharmony_ci return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 426162306a36Sopenharmony_ci} 426262306a36Sopenharmony_ci 426362306a36Sopenharmony_citypedef void (*int_handler_t)(struct adapter *adap); 426462306a36Sopenharmony_ci 426562306a36Sopenharmony_cistruct intr_info { 426662306a36Sopenharmony_ci unsigned int mask; /* bits to check in interrupt status */ 426762306a36Sopenharmony_ci const char *msg; /* message to print or NULL */ 426862306a36Sopenharmony_ci short stat_idx; /* stat counter to increment or -1 */ 426962306a36Sopenharmony_ci unsigned short fatal; /* whether the condition reported is fatal */ 427062306a36Sopenharmony_ci int_handler_t int_handler; /* platform-specific int handler */ 427162306a36Sopenharmony_ci}; 427262306a36Sopenharmony_ci 427362306a36Sopenharmony_ci/** 427462306a36Sopenharmony_ci * t4_handle_intr_status - table driven interrupt handler 427562306a36Sopenharmony_ci * @adapter: the adapter that generated the interrupt 427662306a36Sopenharmony_ci * @reg: the interrupt status register to process 427762306a36Sopenharmony_ci * @acts: table of interrupt actions 427862306a36Sopenharmony_ci * 427962306a36Sopenharmony_ci * A table driven interrupt handler that applies a set of masks to an 428062306a36Sopenharmony_ci * interrupt status word and performs the corresponding actions if the 428162306a36Sopenharmony_ci * interrupts described by the mask have occurred. The actions include 428262306a36Sopenharmony_ci * optionally emitting a warning or alert message. The table is terminated 428362306a36Sopenharmony_ci * by an entry specifying mask 0. Returns the number of fatal interrupt 428462306a36Sopenharmony_ci * conditions. 428562306a36Sopenharmony_ci */ 428662306a36Sopenharmony_cistatic int t4_handle_intr_status(struct adapter *adapter, unsigned int reg, 428762306a36Sopenharmony_ci const struct intr_info *acts) 428862306a36Sopenharmony_ci{ 428962306a36Sopenharmony_ci int fatal = 0; 429062306a36Sopenharmony_ci unsigned int mask = 0; 429162306a36Sopenharmony_ci unsigned int status = t4_read_reg(adapter, reg); 429262306a36Sopenharmony_ci 429362306a36Sopenharmony_ci for ( ; acts->mask; ++acts) { 429462306a36Sopenharmony_ci if (!(status & acts->mask)) 429562306a36Sopenharmony_ci continue; 429662306a36Sopenharmony_ci if (acts->fatal) { 429762306a36Sopenharmony_ci fatal++; 429862306a36Sopenharmony_ci dev_alert(adapter->pdev_dev, "%s (0x%x)\n", acts->msg, 429962306a36Sopenharmony_ci status & acts->mask); 430062306a36Sopenharmony_ci } else if (acts->msg && printk_ratelimit()) 430162306a36Sopenharmony_ci dev_warn(adapter->pdev_dev, "%s (0x%x)\n", acts->msg, 430262306a36Sopenharmony_ci status & acts->mask); 430362306a36Sopenharmony_ci if (acts->int_handler) 430462306a36Sopenharmony_ci acts->int_handler(adapter); 430562306a36Sopenharmony_ci mask |= acts->mask; 430662306a36Sopenharmony_ci } 430762306a36Sopenharmony_ci status &= mask; 430862306a36Sopenharmony_ci if (status) /* clear processed interrupts */ 430962306a36Sopenharmony_ci t4_write_reg(adapter, reg, status); 431062306a36Sopenharmony_ci return fatal; 431162306a36Sopenharmony_ci} 431262306a36Sopenharmony_ci 431362306a36Sopenharmony_ci/* 431462306a36Sopenharmony_ci * Interrupt handler for the PCIE module. 431562306a36Sopenharmony_ci */ 431662306a36Sopenharmony_cistatic void pcie_intr_handler(struct adapter *adapter) 431762306a36Sopenharmony_ci{ 431862306a36Sopenharmony_ci static const struct intr_info sysbus_intr_info[] = { 431962306a36Sopenharmony_ci { RNPP_F, "RXNP array parity error", -1, 1 }, 432062306a36Sopenharmony_ci { RPCP_F, "RXPC array parity error", -1, 1 }, 432162306a36Sopenharmony_ci { RCIP_F, "RXCIF array parity error", -1, 1 }, 432262306a36Sopenharmony_ci { RCCP_F, "Rx completions control array parity error", -1, 1 }, 432362306a36Sopenharmony_ci { RFTP_F, "RXFT array parity error", -1, 1 }, 432462306a36Sopenharmony_ci { 0 } 432562306a36Sopenharmony_ci }; 432662306a36Sopenharmony_ci static const struct intr_info pcie_port_intr_info[] = { 432762306a36Sopenharmony_ci { TPCP_F, "TXPC array parity error", -1, 1 }, 432862306a36Sopenharmony_ci { TNPP_F, "TXNP array parity error", -1, 1 }, 432962306a36Sopenharmony_ci { TFTP_F, "TXFT array parity error", -1, 1 }, 433062306a36Sopenharmony_ci { TCAP_F, "TXCA array parity error", -1, 1 }, 433162306a36Sopenharmony_ci { TCIP_F, "TXCIF array parity error", -1, 1 }, 433262306a36Sopenharmony_ci { RCAP_F, "RXCA array parity error", -1, 1 }, 433362306a36Sopenharmony_ci { OTDD_F, "outbound request TLP discarded", -1, 1 }, 433462306a36Sopenharmony_ci { RDPE_F, "Rx data parity error", -1, 1 }, 433562306a36Sopenharmony_ci { TDUE_F, "Tx uncorrectable data error", -1, 1 }, 433662306a36Sopenharmony_ci { 0 } 433762306a36Sopenharmony_ci }; 433862306a36Sopenharmony_ci static const struct intr_info pcie_intr_info[] = { 433962306a36Sopenharmony_ci { MSIADDRLPERR_F, "MSI AddrL parity error", -1, 1 }, 434062306a36Sopenharmony_ci { MSIADDRHPERR_F, "MSI AddrH parity error", -1, 1 }, 434162306a36Sopenharmony_ci { MSIDATAPERR_F, "MSI data parity error", -1, 1 }, 434262306a36Sopenharmony_ci { MSIXADDRLPERR_F, "MSI-X AddrL parity error", -1, 1 }, 434362306a36Sopenharmony_ci { MSIXADDRHPERR_F, "MSI-X AddrH parity error", -1, 1 }, 434462306a36Sopenharmony_ci { MSIXDATAPERR_F, "MSI-X data parity error", -1, 1 }, 434562306a36Sopenharmony_ci { MSIXDIPERR_F, "MSI-X DI parity error", -1, 1 }, 434662306a36Sopenharmony_ci { PIOCPLPERR_F, "PCI PIO completion FIFO parity error", -1, 1 }, 434762306a36Sopenharmony_ci { PIOREQPERR_F, "PCI PIO request FIFO parity error", -1, 1 }, 434862306a36Sopenharmony_ci { TARTAGPERR_F, "PCI PCI target tag FIFO parity error", -1, 1 }, 434962306a36Sopenharmony_ci { CCNTPERR_F, "PCI CMD channel count parity error", -1, 1 }, 435062306a36Sopenharmony_ci { CREQPERR_F, "PCI CMD channel request parity error", -1, 1 }, 435162306a36Sopenharmony_ci { CRSPPERR_F, "PCI CMD channel response parity error", -1, 1 }, 435262306a36Sopenharmony_ci { DCNTPERR_F, "PCI DMA channel count parity error", -1, 1 }, 435362306a36Sopenharmony_ci { DREQPERR_F, "PCI DMA channel request parity error", -1, 1 }, 435462306a36Sopenharmony_ci { DRSPPERR_F, "PCI DMA channel response parity error", -1, 1 }, 435562306a36Sopenharmony_ci { HCNTPERR_F, "PCI HMA channel count parity error", -1, 1 }, 435662306a36Sopenharmony_ci { HREQPERR_F, "PCI HMA channel request parity error", -1, 1 }, 435762306a36Sopenharmony_ci { HRSPPERR_F, "PCI HMA channel response parity error", -1, 1 }, 435862306a36Sopenharmony_ci { CFGSNPPERR_F, "PCI config snoop FIFO parity error", -1, 1 }, 435962306a36Sopenharmony_ci { FIDPERR_F, "PCI FID parity error", -1, 1 }, 436062306a36Sopenharmony_ci { INTXCLRPERR_F, "PCI INTx clear parity error", -1, 1 }, 436162306a36Sopenharmony_ci { MATAGPERR_F, "PCI MA tag parity error", -1, 1 }, 436262306a36Sopenharmony_ci { PIOTAGPERR_F, "PCI PIO tag parity error", -1, 1 }, 436362306a36Sopenharmony_ci { RXCPLPERR_F, "PCI Rx completion parity error", -1, 1 }, 436462306a36Sopenharmony_ci { RXWRPERR_F, "PCI Rx write parity error", -1, 1 }, 436562306a36Sopenharmony_ci { RPLPERR_F, "PCI replay buffer parity error", -1, 1 }, 436662306a36Sopenharmony_ci { PCIESINT_F, "PCI core secondary fault", -1, 1 }, 436762306a36Sopenharmony_ci { PCIEPINT_F, "PCI core primary fault", -1, 1 }, 436862306a36Sopenharmony_ci { UNXSPLCPLERR_F, "PCI unexpected split completion error", 436962306a36Sopenharmony_ci -1, 0 }, 437062306a36Sopenharmony_ci { 0 } 437162306a36Sopenharmony_ci }; 437262306a36Sopenharmony_ci 437362306a36Sopenharmony_ci static struct intr_info t5_pcie_intr_info[] = { 437462306a36Sopenharmony_ci { MSTGRPPERR_F, "Master Response Read Queue parity error", 437562306a36Sopenharmony_ci -1, 1 }, 437662306a36Sopenharmony_ci { MSTTIMEOUTPERR_F, "Master Timeout FIFO parity error", -1, 1 }, 437762306a36Sopenharmony_ci { MSIXSTIPERR_F, "MSI-X STI SRAM parity error", -1, 1 }, 437862306a36Sopenharmony_ci { MSIXADDRLPERR_F, "MSI-X AddrL parity error", -1, 1 }, 437962306a36Sopenharmony_ci { MSIXADDRHPERR_F, "MSI-X AddrH parity error", -1, 1 }, 438062306a36Sopenharmony_ci { MSIXDATAPERR_F, "MSI-X data parity error", -1, 1 }, 438162306a36Sopenharmony_ci { MSIXDIPERR_F, "MSI-X DI parity error", -1, 1 }, 438262306a36Sopenharmony_ci { PIOCPLGRPPERR_F, "PCI PIO completion Group FIFO parity error", 438362306a36Sopenharmony_ci -1, 1 }, 438462306a36Sopenharmony_ci { PIOREQGRPPERR_F, "PCI PIO request Group FIFO parity error", 438562306a36Sopenharmony_ci -1, 1 }, 438662306a36Sopenharmony_ci { TARTAGPERR_F, "PCI PCI target tag FIFO parity error", -1, 1 }, 438762306a36Sopenharmony_ci { MSTTAGQPERR_F, "PCI master tag queue parity error", -1, 1 }, 438862306a36Sopenharmony_ci { CREQPERR_F, "PCI CMD channel request parity error", -1, 1 }, 438962306a36Sopenharmony_ci { CRSPPERR_F, "PCI CMD channel response parity error", -1, 1 }, 439062306a36Sopenharmony_ci { DREQWRPERR_F, "PCI DMA channel write request parity error", 439162306a36Sopenharmony_ci -1, 1 }, 439262306a36Sopenharmony_ci { DREQPERR_F, "PCI DMA channel request parity error", -1, 1 }, 439362306a36Sopenharmony_ci { DRSPPERR_F, "PCI DMA channel response parity error", -1, 1 }, 439462306a36Sopenharmony_ci { HREQWRPERR_F, "PCI HMA channel count parity error", -1, 1 }, 439562306a36Sopenharmony_ci { HREQPERR_F, "PCI HMA channel request parity error", -1, 1 }, 439662306a36Sopenharmony_ci { HRSPPERR_F, "PCI HMA channel response parity error", -1, 1 }, 439762306a36Sopenharmony_ci { CFGSNPPERR_F, "PCI config snoop FIFO parity error", -1, 1 }, 439862306a36Sopenharmony_ci { FIDPERR_F, "PCI FID parity error", -1, 1 }, 439962306a36Sopenharmony_ci { VFIDPERR_F, "PCI INTx clear parity error", -1, 1 }, 440062306a36Sopenharmony_ci { MAGRPPERR_F, "PCI MA group FIFO parity error", -1, 1 }, 440162306a36Sopenharmony_ci { PIOTAGPERR_F, "PCI PIO tag parity error", -1, 1 }, 440262306a36Sopenharmony_ci { IPRXHDRGRPPERR_F, "PCI IP Rx header group parity error", 440362306a36Sopenharmony_ci -1, 1 }, 440462306a36Sopenharmony_ci { IPRXDATAGRPPERR_F, "PCI IP Rx data group parity error", 440562306a36Sopenharmony_ci -1, 1 }, 440662306a36Sopenharmony_ci { RPLPERR_F, "PCI IP replay buffer parity error", -1, 1 }, 440762306a36Sopenharmony_ci { IPSOTPERR_F, "PCI IP SOT buffer parity error", -1, 1 }, 440862306a36Sopenharmony_ci { TRGT1GRPPERR_F, "PCI TRGT1 group FIFOs parity error", -1, 1 }, 440962306a36Sopenharmony_ci { READRSPERR_F, "Outbound read error", -1, 0 }, 441062306a36Sopenharmony_ci { 0 } 441162306a36Sopenharmony_ci }; 441262306a36Sopenharmony_ci 441362306a36Sopenharmony_ci int fat; 441462306a36Sopenharmony_ci 441562306a36Sopenharmony_ci if (is_t4(adapter->params.chip)) 441662306a36Sopenharmony_ci fat = t4_handle_intr_status(adapter, 441762306a36Sopenharmony_ci PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS_A, 441862306a36Sopenharmony_ci sysbus_intr_info) + 441962306a36Sopenharmony_ci t4_handle_intr_status(adapter, 442062306a36Sopenharmony_ci PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS_A, 442162306a36Sopenharmony_ci pcie_port_intr_info) + 442262306a36Sopenharmony_ci t4_handle_intr_status(adapter, PCIE_INT_CAUSE_A, 442362306a36Sopenharmony_ci pcie_intr_info); 442462306a36Sopenharmony_ci else 442562306a36Sopenharmony_ci fat = t4_handle_intr_status(adapter, PCIE_INT_CAUSE_A, 442662306a36Sopenharmony_ci t5_pcie_intr_info); 442762306a36Sopenharmony_ci 442862306a36Sopenharmony_ci if (fat) 442962306a36Sopenharmony_ci t4_fatal_err(adapter); 443062306a36Sopenharmony_ci} 443162306a36Sopenharmony_ci 443262306a36Sopenharmony_ci/* 443362306a36Sopenharmony_ci * TP interrupt handler. 443462306a36Sopenharmony_ci */ 443562306a36Sopenharmony_cistatic void tp_intr_handler(struct adapter *adapter) 443662306a36Sopenharmony_ci{ 443762306a36Sopenharmony_ci static const struct intr_info tp_intr_info[] = { 443862306a36Sopenharmony_ci { 0x3fffffff, "TP parity error", -1, 1 }, 443962306a36Sopenharmony_ci { FLMTXFLSTEMPTY_F, "TP out of Tx pages", -1, 1 }, 444062306a36Sopenharmony_ci { 0 } 444162306a36Sopenharmony_ci }; 444262306a36Sopenharmony_ci 444362306a36Sopenharmony_ci if (t4_handle_intr_status(adapter, TP_INT_CAUSE_A, tp_intr_info)) 444462306a36Sopenharmony_ci t4_fatal_err(adapter); 444562306a36Sopenharmony_ci} 444662306a36Sopenharmony_ci 444762306a36Sopenharmony_ci/* 444862306a36Sopenharmony_ci * SGE interrupt handler. 444962306a36Sopenharmony_ci */ 445062306a36Sopenharmony_cistatic void sge_intr_handler(struct adapter *adapter) 445162306a36Sopenharmony_ci{ 445262306a36Sopenharmony_ci u32 v = 0, perr; 445362306a36Sopenharmony_ci u32 err; 445462306a36Sopenharmony_ci 445562306a36Sopenharmony_ci static const struct intr_info sge_intr_info[] = { 445662306a36Sopenharmony_ci { ERR_CPL_EXCEED_IQE_SIZE_F, 445762306a36Sopenharmony_ci "SGE received CPL exceeding IQE size", -1, 1 }, 445862306a36Sopenharmony_ci { ERR_INVALID_CIDX_INC_F, 445962306a36Sopenharmony_ci "SGE GTS CIDX increment too large", -1, 0 }, 446062306a36Sopenharmony_ci { ERR_CPL_OPCODE_0_F, "SGE received 0-length CPL", -1, 0 }, 446162306a36Sopenharmony_ci { DBFIFO_LP_INT_F, NULL, -1, 0, t4_db_full }, 446262306a36Sopenharmony_ci { ERR_DATA_CPL_ON_HIGH_QID1_F | ERR_DATA_CPL_ON_HIGH_QID0_F, 446362306a36Sopenharmony_ci "SGE IQID > 1023 received CPL for FL", -1, 0 }, 446462306a36Sopenharmony_ci { ERR_BAD_DB_PIDX3_F, "SGE DBP 3 pidx increment too large", -1, 446562306a36Sopenharmony_ci 0 }, 446662306a36Sopenharmony_ci { ERR_BAD_DB_PIDX2_F, "SGE DBP 2 pidx increment too large", -1, 446762306a36Sopenharmony_ci 0 }, 446862306a36Sopenharmony_ci { ERR_BAD_DB_PIDX1_F, "SGE DBP 1 pidx increment too large", -1, 446962306a36Sopenharmony_ci 0 }, 447062306a36Sopenharmony_ci { ERR_BAD_DB_PIDX0_F, "SGE DBP 0 pidx increment too large", -1, 447162306a36Sopenharmony_ci 0 }, 447262306a36Sopenharmony_ci { ERR_ING_CTXT_PRIO_F, 447362306a36Sopenharmony_ci "SGE too many priority ingress contexts", -1, 0 }, 447462306a36Sopenharmony_ci { INGRESS_SIZE_ERR_F, "SGE illegal ingress QID", -1, 0 }, 447562306a36Sopenharmony_ci { EGRESS_SIZE_ERR_F, "SGE illegal egress QID", -1, 0 }, 447662306a36Sopenharmony_ci { 0 } 447762306a36Sopenharmony_ci }; 447862306a36Sopenharmony_ci 447962306a36Sopenharmony_ci static struct intr_info t4t5_sge_intr_info[] = { 448062306a36Sopenharmony_ci { ERR_DROPPED_DB_F, NULL, -1, 0, t4_db_dropped }, 448162306a36Sopenharmony_ci { DBFIFO_HP_INT_F, NULL, -1, 0, t4_db_full }, 448262306a36Sopenharmony_ci { ERR_EGR_CTXT_PRIO_F, 448362306a36Sopenharmony_ci "SGE too many priority egress contexts", -1, 0 }, 448462306a36Sopenharmony_ci { 0 } 448562306a36Sopenharmony_ci }; 448662306a36Sopenharmony_ci 448762306a36Sopenharmony_ci perr = t4_read_reg(adapter, SGE_INT_CAUSE1_A); 448862306a36Sopenharmony_ci if (perr) { 448962306a36Sopenharmony_ci v |= perr; 449062306a36Sopenharmony_ci dev_alert(adapter->pdev_dev, "SGE Cause1 Parity Error %#x\n", 449162306a36Sopenharmony_ci perr); 449262306a36Sopenharmony_ci } 449362306a36Sopenharmony_ci 449462306a36Sopenharmony_ci perr = t4_read_reg(adapter, SGE_INT_CAUSE2_A); 449562306a36Sopenharmony_ci if (perr) { 449662306a36Sopenharmony_ci v |= perr; 449762306a36Sopenharmony_ci dev_alert(adapter->pdev_dev, "SGE Cause2 Parity Error %#x\n", 449862306a36Sopenharmony_ci perr); 449962306a36Sopenharmony_ci } 450062306a36Sopenharmony_ci 450162306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adapter->params.chip) >= CHELSIO_T5) { 450262306a36Sopenharmony_ci perr = t4_read_reg(adapter, SGE_INT_CAUSE5_A); 450362306a36Sopenharmony_ci /* Parity error (CRC) for err_T_RxCRC is trivial, ignore it */ 450462306a36Sopenharmony_ci perr &= ~ERR_T_RXCRC_F; 450562306a36Sopenharmony_ci if (perr) { 450662306a36Sopenharmony_ci v |= perr; 450762306a36Sopenharmony_ci dev_alert(adapter->pdev_dev, 450862306a36Sopenharmony_ci "SGE Cause5 Parity Error %#x\n", perr); 450962306a36Sopenharmony_ci } 451062306a36Sopenharmony_ci } 451162306a36Sopenharmony_ci 451262306a36Sopenharmony_ci v |= t4_handle_intr_status(adapter, SGE_INT_CAUSE3_A, sge_intr_info); 451362306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5) 451462306a36Sopenharmony_ci v |= t4_handle_intr_status(adapter, SGE_INT_CAUSE3_A, 451562306a36Sopenharmony_ci t4t5_sge_intr_info); 451662306a36Sopenharmony_ci 451762306a36Sopenharmony_ci err = t4_read_reg(adapter, SGE_ERROR_STATS_A); 451862306a36Sopenharmony_ci if (err & ERROR_QID_VALID_F) { 451962306a36Sopenharmony_ci dev_err(adapter->pdev_dev, "SGE error for queue %u\n", 452062306a36Sopenharmony_ci ERROR_QID_G(err)); 452162306a36Sopenharmony_ci if (err & UNCAPTURED_ERROR_F) 452262306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 452362306a36Sopenharmony_ci "SGE UNCAPTURED_ERROR set (clearing)\n"); 452462306a36Sopenharmony_ci t4_write_reg(adapter, SGE_ERROR_STATS_A, ERROR_QID_VALID_F | 452562306a36Sopenharmony_ci UNCAPTURED_ERROR_F); 452662306a36Sopenharmony_ci } 452762306a36Sopenharmony_ci 452862306a36Sopenharmony_ci if (v != 0) 452962306a36Sopenharmony_ci t4_fatal_err(adapter); 453062306a36Sopenharmony_ci} 453162306a36Sopenharmony_ci 453262306a36Sopenharmony_ci#define CIM_OBQ_INTR (OBQULP0PARERR_F | OBQULP1PARERR_F | OBQULP2PARERR_F |\ 453362306a36Sopenharmony_ci OBQULP3PARERR_F | OBQSGEPARERR_F | OBQNCSIPARERR_F) 453462306a36Sopenharmony_ci#define CIM_IBQ_INTR (IBQTP0PARERR_F | IBQTP1PARERR_F | IBQULPPARERR_F |\ 453562306a36Sopenharmony_ci IBQSGEHIPARERR_F | IBQSGELOPARERR_F | IBQNCSIPARERR_F) 453662306a36Sopenharmony_ci 453762306a36Sopenharmony_ci/* 453862306a36Sopenharmony_ci * CIM interrupt handler. 453962306a36Sopenharmony_ci */ 454062306a36Sopenharmony_cistatic void cim_intr_handler(struct adapter *adapter) 454162306a36Sopenharmony_ci{ 454262306a36Sopenharmony_ci static const struct intr_info cim_intr_info[] = { 454362306a36Sopenharmony_ci { PREFDROPINT_F, "CIM control register prefetch drop", -1, 1 }, 454462306a36Sopenharmony_ci { CIM_OBQ_INTR, "CIM OBQ parity error", -1, 1 }, 454562306a36Sopenharmony_ci { CIM_IBQ_INTR, "CIM IBQ parity error", -1, 1 }, 454662306a36Sopenharmony_ci { MBUPPARERR_F, "CIM mailbox uP parity error", -1, 1 }, 454762306a36Sopenharmony_ci { MBHOSTPARERR_F, "CIM mailbox host parity error", -1, 1 }, 454862306a36Sopenharmony_ci { TIEQINPARERRINT_F, "CIM TIEQ outgoing parity error", -1, 1 }, 454962306a36Sopenharmony_ci { TIEQOUTPARERRINT_F, "CIM TIEQ incoming parity error", -1, 1 }, 455062306a36Sopenharmony_ci { TIMER0INT_F, "CIM TIMER0 interrupt", -1, 1 }, 455162306a36Sopenharmony_ci { 0 } 455262306a36Sopenharmony_ci }; 455362306a36Sopenharmony_ci static const struct intr_info cim_upintr_info[] = { 455462306a36Sopenharmony_ci { RSVDSPACEINT_F, "CIM reserved space access", -1, 1 }, 455562306a36Sopenharmony_ci { ILLTRANSINT_F, "CIM illegal transaction", -1, 1 }, 455662306a36Sopenharmony_ci { ILLWRINT_F, "CIM illegal write", -1, 1 }, 455762306a36Sopenharmony_ci { ILLRDINT_F, "CIM illegal read", -1, 1 }, 455862306a36Sopenharmony_ci { ILLRDBEINT_F, "CIM illegal read BE", -1, 1 }, 455962306a36Sopenharmony_ci { ILLWRBEINT_F, "CIM illegal write BE", -1, 1 }, 456062306a36Sopenharmony_ci { SGLRDBOOTINT_F, "CIM single read from boot space", -1, 1 }, 456162306a36Sopenharmony_ci { SGLWRBOOTINT_F, "CIM single write to boot space", -1, 1 }, 456262306a36Sopenharmony_ci { BLKWRBOOTINT_F, "CIM block write to boot space", -1, 1 }, 456362306a36Sopenharmony_ci { SGLRDFLASHINT_F, "CIM single read from flash space", -1, 1 }, 456462306a36Sopenharmony_ci { SGLWRFLASHINT_F, "CIM single write to flash space", -1, 1 }, 456562306a36Sopenharmony_ci { BLKWRFLASHINT_F, "CIM block write to flash space", -1, 1 }, 456662306a36Sopenharmony_ci { SGLRDEEPROMINT_F, "CIM single EEPROM read", -1, 1 }, 456762306a36Sopenharmony_ci { SGLWREEPROMINT_F, "CIM single EEPROM write", -1, 1 }, 456862306a36Sopenharmony_ci { BLKRDEEPROMINT_F, "CIM block EEPROM read", -1, 1 }, 456962306a36Sopenharmony_ci { BLKWREEPROMINT_F, "CIM block EEPROM write", -1, 1 }, 457062306a36Sopenharmony_ci { SGLRDCTLINT_F, "CIM single read from CTL space", -1, 1 }, 457162306a36Sopenharmony_ci { SGLWRCTLINT_F, "CIM single write to CTL space", -1, 1 }, 457262306a36Sopenharmony_ci { BLKRDCTLINT_F, "CIM block read from CTL space", -1, 1 }, 457362306a36Sopenharmony_ci { BLKWRCTLINT_F, "CIM block write to CTL space", -1, 1 }, 457462306a36Sopenharmony_ci { SGLRDPLINT_F, "CIM single read from PL space", -1, 1 }, 457562306a36Sopenharmony_ci { SGLWRPLINT_F, "CIM single write to PL space", -1, 1 }, 457662306a36Sopenharmony_ci { BLKRDPLINT_F, "CIM block read from PL space", -1, 1 }, 457762306a36Sopenharmony_ci { BLKWRPLINT_F, "CIM block write to PL space", -1, 1 }, 457862306a36Sopenharmony_ci { REQOVRLOOKUPINT_F, "CIM request FIFO overwrite", -1, 1 }, 457962306a36Sopenharmony_ci { RSPOVRLOOKUPINT_F, "CIM response FIFO overwrite", -1, 1 }, 458062306a36Sopenharmony_ci { TIMEOUTINT_F, "CIM PIF timeout", -1, 1 }, 458162306a36Sopenharmony_ci { TIMEOUTMAINT_F, "CIM PIF MA timeout", -1, 1 }, 458262306a36Sopenharmony_ci { 0 } 458362306a36Sopenharmony_ci }; 458462306a36Sopenharmony_ci 458562306a36Sopenharmony_ci u32 val, fw_err; 458662306a36Sopenharmony_ci int fat; 458762306a36Sopenharmony_ci 458862306a36Sopenharmony_ci fw_err = t4_read_reg(adapter, PCIE_FW_A); 458962306a36Sopenharmony_ci if (fw_err & PCIE_FW_ERR_F) 459062306a36Sopenharmony_ci t4_report_fw_error(adapter); 459162306a36Sopenharmony_ci 459262306a36Sopenharmony_ci /* When the Firmware detects an internal error which normally 459362306a36Sopenharmony_ci * wouldn't raise a Host Interrupt, it forces a CIM Timer0 interrupt 459462306a36Sopenharmony_ci * in order to make sure the Host sees the Firmware Crash. So 459562306a36Sopenharmony_ci * if we have a Timer0 interrupt and don't see a Firmware Crash, 459662306a36Sopenharmony_ci * ignore the Timer0 interrupt. 459762306a36Sopenharmony_ci */ 459862306a36Sopenharmony_ci 459962306a36Sopenharmony_ci val = t4_read_reg(adapter, CIM_HOST_INT_CAUSE_A); 460062306a36Sopenharmony_ci if (val & TIMER0INT_F) 460162306a36Sopenharmony_ci if (!(fw_err & PCIE_FW_ERR_F) || 460262306a36Sopenharmony_ci (PCIE_FW_EVAL_G(fw_err) != PCIE_FW_EVAL_CRASH)) 460362306a36Sopenharmony_ci t4_write_reg(adapter, CIM_HOST_INT_CAUSE_A, 460462306a36Sopenharmony_ci TIMER0INT_F); 460562306a36Sopenharmony_ci 460662306a36Sopenharmony_ci fat = t4_handle_intr_status(adapter, CIM_HOST_INT_CAUSE_A, 460762306a36Sopenharmony_ci cim_intr_info) + 460862306a36Sopenharmony_ci t4_handle_intr_status(adapter, CIM_HOST_UPACC_INT_CAUSE_A, 460962306a36Sopenharmony_ci cim_upintr_info); 461062306a36Sopenharmony_ci if (fat) 461162306a36Sopenharmony_ci t4_fatal_err(adapter); 461262306a36Sopenharmony_ci} 461362306a36Sopenharmony_ci 461462306a36Sopenharmony_ci/* 461562306a36Sopenharmony_ci * ULP RX interrupt handler. 461662306a36Sopenharmony_ci */ 461762306a36Sopenharmony_cistatic void ulprx_intr_handler(struct adapter *adapter) 461862306a36Sopenharmony_ci{ 461962306a36Sopenharmony_ci static const struct intr_info ulprx_intr_info[] = { 462062306a36Sopenharmony_ci { 0x1800000, "ULPRX context error", -1, 1 }, 462162306a36Sopenharmony_ci { 0x7fffff, "ULPRX parity error", -1, 1 }, 462262306a36Sopenharmony_ci { 0 } 462362306a36Sopenharmony_ci }; 462462306a36Sopenharmony_ci 462562306a36Sopenharmony_ci if (t4_handle_intr_status(adapter, ULP_RX_INT_CAUSE_A, ulprx_intr_info)) 462662306a36Sopenharmony_ci t4_fatal_err(adapter); 462762306a36Sopenharmony_ci} 462862306a36Sopenharmony_ci 462962306a36Sopenharmony_ci/* 463062306a36Sopenharmony_ci * ULP TX interrupt handler. 463162306a36Sopenharmony_ci */ 463262306a36Sopenharmony_cistatic void ulptx_intr_handler(struct adapter *adapter) 463362306a36Sopenharmony_ci{ 463462306a36Sopenharmony_ci static const struct intr_info ulptx_intr_info[] = { 463562306a36Sopenharmony_ci { PBL_BOUND_ERR_CH3_F, "ULPTX channel 3 PBL out of bounds", -1, 463662306a36Sopenharmony_ci 0 }, 463762306a36Sopenharmony_ci { PBL_BOUND_ERR_CH2_F, "ULPTX channel 2 PBL out of bounds", -1, 463862306a36Sopenharmony_ci 0 }, 463962306a36Sopenharmony_ci { PBL_BOUND_ERR_CH1_F, "ULPTX channel 1 PBL out of bounds", -1, 464062306a36Sopenharmony_ci 0 }, 464162306a36Sopenharmony_ci { PBL_BOUND_ERR_CH0_F, "ULPTX channel 0 PBL out of bounds", -1, 464262306a36Sopenharmony_ci 0 }, 464362306a36Sopenharmony_ci { 0xfffffff, "ULPTX parity error", -1, 1 }, 464462306a36Sopenharmony_ci { 0 } 464562306a36Sopenharmony_ci }; 464662306a36Sopenharmony_ci 464762306a36Sopenharmony_ci if (t4_handle_intr_status(adapter, ULP_TX_INT_CAUSE_A, ulptx_intr_info)) 464862306a36Sopenharmony_ci t4_fatal_err(adapter); 464962306a36Sopenharmony_ci} 465062306a36Sopenharmony_ci 465162306a36Sopenharmony_ci/* 465262306a36Sopenharmony_ci * PM TX interrupt handler. 465362306a36Sopenharmony_ci */ 465462306a36Sopenharmony_cistatic void pmtx_intr_handler(struct adapter *adapter) 465562306a36Sopenharmony_ci{ 465662306a36Sopenharmony_ci static const struct intr_info pmtx_intr_info[] = { 465762306a36Sopenharmony_ci { PCMD_LEN_OVFL0_F, "PMTX channel 0 pcmd too large", -1, 1 }, 465862306a36Sopenharmony_ci { PCMD_LEN_OVFL1_F, "PMTX channel 1 pcmd too large", -1, 1 }, 465962306a36Sopenharmony_ci { PCMD_LEN_OVFL2_F, "PMTX channel 2 pcmd too large", -1, 1 }, 466062306a36Sopenharmony_ci { ZERO_C_CMD_ERROR_F, "PMTX 0-length pcmd", -1, 1 }, 466162306a36Sopenharmony_ci { PMTX_FRAMING_ERROR_F, "PMTX framing error", -1, 1 }, 466262306a36Sopenharmony_ci { OESPI_PAR_ERROR_F, "PMTX oespi parity error", -1, 1 }, 466362306a36Sopenharmony_ci { DB_OPTIONS_PAR_ERROR_F, "PMTX db_options parity error", 466462306a36Sopenharmony_ci -1, 1 }, 466562306a36Sopenharmony_ci { ICSPI_PAR_ERROR_F, "PMTX icspi parity error", -1, 1 }, 466662306a36Sopenharmony_ci { PMTX_C_PCMD_PAR_ERROR_F, "PMTX c_pcmd parity error", -1, 1}, 466762306a36Sopenharmony_ci { 0 } 466862306a36Sopenharmony_ci }; 466962306a36Sopenharmony_ci 467062306a36Sopenharmony_ci if (t4_handle_intr_status(adapter, PM_TX_INT_CAUSE_A, pmtx_intr_info)) 467162306a36Sopenharmony_ci t4_fatal_err(adapter); 467262306a36Sopenharmony_ci} 467362306a36Sopenharmony_ci 467462306a36Sopenharmony_ci/* 467562306a36Sopenharmony_ci * PM RX interrupt handler. 467662306a36Sopenharmony_ci */ 467762306a36Sopenharmony_cistatic void pmrx_intr_handler(struct adapter *adapter) 467862306a36Sopenharmony_ci{ 467962306a36Sopenharmony_ci static const struct intr_info pmrx_intr_info[] = { 468062306a36Sopenharmony_ci { ZERO_E_CMD_ERROR_F, "PMRX 0-length pcmd", -1, 1 }, 468162306a36Sopenharmony_ci { PMRX_FRAMING_ERROR_F, "PMRX framing error", -1, 1 }, 468262306a36Sopenharmony_ci { OCSPI_PAR_ERROR_F, "PMRX ocspi parity error", -1, 1 }, 468362306a36Sopenharmony_ci { DB_OPTIONS_PAR_ERROR_F, "PMRX db_options parity error", 468462306a36Sopenharmony_ci -1, 1 }, 468562306a36Sopenharmony_ci { IESPI_PAR_ERROR_F, "PMRX iespi parity error", -1, 1 }, 468662306a36Sopenharmony_ci { PMRX_E_PCMD_PAR_ERROR_F, "PMRX e_pcmd parity error", -1, 1}, 468762306a36Sopenharmony_ci { 0 } 468862306a36Sopenharmony_ci }; 468962306a36Sopenharmony_ci 469062306a36Sopenharmony_ci if (t4_handle_intr_status(adapter, PM_RX_INT_CAUSE_A, pmrx_intr_info)) 469162306a36Sopenharmony_ci t4_fatal_err(adapter); 469262306a36Sopenharmony_ci} 469362306a36Sopenharmony_ci 469462306a36Sopenharmony_ci/* 469562306a36Sopenharmony_ci * CPL switch interrupt handler. 469662306a36Sopenharmony_ci */ 469762306a36Sopenharmony_cistatic void cplsw_intr_handler(struct adapter *adapter) 469862306a36Sopenharmony_ci{ 469962306a36Sopenharmony_ci static const struct intr_info cplsw_intr_info[] = { 470062306a36Sopenharmony_ci { CIM_OP_MAP_PERR_F, "CPLSW CIM op_map parity error", -1, 1 }, 470162306a36Sopenharmony_ci { CIM_OVFL_ERROR_F, "CPLSW CIM overflow", -1, 1 }, 470262306a36Sopenharmony_ci { TP_FRAMING_ERROR_F, "CPLSW TP framing error", -1, 1 }, 470362306a36Sopenharmony_ci { SGE_FRAMING_ERROR_F, "CPLSW SGE framing error", -1, 1 }, 470462306a36Sopenharmony_ci { CIM_FRAMING_ERROR_F, "CPLSW CIM framing error", -1, 1 }, 470562306a36Sopenharmony_ci { ZERO_SWITCH_ERROR_F, "CPLSW no-switch error", -1, 1 }, 470662306a36Sopenharmony_ci { 0 } 470762306a36Sopenharmony_ci }; 470862306a36Sopenharmony_ci 470962306a36Sopenharmony_ci if (t4_handle_intr_status(adapter, CPL_INTR_CAUSE_A, cplsw_intr_info)) 471062306a36Sopenharmony_ci t4_fatal_err(adapter); 471162306a36Sopenharmony_ci} 471262306a36Sopenharmony_ci 471362306a36Sopenharmony_ci/* 471462306a36Sopenharmony_ci * LE interrupt handler. 471562306a36Sopenharmony_ci */ 471662306a36Sopenharmony_cistatic void le_intr_handler(struct adapter *adap) 471762306a36Sopenharmony_ci{ 471862306a36Sopenharmony_ci enum chip_type chip = CHELSIO_CHIP_VERSION(adap->params.chip); 471962306a36Sopenharmony_ci static const struct intr_info le_intr_info[] = { 472062306a36Sopenharmony_ci { LIPMISS_F, "LE LIP miss", -1, 0 }, 472162306a36Sopenharmony_ci { LIP0_F, "LE 0 LIP error", -1, 0 }, 472262306a36Sopenharmony_ci { PARITYERR_F, "LE parity error", -1, 1 }, 472362306a36Sopenharmony_ci { UNKNOWNCMD_F, "LE unknown command", -1, 1 }, 472462306a36Sopenharmony_ci { REQQPARERR_F, "LE request queue parity error", -1, 1 }, 472562306a36Sopenharmony_ci { 0 } 472662306a36Sopenharmony_ci }; 472762306a36Sopenharmony_ci 472862306a36Sopenharmony_ci static struct intr_info t6_le_intr_info[] = { 472962306a36Sopenharmony_ci { T6_LIPMISS_F, "LE LIP miss", -1, 0 }, 473062306a36Sopenharmony_ci { T6_LIP0_F, "LE 0 LIP error", -1, 0 }, 473162306a36Sopenharmony_ci { CMDTIDERR_F, "LE cmd tid error", -1, 1 }, 473262306a36Sopenharmony_ci { TCAMINTPERR_F, "LE parity error", -1, 1 }, 473362306a36Sopenharmony_ci { T6_UNKNOWNCMD_F, "LE unknown command", -1, 1 }, 473462306a36Sopenharmony_ci { SSRAMINTPERR_F, "LE request queue parity error", -1, 1 }, 473562306a36Sopenharmony_ci { HASHTBLMEMCRCERR_F, "LE hash table mem crc error", -1, 0 }, 473662306a36Sopenharmony_ci { 0 } 473762306a36Sopenharmony_ci }; 473862306a36Sopenharmony_ci 473962306a36Sopenharmony_ci if (t4_handle_intr_status(adap, LE_DB_INT_CAUSE_A, 474062306a36Sopenharmony_ci (chip <= CHELSIO_T5) ? 474162306a36Sopenharmony_ci le_intr_info : t6_le_intr_info)) 474262306a36Sopenharmony_ci t4_fatal_err(adap); 474362306a36Sopenharmony_ci} 474462306a36Sopenharmony_ci 474562306a36Sopenharmony_ci/* 474662306a36Sopenharmony_ci * MPS interrupt handler. 474762306a36Sopenharmony_ci */ 474862306a36Sopenharmony_cistatic void mps_intr_handler(struct adapter *adapter) 474962306a36Sopenharmony_ci{ 475062306a36Sopenharmony_ci static const struct intr_info mps_rx_intr_info[] = { 475162306a36Sopenharmony_ci { 0xffffff, "MPS Rx parity error", -1, 1 }, 475262306a36Sopenharmony_ci { 0 } 475362306a36Sopenharmony_ci }; 475462306a36Sopenharmony_ci static const struct intr_info mps_tx_intr_info[] = { 475562306a36Sopenharmony_ci { TPFIFO_V(TPFIFO_M), "MPS Tx TP FIFO parity error", -1, 1 }, 475662306a36Sopenharmony_ci { NCSIFIFO_F, "MPS Tx NC-SI FIFO parity error", -1, 1 }, 475762306a36Sopenharmony_ci { TXDATAFIFO_V(TXDATAFIFO_M), "MPS Tx data FIFO parity error", 475862306a36Sopenharmony_ci -1, 1 }, 475962306a36Sopenharmony_ci { TXDESCFIFO_V(TXDESCFIFO_M), "MPS Tx desc FIFO parity error", 476062306a36Sopenharmony_ci -1, 1 }, 476162306a36Sopenharmony_ci { BUBBLE_F, "MPS Tx underflow", -1, 1 }, 476262306a36Sopenharmony_ci { SECNTERR_F, "MPS Tx SOP/EOP error", -1, 1 }, 476362306a36Sopenharmony_ci { FRMERR_F, "MPS Tx framing error", -1, 1 }, 476462306a36Sopenharmony_ci { 0 } 476562306a36Sopenharmony_ci }; 476662306a36Sopenharmony_ci static const struct intr_info t6_mps_tx_intr_info[] = { 476762306a36Sopenharmony_ci { TPFIFO_V(TPFIFO_M), "MPS Tx TP FIFO parity error", -1, 1 }, 476862306a36Sopenharmony_ci { NCSIFIFO_F, "MPS Tx NC-SI FIFO parity error", -1, 1 }, 476962306a36Sopenharmony_ci { TXDATAFIFO_V(TXDATAFIFO_M), "MPS Tx data FIFO parity error", 477062306a36Sopenharmony_ci -1, 1 }, 477162306a36Sopenharmony_ci { TXDESCFIFO_V(TXDESCFIFO_M), "MPS Tx desc FIFO parity error", 477262306a36Sopenharmony_ci -1, 1 }, 477362306a36Sopenharmony_ci /* MPS Tx Bubble is normal for T6 */ 477462306a36Sopenharmony_ci { SECNTERR_F, "MPS Tx SOP/EOP error", -1, 1 }, 477562306a36Sopenharmony_ci { FRMERR_F, "MPS Tx framing error", -1, 1 }, 477662306a36Sopenharmony_ci { 0 } 477762306a36Sopenharmony_ci }; 477862306a36Sopenharmony_ci static const struct intr_info mps_trc_intr_info[] = { 477962306a36Sopenharmony_ci { FILTMEM_V(FILTMEM_M), "MPS TRC filter parity error", -1, 1 }, 478062306a36Sopenharmony_ci { PKTFIFO_V(PKTFIFO_M), "MPS TRC packet FIFO parity error", 478162306a36Sopenharmony_ci -1, 1 }, 478262306a36Sopenharmony_ci { MISCPERR_F, "MPS TRC misc parity error", -1, 1 }, 478362306a36Sopenharmony_ci { 0 } 478462306a36Sopenharmony_ci }; 478562306a36Sopenharmony_ci static const struct intr_info mps_stat_sram_intr_info[] = { 478662306a36Sopenharmony_ci { 0x1fffff, "MPS statistics SRAM parity error", -1, 1 }, 478762306a36Sopenharmony_ci { 0 } 478862306a36Sopenharmony_ci }; 478962306a36Sopenharmony_ci static const struct intr_info mps_stat_tx_intr_info[] = { 479062306a36Sopenharmony_ci { 0xfffff, "MPS statistics Tx FIFO parity error", -1, 1 }, 479162306a36Sopenharmony_ci { 0 } 479262306a36Sopenharmony_ci }; 479362306a36Sopenharmony_ci static const struct intr_info mps_stat_rx_intr_info[] = { 479462306a36Sopenharmony_ci { 0xffffff, "MPS statistics Rx FIFO parity error", -1, 1 }, 479562306a36Sopenharmony_ci { 0 } 479662306a36Sopenharmony_ci }; 479762306a36Sopenharmony_ci static const struct intr_info mps_cls_intr_info[] = { 479862306a36Sopenharmony_ci { MATCHSRAM_F, "MPS match SRAM parity error", -1, 1 }, 479962306a36Sopenharmony_ci { MATCHTCAM_F, "MPS match TCAM parity error", -1, 1 }, 480062306a36Sopenharmony_ci { HASHSRAM_F, "MPS hash SRAM parity error", -1, 1 }, 480162306a36Sopenharmony_ci { 0 } 480262306a36Sopenharmony_ci }; 480362306a36Sopenharmony_ci 480462306a36Sopenharmony_ci int fat; 480562306a36Sopenharmony_ci 480662306a36Sopenharmony_ci fat = t4_handle_intr_status(adapter, MPS_RX_PERR_INT_CAUSE_A, 480762306a36Sopenharmony_ci mps_rx_intr_info) + 480862306a36Sopenharmony_ci t4_handle_intr_status(adapter, MPS_TX_INT_CAUSE_A, 480962306a36Sopenharmony_ci is_t6(adapter->params.chip) 481062306a36Sopenharmony_ci ? t6_mps_tx_intr_info 481162306a36Sopenharmony_ci : mps_tx_intr_info) + 481262306a36Sopenharmony_ci t4_handle_intr_status(adapter, MPS_TRC_INT_CAUSE_A, 481362306a36Sopenharmony_ci mps_trc_intr_info) + 481462306a36Sopenharmony_ci t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_SRAM_A, 481562306a36Sopenharmony_ci mps_stat_sram_intr_info) + 481662306a36Sopenharmony_ci t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_TX_FIFO_A, 481762306a36Sopenharmony_ci mps_stat_tx_intr_info) + 481862306a36Sopenharmony_ci t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_RX_FIFO_A, 481962306a36Sopenharmony_ci mps_stat_rx_intr_info) + 482062306a36Sopenharmony_ci t4_handle_intr_status(adapter, MPS_CLS_INT_CAUSE_A, 482162306a36Sopenharmony_ci mps_cls_intr_info); 482262306a36Sopenharmony_ci 482362306a36Sopenharmony_ci t4_write_reg(adapter, MPS_INT_CAUSE_A, 0); 482462306a36Sopenharmony_ci t4_read_reg(adapter, MPS_INT_CAUSE_A); /* flush */ 482562306a36Sopenharmony_ci if (fat) 482662306a36Sopenharmony_ci t4_fatal_err(adapter); 482762306a36Sopenharmony_ci} 482862306a36Sopenharmony_ci 482962306a36Sopenharmony_ci#define MEM_INT_MASK (PERR_INT_CAUSE_F | ECC_CE_INT_CAUSE_F | \ 483062306a36Sopenharmony_ci ECC_UE_INT_CAUSE_F) 483162306a36Sopenharmony_ci 483262306a36Sopenharmony_ci/* 483362306a36Sopenharmony_ci * EDC/MC interrupt handler. 483462306a36Sopenharmony_ci */ 483562306a36Sopenharmony_cistatic void mem_intr_handler(struct adapter *adapter, int idx) 483662306a36Sopenharmony_ci{ 483762306a36Sopenharmony_ci static const char name[4][7] = { "EDC0", "EDC1", "MC/MC0", "MC1" }; 483862306a36Sopenharmony_ci 483962306a36Sopenharmony_ci unsigned int addr, cnt_addr, v; 484062306a36Sopenharmony_ci 484162306a36Sopenharmony_ci if (idx <= MEM_EDC1) { 484262306a36Sopenharmony_ci addr = EDC_REG(EDC_INT_CAUSE_A, idx); 484362306a36Sopenharmony_ci cnt_addr = EDC_REG(EDC_ECC_STATUS_A, idx); 484462306a36Sopenharmony_ci } else if (idx == MEM_MC) { 484562306a36Sopenharmony_ci if (is_t4(adapter->params.chip)) { 484662306a36Sopenharmony_ci addr = MC_INT_CAUSE_A; 484762306a36Sopenharmony_ci cnt_addr = MC_ECC_STATUS_A; 484862306a36Sopenharmony_ci } else { 484962306a36Sopenharmony_ci addr = MC_P_INT_CAUSE_A; 485062306a36Sopenharmony_ci cnt_addr = MC_P_ECC_STATUS_A; 485162306a36Sopenharmony_ci } 485262306a36Sopenharmony_ci } else { 485362306a36Sopenharmony_ci addr = MC_REG(MC_P_INT_CAUSE_A, 1); 485462306a36Sopenharmony_ci cnt_addr = MC_REG(MC_P_ECC_STATUS_A, 1); 485562306a36Sopenharmony_ci } 485662306a36Sopenharmony_ci 485762306a36Sopenharmony_ci v = t4_read_reg(adapter, addr) & MEM_INT_MASK; 485862306a36Sopenharmony_ci if (v & PERR_INT_CAUSE_F) 485962306a36Sopenharmony_ci dev_alert(adapter->pdev_dev, "%s FIFO parity error\n", 486062306a36Sopenharmony_ci name[idx]); 486162306a36Sopenharmony_ci if (v & ECC_CE_INT_CAUSE_F) { 486262306a36Sopenharmony_ci u32 cnt = ECC_CECNT_G(t4_read_reg(adapter, cnt_addr)); 486362306a36Sopenharmony_ci 486462306a36Sopenharmony_ci t4_edc_err_read(adapter, idx); 486562306a36Sopenharmony_ci 486662306a36Sopenharmony_ci t4_write_reg(adapter, cnt_addr, ECC_CECNT_V(ECC_CECNT_M)); 486762306a36Sopenharmony_ci if (printk_ratelimit()) 486862306a36Sopenharmony_ci dev_warn(adapter->pdev_dev, 486962306a36Sopenharmony_ci "%u %s correctable ECC data error%s\n", 487062306a36Sopenharmony_ci cnt, name[idx], cnt > 1 ? "s" : ""); 487162306a36Sopenharmony_ci } 487262306a36Sopenharmony_ci if (v & ECC_UE_INT_CAUSE_F) 487362306a36Sopenharmony_ci dev_alert(adapter->pdev_dev, 487462306a36Sopenharmony_ci "%s uncorrectable ECC data error\n", name[idx]); 487562306a36Sopenharmony_ci 487662306a36Sopenharmony_ci t4_write_reg(adapter, addr, v); 487762306a36Sopenharmony_ci if (v & (PERR_INT_CAUSE_F | ECC_UE_INT_CAUSE_F)) 487862306a36Sopenharmony_ci t4_fatal_err(adapter); 487962306a36Sopenharmony_ci} 488062306a36Sopenharmony_ci 488162306a36Sopenharmony_ci/* 488262306a36Sopenharmony_ci * MA interrupt handler. 488362306a36Sopenharmony_ci */ 488462306a36Sopenharmony_cistatic void ma_intr_handler(struct adapter *adap) 488562306a36Sopenharmony_ci{ 488662306a36Sopenharmony_ci u32 v, status = t4_read_reg(adap, MA_INT_CAUSE_A); 488762306a36Sopenharmony_ci 488862306a36Sopenharmony_ci if (status & MEM_PERR_INT_CAUSE_F) { 488962306a36Sopenharmony_ci dev_alert(adap->pdev_dev, 489062306a36Sopenharmony_ci "MA parity error, parity status %#x\n", 489162306a36Sopenharmony_ci t4_read_reg(adap, MA_PARITY_ERROR_STATUS1_A)); 489262306a36Sopenharmony_ci if (is_t5(adap->params.chip)) 489362306a36Sopenharmony_ci dev_alert(adap->pdev_dev, 489462306a36Sopenharmony_ci "MA parity error, parity status %#x\n", 489562306a36Sopenharmony_ci t4_read_reg(adap, 489662306a36Sopenharmony_ci MA_PARITY_ERROR_STATUS2_A)); 489762306a36Sopenharmony_ci } 489862306a36Sopenharmony_ci if (status & MEM_WRAP_INT_CAUSE_F) { 489962306a36Sopenharmony_ci v = t4_read_reg(adap, MA_INT_WRAP_STATUS_A); 490062306a36Sopenharmony_ci dev_alert(adap->pdev_dev, "MA address wrap-around error by " 490162306a36Sopenharmony_ci "client %u to address %#x\n", 490262306a36Sopenharmony_ci MEM_WRAP_CLIENT_NUM_G(v), 490362306a36Sopenharmony_ci MEM_WRAP_ADDRESS_G(v) << 4); 490462306a36Sopenharmony_ci } 490562306a36Sopenharmony_ci t4_write_reg(adap, MA_INT_CAUSE_A, status); 490662306a36Sopenharmony_ci t4_fatal_err(adap); 490762306a36Sopenharmony_ci} 490862306a36Sopenharmony_ci 490962306a36Sopenharmony_ci/* 491062306a36Sopenharmony_ci * SMB interrupt handler. 491162306a36Sopenharmony_ci */ 491262306a36Sopenharmony_cistatic void smb_intr_handler(struct adapter *adap) 491362306a36Sopenharmony_ci{ 491462306a36Sopenharmony_ci static const struct intr_info smb_intr_info[] = { 491562306a36Sopenharmony_ci { MSTTXFIFOPARINT_F, "SMB master Tx FIFO parity error", -1, 1 }, 491662306a36Sopenharmony_ci { MSTRXFIFOPARINT_F, "SMB master Rx FIFO parity error", -1, 1 }, 491762306a36Sopenharmony_ci { SLVFIFOPARINT_F, "SMB slave FIFO parity error", -1, 1 }, 491862306a36Sopenharmony_ci { 0 } 491962306a36Sopenharmony_ci }; 492062306a36Sopenharmony_ci 492162306a36Sopenharmony_ci if (t4_handle_intr_status(adap, SMB_INT_CAUSE_A, smb_intr_info)) 492262306a36Sopenharmony_ci t4_fatal_err(adap); 492362306a36Sopenharmony_ci} 492462306a36Sopenharmony_ci 492562306a36Sopenharmony_ci/* 492662306a36Sopenharmony_ci * NC-SI interrupt handler. 492762306a36Sopenharmony_ci */ 492862306a36Sopenharmony_cistatic void ncsi_intr_handler(struct adapter *adap) 492962306a36Sopenharmony_ci{ 493062306a36Sopenharmony_ci static const struct intr_info ncsi_intr_info[] = { 493162306a36Sopenharmony_ci { CIM_DM_PRTY_ERR_F, "NC-SI CIM parity error", -1, 1 }, 493262306a36Sopenharmony_ci { MPS_DM_PRTY_ERR_F, "NC-SI MPS parity error", -1, 1 }, 493362306a36Sopenharmony_ci { TXFIFO_PRTY_ERR_F, "NC-SI Tx FIFO parity error", -1, 1 }, 493462306a36Sopenharmony_ci { RXFIFO_PRTY_ERR_F, "NC-SI Rx FIFO parity error", -1, 1 }, 493562306a36Sopenharmony_ci { 0 } 493662306a36Sopenharmony_ci }; 493762306a36Sopenharmony_ci 493862306a36Sopenharmony_ci if (t4_handle_intr_status(adap, NCSI_INT_CAUSE_A, ncsi_intr_info)) 493962306a36Sopenharmony_ci t4_fatal_err(adap); 494062306a36Sopenharmony_ci} 494162306a36Sopenharmony_ci 494262306a36Sopenharmony_ci/* 494362306a36Sopenharmony_ci * XGMAC interrupt handler. 494462306a36Sopenharmony_ci */ 494562306a36Sopenharmony_cistatic void xgmac_intr_handler(struct adapter *adap, int port) 494662306a36Sopenharmony_ci{ 494762306a36Sopenharmony_ci u32 v, int_cause_reg; 494862306a36Sopenharmony_ci 494962306a36Sopenharmony_ci if (is_t4(adap->params.chip)) 495062306a36Sopenharmony_ci int_cause_reg = PORT_REG(port, XGMAC_PORT_INT_CAUSE_A); 495162306a36Sopenharmony_ci else 495262306a36Sopenharmony_ci int_cause_reg = T5_PORT_REG(port, MAC_PORT_INT_CAUSE_A); 495362306a36Sopenharmony_ci 495462306a36Sopenharmony_ci v = t4_read_reg(adap, int_cause_reg); 495562306a36Sopenharmony_ci 495662306a36Sopenharmony_ci v &= TXFIFO_PRTY_ERR_F | RXFIFO_PRTY_ERR_F; 495762306a36Sopenharmony_ci if (!v) 495862306a36Sopenharmony_ci return; 495962306a36Sopenharmony_ci 496062306a36Sopenharmony_ci if (v & TXFIFO_PRTY_ERR_F) 496162306a36Sopenharmony_ci dev_alert(adap->pdev_dev, "XGMAC %d Tx FIFO parity error\n", 496262306a36Sopenharmony_ci port); 496362306a36Sopenharmony_ci if (v & RXFIFO_PRTY_ERR_F) 496462306a36Sopenharmony_ci dev_alert(adap->pdev_dev, "XGMAC %d Rx FIFO parity error\n", 496562306a36Sopenharmony_ci port); 496662306a36Sopenharmony_ci t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_INT_CAUSE_A), v); 496762306a36Sopenharmony_ci t4_fatal_err(adap); 496862306a36Sopenharmony_ci} 496962306a36Sopenharmony_ci 497062306a36Sopenharmony_ci/* 497162306a36Sopenharmony_ci * PL interrupt handler. 497262306a36Sopenharmony_ci */ 497362306a36Sopenharmony_cistatic void pl_intr_handler(struct adapter *adap) 497462306a36Sopenharmony_ci{ 497562306a36Sopenharmony_ci static const struct intr_info pl_intr_info[] = { 497662306a36Sopenharmony_ci { FATALPERR_F, "T4 fatal parity error", -1, 1 }, 497762306a36Sopenharmony_ci { PERRVFID_F, "PL VFID_MAP parity error", -1, 1 }, 497862306a36Sopenharmony_ci { 0 } 497962306a36Sopenharmony_ci }; 498062306a36Sopenharmony_ci 498162306a36Sopenharmony_ci if (t4_handle_intr_status(adap, PL_PL_INT_CAUSE_A, pl_intr_info)) 498262306a36Sopenharmony_ci t4_fatal_err(adap); 498362306a36Sopenharmony_ci} 498462306a36Sopenharmony_ci 498562306a36Sopenharmony_ci#define PF_INTR_MASK (PFSW_F) 498662306a36Sopenharmony_ci#define GLBL_INTR_MASK (CIM_F | MPS_F | PL_F | PCIE_F | MC_F | EDC0_F | \ 498762306a36Sopenharmony_ci EDC1_F | LE_F | TP_F | MA_F | PM_TX_F | PM_RX_F | ULP_RX_F | \ 498862306a36Sopenharmony_ci CPL_SWITCH_F | SGE_F | ULP_TX_F | SF_F) 498962306a36Sopenharmony_ci 499062306a36Sopenharmony_ci/** 499162306a36Sopenharmony_ci * t4_slow_intr_handler - control path interrupt handler 499262306a36Sopenharmony_ci * @adapter: the adapter 499362306a36Sopenharmony_ci * 499462306a36Sopenharmony_ci * T4 interrupt handler for non-data global interrupt events, e.g., errors. 499562306a36Sopenharmony_ci * The designation 'slow' is because it involves register reads, while 499662306a36Sopenharmony_ci * data interrupts typically don't involve any MMIOs. 499762306a36Sopenharmony_ci */ 499862306a36Sopenharmony_ciint t4_slow_intr_handler(struct adapter *adapter) 499962306a36Sopenharmony_ci{ 500062306a36Sopenharmony_ci /* There are rare cases where a PL_INT_CAUSE bit may end up getting 500162306a36Sopenharmony_ci * set when the corresponding PL_INT_ENABLE bit isn't set. It's 500262306a36Sopenharmony_ci * easiest just to mask that case here. 500362306a36Sopenharmony_ci */ 500462306a36Sopenharmony_ci u32 raw_cause = t4_read_reg(adapter, PL_INT_CAUSE_A); 500562306a36Sopenharmony_ci u32 enable = t4_read_reg(adapter, PL_INT_ENABLE_A); 500662306a36Sopenharmony_ci u32 cause = raw_cause & enable; 500762306a36Sopenharmony_ci 500862306a36Sopenharmony_ci if (!(cause & GLBL_INTR_MASK)) 500962306a36Sopenharmony_ci return 0; 501062306a36Sopenharmony_ci if (cause & CIM_F) 501162306a36Sopenharmony_ci cim_intr_handler(adapter); 501262306a36Sopenharmony_ci if (cause & MPS_F) 501362306a36Sopenharmony_ci mps_intr_handler(adapter); 501462306a36Sopenharmony_ci if (cause & NCSI_F) 501562306a36Sopenharmony_ci ncsi_intr_handler(adapter); 501662306a36Sopenharmony_ci if (cause & PL_F) 501762306a36Sopenharmony_ci pl_intr_handler(adapter); 501862306a36Sopenharmony_ci if (cause & SMB_F) 501962306a36Sopenharmony_ci smb_intr_handler(adapter); 502062306a36Sopenharmony_ci if (cause & XGMAC0_F) 502162306a36Sopenharmony_ci xgmac_intr_handler(adapter, 0); 502262306a36Sopenharmony_ci if (cause & XGMAC1_F) 502362306a36Sopenharmony_ci xgmac_intr_handler(adapter, 1); 502462306a36Sopenharmony_ci if (cause & XGMAC_KR0_F) 502562306a36Sopenharmony_ci xgmac_intr_handler(adapter, 2); 502662306a36Sopenharmony_ci if (cause & XGMAC_KR1_F) 502762306a36Sopenharmony_ci xgmac_intr_handler(adapter, 3); 502862306a36Sopenharmony_ci if (cause & PCIE_F) 502962306a36Sopenharmony_ci pcie_intr_handler(adapter); 503062306a36Sopenharmony_ci if (cause & MC_F) 503162306a36Sopenharmony_ci mem_intr_handler(adapter, MEM_MC); 503262306a36Sopenharmony_ci if (is_t5(adapter->params.chip) && (cause & MC1_F)) 503362306a36Sopenharmony_ci mem_intr_handler(adapter, MEM_MC1); 503462306a36Sopenharmony_ci if (cause & EDC0_F) 503562306a36Sopenharmony_ci mem_intr_handler(adapter, MEM_EDC0); 503662306a36Sopenharmony_ci if (cause & EDC1_F) 503762306a36Sopenharmony_ci mem_intr_handler(adapter, MEM_EDC1); 503862306a36Sopenharmony_ci if (cause & LE_F) 503962306a36Sopenharmony_ci le_intr_handler(adapter); 504062306a36Sopenharmony_ci if (cause & TP_F) 504162306a36Sopenharmony_ci tp_intr_handler(adapter); 504262306a36Sopenharmony_ci if (cause & MA_F) 504362306a36Sopenharmony_ci ma_intr_handler(adapter); 504462306a36Sopenharmony_ci if (cause & PM_TX_F) 504562306a36Sopenharmony_ci pmtx_intr_handler(adapter); 504662306a36Sopenharmony_ci if (cause & PM_RX_F) 504762306a36Sopenharmony_ci pmrx_intr_handler(adapter); 504862306a36Sopenharmony_ci if (cause & ULP_RX_F) 504962306a36Sopenharmony_ci ulprx_intr_handler(adapter); 505062306a36Sopenharmony_ci if (cause & CPL_SWITCH_F) 505162306a36Sopenharmony_ci cplsw_intr_handler(adapter); 505262306a36Sopenharmony_ci if (cause & SGE_F) 505362306a36Sopenharmony_ci sge_intr_handler(adapter); 505462306a36Sopenharmony_ci if (cause & ULP_TX_F) 505562306a36Sopenharmony_ci ulptx_intr_handler(adapter); 505662306a36Sopenharmony_ci 505762306a36Sopenharmony_ci /* Clear the interrupts just processed for which we are the master. */ 505862306a36Sopenharmony_ci t4_write_reg(adapter, PL_INT_CAUSE_A, raw_cause & GLBL_INTR_MASK); 505962306a36Sopenharmony_ci (void)t4_read_reg(adapter, PL_INT_CAUSE_A); /* flush */ 506062306a36Sopenharmony_ci return 1; 506162306a36Sopenharmony_ci} 506262306a36Sopenharmony_ci 506362306a36Sopenharmony_ci/** 506462306a36Sopenharmony_ci * t4_intr_enable - enable interrupts 506562306a36Sopenharmony_ci * @adapter: the adapter whose interrupts should be enabled 506662306a36Sopenharmony_ci * 506762306a36Sopenharmony_ci * Enable PF-specific interrupts for the calling function and the top-level 506862306a36Sopenharmony_ci * interrupt concentrator for global interrupts. Interrupts are already 506962306a36Sopenharmony_ci * enabled at each module, here we just enable the roots of the interrupt 507062306a36Sopenharmony_ci * hierarchies. 507162306a36Sopenharmony_ci * 507262306a36Sopenharmony_ci * Note: this function should be called only when the driver manages 507362306a36Sopenharmony_ci * non PF-specific interrupts from the various HW modules. Only one PCI 507462306a36Sopenharmony_ci * function at a time should be doing this. 507562306a36Sopenharmony_ci */ 507662306a36Sopenharmony_civoid t4_intr_enable(struct adapter *adapter) 507762306a36Sopenharmony_ci{ 507862306a36Sopenharmony_ci u32 val = 0; 507962306a36Sopenharmony_ci u32 whoami = t4_read_reg(adapter, PL_WHOAMI_A); 508062306a36Sopenharmony_ci u32 pf = CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5 ? 508162306a36Sopenharmony_ci SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami); 508262306a36Sopenharmony_ci 508362306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5) 508462306a36Sopenharmony_ci val = ERR_DROPPED_DB_F | ERR_EGR_CTXT_PRIO_F | DBFIFO_HP_INT_F; 508562306a36Sopenharmony_ci t4_write_reg(adapter, SGE_INT_ENABLE3_A, ERR_CPL_EXCEED_IQE_SIZE_F | 508662306a36Sopenharmony_ci ERR_INVALID_CIDX_INC_F | ERR_CPL_OPCODE_0_F | 508762306a36Sopenharmony_ci ERR_DATA_CPL_ON_HIGH_QID1_F | INGRESS_SIZE_ERR_F | 508862306a36Sopenharmony_ci ERR_DATA_CPL_ON_HIGH_QID0_F | ERR_BAD_DB_PIDX3_F | 508962306a36Sopenharmony_ci ERR_BAD_DB_PIDX2_F | ERR_BAD_DB_PIDX1_F | 509062306a36Sopenharmony_ci ERR_BAD_DB_PIDX0_F | ERR_ING_CTXT_PRIO_F | 509162306a36Sopenharmony_ci DBFIFO_LP_INT_F | EGRESS_SIZE_ERR_F | val); 509262306a36Sopenharmony_ci t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE_A), PF_INTR_MASK); 509362306a36Sopenharmony_ci t4_set_reg_field(adapter, PL_INT_MAP0_A, 0, 1 << pf); 509462306a36Sopenharmony_ci} 509562306a36Sopenharmony_ci 509662306a36Sopenharmony_ci/** 509762306a36Sopenharmony_ci * t4_intr_disable - disable interrupts 509862306a36Sopenharmony_ci * @adapter: the adapter whose interrupts should be disabled 509962306a36Sopenharmony_ci * 510062306a36Sopenharmony_ci * Disable interrupts. We only disable the top-level interrupt 510162306a36Sopenharmony_ci * concentrators. The caller must be a PCI function managing global 510262306a36Sopenharmony_ci * interrupts. 510362306a36Sopenharmony_ci */ 510462306a36Sopenharmony_civoid t4_intr_disable(struct adapter *adapter) 510562306a36Sopenharmony_ci{ 510662306a36Sopenharmony_ci u32 whoami, pf; 510762306a36Sopenharmony_ci 510862306a36Sopenharmony_ci if (pci_channel_offline(adapter->pdev)) 510962306a36Sopenharmony_ci return; 511062306a36Sopenharmony_ci 511162306a36Sopenharmony_ci whoami = t4_read_reg(adapter, PL_WHOAMI_A); 511262306a36Sopenharmony_ci pf = CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5 ? 511362306a36Sopenharmony_ci SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami); 511462306a36Sopenharmony_ci 511562306a36Sopenharmony_ci t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE_A), 0); 511662306a36Sopenharmony_ci t4_set_reg_field(adapter, PL_INT_MAP0_A, 1 << pf, 0); 511762306a36Sopenharmony_ci} 511862306a36Sopenharmony_ci 511962306a36Sopenharmony_ciunsigned int t4_chip_rss_size(struct adapter *adap) 512062306a36Sopenharmony_ci{ 512162306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5) 512262306a36Sopenharmony_ci return RSS_NENTRIES; 512362306a36Sopenharmony_ci else 512462306a36Sopenharmony_ci return T6_RSS_NENTRIES; 512562306a36Sopenharmony_ci} 512662306a36Sopenharmony_ci 512762306a36Sopenharmony_ci/** 512862306a36Sopenharmony_ci * t4_config_rss_range - configure a portion of the RSS mapping table 512962306a36Sopenharmony_ci * @adapter: the adapter 513062306a36Sopenharmony_ci * @mbox: mbox to use for the FW command 513162306a36Sopenharmony_ci * @viid: virtual interface whose RSS subtable is to be written 513262306a36Sopenharmony_ci * @start: start entry in the table to write 513362306a36Sopenharmony_ci * @n: how many table entries to write 513462306a36Sopenharmony_ci * @rspq: values for the response queue lookup table 513562306a36Sopenharmony_ci * @nrspq: number of values in @rspq 513662306a36Sopenharmony_ci * 513762306a36Sopenharmony_ci * Programs the selected part of the VI's RSS mapping table with the 513862306a36Sopenharmony_ci * provided values. If @nrspq < @n the supplied values are used repeatedly 513962306a36Sopenharmony_ci * until the full table range is populated. 514062306a36Sopenharmony_ci * 514162306a36Sopenharmony_ci * The caller must ensure the values in @rspq are in the range allowed for 514262306a36Sopenharmony_ci * @viid. 514362306a36Sopenharmony_ci */ 514462306a36Sopenharmony_ciint t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid, 514562306a36Sopenharmony_ci int start, int n, const u16 *rspq, unsigned int nrspq) 514662306a36Sopenharmony_ci{ 514762306a36Sopenharmony_ci int ret; 514862306a36Sopenharmony_ci const u16 *rsp = rspq; 514962306a36Sopenharmony_ci const u16 *rsp_end = rspq + nrspq; 515062306a36Sopenharmony_ci struct fw_rss_ind_tbl_cmd cmd; 515162306a36Sopenharmony_ci 515262306a36Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 515362306a36Sopenharmony_ci cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_RSS_IND_TBL_CMD) | 515462306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F | 515562306a36Sopenharmony_ci FW_RSS_IND_TBL_CMD_VIID_V(viid)); 515662306a36Sopenharmony_ci cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); 515762306a36Sopenharmony_ci 515862306a36Sopenharmony_ci /* each fw_rss_ind_tbl_cmd takes up to 32 entries */ 515962306a36Sopenharmony_ci while (n > 0) { 516062306a36Sopenharmony_ci int nq = min(n, 32); 516162306a36Sopenharmony_ci __be32 *qp = &cmd.iq0_to_iq2; 516262306a36Sopenharmony_ci 516362306a36Sopenharmony_ci cmd.niqid = cpu_to_be16(nq); 516462306a36Sopenharmony_ci cmd.startidx = cpu_to_be16(start); 516562306a36Sopenharmony_ci 516662306a36Sopenharmony_ci start += nq; 516762306a36Sopenharmony_ci n -= nq; 516862306a36Sopenharmony_ci 516962306a36Sopenharmony_ci while (nq > 0) { 517062306a36Sopenharmony_ci unsigned int v; 517162306a36Sopenharmony_ci 517262306a36Sopenharmony_ci v = FW_RSS_IND_TBL_CMD_IQ0_V(*rsp); 517362306a36Sopenharmony_ci if (++rsp >= rsp_end) 517462306a36Sopenharmony_ci rsp = rspq; 517562306a36Sopenharmony_ci v |= FW_RSS_IND_TBL_CMD_IQ1_V(*rsp); 517662306a36Sopenharmony_ci if (++rsp >= rsp_end) 517762306a36Sopenharmony_ci rsp = rspq; 517862306a36Sopenharmony_ci v |= FW_RSS_IND_TBL_CMD_IQ2_V(*rsp); 517962306a36Sopenharmony_ci if (++rsp >= rsp_end) 518062306a36Sopenharmony_ci rsp = rspq; 518162306a36Sopenharmony_ci 518262306a36Sopenharmony_ci *qp++ = cpu_to_be32(v); 518362306a36Sopenharmony_ci nq -= 3; 518462306a36Sopenharmony_ci } 518562306a36Sopenharmony_ci 518662306a36Sopenharmony_ci ret = t4_wr_mbox(adapter, mbox, &cmd, sizeof(cmd), NULL); 518762306a36Sopenharmony_ci if (ret) 518862306a36Sopenharmony_ci return ret; 518962306a36Sopenharmony_ci } 519062306a36Sopenharmony_ci return 0; 519162306a36Sopenharmony_ci} 519262306a36Sopenharmony_ci 519362306a36Sopenharmony_ci/** 519462306a36Sopenharmony_ci * t4_config_glbl_rss - configure the global RSS mode 519562306a36Sopenharmony_ci * @adapter: the adapter 519662306a36Sopenharmony_ci * @mbox: mbox to use for the FW command 519762306a36Sopenharmony_ci * @mode: global RSS mode 519862306a36Sopenharmony_ci * @flags: mode-specific flags 519962306a36Sopenharmony_ci * 520062306a36Sopenharmony_ci * Sets the global RSS mode. 520162306a36Sopenharmony_ci */ 520262306a36Sopenharmony_ciint t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode, 520362306a36Sopenharmony_ci unsigned int flags) 520462306a36Sopenharmony_ci{ 520562306a36Sopenharmony_ci struct fw_rss_glb_config_cmd c; 520662306a36Sopenharmony_ci 520762306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 520862306a36Sopenharmony_ci c.op_to_write = cpu_to_be32(FW_CMD_OP_V(FW_RSS_GLB_CONFIG_CMD) | 520962306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F); 521062306a36Sopenharmony_ci c.retval_len16 = cpu_to_be32(FW_LEN16(c)); 521162306a36Sopenharmony_ci if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL) { 521262306a36Sopenharmony_ci c.u.manual.mode_pkd = 521362306a36Sopenharmony_ci cpu_to_be32(FW_RSS_GLB_CONFIG_CMD_MODE_V(mode)); 521462306a36Sopenharmony_ci } else if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL) { 521562306a36Sopenharmony_ci c.u.basicvirtual.mode_pkd = 521662306a36Sopenharmony_ci cpu_to_be32(FW_RSS_GLB_CONFIG_CMD_MODE_V(mode)); 521762306a36Sopenharmony_ci c.u.basicvirtual.synmapen_to_hashtoeplitz = cpu_to_be32(flags); 521862306a36Sopenharmony_ci } else 521962306a36Sopenharmony_ci return -EINVAL; 522062306a36Sopenharmony_ci return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL); 522162306a36Sopenharmony_ci} 522262306a36Sopenharmony_ci 522362306a36Sopenharmony_ci/** 522462306a36Sopenharmony_ci * t4_config_vi_rss - configure per VI RSS settings 522562306a36Sopenharmony_ci * @adapter: the adapter 522662306a36Sopenharmony_ci * @mbox: mbox to use for the FW command 522762306a36Sopenharmony_ci * @viid: the VI id 522862306a36Sopenharmony_ci * @flags: RSS flags 522962306a36Sopenharmony_ci * @defq: id of the default RSS queue for the VI. 523062306a36Sopenharmony_ci * 523162306a36Sopenharmony_ci * Configures VI-specific RSS properties. 523262306a36Sopenharmony_ci */ 523362306a36Sopenharmony_ciint t4_config_vi_rss(struct adapter *adapter, int mbox, unsigned int viid, 523462306a36Sopenharmony_ci unsigned int flags, unsigned int defq) 523562306a36Sopenharmony_ci{ 523662306a36Sopenharmony_ci struct fw_rss_vi_config_cmd c; 523762306a36Sopenharmony_ci 523862306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 523962306a36Sopenharmony_ci c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_RSS_VI_CONFIG_CMD) | 524062306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F | 524162306a36Sopenharmony_ci FW_RSS_VI_CONFIG_CMD_VIID_V(viid)); 524262306a36Sopenharmony_ci c.retval_len16 = cpu_to_be32(FW_LEN16(c)); 524362306a36Sopenharmony_ci c.u.basicvirtual.defaultq_to_udpen = cpu_to_be32(flags | 524462306a36Sopenharmony_ci FW_RSS_VI_CONFIG_CMD_DEFAULTQ_V(defq)); 524562306a36Sopenharmony_ci return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL); 524662306a36Sopenharmony_ci} 524762306a36Sopenharmony_ci 524862306a36Sopenharmony_ci/* Read an RSS table row */ 524962306a36Sopenharmony_cistatic int rd_rss_row(struct adapter *adap, int row, u32 *val) 525062306a36Sopenharmony_ci{ 525162306a36Sopenharmony_ci t4_write_reg(adap, TP_RSS_LKP_TABLE_A, 0xfff00000 | row); 525262306a36Sopenharmony_ci return t4_wait_op_done_val(adap, TP_RSS_LKP_TABLE_A, LKPTBLROWVLD_F, 1, 525362306a36Sopenharmony_ci 5, 0, val); 525462306a36Sopenharmony_ci} 525562306a36Sopenharmony_ci 525662306a36Sopenharmony_ci/** 525762306a36Sopenharmony_ci * t4_read_rss - read the contents of the RSS mapping table 525862306a36Sopenharmony_ci * @adapter: the adapter 525962306a36Sopenharmony_ci * @map: holds the contents of the RSS mapping table 526062306a36Sopenharmony_ci * 526162306a36Sopenharmony_ci * Reads the contents of the RSS hash->queue mapping table. 526262306a36Sopenharmony_ci */ 526362306a36Sopenharmony_ciint t4_read_rss(struct adapter *adapter, u16 *map) 526462306a36Sopenharmony_ci{ 526562306a36Sopenharmony_ci int i, ret, nentries; 526662306a36Sopenharmony_ci u32 val; 526762306a36Sopenharmony_ci 526862306a36Sopenharmony_ci nentries = t4_chip_rss_size(adapter); 526962306a36Sopenharmony_ci for (i = 0; i < nentries / 2; ++i) { 527062306a36Sopenharmony_ci ret = rd_rss_row(adapter, i, &val); 527162306a36Sopenharmony_ci if (ret) 527262306a36Sopenharmony_ci return ret; 527362306a36Sopenharmony_ci *map++ = LKPTBLQUEUE0_G(val); 527462306a36Sopenharmony_ci *map++ = LKPTBLQUEUE1_G(val); 527562306a36Sopenharmony_ci } 527662306a36Sopenharmony_ci return 0; 527762306a36Sopenharmony_ci} 527862306a36Sopenharmony_ci 527962306a36Sopenharmony_cistatic unsigned int t4_use_ldst(struct adapter *adap) 528062306a36Sopenharmony_ci{ 528162306a36Sopenharmony_ci return (adap->flags & CXGB4_FW_OK) && !adap->use_bd; 528262306a36Sopenharmony_ci} 528362306a36Sopenharmony_ci 528462306a36Sopenharmony_ci/** 528562306a36Sopenharmony_ci * t4_tp_fw_ldst_rw - Access TP indirect register through LDST 528662306a36Sopenharmony_ci * @adap: the adapter 528762306a36Sopenharmony_ci * @cmd: TP fw ldst address space type 528862306a36Sopenharmony_ci * @vals: where the indirect register values are stored/written 528962306a36Sopenharmony_ci * @nregs: how many indirect registers to read/write 529062306a36Sopenharmony_ci * @start_index: index of first indirect register to read/write 529162306a36Sopenharmony_ci * @rw: Read (1) or Write (0) 529262306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 529362306a36Sopenharmony_ci * 529462306a36Sopenharmony_ci * Access TP indirect registers through LDST 529562306a36Sopenharmony_ci */ 529662306a36Sopenharmony_cistatic int t4_tp_fw_ldst_rw(struct adapter *adap, int cmd, u32 *vals, 529762306a36Sopenharmony_ci unsigned int nregs, unsigned int start_index, 529862306a36Sopenharmony_ci unsigned int rw, bool sleep_ok) 529962306a36Sopenharmony_ci{ 530062306a36Sopenharmony_ci int ret = 0; 530162306a36Sopenharmony_ci unsigned int i; 530262306a36Sopenharmony_ci struct fw_ldst_cmd c; 530362306a36Sopenharmony_ci 530462306a36Sopenharmony_ci for (i = 0; i < nregs; i++) { 530562306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 530662306a36Sopenharmony_ci c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) | 530762306a36Sopenharmony_ci FW_CMD_REQUEST_F | 530862306a36Sopenharmony_ci (rw ? FW_CMD_READ_F : 530962306a36Sopenharmony_ci FW_CMD_WRITE_F) | 531062306a36Sopenharmony_ci FW_LDST_CMD_ADDRSPACE_V(cmd)); 531162306a36Sopenharmony_ci c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c)); 531262306a36Sopenharmony_ci 531362306a36Sopenharmony_ci c.u.addrval.addr = cpu_to_be32(start_index + i); 531462306a36Sopenharmony_ci c.u.addrval.val = rw ? 0 : cpu_to_be32(vals[i]); 531562306a36Sopenharmony_ci ret = t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, 531662306a36Sopenharmony_ci sleep_ok); 531762306a36Sopenharmony_ci if (ret) 531862306a36Sopenharmony_ci return ret; 531962306a36Sopenharmony_ci 532062306a36Sopenharmony_ci if (rw) 532162306a36Sopenharmony_ci vals[i] = be32_to_cpu(c.u.addrval.val); 532262306a36Sopenharmony_ci } 532362306a36Sopenharmony_ci return 0; 532462306a36Sopenharmony_ci} 532562306a36Sopenharmony_ci 532662306a36Sopenharmony_ci/** 532762306a36Sopenharmony_ci * t4_tp_indirect_rw - Read/Write TP indirect register through LDST or backdoor 532862306a36Sopenharmony_ci * @adap: the adapter 532962306a36Sopenharmony_ci * @reg_addr: Address Register 533062306a36Sopenharmony_ci * @reg_data: Data register 533162306a36Sopenharmony_ci * @buff: where the indirect register values are stored/written 533262306a36Sopenharmony_ci * @nregs: how many indirect registers to read/write 533362306a36Sopenharmony_ci * @start_index: index of first indirect register to read/write 533462306a36Sopenharmony_ci * @rw: READ(1) or WRITE(0) 533562306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 533662306a36Sopenharmony_ci * 533762306a36Sopenharmony_ci * Read/Write TP indirect registers through LDST if possible. 533862306a36Sopenharmony_ci * Else, use backdoor access 533962306a36Sopenharmony_ci **/ 534062306a36Sopenharmony_cistatic void t4_tp_indirect_rw(struct adapter *adap, u32 reg_addr, u32 reg_data, 534162306a36Sopenharmony_ci u32 *buff, u32 nregs, u32 start_index, int rw, 534262306a36Sopenharmony_ci bool sleep_ok) 534362306a36Sopenharmony_ci{ 534462306a36Sopenharmony_ci int rc = -EINVAL; 534562306a36Sopenharmony_ci int cmd; 534662306a36Sopenharmony_ci 534762306a36Sopenharmony_ci switch (reg_addr) { 534862306a36Sopenharmony_ci case TP_PIO_ADDR_A: 534962306a36Sopenharmony_ci cmd = FW_LDST_ADDRSPC_TP_PIO; 535062306a36Sopenharmony_ci break; 535162306a36Sopenharmony_ci case TP_TM_PIO_ADDR_A: 535262306a36Sopenharmony_ci cmd = FW_LDST_ADDRSPC_TP_TM_PIO; 535362306a36Sopenharmony_ci break; 535462306a36Sopenharmony_ci case TP_MIB_INDEX_A: 535562306a36Sopenharmony_ci cmd = FW_LDST_ADDRSPC_TP_MIB; 535662306a36Sopenharmony_ci break; 535762306a36Sopenharmony_ci default: 535862306a36Sopenharmony_ci goto indirect_access; 535962306a36Sopenharmony_ci } 536062306a36Sopenharmony_ci 536162306a36Sopenharmony_ci if (t4_use_ldst(adap)) 536262306a36Sopenharmony_ci rc = t4_tp_fw_ldst_rw(adap, cmd, buff, nregs, start_index, rw, 536362306a36Sopenharmony_ci sleep_ok); 536462306a36Sopenharmony_ci 536562306a36Sopenharmony_ciindirect_access: 536662306a36Sopenharmony_ci 536762306a36Sopenharmony_ci if (rc) { 536862306a36Sopenharmony_ci if (rw) 536962306a36Sopenharmony_ci t4_read_indirect(adap, reg_addr, reg_data, buff, nregs, 537062306a36Sopenharmony_ci start_index); 537162306a36Sopenharmony_ci else 537262306a36Sopenharmony_ci t4_write_indirect(adap, reg_addr, reg_data, buff, nregs, 537362306a36Sopenharmony_ci start_index); 537462306a36Sopenharmony_ci } 537562306a36Sopenharmony_ci} 537662306a36Sopenharmony_ci 537762306a36Sopenharmony_ci/** 537862306a36Sopenharmony_ci * t4_tp_pio_read - Read TP PIO registers 537962306a36Sopenharmony_ci * @adap: the adapter 538062306a36Sopenharmony_ci * @buff: where the indirect register values are written 538162306a36Sopenharmony_ci * @nregs: how many indirect registers to read 538262306a36Sopenharmony_ci * @start_index: index of first indirect register to read 538362306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 538462306a36Sopenharmony_ci * 538562306a36Sopenharmony_ci * Read TP PIO Registers 538662306a36Sopenharmony_ci **/ 538762306a36Sopenharmony_civoid t4_tp_pio_read(struct adapter *adap, u32 *buff, u32 nregs, 538862306a36Sopenharmony_ci u32 start_index, bool sleep_ok) 538962306a36Sopenharmony_ci{ 539062306a36Sopenharmony_ci t4_tp_indirect_rw(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, buff, nregs, 539162306a36Sopenharmony_ci start_index, 1, sleep_ok); 539262306a36Sopenharmony_ci} 539362306a36Sopenharmony_ci 539462306a36Sopenharmony_ci/** 539562306a36Sopenharmony_ci * t4_tp_pio_write - Write TP PIO registers 539662306a36Sopenharmony_ci * @adap: the adapter 539762306a36Sopenharmony_ci * @buff: where the indirect register values are stored 539862306a36Sopenharmony_ci * @nregs: how many indirect registers to write 539962306a36Sopenharmony_ci * @start_index: index of first indirect register to write 540062306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 540162306a36Sopenharmony_ci * 540262306a36Sopenharmony_ci * Write TP PIO Registers 540362306a36Sopenharmony_ci **/ 540462306a36Sopenharmony_cistatic void t4_tp_pio_write(struct adapter *adap, u32 *buff, u32 nregs, 540562306a36Sopenharmony_ci u32 start_index, bool sleep_ok) 540662306a36Sopenharmony_ci{ 540762306a36Sopenharmony_ci t4_tp_indirect_rw(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, buff, nregs, 540862306a36Sopenharmony_ci start_index, 0, sleep_ok); 540962306a36Sopenharmony_ci} 541062306a36Sopenharmony_ci 541162306a36Sopenharmony_ci/** 541262306a36Sopenharmony_ci * t4_tp_tm_pio_read - Read TP TM PIO registers 541362306a36Sopenharmony_ci * @adap: the adapter 541462306a36Sopenharmony_ci * @buff: where the indirect register values are written 541562306a36Sopenharmony_ci * @nregs: how many indirect registers to read 541662306a36Sopenharmony_ci * @start_index: index of first indirect register to read 541762306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 541862306a36Sopenharmony_ci * 541962306a36Sopenharmony_ci * Read TP TM PIO Registers 542062306a36Sopenharmony_ci **/ 542162306a36Sopenharmony_civoid t4_tp_tm_pio_read(struct adapter *adap, u32 *buff, u32 nregs, 542262306a36Sopenharmony_ci u32 start_index, bool sleep_ok) 542362306a36Sopenharmony_ci{ 542462306a36Sopenharmony_ci t4_tp_indirect_rw(adap, TP_TM_PIO_ADDR_A, TP_TM_PIO_DATA_A, buff, 542562306a36Sopenharmony_ci nregs, start_index, 1, sleep_ok); 542662306a36Sopenharmony_ci} 542762306a36Sopenharmony_ci 542862306a36Sopenharmony_ci/** 542962306a36Sopenharmony_ci * t4_tp_mib_read - Read TP MIB registers 543062306a36Sopenharmony_ci * @adap: the adapter 543162306a36Sopenharmony_ci * @buff: where the indirect register values are written 543262306a36Sopenharmony_ci * @nregs: how many indirect registers to read 543362306a36Sopenharmony_ci * @start_index: index of first indirect register to read 543462306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 543562306a36Sopenharmony_ci * 543662306a36Sopenharmony_ci * Read TP MIB Registers 543762306a36Sopenharmony_ci **/ 543862306a36Sopenharmony_civoid t4_tp_mib_read(struct adapter *adap, u32 *buff, u32 nregs, u32 start_index, 543962306a36Sopenharmony_ci bool sleep_ok) 544062306a36Sopenharmony_ci{ 544162306a36Sopenharmony_ci t4_tp_indirect_rw(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, buff, nregs, 544262306a36Sopenharmony_ci start_index, 1, sleep_ok); 544362306a36Sopenharmony_ci} 544462306a36Sopenharmony_ci 544562306a36Sopenharmony_ci/** 544662306a36Sopenharmony_ci * t4_read_rss_key - read the global RSS key 544762306a36Sopenharmony_ci * @adap: the adapter 544862306a36Sopenharmony_ci * @key: 10-entry array holding the 320-bit RSS key 544962306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 545062306a36Sopenharmony_ci * 545162306a36Sopenharmony_ci * Reads the global 320-bit RSS key. 545262306a36Sopenharmony_ci */ 545362306a36Sopenharmony_civoid t4_read_rss_key(struct adapter *adap, u32 *key, bool sleep_ok) 545462306a36Sopenharmony_ci{ 545562306a36Sopenharmony_ci t4_tp_pio_read(adap, key, 10, TP_RSS_SECRET_KEY0_A, sleep_ok); 545662306a36Sopenharmony_ci} 545762306a36Sopenharmony_ci 545862306a36Sopenharmony_ci/** 545962306a36Sopenharmony_ci * t4_write_rss_key - program one of the RSS keys 546062306a36Sopenharmony_ci * @adap: the adapter 546162306a36Sopenharmony_ci * @key: 10-entry array holding the 320-bit RSS key 546262306a36Sopenharmony_ci * @idx: which RSS key to write 546362306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 546462306a36Sopenharmony_ci * 546562306a36Sopenharmony_ci * Writes one of the RSS keys with the given 320-bit value. If @idx is 546662306a36Sopenharmony_ci * 0..15 the corresponding entry in the RSS key table is written, 546762306a36Sopenharmony_ci * otherwise the global RSS key is written. 546862306a36Sopenharmony_ci */ 546962306a36Sopenharmony_civoid t4_write_rss_key(struct adapter *adap, const u32 *key, int idx, 547062306a36Sopenharmony_ci bool sleep_ok) 547162306a36Sopenharmony_ci{ 547262306a36Sopenharmony_ci u8 rss_key_addr_cnt = 16; 547362306a36Sopenharmony_ci u32 vrt = t4_read_reg(adap, TP_RSS_CONFIG_VRT_A); 547462306a36Sopenharmony_ci 547562306a36Sopenharmony_ci /* T6 and later: for KeyMode 3 (per-vf and per-vf scramble), 547662306a36Sopenharmony_ci * allows access to key addresses 16-63 by using KeyWrAddrX 547762306a36Sopenharmony_ci * as index[5:4](upper 2) into key table 547862306a36Sopenharmony_ci */ 547962306a36Sopenharmony_ci if ((CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) && 548062306a36Sopenharmony_ci (vrt & KEYEXTEND_F) && (KEYMODE_G(vrt) == 3)) 548162306a36Sopenharmony_ci rss_key_addr_cnt = 32; 548262306a36Sopenharmony_ci 548362306a36Sopenharmony_ci t4_tp_pio_write(adap, (void *)key, 10, TP_RSS_SECRET_KEY0_A, sleep_ok); 548462306a36Sopenharmony_ci 548562306a36Sopenharmony_ci if (idx >= 0 && idx < rss_key_addr_cnt) { 548662306a36Sopenharmony_ci if (rss_key_addr_cnt > 16) 548762306a36Sopenharmony_ci t4_write_reg(adap, TP_RSS_CONFIG_VRT_A, 548862306a36Sopenharmony_ci KEYWRADDRX_V(idx >> 4) | 548962306a36Sopenharmony_ci T6_VFWRADDR_V(idx) | KEYWREN_F); 549062306a36Sopenharmony_ci else 549162306a36Sopenharmony_ci t4_write_reg(adap, TP_RSS_CONFIG_VRT_A, 549262306a36Sopenharmony_ci KEYWRADDR_V(idx) | KEYWREN_F); 549362306a36Sopenharmony_ci } 549462306a36Sopenharmony_ci} 549562306a36Sopenharmony_ci 549662306a36Sopenharmony_ci/** 549762306a36Sopenharmony_ci * t4_read_rss_pf_config - read PF RSS Configuration Table 549862306a36Sopenharmony_ci * @adapter: the adapter 549962306a36Sopenharmony_ci * @index: the entry in the PF RSS table to read 550062306a36Sopenharmony_ci * @valp: where to store the returned value 550162306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 550262306a36Sopenharmony_ci * 550362306a36Sopenharmony_ci * Reads the PF RSS Configuration Table at the specified index and returns 550462306a36Sopenharmony_ci * the value found there. 550562306a36Sopenharmony_ci */ 550662306a36Sopenharmony_civoid t4_read_rss_pf_config(struct adapter *adapter, unsigned int index, 550762306a36Sopenharmony_ci u32 *valp, bool sleep_ok) 550862306a36Sopenharmony_ci{ 550962306a36Sopenharmony_ci t4_tp_pio_read(adapter, valp, 1, TP_RSS_PF0_CONFIG_A + index, sleep_ok); 551062306a36Sopenharmony_ci} 551162306a36Sopenharmony_ci 551262306a36Sopenharmony_ci/** 551362306a36Sopenharmony_ci * t4_read_rss_vf_config - read VF RSS Configuration Table 551462306a36Sopenharmony_ci * @adapter: the adapter 551562306a36Sopenharmony_ci * @index: the entry in the VF RSS table to read 551662306a36Sopenharmony_ci * @vfl: where to store the returned VFL 551762306a36Sopenharmony_ci * @vfh: where to store the returned VFH 551862306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 551962306a36Sopenharmony_ci * 552062306a36Sopenharmony_ci * Reads the VF RSS Configuration Table at the specified index and returns 552162306a36Sopenharmony_ci * the (VFL, VFH) values found there. 552262306a36Sopenharmony_ci */ 552362306a36Sopenharmony_civoid t4_read_rss_vf_config(struct adapter *adapter, unsigned int index, 552462306a36Sopenharmony_ci u32 *vfl, u32 *vfh, bool sleep_ok) 552562306a36Sopenharmony_ci{ 552662306a36Sopenharmony_ci u32 vrt, mask, data; 552762306a36Sopenharmony_ci 552862306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5) { 552962306a36Sopenharmony_ci mask = VFWRADDR_V(VFWRADDR_M); 553062306a36Sopenharmony_ci data = VFWRADDR_V(index); 553162306a36Sopenharmony_ci } else { 553262306a36Sopenharmony_ci mask = T6_VFWRADDR_V(T6_VFWRADDR_M); 553362306a36Sopenharmony_ci data = T6_VFWRADDR_V(index); 553462306a36Sopenharmony_ci } 553562306a36Sopenharmony_ci 553662306a36Sopenharmony_ci /* Request that the index'th VF Table values be read into VFL/VFH. 553762306a36Sopenharmony_ci */ 553862306a36Sopenharmony_ci vrt = t4_read_reg(adapter, TP_RSS_CONFIG_VRT_A); 553962306a36Sopenharmony_ci vrt &= ~(VFRDRG_F | VFWREN_F | KEYWREN_F | mask); 554062306a36Sopenharmony_ci vrt |= data | VFRDEN_F; 554162306a36Sopenharmony_ci t4_write_reg(adapter, TP_RSS_CONFIG_VRT_A, vrt); 554262306a36Sopenharmony_ci 554362306a36Sopenharmony_ci /* Grab the VFL/VFH values ... 554462306a36Sopenharmony_ci */ 554562306a36Sopenharmony_ci t4_tp_pio_read(adapter, vfl, 1, TP_RSS_VFL_CONFIG_A, sleep_ok); 554662306a36Sopenharmony_ci t4_tp_pio_read(adapter, vfh, 1, TP_RSS_VFH_CONFIG_A, sleep_ok); 554762306a36Sopenharmony_ci} 554862306a36Sopenharmony_ci 554962306a36Sopenharmony_ci/** 555062306a36Sopenharmony_ci * t4_read_rss_pf_map - read PF RSS Map 555162306a36Sopenharmony_ci * @adapter: the adapter 555262306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 555362306a36Sopenharmony_ci * 555462306a36Sopenharmony_ci * Reads the PF RSS Map register and returns its value. 555562306a36Sopenharmony_ci */ 555662306a36Sopenharmony_ciu32 t4_read_rss_pf_map(struct adapter *adapter, bool sleep_ok) 555762306a36Sopenharmony_ci{ 555862306a36Sopenharmony_ci u32 pfmap; 555962306a36Sopenharmony_ci 556062306a36Sopenharmony_ci t4_tp_pio_read(adapter, &pfmap, 1, TP_RSS_PF_MAP_A, sleep_ok); 556162306a36Sopenharmony_ci return pfmap; 556262306a36Sopenharmony_ci} 556362306a36Sopenharmony_ci 556462306a36Sopenharmony_ci/** 556562306a36Sopenharmony_ci * t4_read_rss_pf_mask - read PF RSS Mask 556662306a36Sopenharmony_ci * @adapter: the adapter 556762306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 556862306a36Sopenharmony_ci * 556962306a36Sopenharmony_ci * Reads the PF RSS Mask register and returns its value. 557062306a36Sopenharmony_ci */ 557162306a36Sopenharmony_ciu32 t4_read_rss_pf_mask(struct adapter *adapter, bool sleep_ok) 557262306a36Sopenharmony_ci{ 557362306a36Sopenharmony_ci u32 pfmask; 557462306a36Sopenharmony_ci 557562306a36Sopenharmony_ci t4_tp_pio_read(adapter, &pfmask, 1, TP_RSS_PF_MSK_A, sleep_ok); 557662306a36Sopenharmony_ci return pfmask; 557762306a36Sopenharmony_ci} 557862306a36Sopenharmony_ci 557962306a36Sopenharmony_ci/** 558062306a36Sopenharmony_ci * t4_tp_get_tcp_stats - read TP's TCP MIB counters 558162306a36Sopenharmony_ci * @adap: the adapter 558262306a36Sopenharmony_ci * @v4: holds the TCP/IP counter values 558362306a36Sopenharmony_ci * @v6: holds the TCP/IPv6 counter values 558462306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 558562306a36Sopenharmony_ci * 558662306a36Sopenharmony_ci * Returns the values of TP's TCP/IP and TCP/IPv6 MIB counters. 558762306a36Sopenharmony_ci * Either @v4 or @v6 may be %NULL to skip the corresponding stats. 558862306a36Sopenharmony_ci */ 558962306a36Sopenharmony_civoid t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, 559062306a36Sopenharmony_ci struct tp_tcp_stats *v6, bool sleep_ok) 559162306a36Sopenharmony_ci{ 559262306a36Sopenharmony_ci u32 val[TP_MIB_TCP_RXT_SEG_LO_A - TP_MIB_TCP_OUT_RST_A + 1]; 559362306a36Sopenharmony_ci 559462306a36Sopenharmony_ci#define STAT_IDX(x) ((TP_MIB_TCP_##x##_A) - TP_MIB_TCP_OUT_RST_A) 559562306a36Sopenharmony_ci#define STAT(x) val[STAT_IDX(x)] 559662306a36Sopenharmony_ci#define STAT64(x) (((u64)STAT(x##_HI) << 32) | STAT(x##_LO)) 559762306a36Sopenharmony_ci 559862306a36Sopenharmony_ci if (v4) { 559962306a36Sopenharmony_ci t4_tp_mib_read(adap, val, ARRAY_SIZE(val), 560062306a36Sopenharmony_ci TP_MIB_TCP_OUT_RST_A, sleep_ok); 560162306a36Sopenharmony_ci v4->tcp_out_rsts = STAT(OUT_RST); 560262306a36Sopenharmony_ci v4->tcp_in_segs = STAT64(IN_SEG); 560362306a36Sopenharmony_ci v4->tcp_out_segs = STAT64(OUT_SEG); 560462306a36Sopenharmony_ci v4->tcp_retrans_segs = STAT64(RXT_SEG); 560562306a36Sopenharmony_ci } 560662306a36Sopenharmony_ci if (v6) { 560762306a36Sopenharmony_ci t4_tp_mib_read(adap, val, ARRAY_SIZE(val), 560862306a36Sopenharmony_ci TP_MIB_TCP_V6OUT_RST_A, sleep_ok); 560962306a36Sopenharmony_ci v6->tcp_out_rsts = STAT(OUT_RST); 561062306a36Sopenharmony_ci v6->tcp_in_segs = STAT64(IN_SEG); 561162306a36Sopenharmony_ci v6->tcp_out_segs = STAT64(OUT_SEG); 561262306a36Sopenharmony_ci v6->tcp_retrans_segs = STAT64(RXT_SEG); 561362306a36Sopenharmony_ci } 561462306a36Sopenharmony_ci#undef STAT64 561562306a36Sopenharmony_ci#undef STAT 561662306a36Sopenharmony_ci#undef STAT_IDX 561762306a36Sopenharmony_ci} 561862306a36Sopenharmony_ci 561962306a36Sopenharmony_ci/** 562062306a36Sopenharmony_ci * t4_tp_get_err_stats - read TP's error MIB counters 562162306a36Sopenharmony_ci * @adap: the adapter 562262306a36Sopenharmony_ci * @st: holds the counter values 562362306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 562462306a36Sopenharmony_ci * 562562306a36Sopenharmony_ci * Returns the values of TP's error counters. 562662306a36Sopenharmony_ci */ 562762306a36Sopenharmony_civoid t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st, 562862306a36Sopenharmony_ci bool sleep_ok) 562962306a36Sopenharmony_ci{ 563062306a36Sopenharmony_ci int nchan = adap->params.arch.nchan; 563162306a36Sopenharmony_ci 563262306a36Sopenharmony_ci t4_tp_mib_read(adap, st->mac_in_errs, nchan, TP_MIB_MAC_IN_ERR_0_A, 563362306a36Sopenharmony_ci sleep_ok); 563462306a36Sopenharmony_ci t4_tp_mib_read(adap, st->hdr_in_errs, nchan, TP_MIB_HDR_IN_ERR_0_A, 563562306a36Sopenharmony_ci sleep_ok); 563662306a36Sopenharmony_ci t4_tp_mib_read(adap, st->tcp_in_errs, nchan, TP_MIB_TCP_IN_ERR_0_A, 563762306a36Sopenharmony_ci sleep_ok); 563862306a36Sopenharmony_ci t4_tp_mib_read(adap, st->tnl_cong_drops, nchan, 563962306a36Sopenharmony_ci TP_MIB_TNL_CNG_DROP_0_A, sleep_ok); 564062306a36Sopenharmony_ci t4_tp_mib_read(adap, st->ofld_chan_drops, nchan, 564162306a36Sopenharmony_ci TP_MIB_OFD_CHN_DROP_0_A, sleep_ok); 564262306a36Sopenharmony_ci t4_tp_mib_read(adap, st->tnl_tx_drops, nchan, TP_MIB_TNL_DROP_0_A, 564362306a36Sopenharmony_ci sleep_ok); 564462306a36Sopenharmony_ci t4_tp_mib_read(adap, st->ofld_vlan_drops, nchan, 564562306a36Sopenharmony_ci TP_MIB_OFD_VLN_DROP_0_A, sleep_ok); 564662306a36Sopenharmony_ci t4_tp_mib_read(adap, st->tcp6_in_errs, nchan, 564762306a36Sopenharmony_ci TP_MIB_TCP_V6IN_ERR_0_A, sleep_ok); 564862306a36Sopenharmony_ci t4_tp_mib_read(adap, &st->ofld_no_neigh, 2, TP_MIB_OFD_ARP_DROP_A, 564962306a36Sopenharmony_ci sleep_ok); 565062306a36Sopenharmony_ci} 565162306a36Sopenharmony_ci 565262306a36Sopenharmony_ci/** 565362306a36Sopenharmony_ci * t4_tp_get_cpl_stats - read TP's CPL MIB counters 565462306a36Sopenharmony_ci * @adap: the adapter 565562306a36Sopenharmony_ci * @st: holds the counter values 565662306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 565762306a36Sopenharmony_ci * 565862306a36Sopenharmony_ci * Returns the values of TP's CPL counters. 565962306a36Sopenharmony_ci */ 566062306a36Sopenharmony_civoid t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st, 566162306a36Sopenharmony_ci bool sleep_ok) 566262306a36Sopenharmony_ci{ 566362306a36Sopenharmony_ci int nchan = adap->params.arch.nchan; 566462306a36Sopenharmony_ci 566562306a36Sopenharmony_ci t4_tp_mib_read(adap, st->req, nchan, TP_MIB_CPL_IN_REQ_0_A, sleep_ok); 566662306a36Sopenharmony_ci 566762306a36Sopenharmony_ci t4_tp_mib_read(adap, st->rsp, nchan, TP_MIB_CPL_OUT_RSP_0_A, sleep_ok); 566862306a36Sopenharmony_ci} 566962306a36Sopenharmony_ci 567062306a36Sopenharmony_ci/** 567162306a36Sopenharmony_ci * t4_tp_get_rdma_stats - read TP's RDMA MIB counters 567262306a36Sopenharmony_ci * @adap: the adapter 567362306a36Sopenharmony_ci * @st: holds the counter values 567462306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 567562306a36Sopenharmony_ci * 567662306a36Sopenharmony_ci * Returns the values of TP's RDMA counters. 567762306a36Sopenharmony_ci */ 567862306a36Sopenharmony_civoid t4_tp_get_rdma_stats(struct adapter *adap, struct tp_rdma_stats *st, 567962306a36Sopenharmony_ci bool sleep_ok) 568062306a36Sopenharmony_ci{ 568162306a36Sopenharmony_ci t4_tp_mib_read(adap, &st->rqe_dfr_pkt, 2, TP_MIB_RQE_DFR_PKT_A, 568262306a36Sopenharmony_ci sleep_ok); 568362306a36Sopenharmony_ci} 568462306a36Sopenharmony_ci 568562306a36Sopenharmony_ci/** 568662306a36Sopenharmony_ci * t4_get_fcoe_stats - read TP's FCoE MIB counters for a port 568762306a36Sopenharmony_ci * @adap: the adapter 568862306a36Sopenharmony_ci * @idx: the port index 568962306a36Sopenharmony_ci * @st: holds the counter values 569062306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 569162306a36Sopenharmony_ci * 569262306a36Sopenharmony_ci * Returns the values of TP's FCoE counters for the selected port. 569362306a36Sopenharmony_ci */ 569462306a36Sopenharmony_civoid t4_get_fcoe_stats(struct adapter *adap, unsigned int idx, 569562306a36Sopenharmony_ci struct tp_fcoe_stats *st, bool sleep_ok) 569662306a36Sopenharmony_ci{ 569762306a36Sopenharmony_ci u32 val[2]; 569862306a36Sopenharmony_ci 569962306a36Sopenharmony_ci t4_tp_mib_read(adap, &st->frames_ddp, 1, TP_MIB_FCOE_DDP_0_A + idx, 570062306a36Sopenharmony_ci sleep_ok); 570162306a36Sopenharmony_ci 570262306a36Sopenharmony_ci t4_tp_mib_read(adap, &st->frames_drop, 1, 570362306a36Sopenharmony_ci TP_MIB_FCOE_DROP_0_A + idx, sleep_ok); 570462306a36Sopenharmony_ci 570562306a36Sopenharmony_ci t4_tp_mib_read(adap, val, 2, TP_MIB_FCOE_BYTE_0_HI_A + 2 * idx, 570662306a36Sopenharmony_ci sleep_ok); 570762306a36Sopenharmony_ci 570862306a36Sopenharmony_ci st->octets_ddp = ((u64)val[0] << 32) | val[1]; 570962306a36Sopenharmony_ci} 571062306a36Sopenharmony_ci 571162306a36Sopenharmony_ci/** 571262306a36Sopenharmony_ci * t4_get_usm_stats - read TP's non-TCP DDP MIB counters 571362306a36Sopenharmony_ci * @adap: the adapter 571462306a36Sopenharmony_ci * @st: holds the counter values 571562306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 571662306a36Sopenharmony_ci * 571762306a36Sopenharmony_ci * Returns the values of TP's counters for non-TCP directly-placed packets. 571862306a36Sopenharmony_ci */ 571962306a36Sopenharmony_civoid t4_get_usm_stats(struct adapter *adap, struct tp_usm_stats *st, 572062306a36Sopenharmony_ci bool sleep_ok) 572162306a36Sopenharmony_ci{ 572262306a36Sopenharmony_ci u32 val[4]; 572362306a36Sopenharmony_ci 572462306a36Sopenharmony_ci t4_tp_mib_read(adap, val, 4, TP_MIB_USM_PKTS_A, sleep_ok); 572562306a36Sopenharmony_ci st->frames = val[0]; 572662306a36Sopenharmony_ci st->drops = val[1]; 572762306a36Sopenharmony_ci st->octets = ((u64)val[2] << 32) | val[3]; 572862306a36Sopenharmony_ci} 572962306a36Sopenharmony_ci 573062306a36Sopenharmony_ci/** 573162306a36Sopenharmony_ci * t4_read_mtu_tbl - returns the values in the HW path MTU table 573262306a36Sopenharmony_ci * @adap: the adapter 573362306a36Sopenharmony_ci * @mtus: where to store the MTU values 573462306a36Sopenharmony_ci * @mtu_log: where to store the MTU base-2 log (may be %NULL) 573562306a36Sopenharmony_ci * 573662306a36Sopenharmony_ci * Reads the HW path MTU table. 573762306a36Sopenharmony_ci */ 573862306a36Sopenharmony_civoid t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log) 573962306a36Sopenharmony_ci{ 574062306a36Sopenharmony_ci u32 v; 574162306a36Sopenharmony_ci int i; 574262306a36Sopenharmony_ci 574362306a36Sopenharmony_ci for (i = 0; i < NMTUS; ++i) { 574462306a36Sopenharmony_ci t4_write_reg(adap, TP_MTU_TABLE_A, 574562306a36Sopenharmony_ci MTUINDEX_V(0xff) | MTUVALUE_V(i)); 574662306a36Sopenharmony_ci v = t4_read_reg(adap, TP_MTU_TABLE_A); 574762306a36Sopenharmony_ci mtus[i] = MTUVALUE_G(v); 574862306a36Sopenharmony_ci if (mtu_log) 574962306a36Sopenharmony_ci mtu_log[i] = MTUWIDTH_G(v); 575062306a36Sopenharmony_ci } 575162306a36Sopenharmony_ci} 575262306a36Sopenharmony_ci 575362306a36Sopenharmony_ci/** 575462306a36Sopenharmony_ci * t4_read_cong_tbl - reads the congestion control table 575562306a36Sopenharmony_ci * @adap: the adapter 575662306a36Sopenharmony_ci * @incr: where to store the alpha values 575762306a36Sopenharmony_ci * 575862306a36Sopenharmony_ci * Reads the additive increments programmed into the HW congestion 575962306a36Sopenharmony_ci * control table. 576062306a36Sopenharmony_ci */ 576162306a36Sopenharmony_civoid t4_read_cong_tbl(struct adapter *adap, u16 incr[NMTUS][NCCTRL_WIN]) 576262306a36Sopenharmony_ci{ 576362306a36Sopenharmony_ci unsigned int mtu, w; 576462306a36Sopenharmony_ci 576562306a36Sopenharmony_ci for (mtu = 0; mtu < NMTUS; ++mtu) 576662306a36Sopenharmony_ci for (w = 0; w < NCCTRL_WIN; ++w) { 576762306a36Sopenharmony_ci t4_write_reg(adap, TP_CCTRL_TABLE_A, 576862306a36Sopenharmony_ci ROWINDEX_V(0xffff) | (mtu << 5) | w); 576962306a36Sopenharmony_ci incr[mtu][w] = (u16)t4_read_reg(adap, 577062306a36Sopenharmony_ci TP_CCTRL_TABLE_A) & 0x1fff; 577162306a36Sopenharmony_ci } 577262306a36Sopenharmony_ci} 577362306a36Sopenharmony_ci 577462306a36Sopenharmony_ci/** 577562306a36Sopenharmony_ci * t4_tp_wr_bits_indirect - set/clear bits in an indirect TP register 577662306a36Sopenharmony_ci * @adap: the adapter 577762306a36Sopenharmony_ci * @addr: the indirect TP register address 577862306a36Sopenharmony_ci * @mask: specifies the field within the register to modify 577962306a36Sopenharmony_ci * @val: new value for the field 578062306a36Sopenharmony_ci * 578162306a36Sopenharmony_ci * Sets a field of an indirect TP register to the given value. 578262306a36Sopenharmony_ci */ 578362306a36Sopenharmony_civoid t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr, 578462306a36Sopenharmony_ci unsigned int mask, unsigned int val) 578562306a36Sopenharmony_ci{ 578662306a36Sopenharmony_ci t4_write_reg(adap, TP_PIO_ADDR_A, addr); 578762306a36Sopenharmony_ci val |= t4_read_reg(adap, TP_PIO_DATA_A) & ~mask; 578862306a36Sopenharmony_ci t4_write_reg(adap, TP_PIO_DATA_A, val); 578962306a36Sopenharmony_ci} 579062306a36Sopenharmony_ci 579162306a36Sopenharmony_ci/** 579262306a36Sopenharmony_ci * init_cong_ctrl - initialize congestion control parameters 579362306a36Sopenharmony_ci * @a: the alpha values for congestion control 579462306a36Sopenharmony_ci * @b: the beta values for congestion control 579562306a36Sopenharmony_ci * 579662306a36Sopenharmony_ci * Initialize the congestion control parameters. 579762306a36Sopenharmony_ci */ 579862306a36Sopenharmony_cistatic void init_cong_ctrl(unsigned short *a, unsigned short *b) 579962306a36Sopenharmony_ci{ 580062306a36Sopenharmony_ci a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1; 580162306a36Sopenharmony_ci a[9] = 2; 580262306a36Sopenharmony_ci a[10] = 3; 580362306a36Sopenharmony_ci a[11] = 4; 580462306a36Sopenharmony_ci a[12] = 5; 580562306a36Sopenharmony_ci a[13] = 6; 580662306a36Sopenharmony_ci a[14] = 7; 580762306a36Sopenharmony_ci a[15] = 8; 580862306a36Sopenharmony_ci a[16] = 9; 580962306a36Sopenharmony_ci a[17] = 10; 581062306a36Sopenharmony_ci a[18] = 14; 581162306a36Sopenharmony_ci a[19] = 17; 581262306a36Sopenharmony_ci a[20] = 21; 581362306a36Sopenharmony_ci a[21] = 25; 581462306a36Sopenharmony_ci a[22] = 30; 581562306a36Sopenharmony_ci a[23] = 35; 581662306a36Sopenharmony_ci a[24] = 45; 581762306a36Sopenharmony_ci a[25] = 60; 581862306a36Sopenharmony_ci a[26] = 80; 581962306a36Sopenharmony_ci a[27] = 100; 582062306a36Sopenharmony_ci a[28] = 200; 582162306a36Sopenharmony_ci a[29] = 300; 582262306a36Sopenharmony_ci a[30] = 400; 582362306a36Sopenharmony_ci a[31] = 500; 582462306a36Sopenharmony_ci 582562306a36Sopenharmony_ci b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0; 582662306a36Sopenharmony_ci b[9] = b[10] = 1; 582762306a36Sopenharmony_ci b[11] = b[12] = 2; 582862306a36Sopenharmony_ci b[13] = b[14] = b[15] = b[16] = 3; 582962306a36Sopenharmony_ci b[17] = b[18] = b[19] = b[20] = b[21] = 4; 583062306a36Sopenharmony_ci b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5; 583162306a36Sopenharmony_ci b[28] = b[29] = 6; 583262306a36Sopenharmony_ci b[30] = b[31] = 7; 583362306a36Sopenharmony_ci} 583462306a36Sopenharmony_ci 583562306a36Sopenharmony_ci/* The minimum additive increment value for the congestion control table */ 583662306a36Sopenharmony_ci#define CC_MIN_INCR 2U 583762306a36Sopenharmony_ci 583862306a36Sopenharmony_ci/** 583962306a36Sopenharmony_ci * t4_load_mtus - write the MTU and congestion control HW tables 584062306a36Sopenharmony_ci * @adap: the adapter 584162306a36Sopenharmony_ci * @mtus: the values for the MTU table 584262306a36Sopenharmony_ci * @alpha: the values for the congestion control alpha parameter 584362306a36Sopenharmony_ci * @beta: the values for the congestion control beta parameter 584462306a36Sopenharmony_ci * 584562306a36Sopenharmony_ci * Write the HW MTU table with the supplied MTUs and the high-speed 584662306a36Sopenharmony_ci * congestion control table with the supplied alpha, beta, and MTUs. 584762306a36Sopenharmony_ci * We write the two tables together because the additive increments 584862306a36Sopenharmony_ci * depend on the MTUs. 584962306a36Sopenharmony_ci */ 585062306a36Sopenharmony_civoid t4_load_mtus(struct adapter *adap, const unsigned short *mtus, 585162306a36Sopenharmony_ci const unsigned short *alpha, const unsigned short *beta) 585262306a36Sopenharmony_ci{ 585362306a36Sopenharmony_ci static const unsigned int avg_pkts[NCCTRL_WIN] = { 585462306a36Sopenharmony_ci 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640, 585562306a36Sopenharmony_ci 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480, 585662306a36Sopenharmony_ci 28672, 40960, 57344, 81920, 114688, 163840, 229376 585762306a36Sopenharmony_ci }; 585862306a36Sopenharmony_ci 585962306a36Sopenharmony_ci unsigned int i, w; 586062306a36Sopenharmony_ci 586162306a36Sopenharmony_ci for (i = 0; i < NMTUS; ++i) { 586262306a36Sopenharmony_ci unsigned int mtu = mtus[i]; 586362306a36Sopenharmony_ci unsigned int log2 = fls(mtu); 586462306a36Sopenharmony_ci 586562306a36Sopenharmony_ci if (!(mtu & ((1 << log2) >> 2))) /* round */ 586662306a36Sopenharmony_ci log2--; 586762306a36Sopenharmony_ci t4_write_reg(adap, TP_MTU_TABLE_A, MTUINDEX_V(i) | 586862306a36Sopenharmony_ci MTUWIDTH_V(log2) | MTUVALUE_V(mtu)); 586962306a36Sopenharmony_ci 587062306a36Sopenharmony_ci for (w = 0; w < NCCTRL_WIN; ++w) { 587162306a36Sopenharmony_ci unsigned int inc; 587262306a36Sopenharmony_ci 587362306a36Sopenharmony_ci inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w], 587462306a36Sopenharmony_ci CC_MIN_INCR); 587562306a36Sopenharmony_ci 587662306a36Sopenharmony_ci t4_write_reg(adap, TP_CCTRL_TABLE_A, (i << 21) | 587762306a36Sopenharmony_ci (w << 16) | (beta[w] << 13) | inc); 587862306a36Sopenharmony_ci } 587962306a36Sopenharmony_ci } 588062306a36Sopenharmony_ci} 588162306a36Sopenharmony_ci 588262306a36Sopenharmony_ci/* Calculates a rate in bytes/s given the number of 256-byte units per 4K core 588362306a36Sopenharmony_ci * clocks. The formula is 588462306a36Sopenharmony_ci * 588562306a36Sopenharmony_ci * bytes/s = bytes256 * 256 * ClkFreq / 4096 588662306a36Sopenharmony_ci * 588762306a36Sopenharmony_ci * which is equivalent to 588862306a36Sopenharmony_ci * 588962306a36Sopenharmony_ci * bytes/s = 62.5 * bytes256 * ClkFreq_ms 589062306a36Sopenharmony_ci */ 589162306a36Sopenharmony_cistatic u64 chan_rate(struct adapter *adap, unsigned int bytes256) 589262306a36Sopenharmony_ci{ 589362306a36Sopenharmony_ci u64 v = bytes256 * adap->params.vpd.cclk; 589462306a36Sopenharmony_ci 589562306a36Sopenharmony_ci return v * 62 + v / 2; 589662306a36Sopenharmony_ci} 589762306a36Sopenharmony_ci 589862306a36Sopenharmony_ci/** 589962306a36Sopenharmony_ci * t4_get_chan_txrate - get the current per channel Tx rates 590062306a36Sopenharmony_ci * @adap: the adapter 590162306a36Sopenharmony_ci * @nic_rate: rates for NIC traffic 590262306a36Sopenharmony_ci * @ofld_rate: rates for offloaded traffic 590362306a36Sopenharmony_ci * 590462306a36Sopenharmony_ci * Return the current Tx rates in bytes/s for NIC and offloaded traffic 590562306a36Sopenharmony_ci * for each channel. 590662306a36Sopenharmony_ci */ 590762306a36Sopenharmony_civoid t4_get_chan_txrate(struct adapter *adap, u64 *nic_rate, u64 *ofld_rate) 590862306a36Sopenharmony_ci{ 590962306a36Sopenharmony_ci u32 v; 591062306a36Sopenharmony_ci 591162306a36Sopenharmony_ci v = t4_read_reg(adap, TP_TX_TRATE_A); 591262306a36Sopenharmony_ci nic_rate[0] = chan_rate(adap, TNLRATE0_G(v)); 591362306a36Sopenharmony_ci nic_rate[1] = chan_rate(adap, TNLRATE1_G(v)); 591462306a36Sopenharmony_ci if (adap->params.arch.nchan == NCHAN) { 591562306a36Sopenharmony_ci nic_rate[2] = chan_rate(adap, TNLRATE2_G(v)); 591662306a36Sopenharmony_ci nic_rate[3] = chan_rate(adap, TNLRATE3_G(v)); 591762306a36Sopenharmony_ci } 591862306a36Sopenharmony_ci 591962306a36Sopenharmony_ci v = t4_read_reg(adap, TP_TX_ORATE_A); 592062306a36Sopenharmony_ci ofld_rate[0] = chan_rate(adap, OFDRATE0_G(v)); 592162306a36Sopenharmony_ci ofld_rate[1] = chan_rate(adap, OFDRATE1_G(v)); 592262306a36Sopenharmony_ci if (adap->params.arch.nchan == NCHAN) { 592362306a36Sopenharmony_ci ofld_rate[2] = chan_rate(adap, OFDRATE2_G(v)); 592462306a36Sopenharmony_ci ofld_rate[3] = chan_rate(adap, OFDRATE3_G(v)); 592562306a36Sopenharmony_ci } 592662306a36Sopenharmony_ci} 592762306a36Sopenharmony_ci 592862306a36Sopenharmony_ci/** 592962306a36Sopenharmony_ci * t4_set_trace_filter - configure one of the tracing filters 593062306a36Sopenharmony_ci * @adap: the adapter 593162306a36Sopenharmony_ci * @tp: the desired trace filter parameters 593262306a36Sopenharmony_ci * @idx: which filter to configure 593362306a36Sopenharmony_ci * @enable: whether to enable or disable the filter 593462306a36Sopenharmony_ci * 593562306a36Sopenharmony_ci * Configures one of the tracing filters available in HW. If @enable is 593662306a36Sopenharmony_ci * %0 @tp is not examined and may be %NULL. The user is responsible to 593762306a36Sopenharmony_ci * set the single/multiple trace mode by writing to MPS_TRC_CFG_A register 593862306a36Sopenharmony_ci */ 593962306a36Sopenharmony_ciint t4_set_trace_filter(struct adapter *adap, const struct trace_params *tp, 594062306a36Sopenharmony_ci int idx, int enable) 594162306a36Sopenharmony_ci{ 594262306a36Sopenharmony_ci int i, ofst = idx * 4; 594362306a36Sopenharmony_ci u32 data_reg, mask_reg, cfg; 594462306a36Sopenharmony_ci 594562306a36Sopenharmony_ci if (!enable) { 594662306a36Sopenharmony_ci t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A_A + ofst, 0); 594762306a36Sopenharmony_ci return 0; 594862306a36Sopenharmony_ci } 594962306a36Sopenharmony_ci 595062306a36Sopenharmony_ci cfg = t4_read_reg(adap, MPS_TRC_CFG_A); 595162306a36Sopenharmony_ci if (cfg & TRCMULTIFILTER_F) { 595262306a36Sopenharmony_ci /* If multiple tracers are enabled, then maximum 595362306a36Sopenharmony_ci * capture size is 2.5KB (FIFO size of a single channel) 595462306a36Sopenharmony_ci * minus 2 flits for CPL_TRACE_PKT header. 595562306a36Sopenharmony_ci */ 595662306a36Sopenharmony_ci if (tp->snap_len > ((10 * 1024 / 4) - (2 * 8))) 595762306a36Sopenharmony_ci return -EINVAL; 595862306a36Sopenharmony_ci } else { 595962306a36Sopenharmony_ci /* If multiple tracers are disabled, to avoid deadlocks 596062306a36Sopenharmony_ci * maximum packet capture size of 9600 bytes is recommended. 596162306a36Sopenharmony_ci * Also in this mode, only trace0 can be enabled and running. 596262306a36Sopenharmony_ci */ 596362306a36Sopenharmony_ci if (tp->snap_len > 9600 || idx) 596462306a36Sopenharmony_ci return -EINVAL; 596562306a36Sopenharmony_ci } 596662306a36Sopenharmony_ci 596762306a36Sopenharmony_ci if (tp->port > (is_t4(adap->params.chip) ? 11 : 19) || tp->invert > 1 || 596862306a36Sopenharmony_ci tp->skip_len > TFLENGTH_M || tp->skip_ofst > TFOFFSET_M || 596962306a36Sopenharmony_ci tp->min_len > TFMINPKTSIZE_M) 597062306a36Sopenharmony_ci return -EINVAL; 597162306a36Sopenharmony_ci 597262306a36Sopenharmony_ci /* stop the tracer we'll be changing */ 597362306a36Sopenharmony_ci t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A_A + ofst, 0); 597462306a36Sopenharmony_ci 597562306a36Sopenharmony_ci idx *= (MPS_TRC_FILTER1_MATCH_A - MPS_TRC_FILTER0_MATCH_A); 597662306a36Sopenharmony_ci data_reg = MPS_TRC_FILTER0_MATCH_A + idx; 597762306a36Sopenharmony_ci mask_reg = MPS_TRC_FILTER0_DONT_CARE_A + idx; 597862306a36Sopenharmony_ci 597962306a36Sopenharmony_ci for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) { 598062306a36Sopenharmony_ci t4_write_reg(adap, data_reg, tp->data[i]); 598162306a36Sopenharmony_ci t4_write_reg(adap, mask_reg, ~tp->mask[i]); 598262306a36Sopenharmony_ci } 598362306a36Sopenharmony_ci t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_B_A + ofst, 598462306a36Sopenharmony_ci TFCAPTUREMAX_V(tp->snap_len) | 598562306a36Sopenharmony_ci TFMINPKTSIZE_V(tp->min_len)); 598662306a36Sopenharmony_ci t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A_A + ofst, 598762306a36Sopenharmony_ci TFOFFSET_V(tp->skip_ofst) | TFLENGTH_V(tp->skip_len) | 598862306a36Sopenharmony_ci (is_t4(adap->params.chip) ? 598962306a36Sopenharmony_ci TFPORT_V(tp->port) | TFEN_F | TFINVERTMATCH_V(tp->invert) : 599062306a36Sopenharmony_ci T5_TFPORT_V(tp->port) | T5_TFEN_F | 599162306a36Sopenharmony_ci T5_TFINVERTMATCH_V(tp->invert))); 599262306a36Sopenharmony_ci 599362306a36Sopenharmony_ci return 0; 599462306a36Sopenharmony_ci} 599562306a36Sopenharmony_ci 599662306a36Sopenharmony_ci/** 599762306a36Sopenharmony_ci * t4_get_trace_filter - query one of the tracing filters 599862306a36Sopenharmony_ci * @adap: the adapter 599962306a36Sopenharmony_ci * @tp: the current trace filter parameters 600062306a36Sopenharmony_ci * @idx: which trace filter to query 600162306a36Sopenharmony_ci * @enabled: non-zero if the filter is enabled 600262306a36Sopenharmony_ci * 600362306a36Sopenharmony_ci * Returns the current settings of one of the HW tracing filters. 600462306a36Sopenharmony_ci */ 600562306a36Sopenharmony_civoid t4_get_trace_filter(struct adapter *adap, struct trace_params *tp, int idx, 600662306a36Sopenharmony_ci int *enabled) 600762306a36Sopenharmony_ci{ 600862306a36Sopenharmony_ci u32 ctla, ctlb; 600962306a36Sopenharmony_ci int i, ofst = idx * 4; 601062306a36Sopenharmony_ci u32 data_reg, mask_reg; 601162306a36Sopenharmony_ci 601262306a36Sopenharmony_ci ctla = t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A_A + ofst); 601362306a36Sopenharmony_ci ctlb = t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_B_A + ofst); 601462306a36Sopenharmony_ci 601562306a36Sopenharmony_ci if (is_t4(adap->params.chip)) { 601662306a36Sopenharmony_ci *enabled = !!(ctla & TFEN_F); 601762306a36Sopenharmony_ci tp->port = TFPORT_G(ctla); 601862306a36Sopenharmony_ci tp->invert = !!(ctla & TFINVERTMATCH_F); 601962306a36Sopenharmony_ci } else { 602062306a36Sopenharmony_ci *enabled = !!(ctla & T5_TFEN_F); 602162306a36Sopenharmony_ci tp->port = T5_TFPORT_G(ctla); 602262306a36Sopenharmony_ci tp->invert = !!(ctla & T5_TFINVERTMATCH_F); 602362306a36Sopenharmony_ci } 602462306a36Sopenharmony_ci tp->snap_len = TFCAPTUREMAX_G(ctlb); 602562306a36Sopenharmony_ci tp->min_len = TFMINPKTSIZE_G(ctlb); 602662306a36Sopenharmony_ci tp->skip_ofst = TFOFFSET_G(ctla); 602762306a36Sopenharmony_ci tp->skip_len = TFLENGTH_G(ctla); 602862306a36Sopenharmony_ci 602962306a36Sopenharmony_ci ofst = (MPS_TRC_FILTER1_MATCH_A - MPS_TRC_FILTER0_MATCH_A) * idx; 603062306a36Sopenharmony_ci data_reg = MPS_TRC_FILTER0_MATCH_A + ofst; 603162306a36Sopenharmony_ci mask_reg = MPS_TRC_FILTER0_DONT_CARE_A + ofst; 603262306a36Sopenharmony_ci 603362306a36Sopenharmony_ci for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) { 603462306a36Sopenharmony_ci tp->mask[i] = ~t4_read_reg(adap, mask_reg); 603562306a36Sopenharmony_ci tp->data[i] = t4_read_reg(adap, data_reg) & tp->mask[i]; 603662306a36Sopenharmony_ci } 603762306a36Sopenharmony_ci} 603862306a36Sopenharmony_ci 603962306a36Sopenharmony_ci/** 604062306a36Sopenharmony_ci * t4_pmtx_get_stats - returns the HW stats from PMTX 604162306a36Sopenharmony_ci * @adap: the adapter 604262306a36Sopenharmony_ci * @cnt: where to store the count statistics 604362306a36Sopenharmony_ci * @cycles: where to store the cycle statistics 604462306a36Sopenharmony_ci * 604562306a36Sopenharmony_ci * Returns performance statistics from PMTX. 604662306a36Sopenharmony_ci */ 604762306a36Sopenharmony_civoid t4_pmtx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]) 604862306a36Sopenharmony_ci{ 604962306a36Sopenharmony_ci int i; 605062306a36Sopenharmony_ci u32 data[2]; 605162306a36Sopenharmony_ci 605262306a36Sopenharmony_ci for (i = 0; i < adap->params.arch.pm_stats_cnt; i++) { 605362306a36Sopenharmony_ci t4_write_reg(adap, PM_TX_STAT_CONFIG_A, i + 1); 605462306a36Sopenharmony_ci cnt[i] = t4_read_reg(adap, PM_TX_STAT_COUNT_A); 605562306a36Sopenharmony_ci if (is_t4(adap->params.chip)) { 605662306a36Sopenharmony_ci cycles[i] = t4_read_reg64(adap, PM_TX_STAT_LSB_A); 605762306a36Sopenharmony_ci } else { 605862306a36Sopenharmony_ci t4_read_indirect(adap, PM_TX_DBG_CTRL_A, 605962306a36Sopenharmony_ci PM_TX_DBG_DATA_A, data, 2, 606062306a36Sopenharmony_ci PM_TX_DBG_STAT_MSB_A); 606162306a36Sopenharmony_ci cycles[i] = (((u64)data[0] << 32) | data[1]); 606262306a36Sopenharmony_ci } 606362306a36Sopenharmony_ci } 606462306a36Sopenharmony_ci} 606562306a36Sopenharmony_ci 606662306a36Sopenharmony_ci/** 606762306a36Sopenharmony_ci * t4_pmrx_get_stats - returns the HW stats from PMRX 606862306a36Sopenharmony_ci * @adap: the adapter 606962306a36Sopenharmony_ci * @cnt: where to store the count statistics 607062306a36Sopenharmony_ci * @cycles: where to store the cycle statistics 607162306a36Sopenharmony_ci * 607262306a36Sopenharmony_ci * Returns performance statistics from PMRX. 607362306a36Sopenharmony_ci */ 607462306a36Sopenharmony_civoid t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]) 607562306a36Sopenharmony_ci{ 607662306a36Sopenharmony_ci int i; 607762306a36Sopenharmony_ci u32 data[2]; 607862306a36Sopenharmony_ci 607962306a36Sopenharmony_ci for (i = 0; i < adap->params.arch.pm_stats_cnt; i++) { 608062306a36Sopenharmony_ci t4_write_reg(adap, PM_RX_STAT_CONFIG_A, i + 1); 608162306a36Sopenharmony_ci cnt[i] = t4_read_reg(adap, PM_RX_STAT_COUNT_A); 608262306a36Sopenharmony_ci if (is_t4(adap->params.chip)) { 608362306a36Sopenharmony_ci cycles[i] = t4_read_reg64(adap, PM_RX_STAT_LSB_A); 608462306a36Sopenharmony_ci } else { 608562306a36Sopenharmony_ci t4_read_indirect(adap, PM_RX_DBG_CTRL_A, 608662306a36Sopenharmony_ci PM_RX_DBG_DATA_A, data, 2, 608762306a36Sopenharmony_ci PM_RX_DBG_STAT_MSB_A); 608862306a36Sopenharmony_ci cycles[i] = (((u64)data[0] << 32) | data[1]); 608962306a36Sopenharmony_ci } 609062306a36Sopenharmony_ci } 609162306a36Sopenharmony_ci} 609262306a36Sopenharmony_ci 609362306a36Sopenharmony_ci/** 609462306a36Sopenharmony_ci * compute_mps_bg_map - compute the MPS Buffer Group Map for a Port 609562306a36Sopenharmony_ci * @adapter: the adapter 609662306a36Sopenharmony_ci * @pidx: the port index 609762306a36Sopenharmony_ci * 609862306a36Sopenharmony_ci * Computes and returns a bitmap indicating which MPS buffer groups are 609962306a36Sopenharmony_ci * associated with the given Port. Bit i is set if buffer group i is 610062306a36Sopenharmony_ci * used by the Port. 610162306a36Sopenharmony_ci */ 610262306a36Sopenharmony_cistatic inline unsigned int compute_mps_bg_map(struct adapter *adapter, 610362306a36Sopenharmony_ci int pidx) 610462306a36Sopenharmony_ci{ 610562306a36Sopenharmony_ci unsigned int chip_version, nports; 610662306a36Sopenharmony_ci 610762306a36Sopenharmony_ci chip_version = CHELSIO_CHIP_VERSION(adapter->params.chip); 610862306a36Sopenharmony_ci nports = 1 << NUMPORTS_G(t4_read_reg(adapter, MPS_CMN_CTL_A)); 610962306a36Sopenharmony_ci 611062306a36Sopenharmony_ci switch (chip_version) { 611162306a36Sopenharmony_ci case CHELSIO_T4: 611262306a36Sopenharmony_ci case CHELSIO_T5: 611362306a36Sopenharmony_ci switch (nports) { 611462306a36Sopenharmony_ci case 1: return 0xf; 611562306a36Sopenharmony_ci case 2: return 3 << (2 * pidx); 611662306a36Sopenharmony_ci case 4: return 1 << pidx; 611762306a36Sopenharmony_ci } 611862306a36Sopenharmony_ci break; 611962306a36Sopenharmony_ci 612062306a36Sopenharmony_ci case CHELSIO_T6: 612162306a36Sopenharmony_ci switch (nports) { 612262306a36Sopenharmony_ci case 2: return 1 << (2 * pidx); 612362306a36Sopenharmony_ci } 612462306a36Sopenharmony_ci break; 612562306a36Sopenharmony_ci } 612662306a36Sopenharmony_ci 612762306a36Sopenharmony_ci dev_err(adapter->pdev_dev, "Need MPS Buffer Group Map for Chip %0x, Nports %d\n", 612862306a36Sopenharmony_ci chip_version, nports); 612962306a36Sopenharmony_ci 613062306a36Sopenharmony_ci return 0; 613162306a36Sopenharmony_ci} 613262306a36Sopenharmony_ci 613362306a36Sopenharmony_ci/** 613462306a36Sopenharmony_ci * t4_get_mps_bg_map - return the buffer groups associated with a port 613562306a36Sopenharmony_ci * @adapter: the adapter 613662306a36Sopenharmony_ci * @pidx: the port index 613762306a36Sopenharmony_ci * 613862306a36Sopenharmony_ci * Returns a bitmap indicating which MPS buffer groups are associated 613962306a36Sopenharmony_ci * with the given Port. Bit i is set if buffer group i is used by the 614062306a36Sopenharmony_ci * Port. 614162306a36Sopenharmony_ci */ 614262306a36Sopenharmony_ciunsigned int t4_get_mps_bg_map(struct adapter *adapter, int pidx) 614362306a36Sopenharmony_ci{ 614462306a36Sopenharmony_ci u8 *mps_bg_map; 614562306a36Sopenharmony_ci unsigned int nports; 614662306a36Sopenharmony_ci 614762306a36Sopenharmony_ci nports = 1 << NUMPORTS_G(t4_read_reg(adapter, MPS_CMN_CTL_A)); 614862306a36Sopenharmony_ci if (pidx >= nports) { 614962306a36Sopenharmony_ci CH_WARN(adapter, "MPS Port Index %d >= Nports %d\n", 615062306a36Sopenharmony_ci pidx, nports); 615162306a36Sopenharmony_ci return 0; 615262306a36Sopenharmony_ci } 615362306a36Sopenharmony_ci 615462306a36Sopenharmony_ci /* If we've already retrieved/computed this, just return the result. 615562306a36Sopenharmony_ci */ 615662306a36Sopenharmony_ci mps_bg_map = adapter->params.mps_bg_map; 615762306a36Sopenharmony_ci if (mps_bg_map[pidx]) 615862306a36Sopenharmony_ci return mps_bg_map[pidx]; 615962306a36Sopenharmony_ci 616062306a36Sopenharmony_ci /* Newer Firmware can tell us what the MPS Buffer Group Map is. 616162306a36Sopenharmony_ci * If we're talking to such Firmware, let it tell us. If the new 616262306a36Sopenharmony_ci * API isn't supported, revert back to old hardcoded way. The value 616362306a36Sopenharmony_ci * obtained from Firmware is encoded in below format: 616462306a36Sopenharmony_ci * 616562306a36Sopenharmony_ci * val = (( MPSBGMAP[Port 3] << 24 ) | 616662306a36Sopenharmony_ci * ( MPSBGMAP[Port 2] << 16 ) | 616762306a36Sopenharmony_ci * ( MPSBGMAP[Port 1] << 8 ) | 616862306a36Sopenharmony_ci * ( MPSBGMAP[Port 0] << 0 )) 616962306a36Sopenharmony_ci */ 617062306a36Sopenharmony_ci if (adapter->flags & CXGB4_FW_OK) { 617162306a36Sopenharmony_ci u32 param, val; 617262306a36Sopenharmony_ci int ret; 617362306a36Sopenharmony_ci 617462306a36Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 617562306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_MPSBGMAP)); 617662306a36Sopenharmony_ci ret = t4_query_params_ns(adapter, adapter->mbox, adapter->pf, 617762306a36Sopenharmony_ci 0, 1, ¶m, &val); 617862306a36Sopenharmony_ci if (!ret) { 617962306a36Sopenharmony_ci int p; 618062306a36Sopenharmony_ci 618162306a36Sopenharmony_ci /* Store the BG Map for all of the Ports in order to 618262306a36Sopenharmony_ci * avoid more calls to the Firmware in the future. 618362306a36Sopenharmony_ci */ 618462306a36Sopenharmony_ci for (p = 0; p < MAX_NPORTS; p++, val >>= 8) 618562306a36Sopenharmony_ci mps_bg_map[p] = val & 0xff; 618662306a36Sopenharmony_ci 618762306a36Sopenharmony_ci return mps_bg_map[pidx]; 618862306a36Sopenharmony_ci } 618962306a36Sopenharmony_ci } 619062306a36Sopenharmony_ci 619162306a36Sopenharmony_ci /* Either we're not talking to the Firmware or we're dealing with 619262306a36Sopenharmony_ci * older Firmware which doesn't support the new API to get the MPS 619362306a36Sopenharmony_ci * Buffer Group Map. Fall back to computing it ourselves. 619462306a36Sopenharmony_ci */ 619562306a36Sopenharmony_ci mps_bg_map[pidx] = compute_mps_bg_map(adapter, pidx); 619662306a36Sopenharmony_ci return mps_bg_map[pidx]; 619762306a36Sopenharmony_ci} 619862306a36Sopenharmony_ci 619962306a36Sopenharmony_ci/** 620062306a36Sopenharmony_ci * t4_get_tp_e2c_map - return the E2C channel map associated with a port 620162306a36Sopenharmony_ci * @adapter: the adapter 620262306a36Sopenharmony_ci * @pidx: the port index 620362306a36Sopenharmony_ci */ 620462306a36Sopenharmony_cistatic unsigned int t4_get_tp_e2c_map(struct adapter *adapter, int pidx) 620562306a36Sopenharmony_ci{ 620662306a36Sopenharmony_ci unsigned int nports; 620762306a36Sopenharmony_ci u32 param, val = 0; 620862306a36Sopenharmony_ci int ret; 620962306a36Sopenharmony_ci 621062306a36Sopenharmony_ci nports = 1 << NUMPORTS_G(t4_read_reg(adapter, MPS_CMN_CTL_A)); 621162306a36Sopenharmony_ci if (pidx >= nports) { 621262306a36Sopenharmony_ci CH_WARN(adapter, "TP E2C Channel Port Index %d >= Nports %d\n", 621362306a36Sopenharmony_ci pidx, nports); 621462306a36Sopenharmony_ci return 0; 621562306a36Sopenharmony_ci } 621662306a36Sopenharmony_ci 621762306a36Sopenharmony_ci /* FW version >= 1.16.44.0 can determine E2C channel map using 621862306a36Sopenharmony_ci * FW_PARAMS_PARAM_DEV_TPCHMAP API. 621962306a36Sopenharmony_ci */ 622062306a36Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 622162306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_TPCHMAP)); 622262306a36Sopenharmony_ci ret = t4_query_params_ns(adapter, adapter->mbox, adapter->pf, 622362306a36Sopenharmony_ci 0, 1, ¶m, &val); 622462306a36Sopenharmony_ci if (!ret) 622562306a36Sopenharmony_ci return (val >> (8 * pidx)) & 0xff; 622662306a36Sopenharmony_ci 622762306a36Sopenharmony_ci return 0; 622862306a36Sopenharmony_ci} 622962306a36Sopenharmony_ci 623062306a36Sopenharmony_ci/** 623162306a36Sopenharmony_ci * t4_get_tp_ch_map - return TP ingress channels associated with a port 623262306a36Sopenharmony_ci * @adap: the adapter 623362306a36Sopenharmony_ci * @pidx: the port index 623462306a36Sopenharmony_ci * 623562306a36Sopenharmony_ci * Returns a bitmap indicating which TP Ingress Channels are associated 623662306a36Sopenharmony_ci * with a given Port. Bit i is set if TP Ingress Channel i is used by 623762306a36Sopenharmony_ci * the Port. 623862306a36Sopenharmony_ci */ 623962306a36Sopenharmony_ciunsigned int t4_get_tp_ch_map(struct adapter *adap, int pidx) 624062306a36Sopenharmony_ci{ 624162306a36Sopenharmony_ci unsigned int chip_version = CHELSIO_CHIP_VERSION(adap->params.chip); 624262306a36Sopenharmony_ci unsigned int nports = 1 << NUMPORTS_G(t4_read_reg(adap, MPS_CMN_CTL_A)); 624362306a36Sopenharmony_ci 624462306a36Sopenharmony_ci if (pidx >= nports) { 624562306a36Sopenharmony_ci dev_warn(adap->pdev_dev, "TP Port Index %d >= Nports %d\n", 624662306a36Sopenharmony_ci pidx, nports); 624762306a36Sopenharmony_ci return 0; 624862306a36Sopenharmony_ci } 624962306a36Sopenharmony_ci 625062306a36Sopenharmony_ci switch (chip_version) { 625162306a36Sopenharmony_ci case CHELSIO_T4: 625262306a36Sopenharmony_ci case CHELSIO_T5: 625362306a36Sopenharmony_ci /* Note that this happens to be the same values as the MPS 625462306a36Sopenharmony_ci * Buffer Group Map for these Chips. But we replicate the code 625562306a36Sopenharmony_ci * here because they're really separate concepts. 625662306a36Sopenharmony_ci */ 625762306a36Sopenharmony_ci switch (nports) { 625862306a36Sopenharmony_ci case 1: return 0xf; 625962306a36Sopenharmony_ci case 2: return 3 << (2 * pidx); 626062306a36Sopenharmony_ci case 4: return 1 << pidx; 626162306a36Sopenharmony_ci } 626262306a36Sopenharmony_ci break; 626362306a36Sopenharmony_ci 626462306a36Sopenharmony_ci case CHELSIO_T6: 626562306a36Sopenharmony_ci switch (nports) { 626662306a36Sopenharmony_ci case 1: 626762306a36Sopenharmony_ci case 2: return 1 << pidx; 626862306a36Sopenharmony_ci } 626962306a36Sopenharmony_ci break; 627062306a36Sopenharmony_ci } 627162306a36Sopenharmony_ci 627262306a36Sopenharmony_ci dev_err(adap->pdev_dev, "Need TP Channel Map for Chip %0x, Nports %d\n", 627362306a36Sopenharmony_ci chip_version, nports); 627462306a36Sopenharmony_ci return 0; 627562306a36Sopenharmony_ci} 627662306a36Sopenharmony_ci 627762306a36Sopenharmony_ci/** 627862306a36Sopenharmony_ci * t4_get_port_type_description - return Port Type string description 627962306a36Sopenharmony_ci * @port_type: firmware Port Type enumeration 628062306a36Sopenharmony_ci */ 628162306a36Sopenharmony_ciconst char *t4_get_port_type_description(enum fw_port_type port_type) 628262306a36Sopenharmony_ci{ 628362306a36Sopenharmony_ci static const char *const port_type_description[] = { 628462306a36Sopenharmony_ci "Fiber_XFI", 628562306a36Sopenharmony_ci "Fiber_XAUI", 628662306a36Sopenharmony_ci "BT_SGMII", 628762306a36Sopenharmony_ci "BT_XFI", 628862306a36Sopenharmony_ci "BT_XAUI", 628962306a36Sopenharmony_ci "KX4", 629062306a36Sopenharmony_ci "CX4", 629162306a36Sopenharmony_ci "KX", 629262306a36Sopenharmony_ci "KR", 629362306a36Sopenharmony_ci "SFP", 629462306a36Sopenharmony_ci "BP_AP", 629562306a36Sopenharmony_ci "BP4_AP", 629662306a36Sopenharmony_ci "QSFP_10G", 629762306a36Sopenharmony_ci "QSA", 629862306a36Sopenharmony_ci "QSFP", 629962306a36Sopenharmony_ci "BP40_BA", 630062306a36Sopenharmony_ci "KR4_100G", 630162306a36Sopenharmony_ci "CR4_QSFP", 630262306a36Sopenharmony_ci "CR_QSFP", 630362306a36Sopenharmony_ci "CR2_QSFP", 630462306a36Sopenharmony_ci "SFP28", 630562306a36Sopenharmony_ci "KR_SFP28", 630662306a36Sopenharmony_ci "KR_XLAUI" 630762306a36Sopenharmony_ci }; 630862306a36Sopenharmony_ci 630962306a36Sopenharmony_ci if (port_type < ARRAY_SIZE(port_type_description)) 631062306a36Sopenharmony_ci return port_type_description[port_type]; 631162306a36Sopenharmony_ci return "UNKNOWN"; 631262306a36Sopenharmony_ci} 631362306a36Sopenharmony_ci 631462306a36Sopenharmony_ci/** 631562306a36Sopenharmony_ci * t4_get_port_stats_offset - collect port stats relative to a previous 631662306a36Sopenharmony_ci * snapshot 631762306a36Sopenharmony_ci * @adap: The adapter 631862306a36Sopenharmony_ci * @idx: The port 631962306a36Sopenharmony_ci * @stats: Current stats to fill 632062306a36Sopenharmony_ci * @offset: Previous stats snapshot 632162306a36Sopenharmony_ci */ 632262306a36Sopenharmony_civoid t4_get_port_stats_offset(struct adapter *adap, int idx, 632362306a36Sopenharmony_ci struct port_stats *stats, 632462306a36Sopenharmony_ci struct port_stats *offset) 632562306a36Sopenharmony_ci{ 632662306a36Sopenharmony_ci u64 *s, *o; 632762306a36Sopenharmony_ci int i; 632862306a36Sopenharmony_ci 632962306a36Sopenharmony_ci t4_get_port_stats(adap, idx, stats); 633062306a36Sopenharmony_ci for (i = 0, s = (u64 *)stats, o = (u64 *)offset; 633162306a36Sopenharmony_ci i < (sizeof(struct port_stats) / sizeof(u64)); 633262306a36Sopenharmony_ci i++, s++, o++) 633362306a36Sopenharmony_ci *s -= *o; 633462306a36Sopenharmony_ci} 633562306a36Sopenharmony_ci 633662306a36Sopenharmony_ci/** 633762306a36Sopenharmony_ci * t4_get_port_stats - collect port statistics 633862306a36Sopenharmony_ci * @adap: the adapter 633962306a36Sopenharmony_ci * @idx: the port index 634062306a36Sopenharmony_ci * @p: the stats structure to fill 634162306a36Sopenharmony_ci * 634262306a36Sopenharmony_ci * Collect statistics related to the given port from HW. 634362306a36Sopenharmony_ci */ 634462306a36Sopenharmony_civoid t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p) 634562306a36Sopenharmony_ci{ 634662306a36Sopenharmony_ci u32 bgmap = t4_get_mps_bg_map(adap, idx); 634762306a36Sopenharmony_ci u32 stat_ctl = t4_read_reg(adap, MPS_STAT_CTL_A); 634862306a36Sopenharmony_ci 634962306a36Sopenharmony_ci#define GET_STAT(name) \ 635062306a36Sopenharmony_ci t4_read_reg64(adap, \ 635162306a36Sopenharmony_ci (is_t4(adap->params.chip) ? PORT_REG(idx, MPS_PORT_STAT_##name##_L) : \ 635262306a36Sopenharmony_ci T5_PORT_REG(idx, MPS_PORT_STAT_##name##_L))) 635362306a36Sopenharmony_ci#define GET_STAT_COM(name) t4_read_reg64(adap, MPS_STAT_##name##_L) 635462306a36Sopenharmony_ci 635562306a36Sopenharmony_ci p->tx_octets = GET_STAT(TX_PORT_BYTES); 635662306a36Sopenharmony_ci p->tx_frames = GET_STAT(TX_PORT_FRAMES); 635762306a36Sopenharmony_ci p->tx_bcast_frames = GET_STAT(TX_PORT_BCAST); 635862306a36Sopenharmony_ci p->tx_mcast_frames = GET_STAT(TX_PORT_MCAST); 635962306a36Sopenharmony_ci p->tx_ucast_frames = GET_STAT(TX_PORT_UCAST); 636062306a36Sopenharmony_ci p->tx_error_frames = GET_STAT(TX_PORT_ERROR); 636162306a36Sopenharmony_ci p->tx_frames_64 = GET_STAT(TX_PORT_64B); 636262306a36Sopenharmony_ci p->tx_frames_65_127 = GET_STAT(TX_PORT_65B_127B); 636362306a36Sopenharmony_ci p->tx_frames_128_255 = GET_STAT(TX_PORT_128B_255B); 636462306a36Sopenharmony_ci p->tx_frames_256_511 = GET_STAT(TX_PORT_256B_511B); 636562306a36Sopenharmony_ci p->tx_frames_512_1023 = GET_STAT(TX_PORT_512B_1023B); 636662306a36Sopenharmony_ci p->tx_frames_1024_1518 = GET_STAT(TX_PORT_1024B_1518B); 636762306a36Sopenharmony_ci p->tx_frames_1519_max = GET_STAT(TX_PORT_1519B_MAX); 636862306a36Sopenharmony_ci p->tx_drop = GET_STAT(TX_PORT_DROP); 636962306a36Sopenharmony_ci p->tx_pause = GET_STAT(TX_PORT_PAUSE); 637062306a36Sopenharmony_ci p->tx_ppp0 = GET_STAT(TX_PORT_PPP0); 637162306a36Sopenharmony_ci p->tx_ppp1 = GET_STAT(TX_PORT_PPP1); 637262306a36Sopenharmony_ci p->tx_ppp2 = GET_STAT(TX_PORT_PPP2); 637362306a36Sopenharmony_ci p->tx_ppp3 = GET_STAT(TX_PORT_PPP3); 637462306a36Sopenharmony_ci p->tx_ppp4 = GET_STAT(TX_PORT_PPP4); 637562306a36Sopenharmony_ci p->tx_ppp5 = GET_STAT(TX_PORT_PPP5); 637662306a36Sopenharmony_ci p->tx_ppp6 = GET_STAT(TX_PORT_PPP6); 637762306a36Sopenharmony_ci p->tx_ppp7 = GET_STAT(TX_PORT_PPP7); 637862306a36Sopenharmony_ci 637962306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adap->params.chip) >= CHELSIO_T5) { 638062306a36Sopenharmony_ci if (stat_ctl & COUNTPAUSESTATTX_F) 638162306a36Sopenharmony_ci p->tx_frames_64 -= p->tx_pause; 638262306a36Sopenharmony_ci if (stat_ctl & COUNTPAUSEMCTX_F) 638362306a36Sopenharmony_ci p->tx_mcast_frames -= p->tx_pause; 638462306a36Sopenharmony_ci } 638562306a36Sopenharmony_ci p->rx_octets = GET_STAT(RX_PORT_BYTES); 638662306a36Sopenharmony_ci p->rx_frames = GET_STAT(RX_PORT_FRAMES); 638762306a36Sopenharmony_ci p->rx_bcast_frames = GET_STAT(RX_PORT_BCAST); 638862306a36Sopenharmony_ci p->rx_mcast_frames = GET_STAT(RX_PORT_MCAST); 638962306a36Sopenharmony_ci p->rx_ucast_frames = GET_STAT(RX_PORT_UCAST); 639062306a36Sopenharmony_ci p->rx_too_long = GET_STAT(RX_PORT_MTU_ERROR); 639162306a36Sopenharmony_ci p->rx_jabber = GET_STAT(RX_PORT_MTU_CRC_ERROR); 639262306a36Sopenharmony_ci p->rx_fcs_err = GET_STAT(RX_PORT_CRC_ERROR); 639362306a36Sopenharmony_ci p->rx_len_err = GET_STAT(RX_PORT_LEN_ERROR); 639462306a36Sopenharmony_ci p->rx_symbol_err = GET_STAT(RX_PORT_SYM_ERROR); 639562306a36Sopenharmony_ci p->rx_runt = GET_STAT(RX_PORT_LESS_64B); 639662306a36Sopenharmony_ci p->rx_frames_64 = GET_STAT(RX_PORT_64B); 639762306a36Sopenharmony_ci p->rx_frames_65_127 = GET_STAT(RX_PORT_65B_127B); 639862306a36Sopenharmony_ci p->rx_frames_128_255 = GET_STAT(RX_PORT_128B_255B); 639962306a36Sopenharmony_ci p->rx_frames_256_511 = GET_STAT(RX_PORT_256B_511B); 640062306a36Sopenharmony_ci p->rx_frames_512_1023 = GET_STAT(RX_PORT_512B_1023B); 640162306a36Sopenharmony_ci p->rx_frames_1024_1518 = GET_STAT(RX_PORT_1024B_1518B); 640262306a36Sopenharmony_ci p->rx_frames_1519_max = GET_STAT(RX_PORT_1519B_MAX); 640362306a36Sopenharmony_ci p->rx_pause = GET_STAT(RX_PORT_PAUSE); 640462306a36Sopenharmony_ci p->rx_ppp0 = GET_STAT(RX_PORT_PPP0); 640562306a36Sopenharmony_ci p->rx_ppp1 = GET_STAT(RX_PORT_PPP1); 640662306a36Sopenharmony_ci p->rx_ppp2 = GET_STAT(RX_PORT_PPP2); 640762306a36Sopenharmony_ci p->rx_ppp3 = GET_STAT(RX_PORT_PPP3); 640862306a36Sopenharmony_ci p->rx_ppp4 = GET_STAT(RX_PORT_PPP4); 640962306a36Sopenharmony_ci p->rx_ppp5 = GET_STAT(RX_PORT_PPP5); 641062306a36Sopenharmony_ci p->rx_ppp6 = GET_STAT(RX_PORT_PPP6); 641162306a36Sopenharmony_ci p->rx_ppp7 = GET_STAT(RX_PORT_PPP7); 641262306a36Sopenharmony_ci 641362306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adap->params.chip) >= CHELSIO_T5) { 641462306a36Sopenharmony_ci if (stat_ctl & COUNTPAUSESTATRX_F) 641562306a36Sopenharmony_ci p->rx_frames_64 -= p->rx_pause; 641662306a36Sopenharmony_ci if (stat_ctl & COUNTPAUSEMCRX_F) 641762306a36Sopenharmony_ci p->rx_mcast_frames -= p->rx_pause; 641862306a36Sopenharmony_ci } 641962306a36Sopenharmony_ci 642062306a36Sopenharmony_ci p->rx_ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_DROP_FRAME) : 0; 642162306a36Sopenharmony_ci p->rx_ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_DROP_FRAME) : 0; 642262306a36Sopenharmony_ci p->rx_ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_DROP_FRAME) : 0; 642362306a36Sopenharmony_ci p->rx_ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_DROP_FRAME) : 0; 642462306a36Sopenharmony_ci p->rx_trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_TRUNC_FRAME) : 0; 642562306a36Sopenharmony_ci p->rx_trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_TRUNC_FRAME) : 0; 642662306a36Sopenharmony_ci p->rx_trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_TRUNC_FRAME) : 0; 642762306a36Sopenharmony_ci p->rx_trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_TRUNC_FRAME) : 0; 642862306a36Sopenharmony_ci 642962306a36Sopenharmony_ci#undef GET_STAT 643062306a36Sopenharmony_ci#undef GET_STAT_COM 643162306a36Sopenharmony_ci} 643262306a36Sopenharmony_ci 643362306a36Sopenharmony_ci/** 643462306a36Sopenharmony_ci * t4_get_lb_stats - collect loopback port statistics 643562306a36Sopenharmony_ci * @adap: the adapter 643662306a36Sopenharmony_ci * @idx: the loopback port index 643762306a36Sopenharmony_ci * @p: the stats structure to fill 643862306a36Sopenharmony_ci * 643962306a36Sopenharmony_ci * Return HW statistics for the given loopback port. 644062306a36Sopenharmony_ci */ 644162306a36Sopenharmony_civoid t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p) 644262306a36Sopenharmony_ci{ 644362306a36Sopenharmony_ci u32 bgmap = t4_get_mps_bg_map(adap, idx); 644462306a36Sopenharmony_ci 644562306a36Sopenharmony_ci#define GET_STAT(name) \ 644662306a36Sopenharmony_ci t4_read_reg64(adap, \ 644762306a36Sopenharmony_ci (is_t4(adap->params.chip) ? \ 644862306a36Sopenharmony_ci PORT_REG(idx, MPS_PORT_STAT_LB_PORT_##name##_L) : \ 644962306a36Sopenharmony_ci T5_PORT_REG(idx, MPS_PORT_STAT_LB_PORT_##name##_L))) 645062306a36Sopenharmony_ci#define GET_STAT_COM(name) t4_read_reg64(adap, MPS_STAT_##name##_L) 645162306a36Sopenharmony_ci 645262306a36Sopenharmony_ci p->octets = GET_STAT(BYTES); 645362306a36Sopenharmony_ci p->frames = GET_STAT(FRAMES); 645462306a36Sopenharmony_ci p->bcast_frames = GET_STAT(BCAST); 645562306a36Sopenharmony_ci p->mcast_frames = GET_STAT(MCAST); 645662306a36Sopenharmony_ci p->ucast_frames = GET_STAT(UCAST); 645762306a36Sopenharmony_ci p->error_frames = GET_STAT(ERROR); 645862306a36Sopenharmony_ci 645962306a36Sopenharmony_ci p->frames_64 = GET_STAT(64B); 646062306a36Sopenharmony_ci p->frames_65_127 = GET_STAT(65B_127B); 646162306a36Sopenharmony_ci p->frames_128_255 = GET_STAT(128B_255B); 646262306a36Sopenharmony_ci p->frames_256_511 = GET_STAT(256B_511B); 646362306a36Sopenharmony_ci p->frames_512_1023 = GET_STAT(512B_1023B); 646462306a36Sopenharmony_ci p->frames_1024_1518 = GET_STAT(1024B_1518B); 646562306a36Sopenharmony_ci p->frames_1519_max = GET_STAT(1519B_MAX); 646662306a36Sopenharmony_ci p->drop = GET_STAT(DROP_FRAMES); 646762306a36Sopenharmony_ci 646862306a36Sopenharmony_ci p->ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_DROP_FRAME) : 0; 646962306a36Sopenharmony_ci p->ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_DROP_FRAME) : 0; 647062306a36Sopenharmony_ci p->ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_DROP_FRAME) : 0; 647162306a36Sopenharmony_ci p->ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_DROP_FRAME) : 0; 647262306a36Sopenharmony_ci p->trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_TRUNC_FRAME) : 0; 647362306a36Sopenharmony_ci p->trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_TRUNC_FRAME) : 0; 647462306a36Sopenharmony_ci p->trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_TRUNC_FRAME) : 0; 647562306a36Sopenharmony_ci p->trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_TRUNC_FRAME) : 0; 647662306a36Sopenharmony_ci 647762306a36Sopenharmony_ci#undef GET_STAT 647862306a36Sopenharmony_ci#undef GET_STAT_COM 647962306a36Sopenharmony_ci} 648062306a36Sopenharmony_ci 648162306a36Sopenharmony_ci/* t4_mk_filtdelwr - create a delete filter WR 648262306a36Sopenharmony_ci * @ftid: the filter ID 648362306a36Sopenharmony_ci * @wr: the filter work request to populate 648462306a36Sopenharmony_ci * @qid: ingress queue to receive the delete notification 648562306a36Sopenharmony_ci * 648662306a36Sopenharmony_ci * Creates a filter work request to delete the supplied filter. If @qid is 648762306a36Sopenharmony_ci * negative the delete notification is suppressed. 648862306a36Sopenharmony_ci */ 648962306a36Sopenharmony_civoid t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid) 649062306a36Sopenharmony_ci{ 649162306a36Sopenharmony_ci memset(wr, 0, sizeof(*wr)); 649262306a36Sopenharmony_ci wr->op_pkd = cpu_to_be32(FW_WR_OP_V(FW_FILTER_WR)); 649362306a36Sopenharmony_ci wr->len16_pkd = cpu_to_be32(FW_WR_LEN16_V(sizeof(*wr) / 16)); 649462306a36Sopenharmony_ci wr->tid_to_iq = cpu_to_be32(FW_FILTER_WR_TID_V(ftid) | 649562306a36Sopenharmony_ci FW_FILTER_WR_NOREPLY_V(qid < 0)); 649662306a36Sopenharmony_ci wr->del_filter_to_l2tix = cpu_to_be32(FW_FILTER_WR_DEL_FILTER_F); 649762306a36Sopenharmony_ci if (qid >= 0) 649862306a36Sopenharmony_ci wr->rx_chan_rx_rpl_iq = 649962306a36Sopenharmony_ci cpu_to_be16(FW_FILTER_WR_RX_RPL_IQ_V(qid)); 650062306a36Sopenharmony_ci} 650162306a36Sopenharmony_ci 650262306a36Sopenharmony_ci#define INIT_CMD(var, cmd, rd_wr) do { \ 650362306a36Sopenharmony_ci (var).op_to_write = cpu_to_be32(FW_CMD_OP_V(FW_##cmd##_CMD) | \ 650462306a36Sopenharmony_ci FW_CMD_REQUEST_F | \ 650562306a36Sopenharmony_ci FW_CMD_##rd_wr##_F); \ 650662306a36Sopenharmony_ci (var).retval_len16 = cpu_to_be32(FW_LEN16(var)); \ 650762306a36Sopenharmony_ci} while (0) 650862306a36Sopenharmony_ci 650962306a36Sopenharmony_ciint t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox, 651062306a36Sopenharmony_ci u32 addr, u32 val) 651162306a36Sopenharmony_ci{ 651262306a36Sopenharmony_ci u32 ldst_addrspace; 651362306a36Sopenharmony_ci struct fw_ldst_cmd c; 651462306a36Sopenharmony_ci 651562306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 651662306a36Sopenharmony_ci ldst_addrspace = FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_FIRMWARE); 651762306a36Sopenharmony_ci c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) | 651862306a36Sopenharmony_ci FW_CMD_REQUEST_F | 651962306a36Sopenharmony_ci FW_CMD_WRITE_F | 652062306a36Sopenharmony_ci ldst_addrspace); 652162306a36Sopenharmony_ci c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c)); 652262306a36Sopenharmony_ci c.u.addrval.addr = cpu_to_be32(addr); 652362306a36Sopenharmony_ci c.u.addrval.val = cpu_to_be32(val); 652462306a36Sopenharmony_ci 652562306a36Sopenharmony_ci return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 652662306a36Sopenharmony_ci} 652762306a36Sopenharmony_ci 652862306a36Sopenharmony_ci/** 652962306a36Sopenharmony_ci * t4_mdio_rd - read a PHY register through MDIO 653062306a36Sopenharmony_ci * @adap: the adapter 653162306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 653262306a36Sopenharmony_ci * @phy_addr: the PHY address 653362306a36Sopenharmony_ci * @mmd: the PHY MMD to access (0 for clause 22 PHYs) 653462306a36Sopenharmony_ci * @reg: the register to read 653562306a36Sopenharmony_ci * @valp: where to store the value 653662306a36Sopenharmony_ci * 653762306a36Sopenharmony_ci * Issues a FW command through the given mailbox to read a PHY register. 653862306a36Sopenharmony_ci */ 653962306a36Sopenharmony_ciint t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, 654062306a36Sopenharmony_ci unsigned int mmd, unsigned int reg, u16 *valp) 654162306a36Sopenharmony_ci{ 654262306a36Sopenharmony_ci int ret; 654362306a36Sopenharmony_ci u32 ldst_addrspace; 654462306a36Sopenharmony_ci struct fw_ldst_cmd c; 654562306a36Sopenharmony_ci 654662306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 654762306a36Sopenharmony_ci ldst_addrspace = FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_MDIO); 654862306a36Sopenharmony_ci c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) | 654962306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_READ_F | 655062306a36Sopenharmony_ci ldst_addrspace); 655162306a36Sopenharmony_ci c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c)); 655262306a36Sopenharmony_ci c.u.mdio.paddr_mmd = cpu_to_be16(FW_LDST_CMD_PADDR_V(phy_addr) | 655362306a36Sopenharmony_ci FW_LDST_CMD_MMD_V(mmd)); 655462306a36Sopenharmony_ci c.u.mdio.raddr = cpu_to_be16(reg); 655562306a36Sopenharmony_ci 655662306a36Sopenharmony_ci ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); 655762306a36Sopenharmony_ci if (ret == 0) 655862306a36Sopenharmony_ci *valp = be16_to_cpu(c.u.mdio.rval); 655962306a36Sopenharmony_ci return ret; 656062306a36Sopenharmony_ci} 656162306a36Sopenharmony_ci 656262306a36Sopenharmony_ci/** 656362306a36Sopenharmony_ci * t4_mdio_wr - write a PHY register through MDIO 656462306a36Sopenharmony_ci * @adap: the adapter 656562306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 656662306a36Sopenharmony_ci * @phy_addr: the PHY address 656762306a36Sopenharmony_ci * @mmd: the PHY MMD to access (0 for clause 22 PHYs) 656862306a36Sopenharmony_ci * @reg: the register to write 656962306a36Sopenharmony_ci * @val: value to write 657062306a36Sopenharmony_ci * 657162306a36Sopenharmony_ci * Issues a FW command through the given mailbox to write a PHY register. 657262306a36Sopenharmony_ci */ 657362306a36Sopenharmony_ciint t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, 657462306a36Sopenharmony_ci unsigned int mmd, unsigned int reg, u16 val) 657562306a36Sopenharmony_ci{ 657662306a36Sopenharmony_ci u32 ldst_addrspace; 657762306a36Sopenharmony_ci struct fw_ldst_cmd c; 657862306a36Sopenharmony_ci 657962306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 658062306a36Sopenharmony_ci ldst_addrspace = FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_MDIO); 658162306a36Sopenharmony_ci c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) | 658262306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F | 658362306a36Sopenharmony_ci ldst_addrspace); 658462306a36Sopenharmony_ci c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c)); 658562306a36Sopenharmony_ci c.u.mdio.paddr_mmd = cpu_to_be16(FW_LDST_CMD_PADDR_V(phy_addr) | 658662306a36Sopenharmony_ci FW_LDST_CMD_MMD_V(mmd)); 658762306a36Sopenharmony_ci c.u.mdio.raddr = cpu_to_be16(reg); 658862306a36Sopenharmony_ci c.u.mdio.rval = cpu_to_be16(val); 658962306a36Sopenharmony_ci 659062306a36Sopenharmony_ci return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 659162306a36Sopenharmony_ci} 659262306a36Sopenharmony_ci 659362306a36Sopenharmony_ci/** 659462306a36Sopenharmony_ci * t4_sge_decode_idma_state - decode the idma state 659562306a36Sopenharmony_ci * @adapter: the adapter 659662306a36Sopenharmony_ci * @state: the state idma is stuck in 659762306a36Sopenharmony_ci */ 659862306a36Sopenharmony_civoid t4_sge_decode_idma_state(struct adapter *adapter, int state) 659962306a36Sopenharmony_ci{ 660062306a36Sopenharmony_ci static const char * const t4_decode[] = { 660162306a36Sopenharmony_ci "IDMA_IDLE", 660262306a36Sopenharmony_ci "IDMA_PUSH_MORE_CPL_FIFO", 660362306a36Sopenharmony_ci "IDMA_PUSH_CPL_MSG_HEADER_TO_FIFO", 660462306a36Sopenharmony_ci "Not used", 660562306a36Sopenharmony_ci "IDMA_PHYSADDR_SEND_PCIEHDR", 660662306a36Sopenharmony_ci "IDMA_PHYSADDR_SEND_PAYLOAD_FIRST", 660762306a36Sopenharmony_ci "IDMA_PHYSADDR_SEND_PAYLOAD", 660862306a36Sopenharmony_ci "IDMA_SEND_FIFO_TO_IMSG", 660962306a36Sopenharmony_ci "IDMA_FL_REQ_DATA_FL_PREP", 661062306a36Sopenharmony_ci "IDMA_FL_REQ_DATA_FL", 661162306a36Sopenharmony_ci "IDMA_FL_DROP", 661262306a36Sopenharmony_ci "IDMA_FL_H_REQ_HEADER_FL", 661362306a36Sopenharmony_ci "IDMA_FL_H_SEND_PCIEHDR", 661462306a36Sopenharmony_ci "IDMA_FL_H_PUSH_CPL_FIFO", 661562306a36Sopenharmony_ci "IDMA_FL_H_SEND_CPL", 661662306a36Sopenharmony_ci "IDMA_FL_H_SEND_IP_HDR_FIRST", 661762306a36Sopenharmony_ci "IDMA_FL_H_SEND_IP_HDR", 661862306a36Sopenharmony_ci "IDMA_FL_H_REQ_NEXT_HEADER_FL", 661962306a36Sopenharmony_ci "IDMA_FL_H_SEND_NEXT_PCIEHDR", 662062306a36Sopenharmony_ci "IDMA_FL_H_SEND_IP_HDR_PADDING", 662162306a36Sopenharmony_ci "IDMA_FL_D_SEND_PCIEHDR", 662262306a36Sopenharmony_ci "IDMA_FL_D_SEND_CPL_AND_IP_HDR", 662362306a36Sopenharmony_ci "IDMA_FL_D_REQ_NEXT_DATA_FL", 662462306a36Sopenharmony_ci "IDMA_FL_SEND_PCIEHDR", 662562306a36Sopenharmony_ci "IDMA_FL_PUSH_CPL_FIFO", 662662306a36Sopenharmony_ci "IDMA_FL_SEND_CPL", 662762306a36Sopenharmony_ci "IDMA_FL_SEND_PAYLOAD_FIRST", 662862306a36Sopenharmony_ci "IDMA_FL_SEND_PAYLOAD", 662962306a36Sopenharmony_ci "IDMA_FL_REQ_NEXT_DATA_FL", 663062306a36Sopenharmony_ci "IDMA_FL_SEND_NEXT_PCIEHDR", 663162306a36Sopenharmony_ci "IDMA_FL_SEND_PADDING", 663262306a36Sopenharmony_ci "IDMA_FL_SEND_COMPLETION_TO_IMSG", 663362306a36Sopenharmony_ci "IDMA_FL_SEND_FIFO_TO_IMSG", 663462306a36Sopenharmony_ci "IDMA_FL_REQ_DATAFL_DONE", 663562306a36Sopenharmony_ci "IDMA_FL_REQ_HEADERFL_DONE", 663662306a36Sopenharmony_ci }; 663762306a36Sopenharmony_ci static const char * const t5_decode[] = { 663862306a36Sopenharmony_ci "IDMA_IDLE", 663962306a36Sopenharmony_ci "IDMA_ALMOST_IDLE", 664062306a36Sopenharmony_ci "IDMA_PUSH_MORE_CPL_FIFO", 664162306a36Sopenharmony_ci "IDMA_PUSH_CPL_MSG_HEADER_TO_FIFO", 664262306a36Sopenharmony_ci "IDMA_SGEFLRFLUSH_SEND_PCIEHDR", 664362306a36Sopenharmony_ci "IDMA_PHYSADDR_SEND_PCIEHDR", 664462306a36Sopenharmony_ci "IDMA_PHYSADDR_SEND_PAYLOAD_FIRST", 664562306a36Sopenharmony_ci "IDMA_PHYSADDR_SEND_PAYLOAD", 664662306a36Sopenharmony_ci "IDMA_SEND_FIFO_TO_IMSG", 664762306a36Sopenharmony_ci "IDMA_FL_REQ_DATA_FL", 664862306a36Sopenharmony_ci "IDMA_FL_DROP", 664962306a36Sopenharmony_ci "IDMA_FL_DROP_SEND_INC", 665062306a36Sopenharmony_ci "IDMA_FL_H_REQ_HEADER_FL", 665162306a36Sopenharmony_ci "IDMA_FL_H_SEND_PCIEHDR", 665262306a36Sopenharmony_ci "IDMA_FL_H_PUSH_CPL_FIFO", 665362306a36Sopenharmony_ci "IDMA_FL_H_SEND_CPL", 665462306a36Sopenharmony_ci "IDMA_FL_H_SEND_IP_HDR_FIRST", 665562306a36Sopenharmony_ci "IDMA_FL_H_SEND_IP_HDR", 665662306a36Sopenharmony_ci "IDMA_FL_H_REQ_NEXT_HEADER_FL", 665762306a36Sopenharmony_ci "IDMA_FL_H_SEND_NEXT_PCIEHDR", 665862306a36Sopenharmony_ci "IDMA_FL_H_SEND_IP_HDR_PADDING", 665962306a36Sopenharmony_ci "IDMA_FL_D_SEND_PCIEHDR", 666062306a36Sopenharmony_ci "IDMA_FL_D_SEND_CPL_AND_IP_HDR", 666162306a36Sopenharmony_ci "IDMA_FL_D_REQ_NEXT_DATA_FL", 666262306a36Sopenharmony_ci "IDMA_FL_SEND_PCIEHDR", 666362306a36Sopenharmony_ci "IDMA_FL_PUSH_CPL_FIFO", 666462306a36Sopenharmony_ci "IDMA_FL_SEND_CPL", 666562306a36Sopenharmony_ci "IDMA_FL_SEND_PAYLOAD_FIRST", 666662306a36Sopenharmony_ci "IDMA_FL_SEND_PAYLOAD", 666762306a36Sopenharmony_ci "IDMA_FL_REQ_NEXT_DATA_FL", 666862306a36Sopenharmony_ci "IDMA_FL_SEND_NEXT_PCIEHDR", 666962306a36Sopenharmony_ci "IDMA_FL_SEND_PADDING", 667062306a36Sopenharmony_ci "IDMA_FL_SEND_COMPLETION_TO_IMSG", 667162306a36Sopenharmony_ci }; 667262306a36Sopenharmony_ci static const char * const t6_decode[] = { 667362306a36Sopenharmony_ci "IDMA_IDLE", 667462306a36Sopenharmony_ci "IDMA_PUSH_MORE_CPL_FIFO", 667562306a36Sopenharmony_ci "IDMA_PUSH_CPL_MSG_HEADER_TO_FIFO", 667662306a36Sopenharmony_ci "IDMA_SGEFLRFLUSH_SEND_PCIEHDR", 667762306a36Sopenharmony_ci "IDMA_PHYSADDR_SEND_PCIEHDR", 667862306a36Sopenharmony_ci "IDMA_PHYSADDR_SEND_PAYLOAD_FIRST", 667962306a36Sopenharmony_ci "IDMA_PHYSADDR_SEND_PAYLOAD", 668062306a36Sopenharmony_ci "IDMA_FL_REQ_DATA_FL", 668162306a36Sopenharmony_ci "IDMA_FL_DROP", 668262306a36Sopenharmony_ci "IDMA_FL_DROP_SEND_INC", 668362306a36Sopenharmony_ci "IDMA_FL_H_REQ_HEADER_FL", 668462306a36Sopenharmony_ci "IDMA_FL_H_SEND_PCIEHDR", 668562306a36Sopenharmony_ci "IDMA_FL_H_PUSH_CPL_FIFO", 668662306a36Sopenharmony_ci "IDMA_FL_H_SEND_CPL", 668762306a36Sopenharmony_ci "IDMA_FL_H_SEND_IP_HDR_FIRST", 668862306a36Sopenharmony_ci "IDMA_FL_H_SEND_IP_HDR", 668962306a36Sopenharmony_ci "IDMA_FL_H_REQ_NEXT_HEADER_FL", 669062306a36Sopenharmony_ci "IDMA_FL_H_SEND_NEXT_PCIEHDR", 669162306a36Sopenharmony_ci "IDMA_FL_H_SEND_IP_HDR_PADDING", 669262306a36Sopenharmony_ci "IDMA_FL_D_SEND_PCIEHDR", 669362306a36Sopenharmony_ci "IDMA_FL_D_SEND_CPL_AND_IP_HDR", 669462306a36Sopenharmony_ci "IDMA_FL_D_REQ_NEXT_DATA_FL", 669562306a36Sopenharmony_ci "IDMA_FL_SEND_PCIEHDR", 669662306a36Sopenharmony_ci "IDMA_FL_PUSH_CPL_FIFO", 669762306a36Sopenharmony_ci "IDMA_FL_SEND_CPL", 669862306a36Sopenharmony_ci "IDMA_FL_SEND_PAYLOAD_FIRST", 669962306a36Sopenharmony_ci "IDMA_FL_SEND_PAYLOAD", 670062306a36Sopenharmony_ci "IDMA_FL_REQ_NEXT_DATA_FL", 670162306a36Sopenharmony_ci "IDMA_FL_SEND_NEXT_PCIEHDR", 670262306a36Sopenharmony_ci "IDMA_FL_SEND_PADDING", 670362306a36Sopenharmony_ci "IDMA_FL_SEND_COMPLETION_TO_IMSG", 670462306a36Sopenharmony_ci }; 670562306a36Sopenharmony_ci static const u32 sge_regs[] = { 670662306a36Sopenharmony_ci SGE_DEBUG_DATA_LOW_INDEX_2_A, 670762306a36Sopenharmony_ci SGE_DEBUG_DATA_LOW_INDEX_3_A, 670862306a36Sopenharmony_ci SGE_DEBUG_DATA_HIGH_INDEX_10_A, 670962306a36Sopenharmony_ci }; 671062306a36Sopenharmony_ci const char **sge_idma_decode; 671162306a36Sopenharmony_ci int sge_idma_decode_nstates; 671262306a36Sopenharmony_ci int i; 671362306a36Sopenharmony_ci unsigned int chip_version = CHELSIO_CHIP_VERSION(adapter->params.chip); 671462306a36Sopenharmony_ci 671562306a36Sopenharmony_ci /* Select the right set of decode strings to dump depending on the 671662306a36Sopenharmony_ci * adapter chip type. 671762306a36Sopenharmony_ci */ 671862306a36Sopenharmony_ci switch (chip_version) { 671962306a36Sopenharmony_ci case CHELSIO_T4: 672062306a36Sopenharmony_ci sge_idma_decode = (const char **)t4_decode; 672162306a36Sopenharmony_ci sge_idma_decode_nstates = ARRAY_SIZE(t4_decode); 672262306a36Sopenharmony_ci break; 672362306a36Sopenharmony_ci 672462306a36Sopenharmony_ci case CHELSIO_T5: 672562306a36Sopenharmony_ci sge_idma_decode = (const char **)t5_decode; 672662306a36Sopenharmony_ci sge_idma_decode_nstates = ARRAY_SIZE(t5_decode); 672762306a36Sopenharmony_ci break; 672862306a36Sopenharmony_ci 672962306a36Sopenharmony_ci case CHELSIO_T6: 673062306a36Sopenharmony_ci sge_idma_decode = (const char **)t6_decode; 673162306a36Sopenharmony_ci sge_idma_decode_nstates = ARRAY_SIZE(t6_decode); 673262306a36Sopenharmony_ci break; 673362306a36Sopenharmony_ci 673462306a36Sopenharmony_ci default: 673562306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 673662306a36Sopenharmony_ci "Unsupported chip version %d\n", chip_version); 673762306a36Sopenharmony_ci return; 673862306a36Sopenharmony_ci } 673962306a36Sopenharmony_ci 674062306a36Sopenharmony_ci if (is_t4(adapter->params.chip)) { 674162306a36Sopenharmony_ci sge_idma_decode = (const char **)t4_decode; 674262306a36Sopenharmony_ci sge_idma_decode_nstates = ARRAY_SIZE(t4_decode); 674362306a36Sopenharmony_ci } else { 674462306a36Sopenharmony_ci sge_idma_decode = (const char **)t5_decode; 674562306a36Sopenharmony_ci sge_idma_decode_nstates = ARRAY_SIZE(t5_decode); 674662306a36Sopenharmony_ci } 674762306a36Sopenharmony_ci 674862306a36Sopenharmony_ci if (state < sge_idma_decode_nstates) 674962306a36Sopenharmony_ci CH_WARN(adapter, "idma state %s\n", sge_idma_decode[state]); 675062306a36Sopenharmony_ci else 675162306a36Sopenharmony_ci CH_WARN(adapter, "idma state %d unknown\n", state); 675262306a36Sopenharmony_ci 675362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sge_regs); i++) 675462306a36Sopenharmony_ci CH_WARN(adapter, "SGE register %#x value %#x\n", 675562306a36Sopenharmony_ci sge_regs[i], t4_read_reg(adapter, sge_regs[i])); 675662306a36Sopenharmony_ci} 675762306a36Sopenharmony_ci 675862306a36Sopenharmony_ci/** 675962306a36Sopenharmony_ci * t4_sge_ctxt_flush - flush the SGE context cache 676062306a36Sopenharmony_ci * @adap: the adapter 676162306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 676262306a36Sopenharmony_ci * @ctxt_type: Egress or Ingress 676362306a36Sopenharmony_ci * 676462306a36Sopenharmony_ci * Issues a FW command through the given mailbox to flush the 676562306a36Sopenharmony_ci * SGE context cache. 676662306a36Sopenharmony_ci */ 676762306a36Sopenharmony_ciint t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox, int ctxt_type) 676862306a36Sopenharmony_ci{ 676962306a36Sopenharmony_ci int ret; 677062306a36Sopenharmony_ci u32 ldst_addrspace; 677162306a36Sopenharmony_ci struct fw_ldst_cmd c; 677262306a36Sopenharmony_ci 677362306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 677462306a36Sopenharmony_ci ldst_addrspace = FW_LDST_CMD_ADDRSPACE_V(ctxt_type == CTXT_EGRESS ? 677562306a36Sopenharmony_ci FW_LDST_ADDRSPC_SGE_EGRC : 677662306a36Sopenharmony_ci FW_LDST_ADDRSPC_SGE_INGC); 677762306a36Sopenharmony_ci c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) | 677862306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_READ_F | 677962306a36Sopenharmony_ci ldst_addrspace); 678062306a36Sopenharmony_ci c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c)); 678162306a36Sopenharmony_ci c.u.idctxt.msg_ctxtflush = cpu_to_be32(FW_LDST_CMD_CTXTFLUSH_F); 678262306a36Sopenharmony_ci 678362306a36Sopenharmony_ci ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); 678462306a36Sopenharmony_ci return ret; 678562306a36Sopenharmony_ci} 678662306a36Sopenharmony_ci 678762306a36Sopenharmony_ci/** 678862306a36Sopenharmony_ci * t4_read_sge_dbqtimers - read SGE Doorbell Queue Timer values 678962306a36Sopenharmony_ci * @adap: the adapter 679062306a36Sopenharmony_ci * @ndbqtimers: size of the provided SGE Doorbell Queue Timer table 679162306a36Sopenharmony_ci * @dbqtimers: SGE Doorbell Queue Timer table 679262306a36Sopenharmony_ci * 679362306a36Sopenharmony_ci * Reads the SGE Doorbell Queue Timer values into the provided table. 679462306a36Sopenharmony_ci * Returns 0 on success (Firmware and Hardware support this feature), 679562306a36Sopenharmony_ci * an error on failure. 679662306a36Sopenharmony_ci */ 679762306a36Sopenharmony_ciint t4_read_sge_dbqtimers(struct adapter *adap, unsigned int ndbqtimers, 679862306a36Sopenharmony_ci u16 *dbqtimers) 679962306a36Sopenharmony_ci{ 680062306a36Sopenharmony_ci int ret, dbqtimerix; 680162306a36Sopenharmony_ci 680262306a36Sopenharmony_ci ret = 0; 680362306a36Sopenharmony_ci dbqtimerix = 0; 680462306a36Sopenharmony_ci while (dbqtimerix < ndbqtimers) { 680562306a36Sopenharmony_ci int nparams, param; 680662306a36Sopenharmony_ci u32 params[7], vals[7]; 680762306a36Sopenharmony_ci 680862306a36Sopenharmony_ci nparams = ndbqtimers - dbqtimerix; 680962306a36Sopenharmony_ci if (nparams > ARRAY_SIZE(params)) 681062306a36Sopenharmony_ci nparams = ARRAY_SIZE(params); 681162306a36Sopenharmony_ci 681262306a36Sopenharmony_ci for (param = 0; param < nparams; param++) 681362306a36Sopenharmony_ci params[param] = 681462306a36Sopenharmony_ci (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 681562306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DBQ_TIMER) | 681662306a36Sopenharmony_ci FW_PARAMS_PARAM_Y_V(dbqtimerix + param)); 681762306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 681862306a36Sopenharmony_ci nparams, params, vals); 681962306a36Sopenharmony_ci if (ret) 682062306a36Sopenharmony_ci break; 682162306a36Sopenharmony_ci 682262306a36Sopenharmony_ci for (param = 0; param < nparams; param++) 682362306a36Sopenharmony_ci dbqtimers[dbqtimerix++] = vals[param]; 682462306a36Sopenharmony_ci } 682562306a36Sopenharmony_ci return ret; 682662306a36Sopenharmony_ci} 682762306a36Sopenharmony_ci 682862306a36Sopenharmony_ci/** 682962306a36Sopenharmony_ci * t4_fw_hello - establish communication with FW 683062306a36Sopenharmony_ci * @adap: the adapter 683162306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 683262306a36Sopenharmony_ci * @evt_mbox: mailbox to receive async FW events 683362306a36Sopenharmony_ci * @master: specifies the caller's willingness to be the device master 683462306a36Sopenharmony_ci * @state: returns the current device state (if non-NULL) 683562306a36Sopenharmony_ci * 683662306a36Sopenharmony_ci * Issues a command to establish communication with FW. Returns either 683762306a36Sopenharmony_ci * an error (negative integer) or the mailbox of the Master PF. 683862306a36Sopenharmony_ci */ 683962306a36Sopenharmony_ciint t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox, 684062306a36Sopenharmony_ci enum dev_master master, enum dev_state *state) 684162306a36Sopenharmony_ci{ 684262306a36Sopenharmony_ci int ret; 684362306a36Sopenharmony_ci struct fw_hello_cmd c; 684462306a36Sopenharmony_ci u32 v; 684562306a36Sopenharmony_ci unsigned int master_mbox; 684662306a36Sopenharmony_ci int retries = FW_CMD_HELLO_RETRIES; 684762306a36Sopenharmony_ci 684862306a36Sopenharmony_ciretry: 684962306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 685062306a36Sopenharmony_ci INIT_CMD(c, HELLO, WRITE); 685162306a36Sopenharmony_ci c.err_to_clearinit = cpu_to_be32( 685262306a36Sopenharmony_ci FW_HELLO_CMD_MASTERDIS_V(master == MASTER_CANT) | 685362306a36Sopenharmony_ci FW_HELLO_CMD_MASTERFORCE_V(master == MASTER_MUST) | 685462306a36Sopenharmony_ci FW_HELLO_CMD_MBMASTER_V(master == MASTER_MUST ? 685562306a36Sopenharmony_ci mbox : FW_HELLO_CMD_MBMASTER_M) | 685662306a36Sopenharmony_ci FW_HELLO_CMD_MBASYNCNOT_V(evt_mbox) | 685762306a36Sopenharmony_ci FW_HELLO_CMD_STAGE_V(fw_hello_cmd_stage_os) | 685862306a36Sopenharmony_ci FW_HELLO_CMD_CLEARINIT_F); 685962306a36Sopenharmony_ci 686062306a36Sopenharmony_ci /* 686162306a36Sopenharmony_ci * Issue the HELLO command to the firmware. If it's not successful 686262306a36Sopenharmony_ci * but indicates that we got a "busy" or "timeout" condition, retry 686362306a36Sopenharmony_ci * the HELLO until we exhaust our retry limit. If we do exceed our 686462306a36Sopenharmony_ci * retry limit, check to see if the firmware left us any error 686562306a36Sopenharmony_ci * information and report that if so. 686662306a36Sopenharmony_ci */ 686762306a36Sopenharmony_ci ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); 686862306a36Sopenharmony_ci if (ret < 0) { 686962306a36Sopenharmony_ci if ((ret == -EBUSY || ret == -ETIMEDOUT) && retries-- > 0) 687062306a36Sopenharmony_ci goto retry; 687162306a36Sopenharmony_ci if (t4_read_reg(adap, PCIE_FW_A) & PCIE_FW_ERR_F) 687262306a36Sopenharmony_ci t4_report_fw_error(adap); 687362306a36Sopenharmony_ci return ret; 687462306a36Sopenharmony_ci } 687562306a36Sopenharmony_ci 687662306a36Sopenharmony_ci v = be32_to_cpu(c.err_to_clearinit); 687762306a36Sopenharmony_ci master_mbox = FW_HELLO_CMD_MBMASTER_G(v); 687862306a36Sopenharmony_ci if (state) { 687962306a36Sopenharmony_ci if (v & FW_HELLO_CMD_ERR_F) 688062306a36Sopenharmony_ci *state = DEV_STATE_ERR; 688162306a36Sopenharmony_ci else if (v & FW_HELLO_CMD_INIT_F) 688262306a36Sopenharmony_ci *state = DEV_STATE_INIT; 688362306a36Sopenharmony_ci else 688462306a36Sopenharmony_ci *state = DEV_STATE_UNINIT; 688562306a36Sopenharmony_ci } 688662306a36Sopenharmony_ci 688762306a36Sopenharmony_ci /* 688862306a36Sopenharmony_ci * If we're not the Master PF then we need to wait around for the 688962306a36Sopenharmony_ci * Master PF Driver to finish setting up the adapter. 689062306a36Sopenharmony_ci * 689162306a36Sopenharmony_ci * Note that we also do this wait if we're a non-Master-capable PF and 689262306a36Sopenharmony_ci * there is no current Master PF; a Master PF may show up momentarily 689362306a36Sopenharmony_ci * and we wouldn't want to fail pointlessly. (This can happen when an 689462306a36Sopenharmony_ci * OS loads lots of different drivers rapidly at the same time). In 689562306a36Sopenharmony_ci * this case, the Master PF returned by the firmware will be 689662306a36Sopenharmony_ci * PCIE_FW_MASTER_M so the test below will work ... 689762306a36Sopenharmony_ci */ 689862306a36Sopenharmony_ci if ((v & (FW_HELLO_CMD_ERR_F|FW_HELLO_CMD_INIT_F)) == 0 && 689962306a36Sopenharmony_ci master_mbox != mbox) { 690062306a36Sopenharmony_ci int waiting = FW_CMD_HELLO_TIMEOUT; 690162306a36Sopenharmony_ci 690262306a36Sopenharmony_ci /* 690362306a36Sopenharmony_ci * Wait for the firmware to either indicate an error or 690462306a36Sopenharmony_ci * initialized state. If we see either of these we bail out 690562306a36Sopenharmony_ci * and report the issue to the caller. If we exhaust the 690662306a36Sopenharmony_ci * "hello timeout" and we haven't exhausted our retries, try 690762306a36Sopenharmony_ci * again. Otherwise bail with a timeout error. 690862306a36Sopenharmony_ci */ 690962306a36Sopenharmony_ci for (;;) { 691062306a36Sopenharmony_ci u32 pcie_fw; 691162306a36Sopenharmony_ci 691262306a36Sopenharmony_ci msleep(50); 691362306a36Sopenharmony_ci waiting -= 50; 691462306a36Sopenharmony_ci 691562306a36Sopenharmony_ci /* 691662306a36Sopenharmony_ci * If neither Error nor Initialized are indicated 691762306a36Sopenharmony_ci * by the firmware keep waiting till we exhaust our 691862306a36Sopenharmony_ci * timeout ... and then retry if we haven't exhausted 691962306a36Sopenharmony_ci * our retries ... 692062306a36Sopenharmony_ci */ 692162306a36Sopenharmony_ci pcie_fw = t4_read_reg(adap, PCIE_FW_A); 692262306a36Sopenharmony_ci if (!(pcie_fw & (PCIE_FW_ERR_F|PCIE_FW_INIT_F))) { 692362306a36Sopenharmony_ci if (waiting <= 0) { 692462306a36Sopenharmony_ci if (retries-- > 0) 692562306a36Sopenharmony_ci goto retry; 692662306a36Sopenharmony_ci 692762306a36Sopenharmony_ci return -ETIMEDOUT; 692862306a36Sopenharmony_ci } 692962306a36Sopenharmony_ci continue; 693062306a36Sopenharmony_ci } 693162306a36Sopenharmony_ci 693262306a36Sopenharmony_ci /* 693362306a36Sopenharmony_ci * We either have an Error or Initialized condition 693462306a36Sopenharmony_ci * report errors preferentially. 693562306a36Sopenharmony_ci */ 693662306a36Sopenharmony_ci if (state) { 693762306a36Sopenharmony_ci if (pcie_fw & PCIE_FW_ERR_F) 693862306a36Sopenharmony_ci *state = DEV_STATE_ERR; 693962306a36Sopenharmony_ci else if (pcie_fw & PCIE_FW_INIT_F) 694062306a36Sopenharmony_ci *state = DEV_STATE_INIT; 694162306a36Sopenharmony_ci } 694262306a36Sopenharmony_ci 694362306a36Sopenharmony_ci /* 694462306a36Sopenharmony_ci * If we arrived before a Master PF was selected and 694562306a36Sopenharmony_ci * there's not a valid Master PF, grab its identity 694662306a36Sopenharmony_ci * for our caller. 694762306a36Sopenharmony_ci */ 694862306a36Sopenharmony_ci if (master_mbox == PCIE_FW_MASTER_M && 694962306a36Sopenharmony_ci (pcie_fw & PCIE_FW_MASTER_VLD_F)) 695062306a36Sopenharmony_ci master_mbox = PCIE_FW_MASTER_G(pcie_fw); 695162306a36Sopenharmony_ci break; 695262306a36Sopenharmony_ci } 695362306a36Sopenharmony_ci } 695462306a36Sopenharmony_ci 695562306a36Sopenharmony_ci return master_mbox; 695662306a36Sopenharmony_ci} 695762306a36Sopenharmony_ci 695862306a36Sopenharmony_ci/** 695962306a36Sopenharmony_ci * t4_fw_bye - end communication with FW 696062306a36Sopenharmony_ci * @adap: the adapter 696162306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 696262306a36Sopenharmony_ci * 696362306a36Sopenharmony_ci * Issues a command to terminate communication with FW. 696462306a36Sopenharmony_ci */ 696562306a36Sopenharmony_ciint t4_fw_bye(struct adapter *adap, unsigned int mbox) 696662306a36Sopenharmony_ci{ 696762306a36Sopenharmony_ci struct fw_bye_cmd c; 696862306a36Sopenharmony_ci 696962306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 697062306a36Sopenharmony_ci INIT_CMD(c, BYE, WRITE); 697162306a36Sopenharmony_ci return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 697262306a36Sopenharmony_ci} 697362306a36Sopenharmony_ci 697462306a36Sopenharmony_ci/** 697562306a36Sopenharmony_ci * t4_early_init - ask FW to initialize the device 697662306a36Sopenharmony_ci * @adap: the adapter 697762306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 697862306a36Sopenharmony_ci * 697962306a36Sopenharmony_ci * Issues a command to FW to partially initialize the device. This 698062306a36Sopenharmony_ci * performs initialization that generally doesn't depend on user input. 698162306a36Sopenharmony_ci */ 698262306a36Sopenharmony_ciint t4_early_init(struct adapter *adap, unsigned int mbox) 698362306a36Sopenharmony_ci{ 698462306a36Sopenharmony_ci struct fw_initialize_cmd c; 698562306a36Sopenharmony_ci 698662306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 698762306a36Sopenharmony_ci INIT_CMD(c, INITIALIZE, WRITE); 698862306a36Sopenharmony_ci return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 698962306a36Sopenharmony_ci} 699062306a36Sopenharmony_ci 699162306a36Sopenharmony_ci/** 699262306a36Sopenharmony_ci * t4_fw_reset - issue a reset to FW 699362306a36Sopenharmony_ci * @adap: the adapter 699462306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 699562306a36Sopenharmony_ci * @reset: specifies the type of reset to perform 699662306a36Sopenharmony_ci * 699762306a36Sopenharmony_ci * Issues a reset command of the specified type to FW. 699862306a36Sopenharmony_ci */ 699962306a36Sopenharmony_ciint t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset) 700062306a36Sopenharmony_ci{ 700162306a36Sopenharmony_ci struct fw_reset_cmd c; 700262306a36Sopenharmony_ci 700362306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 700462306a36Sopenharmony_ci INIT_CMD(c, RESET, WRITE); 700562306a36Sopenharmony_ci c.val = cpu_to_be32(reset); 700662306a36Sopenharmony_ci return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 700762306a36Sopenharmony_ci} 700862306a36Sopenharmony_ci 700962306a36Sopenharmony_ci/** 701062306a36Sopenharmony_ci * t4_fw_halt - issue a reset/halt to FW and put uP into RESET 701162306a36Sopenharmony_ci * @adap: the adapter 701262306a36Sopenharmony_ci * @mbox: mailbox to use for the FW RESET command (if desired) 701362306a36Sopenharmony_ci * @force: force uP into RESET even if FW RESET command fails 701462306a36Sopenharmony_ci * 701562306a36Sopenharmony_ci * Issues a RESET command to firmware (if desired) with a HALT indication 701662306a36Sopenharmony_ci * and then puts the microprocessor into RESET state. The RESET command 701762306a36Sopenharmony_ci * will only be issued if a legitimate mailbox is provided (mbox <= 701862306a36Sopenharmony_ci * PCIE_FW_MASTER_M). 701962306a36Sopenharmony_ci * 702062306a36Sopenharmony_ci * This is generally used in order for the host to safely manipulate the 702162306a36Sopenharmony_ci * adapter without fear of conflicting with whatever the firmware might 702262306a36Sopenharmony_ci * be doing. The only way out of this state is to RESTART the firmware 702362306a36Sopenharmony_ci * ... 702462306a36Sopenharmony_ci */ 702562306a36Sopenharmony_cistatic int t4_fw_halt(struct adapter *adap, unsigned int mbox, int force) 702662306a36Sopenharmony_ci{ 702762306a36Sopenharmony_ci int ret = 0; 702862306a36Sopenharmony_ci 702962306a36Sopenharmony_ci /* 703062306a36Sopenharmony_ci * If a legitimate mailbox is provided, issue a RESET command 703162306a36Sopenharmony_ci * with a HALT indication. 703262306a36Sopenharmony_ci */ 703362306a36Sopenharmony_ci if (mbox <= PCIE_FW_MASTER_M) { 703462306a36Sopenharmony_ci struct fw_reset_cmd c; 703562306a36Sopenharmony_ci 703662306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 703762306a36Sopenharmony_ci INIT_CMD(c, RESET, WRITE); 703862306a36Sopenharmony_ci c.val = cpu_to_be32(PIORST_F | PIORSTMODE_F); 703962306a36Sopenharmony_ci c.halt_pkd = cpu_to_be32(FW_RESET_CMD_HALT_F); 704062306a36Sopenharmony_ci ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 704162306a36Sopenharmony_ci } 704262306a36Sopenharmony_ci 704362306a36Sopenharmony_ci /* 704462306a36Sopenharmony_ci * Normally we won't complete the operation if the firmware RESET 704562306a36Sopenharmony_ci * command fails but if our caller insists we'll go ahead and put the 704662306a36Sopenharmony_ci * uP into RESET. This can be useful if the firmware is hung or even 704762306a36Sopenharmony_ci * missing ... We'll have to take the risk of putting the uP into 704862306a36Sopenharmony_ci * RESET without the cooperation of firmware in that case. 704962306a36Sopenharmony_ci * 705062306a36Sopenharmony_ci * We also force the firmware's HALT flag to be on in case we bypassed 705162306a36Sopenharmony_ci * the firmware RESET command above or we're dealing with old firmware 705262306a36Sopenharmony_ci * which doesn't have the HALT capability. This will serve as a flag 705362306a36Sopenharmony_ci * for the incoming firmware to know that it's coming out of a HALT 705462306a36Sopenharmony_ci * rather than a RESET ... if it's new enough to understand that ... 705562306a36Sopenharmony_ci */ 705662306a36Sopenharmony_ci if (ret == 0 || force) { 705762306a36Sopenharmony_ci t4_set_reg_field(adap, CIM_BOOT_CFG_A, UPCRST_F, UPCRST_F); 705862306a36Sopenharmony_ci t4_set_reg_field(adap, PCIE_FW_A, PCIE_FW_HALT_F, 705962306a36Sopenharmony_ci PCIE_FW_HALT_F); 706062306a36Sopenharmony_ci } 706162306a36Sopenharmony_ci 706262306a36Sopenharmony_ci /* 706362306a36Sopenharmony_ci * And we always return the result of the firmware RESET command 706462306a36Sopenharmony_ci * even when we force the uP into RESET ... 706562306a36Sopenharmony_ci */ 706662306a36Sopenharmony_ci return ret; 706762306a36Sopenharmony_ci} 706862306a36Sopenharmony_ci 706962306a36Sopenharmony_ci/** 707062306a36Sopenharmony_ci * t4_fw_restart - restart the firmware by taking the uP out of RESET 707162306a36Sopenharmony_ci * @adap: the adapter 707262306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 707362306a36Sopenharmony_ci * @reset: if we want to do a RESET to restart things 707462306a36Sopenharmony_ci * 707562306a36Sopenharmony_ci * Restart firmware previously halted by t4_fw_halt(). On successful 707662306a36Sopenharmony_ci * return the previous PF Master remains as the new PF Master and there 707762306a36Sopenharmony_ci * is no need to issue a new HELLO command, etc. 707862306a36Sopenharmony_ci * 707962306a36Sopenharmony_ci * We do this in two ways: 708062306a36Sopenharmony_ci * 708162306a36Sopenharmony_ci * 1. If we're dealing with newer firmware we'll simply want to take 708262306a36Sopenharmony_ci * the chip's microprocessor out of RESET. This will cause the 708362306a36Sopenharmony_ci * firmware to start up from its start vector. And then we'll loop 708462306a36Sopenharmony_ci * until the firmware indicates it's started again (PCIE_FW.HALT 708562306a36Sopenharmony_ci * reset to 0) or we timeout. 708662306a36Sopenharmony_ci * 708762306a36Sopenharmony_ci * 2. If we're dealing with older firmware then we'll need to RESET 708862306a36Sopenharmony_ci * the chip since older firmware won't recognize the PCIE_FW.HALT 708962306a36Sopenharmony_ci * flag and automatically RESET itself on startup. 709062306a36Sopenharmony_ci */ 709162306a36Sopenharmony_cistatic int t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset) 709262306a36Sopenharmony_ci{ 709362306a36Sopenharmony_ci if (reset) { 709462306a36Sopenharmony_ci /* 709562306a36Sopenharmony_ci * Since we're directing the RESET instead of the firmware 709662306a36Sopenharmony_ci * doing it automatically, we need to clear the PCIE_FW.HALT 709762306a36Sopenharmony_ci * bit. 709862306a36Sopenharmony_ci */ 709962306a36Sopenharmony_ci t4_set_reg_field(adap, PCIE_FW_A, PCIE_FW_HALT_F, 0); 710062306a36Sopenharmony_ci 710162306a36Sopenharmony_ci /* 710262306a36Sopenharmony_ci * If we've been given a valid mailbox, first try to get the 710362306a36Sopenharmony_ci * firmware to do the RESET. If that works, great and we can 710462306a36Sopenharmony_ci * return success. Otherwise, if we haven't been given a 710562306a36Sopenharmony_ci * valid mailbox or the RESET command failed, fall back to 710662306a36Sopenharmony_ci * hitting the chip with a hammer. 710762306a36Sopenharmony_ci */ 710862306a36Sopenharmony_ci if (mbox <= PCIE_FW_MASTER_M) { 710962306a36Sopenharmony_ci t4_set_reg_field(adap, CIM_BOOT_CFG_A, UPCRST_F, 0); 711062306a36Sopenharmony_ci msleep(100); 711162306a36Sopenharmony_ci if (t4_fw_reset(adap, mbox, 711262306a36Sopenharmony_ci PIORST_F | PIORSTMODE_F) == 0) 711362306a36Sopenharmony_ci return 0; 711462306a36Sopenharmony_ci } 711562306a36Sopenharmony_ci 711662306a36Sopenharmony_ci t4_write_reg(adap, PL_RST_A, PIORST_F | PIORSTMODE_F); 711762306a36Sopenharmony_ci msleep(2000); 711862306a36Sopenharmony_ci } else { 711962306a36Sopenharmony_ci int ms; 712062306a36Sopenharmony_ci 712162306a36Sopenharmony_ci t4_set_reg_field(adap, CIM_BOOT_CFG_A, UPCRST_F, 0); 712262306a36Sopenharmony_ci for (ms = 0; ms < FW_CMD_MAX_TIMEOUT; ) { 712362306a36Sopenharmony_ci if (!(t4_read_reg(adap, PCIE_FW_A) & PCIE_FW_HALT_F)) 712462306a36Sopenharmony_ci return 0; 712562306a36Sopenharmony_ci msleep(100); 712662306a36Sopenharmony_ci ms += 100; 712762306a36Sopenharmony_ci } 712862306a36Sopenharmony_ci return -ETIMEDOUT; 712962306a36Sopenharmony_ci } 713062306a36Sopenharmony_ci return 0; 713162306a36Sopenharmony_ci} 713262306a36Sopenharmony_ci 713362306a36Sopenharmony_ci/** 713462306a36Sopenharmony_ci * t4_fw_upgrade - perform all of the steps necessary to upgrade FW 713562306a36Sopenharmony_ci * @adap: the adapter 713662306a36Sopenharmony_ci * @mbox: mailbox to use for the FW RESET command (if desired) 713762306a36Sopenharmony_ci * @fw_data: the firmware image to write 713862306a36Sopenharmony_ci * @size: image size 713962306a36Sopenharmony_ci * @force: force upgrade even if firmware doesn't cooperate 714062306a36Sopenharmony_ci * 714162306a36Sopenharmony_ci * Perform all of the steps necessary for upgrading an adapter's 714262306a36Sopenharmony_ci * firmware image. Normally this requires the cooperation of the 714362306a36Sopenharmony_ci * existing firmware in order to halt all existing activities 714462306a36Sopenharmony_ci * but if an invalid mailbox token is passed in we skip that step 714562306a36Sopenharmony_ci * (though we'll still put the adapter microprocessor into RESET in 714662306a36Sopenharmony_ci * that case). 714762306a36Sopenharmony_ci * 714862306a36Sopenharmony_ci * On successful return the new firmware will have been loaded and 714962306a36Sopenharmony_ci * the adapter will have been fully RESET losing all previous setup 715062306a36Sopenharmony_ci * state. On unsuccessful return the adapter may be completely hosed ... 715162306a36Sopenharmony_ci * positive errno indicates that the adapter is ~probably~ intact, a 715262306a36Sopenharmony_ci * negative errno indicates that things are looking bad ... 715362306a36Sopenharmony_ci */ 715462306a36Sopenharmony_ciint t4_fw_upgrade(struct adapter *adap, unsigned int mbox, 715562306a36Sopenharmony_ci const u8 *fw_data, unsigned int size, int force) 715662306a36Sopenharmony_ci{ 715762306a36Sopenharmony_ci const struct fw_hdr *fw_hdr = (const struct fw_hdr *)fw_data; 715862306a36Sopenharmony_ci int reset, ret; 715962306a36Sopenharmony_ci 716062306a36Sopenharmony_ci if (!t4_fw_matches_chip(adap, fw_hdr)) 716162306a36Sopenharmony_ci return -EINVAL; 716262306a36Sopenharmony_ci 716362306a36Sopenharmony_ci /* Disable CXGB4_FW_OK flag so that mbox commands with CXGB4_FW_OK flag 716462306a36Sopenharmony_ci * set wont be sent when we are flashing FW. 716562306a36Sopenharmony_ci */ 716662306a36Sopenharmony_ci adap->flags &= ~CXGB4_FW_OK; 716762306a36Sopenharmony_ci 716862306a36Sopenharmony_ci ret = t4_fw_halt(adap, mbox, force); 716962306a36Sopenharmony_ci if (ret < 0 && !force) 717062306a36Sopenharmony_ci goto out; 717162306a36Sopenharmony_ci 717262306a36Sopenharmony_ci ret = t4_load_fw(adap, fw_data, size); 717362306a36Sopenharmony_ci if (ret < 0) 717462306a36Sopenharmony_ci goto out; 717562306a36Sopenharmony_ci 717662306a36Sopenharmony_ci /* 717762306a36Sopenharmony_ci * If there was a Firmware Configuration File stored in FLASH, 717862306a36Sopenharmony_ci * there's a good chance that it won't be compatible with the new 717962306a36Sopenharmony_ci * Firmware. In order to prevent difficult to diagnose adapter 718062306a36Sopenharmony_ci * initialization issues, we clear out the Firmware Configuration File 718162306a36Sopenharmony_ci * portion of the FLASH . The user will need to re-FLASH a new 718262306a36Sopenharmony_ci * Firmware Configuration File which is compatible with the new 718362306a36Sopenharmony_ci * Firmware if that's desired. 718462306a36Sopenharmony_ci */ 718562306a36Sopenharmony_ci (void)t4_load_cfg(adap, NULL, 0); 718662306a36Sopenharmony_ci 718762306a36Sopenharmony_ci /* 718862306a36Sopenharmony_ci * Older versions of the firmware don't understand the new 718962306a36Sopenharmony_ci * PCIE_FW.HALT flag and so won't know to perform a RESET when they 719062306a36Sopenharmony_ci * restart. So for newly loaded older firmware we'll have to do the 719162306a36Sopenharmony_ci * RESET for it so it starts up on a clean slate. We can tell if 719262306a36Sopenharmony_ci * the newly loaded firmware will handle this right by checking 719362306a36Sopenharmony_ci * its header flags to see if it advertises the capability. 719462306a36Sopenharmony_ci */ 719562306a36Sopenharmony_ci reset = ((be32_to_cpu(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0); 719662306a36Sopenharmony_ci ret = t4_fw_restart(adap, mbox, reset); 719762306a36Sopenharmony_ci 719862306a36Sopenharmony_ci /* Grab potentially new Firmware Device Log parameters so we can see 719962306a36Sopenharmony_ci * how healthy the new Firmware is. It's okay to contact the new 720062306a36Sopenharmony_ci * Firmware for these parameters even though, as far as it's 720162306a36Sopenharmony_ci * concerned, we've never said "HELLO" to it ... 720262306a36Sopenharmony_ci */ 720362306a36Sopenharmony_ci (void)t4_init_devlog_params(adap); 720462306a36Sopenharmony_ciout: 720562306a36Sopenharmony_ci adap->flags |= CXGB4_FW_OK; 720662306a36Sopenharmony_ci return ret; 720762306a36Sopenharmony_ci} 720862306a36Sopenharmony_ci 720962306a36Sopenharmony_ci/** 721062306a36Sopenharmony_ci * t4_fl_pkt_align - return the fl packet alignment 721162306a36Sopenharmony_ci * @adap: the adapter 721262306a36Sopenharmony_ci * 721362306a36Sopenharmony_ci * T4 has a single field to specify the packing and padding boundary. 721462306a36Sopenharmony_ci * T5 onwards has separate fields for this and hence the alignment for 721562306a36Sopenharmony_ci * next packet offset is maximum of these two. 721662306a36Sopenharmony_ci * 721762306a36Sopenharmony_ci */ 721862306a36Sopenharmony_ciint t4_fl_pkt_align(struct adapter *adap) 721962306a36Sopenharmony_ci{ 722062306a36Sopenharmony_ci u32 sge_control, sge_control2; 722162306a36Sopenharmony_ci unsigned int ingpadboundary, ingpackboundary, fl_align, ingpad_shift; 722262306a36Sopenharmony_ci 722362306a36Sopenharmony_ci sge_control = t4_read_reg(adap, SGE_CONTROL_A); 722462306a36Sopenharmony_ci 722562306a36Sopenharmony_ci /* T4 uses a single control field to specify both the PCIe Padding and 722662306a36Sopenharmony_ci * Packing Boundary. T5 introduced the ability to specify these 722762306a36Sopenharmony_ci * separately. The actual Ingress Packet Data alignment boundary 722862306a36Sopenharmony_ci * within Packed Buffer Mode is the maximum of these two 722962306a36Sopenharmony_ci * specifications. (Note that it makes no real practical sense to 723062306a36Sopenharmony_ci * have the Padding Boundary be larger than the Packing Boundary but you 723162306a36Sopenharmony_ci * could set the chip up that way and, in fact, legacy T4 code would 723262306a36Sopenharmony_ci * end doing this because it would initialize the Padding Boundary and 723362306a36Sopenharmony_ci * leave the Packing Boundary initialized to 0 (16 bytes).) 723462306a36Sopenharmony_ci * Padding Boundary values in T6 starts from 8B, 723562306a36Sopenharmony_ci * where as it is 32B for T4 and T5. 723662306a36Sopenharmony_ci */ 723762306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5) 723862306a36Sopenharmony_ci ingpad_shift = INGPADBOUNDARY_SHIFT_X; 723962306a36Sopenharmony_ci else 724062306a36Sopenharmony_ci ingpad_shift = T6_INGPADBOUNDARY_SHIFT_X; 724162306a36Sopenharmony_ci 724262306a36Sopenharmony_ci ingpadboundary = 1 << (INGPADBOUNDARY_G(sge_control) + ingpad_shift); 724362306a36Sopenharmony_ci 724462306a36Sopenharmony_ci fl_align = ingpadboundary; 724562306a36Sopenharmony_ci if (!is_t4(adap->params.chip)) { 724662306a36Sopenharmony_ci /* T5 has a weird interpretation of one of the PCIe Packing 724762306a36Sopenharmony_ci * Boundary values. No idea why ... 724862306a36Sopenharmony_ci */ 724962306a36Sopenharmony_ci sge_control2 = t4_read_reg(adap, SGE_CONTROL2_A); 725062306a36Sopenharmony_ci ingpackboundary = INGPACKBOUNDARY_G(sge_control2); 725162306a36Sopenharmony_ci if (ingpackboundary == INGPACKBOUNDARY_16B_X) 725262306a36Sopenharmony_ci ingpackboundary = 16; 725362306a36Sopenharmony_ci else 725462306a36Sopenharmony_ci ingpackboundary = 1 << (ingpackboundary + 725562306a36Sopenharmony_ci INGPACKBOUNDARY_SHIFT_X); 725662306a36Sopenharmony_ci 725762306a36Sopenharmony_ci fl_align = max(ingpadboundary, ingpackboundary); 725862306a36Sopenharmony_ci } 725962306a36Sopenharmony_ci return fl_align; 726062306a36Sopenharmony_ci} 726162306a36Sopenharmony_ci 726262306a36Sopenharmony_ci/** 726362306a36Sopenharmony_ci * t4_fixup_host_params - fix up host-dependent parameters 726462306a36Sopenharmony_ci * @adap: the adapter 726562306a36Sopenharmony_ci * @page_size: the host's Base Page Size 726662306a36Sopenharmony_ci * @cache_line_size: the host's Cache Line Size 726762306a36Sopenharmony_ci * 726862306a36Sopenharmony_ci * Various registers in T4 contain values which are dependent on the 726962306a36Sopenharmony_ci * host's Base Page and Cache Line Sizes. This function will fix all of 727062306a36Sopenharmony_ci * those registers with the appropriate values as passed in ... 727162306a36Sopenharmony_ci */ 727262306a36Sopenharmony_ciint t4_fixup_host_params(struct adapter *adap, unsigned int page_size, 727362306a36Sopenharmony_ci unsigned int cache_line_size) 727462306a36Sopenharmony_ci{ 727562306a36Sopenharmony_ci unsigned int page_shift = fls(page_size) - 1; 727662306a36Sopenharmony_ci unsigned int sge_hps = page_shift - 10; 727762306a36Sopenharmony_ci unsigned int stat_len = cache_line_size > 64 ? 128 : 64; 727862306a36Sopenharmony_ci unsigned int fl_align = cache_line_size < 32 ? 32 : cache_line_size; 727962306a36Sopenharmony_ci unsigned int fl_align_log = fls(fl_align) - 1; 728062306a36Sopenharmony_ci 728162306a36Sopenharmony_ci t4_write_reg(adap, SGE_HOST_PAGE_SIZE_A, 728262306a36Sopenharmony_ci HOSTPAGESIZEPF0_V(sge_hps) | 728362306a36Sopenharmony_ci HOSTPAGESIZEPF1_V(sge_hps) | 728462306a36Sopenharmony_ci HOSTPAGESIZEPF2_V(sge_hps) | 728562306a36Sopenharmony_ci HOSTPAGESIZEPF3_V(sge_hps) | 728662306a36Sopenharmony_ci HOSTPAGESIZEPF4_V(sge_hps) | 728762306a36Sopenharmony_ci HOSTPAGESIZEPF5_V(sge_hps) | 728862306a36Sopenharmony_ci HOSTPAGESIZEPF6_V(sge_hps) | 728962306a36Sopenharmony_ci HOSTPAGESIZEPF7_V(sge_hps)); 729062306a36Sopenharmony_ci 729162306a36Sopenharmony_ci if (is_t4(adap->params.chip)) { 729262306a36Sopenharmony_ci t4_set_reg_field(adap, SGE_CONTROL_A, 729362306a36Sopenharmony_ci INGPADBOUNDARY_V(INGPADBOUNDARY_M) | 729462306a36Sopenharmony_ci EGRSTATUSPAGESIZE_F, 729562306a36Sopenharmony_ci INGPADBOUNDARY_V(fl_align_log - 729662306a36Sopenharmony_ci INGPADBOUNDARY_SHIFT_X) | 729762306a36Sopenharmony_ci EGRSTATUSPAGESIZE_V(stat_len != 64)); 729862306a36Sopenharmony_ci } else { 729962306a36Sopenharmony_ci unsigned int pack_align; 730062306a36Sopenharmony_ci unsigned int ingpad, ingpack; 730162306a36Sopenharmony_ci 730262306a36Sopenharmony_ci /* T5 introduced the separation of the Free List Padding and 730362306a36Sopenharmony_ci * Packing Boundaries. Thus, we can select a smaller Padding 730462306a36Sopenharmony_ci * Boundary to avoid uselessly chewing up PCIe Link and Memory 730562306a36Sopenharmony_ci * Bandwidth, and use a Packing Boundary which is large enough 730662306a36Sopenharmony_ci * to avoid false sharing between CPUs, etc. 730762306a36Sopenharmony_ci * 730862306a36Sopenharmony_ci * For the PCI Link, the smaller the Padding Boundary the 730962306a36Sopenharmony_ci * better. For the Memory Controller, a smaller Padding 731062306a36Sopenharmony_ci * Boundary is better until we cross under the Memory Line 731162306a36Sopenharmony_ci * Size (the minimum unit of transfer to/from Memory). If we 731262306a36Sopenharmony_ci * have a Padding Boundary which is smaller than the Memory 731362306a36Sopenharmony_ci * Line Size, that'll involve a Read-Modify-Write cycle on the 731462306a36Sopenharmony_ci * Memory Controller which is never good. 731562306a36Sopenharmony_ci */ 731662306a36Sopenharmony_ci 731762306a36Sopenharmony_ci /* We want the Packing Boundary to be based on the Cache Line 731862306a36Sopenharmony_ci * Size in order to help avoid False Sharing performance 731962306a36Sopenharmony_ci * issues between CPUs, etc. We also want the Packing 732062306a36Sopenharmony_ci * Boundary to incorporate the PCI-E Maximum Payload Size. We 732162306a36Sopenharmony_ci * get best performance when the Packing Boundary is a 732262306a36Sopenharmony_ci * multiple of the Maximum Payload Size. 732362306a36Sopenharmony_ci */ 732462306a36Sopenharmony_ci pack_align = fl_align; 732562306a36Sopenharmony_ci if (pci_is_pcie(adap->pdev)) { 732662306a36Sopenharmony_ci unsigned int mps, mps_log; 732762306a36Sopenharmony_ci u16 devctl; 732862306a36Sopenharmony_ci 732962306a36Sopenharmony_ci /* The PCIe Device Control Maximum Payload Size field 733062306a36Sopenharmony_ci * [bits 7:5] encodes sizes as powers of 2 starting at 733162306a36Sopenharmony_ci * 128 bytes. 733262306a36Sopenharmony_ci */ 733362306a36Sopenharmony_ci pcie_capability_read_word(adap->pdev, PCI_EXP_DEVCTL, 733462306a36Sopenharmony_ci &devctl); 733562306a36Sopenharmony_ci mps_log = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5) + 7; 733662306a36Sopenharmony_ci mps = 1 << mps_log; 733762306a36Sopenharmony_ci if (mps > pack_align) 733862306a36Sopenharmony_ci pack_align = mps; 733962306a36Sopenharmony_ci } 734062306a36Sopenharmony_ci 734162306a36Sopenharmony_ci /* N.B. T5/T6 have a crazy special interpretation of the "0" 734262306a36Sopenharmony_ci * value for the Packing Boundary. This corresponds to 16 734362306a36Sopenharmony_ci * bytes instead of the expected 32 bytes. So if we want 32 734462306a36Sopenharmony_ci * bytes, the best we can really do is 64 bytes ... 734562306a36Sopenharmony_ci */ 734662306a36Sopenharmony_ci if (pack_align <= 16) { 734762306a36Sopenharmony_ci ingpack = INGPACKBOUNDARY_16B_X; 734862306a36Sopenharmony_ci fl_align = 16; 734962306a36Sopenharmony_ci } else if (pack_align == 32) { 735062306a36Sopenharmony_ci ingpack = INGPACKBOUNDARY_64B_X; 735162306a36Sopenharmony_ci fl_align = 64; 735262306a36Sopenharmony_ci } else { 735362306a36Sopenharmony_ci unsigned int pack_align_log = fls(pack_align) - 1; 735462306a36Sopenharmony_ci 735562306a36Sopenharmony_ci ingpack = pack_align_log - INGPACKBOUNDARY_SHIFT_X; 735662306a36Sopenharmony_ci fl_align = pack_align; 735762306a36Sopenharmony_ci } 735862306a36Sopenharmony_ci 735962306a36Sopenharmony_ci /* Use the smallest Ingress Padding which isn't smaller than 736062306a36Sopenharmony_ci * the Memory Controller Read/Write Size. We'll take that as 736162306a36Sopenharmony_ci * being 8 bytes since we don't know of any system with a 736262306a36Sopenharmony_ci * wider Memory Controller Bus Width. 736362306a36Sopenharmony_ci */ 736462306a36Sopenharmony_ci if (is_t5(adap->params.chip)) 736562306a36Sopenharmony_ci ingpad = INGPADBOUNDARY_32B_X; 736662306a36Sopenharmony_ci else 736762306a36Sopenharmony_ci ingpad = T6_INGPADBOUNDARY_8B_X; 736862306a36Sopenharmony_ci 736962306a36Sopenharmony_ci t4_set_reg_field(adap, SGE_CONTROL_A, 737062306a36Sopenharmony_ci INGPADBOUNDARY_V(INGPADBOUNDARY_M) | 737162306a36Sopenharmony_ci EGRSTATUSPAGESIZE_F, 737262306a36Sopenharmony_ci INGPADBOUNDARY_V(ingpad) | 737362306a36Sopenharmony_ci EGRSTATUSPAGESIZE_V(stat_len != 64)); 737462306a36Sopenharmony_ci t4_set_reg_field(adap, SGE_CONTROL2_A, 737562306a36Sopenharmony_ci INGPACKBOUNDARY_V(INGPACKBOUNDARY_M), 737662306a36Sopenharmony_ci INGPACKBOUNDARY_V(ingpack)); 737762306a36Sopenharmony_ci } 737862306a36Sopenharmony_ci /* 737962306a36Sopenharmony_ci * Adjust various SGE Free List Host Buffer Sizes. 738062306a36Sopenharmony_ci * 738162306a36Sopenharmony_ci * This is something of a crock since we're using fixed indices into 738262306a36Sopenharmony_ci * the array which are also known by the sge.c code and the T4 738362306a36Sopenharmony_ci * Firmware Configuration File. We need to come up with a much better 738462306a36Sopenharmony_ci * approach to managing this array. For now, the first four entries 738562306a36Sopenharmony_ci * are: 738662306a36Sopenharmony_ci * 738762306a36Sopenharmony_ci * 0: Host Page Size 738862306a36Sopenharmony_ci * 1: 64KB 738962306a36Sopenharmony_ci * 2: Buffer size corresponding to 1500 byte MTU (unpacked mode) 739062306a36Sopenharmony_ci * 3: Buffer size corresponding to 9000 byte MTU (unpacked mode) 739162306a36Sopenharmony_ci * 739262306a36Sopenharmony_ci * For the single-MTU buffers in unpacked mode we need to include 739362306a36Sopenharmony_ci * space for the SGE Control Packet Shift, 14 byte Ethernet header, 739462306a36Sopenharmony_ci * possible 4 byte VLAN tag, all rounded up to the next Ingress Packet 739562306a36Sopenharmony_ci * Padding boundary. All of these are accommodated in the Factory 739662306a36Sopenharmony_ci * Default Firmware Configuration File but we need to adjust it for 739762306a36Sopenharmony_ci * this host's cache line size. 739862306a36Sopenharmony_ci */ 739962306a36Sopenharmony_ci t4_write_reg(adap, SGE_FL_BUFFER_SIZE0_A, page_size); 740062306a36Sopenharmony_ci t4_write_reg(adap, SGE_FL_BUFFER_SIZE2_A, 740162306a36Sopenharmony_ci (t4_read_reg(adap, SGE_FL_BUFFER_SIZE2_A) + fl_align-1) 740262306a36Sopenharmony_ci & ~(fl_align-1)); 740362306a36Sopenharmony_ci t4_write_reg(adap, SGE_FL_BUFFER_SIZE3_A, 740462306a36Sopenharmony_ci (t4_read_reg(adap, SGE_FL_BUFFER_SIZE3_A) + fl_align-1) 740562306a36Sopenharmony_ci & ~(fl_align-1)); 740662306a36Sopenharmony_ci 740762306a36Sopenharmony_ci t4_write_reg(adap, ULP_RX_TDDP_PSZ_A, HPZ0_V(page_shift - 12)); 740862306a36Sopenharmony_ci 740962306a36Sopenharmony_ci return 0; 741062306a36Sopenharmony_ci} 741162306a36Sopenharmony_ci 741262306a36Sopenharmony_ci/** 741362306a36Sopenharmony_ci * t4_fw_initialize - ask FW to initialize the device 741462306a36Sopenharmony_ci * @adap: the adapter 741562306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 741662306a36Sopenharmony_ci * 741762306a36Sopenharmony_ci * Issues a command to FW to partially initialize the device. This 741862306a36Sopenharmony_ci * performs initialization that generally doesn't depend on user input. 741962306a36Sopenharmony_ci */ 742062306a36Sopenharmony_ciint t4_fw_initialize(struct adapter *adap, unsigned int mbox) 742162306a36Sopenharmony_ci{ 742262306a36Sopenharmony_ci struct fw_initialize_cmd c; 742362306a36Sopenharmony_ci 742462306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 742562306a36Sopenharmony_ci INIT_CMD(c, INITIALIZE, WRITE); 742662306a36Sopenharmony_ci return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 742762306a36Sopenharmony_ci} 742862306a36Sopenharmony_ci 742962306a36Sopenharmony_ci/** 743062306a36Sopenharmony_ci * t4_query_params_rw - query FW or device parameters 743162306a36Sopenharmony_ci * @adap: the adapter 743262306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 743362306a36Sopenharmony_ci * @pf: the PF 743462306a36Sopenharmony_ci * @vf: the VF 743562306a36Sopenharmony_ci * @nparams: the number of parameters 743662306a36Sopenharmony_ci * @params: the parameter names 743762306a36Sopenharmony_ci * @val: the parameter values 743862306a36Sopenharmony_ci * @rw: Write and read flag 743962306a36Sopenharmony_ci * @sleep_ok: if true, we may sleep awaiting mbox cmd completion 744062306a36Sopenharmony_ci * 744162306a36Sopenharmony_ci * Reads the value of FW or device parameters. Up to 7 parameters can be 744262306a36Sopenharmony_ci * queried at once. 744362306a36Sopenharmony_ci */ 744462306a36Sopenharmony_ciint t4_query_params_rw(struct adapter *adap, unsigned int mbox, unsigned int pf, 744562306a36Sopenharmony_ci unsigned int vf, unsigned int nparams, const u32 *params, 744662306a36Sopenharmony_ci u32 *val, int rw, bool sleep_ok) 744762306a36Sopenharmony_ci{ 744862306a36Sopenharmony_ci int i, ret; 744962306a36Sopenharmony_ci struct fw_params_cmd c; 745062306a36Sopenharmony_ci __be32 *p = &c.param[0].mnem; 745162306a36Sopenharmony_ci 745262306a36Sopenharmony_ci if (nparams > 7) 745362306a36Sopenharmony_ci return -EINVAL; 745462306a36Sopenharmony_ci 745562306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 745662306a36Sopenharmony_ci c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) | 745762306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_READ_F | 745862306a36Sopenharmony_ci FW_PARAMS_CMD_PFN_V(pf) | 745962306a36Sopenharmony_ci FW_PARAMS_CMD_VFN_V(vf)); 746062306a36Sopenharmony_ci c.retval_len16 = cpu_to_be32(FW_LEN16(c)); 746162306a36Sopenharmony_ci 746262306a36Sopenharmony_ci for (i = 0; i < nparams; i++) { 746362306a36Sopenharmony_ci *p++ = cpu_to_be32(*params++); 746462306a36Sopenharmony_ci if (rw) 746562306a36Sopenharmony_ci *p = cpu_to_be32(*(val + i)); 746662306a36Sopenharmony_ci p++; 746762306a36Sopenharmony_ci } 746862306a36Sopenharmony_ci 746962306a36Sopenharmony_ci ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok); 747062306a36Sopenharmony_ci if (ret == 0) 747162306a36Sopenharmony_ci for (i = 0, p = &c.param[0].val; i < nparams; i++, p += 2) 747262306a36Sopenharmony_ci *val++ = be32_to_cpu(*p); 747362306a36Sopenharmony_ci return ret; 747462306a36Sopenharmony_ci} 747562306a36Sopenharmony_ci 747662306a36Sopenharmony_ciint t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, 747762306a36Sopenharmony_ci unsigned int vf, unsigned int nparams, const u32 *params, 747862306a36Sopenharmony_ci u32 *val) 747962306a36Sopenharmony_ci{ 748062306a36Sopenharmony_ci return t4_query_params_rw(adap, mbox, pf, vf, nparams, params, val, 0, 748162306a36Sopenharmony_ci true); 748262306a36Sopenharmony_ci} 748362306a36Sopenharmony_ci 748462306a36Sopenharmony_ciint t4_query_params_ns(struct adapter *adap, unsigned int mbox, unsigned int pf, 748562306a36Sopenharmony_ci unsigned int vf, unsigned int nparams, const u32 *params, 748662306a36Sopenharmony_ci u32 *val) 748762306a36Sopenharmony_ci{ 748862306a36Sopenharmony_ci return t4_query_params_rw(adap, mbox, pf, vf, nparams, params, val, 0, 748962306a36Sopenharmony_ci false); 749062306a36Sopenharmony_ci} 749162306a36Sopenharmony_ci 749262306a36Sopenharmony_ci/** 749362306a36Sopenharmony_ci * t4_set_params_timeout - sets FW or device parameters 749462306a36Sopenharmony_ci * @adap: the adapter 749562306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 749662306a36Sopenharmony_ci * @pf: the PF 749762306a36Sopenharmony_ci * @vf: the VF 749862306a36Sopenharmony_ci * @nparams: the number of parameters 749962306a36Sopenharmony_ci * @params: the parameter names 750062306a36Sopenharmony_ci * @val: the parameter values 750162306a36Sopenharmony_ci * @timeout: the timeout time 750262306a36Sopenharmony_ci * 750362306a36Sopenharmony_ci * Sets the value of FW or device parameters. Up to 7 parameters can be 750462306a36Sopenharmony_ci * specified at once. 750562306a36Sopenharmony_ci */ 750662306a36Sopenharmony_ciint t4_set_params_timeout(struct adapter *adap, unsigned int mbox, 750762306a36Sopenharmony_ci unsigned int pf, unsigned int vf, 750862306a36Sopenharmony_ci unsigned int nparams, const u32 *params, 750962306a36Sopenharmony_ci const u32 *val, int timeout) 751062306a36Sopenharmony_ci{ 751162306a36Sopenharmony_ci struct fw_params_cmd c; 751262306a36Sopenharmony_ci __be32 *p = &c.param[0].mnem; 751362306a36Sopenharmony_ci 751462306a36Sopenharmony_ci if (nparams > 7) 751562306a36Sopenharmony_ci return -EINVAL; 751662306a36Sopenharmony_ci 751762306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 751862306a36Sopenharmony_ci c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) | 751962306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F | 752062306a36Sopenharmony_ci FW_PARAMS_CMD_PFN_V(pf) | 752162306a36Sopenharmony_ci FW_PARAMS_CMD_VFN_V(vf)); 752262306a36Sopenharmony_ci c.retval_len16 = cpu_to_be32(FW_LEN16(c)); 752362306a36Sopenharmony_ci 752462306a36Sopenharmony_ci while (nparams--) { 752562306a36Sopenharmony_ci *p++ = cpu_to_be32(*params++); 752662306a36Sopenharmony_ci *p++ = cpu_to_be32(*val++); 752762306a36Sopenharmony_ci } 752862306a36Sopenharmony_ci 752962306a36Sopenharmony_ci return t4_wr_mbox_timeout(adap, mbox, &c, sizeof(c), NULL, timeout); 753062306a36Sopenharmony_ci} 753162306a36Sopenharmony_ci 753262306a36Sopenharmony_ci/** 753362306a36Sopenharmony_ci * t4_set_params - sets FW or device parameters 753462306a36Sopenharmony_ci * @adap: the adapter 753562306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 753662306a36Sopenharmony_ci * @pf: the PF 753762306a36Sopenharmony_ci * @vf: the VF 753862306a36Sopenharmony_ci * @nparams: the number of parameters 753962306a36Sopenharmony_ci * @params: the parameter names 754062306a36Sopenharmony_ci * @val: the parameter values 754162306a36Sopenharmony_ci * 754262306a36Sopenharmony_ci * Sets the value of FW or device parameters. Up to 7 parameters can be 754362306a36Sopenharmony_ci * specified at once. 754462306a36Sopenharmony_ci */ 754562306a36Sopenharmony_ciint t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf, 754662306a36Sopenharmony_ci unsigned int vf, unsigned int nparams, const u32 *params, 754762306a36Sopenharmony_ci const u32 *val) 754862306a36Sopenharmony_ci{ 754962306a36Sopenharmony_ci return t4_set_params_timeout(adap, mbox, pf, vf, nparams, params, val, 755062306a36Sopenharmony_ci FW_CMD_MAX_TIMEOUT); 755162306a36Sopenharmony_ci} 755262306a36Sopenharmony_ci 755362306a36Sopenharmony_ci/** 755462306a36Sopenharmony_ci * t4_cfg_pfvf - configure PF/VF resource limits 755562306a36Sopenharmony_ci * @adap: the adapter 755662306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 755762306a36Sopenharmony_ci * @pf: the PF being configured 755862306a36Sopenharmony_ci * @vf: the VF being configured 755962306a36Sopenharmony_ci * @txq: the max number of egress queues 756062306a36Sopenharmony_ci * @txq_eth_ctrl: the max number of egress Ethernet or control queues 756162306a36Sopenharmony_ci * @rxqi: the max number of interrupt-capable ingress queues 756262306a36Sopenharmony_ci * @rxq: the max number of interruptless ingress queues 756362306a36Sopenharmony_ci * @tc: the PCI traffic class 756462306a36Sopenharmony_ci * @vi: the max number of virtual interfaces 756562306a36Sopenharmony_ci * @cmask: the channel access rights mask for the PF/VF 756662306a36Sopenharmony_ci * @pmask: the port access rights mask for the PF/VF 756762306a36Sopenharmony_ci * @nexact: the maximum number of exact MPS filters 756862306a36Sopenharmony_ci * @rcaps: read capabilities 756962306a36Sopenharmony_ci * @wxcaps: write/execute capabilities 757062306a36Sopenharmony_ci * 757162306a36Sopenharmony_ci * Configures resource limits and capabilities for a physical or virtual 757262306a36Sopenharmony_ci * function. 757362306a36Sopenharmony_ci */ 757462306a36Sopenharmony_ciint t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf, 757562306a36Sopenharmony_ci unsigned int vf, unsigned int txq, unsigned int txq_eth_ctrl, 757662306a36Sopenharmony_ci unsigned int rxqi, unsigned int rxq, unsigned int tc, 757762306a36Sopenharmony_ci unsigned int vi, unsigned int cmask, unsigned int pmask, 757862306a36Sopenharmony_ci unsigned int nexact, unsigned int rcaps, unsigned int wxcaps) 757962306a36Sopenharmony_ci{ 758062306a36Sopenharmony_ci struct fw_pfvf_cmd c; 758162306a36Sopenharmony_ci 758262306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 758362306a36Sopenharmony_ci c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PFVF_CMD) | FW_CMD_REQUEST_F | 758462306a36Sopenharmony_ci FW_CMD_WRITE_F | FW_PFVF_CMD_PFN_V(pf) | 758562306a36Sopenharmony_ci FW_PFVF_CMD_VFN_V(vf)); 758662306a36Sopenharmony_ci c.retval_len16 = cpu_to_be32(FW_LEN16(c)); 758762306a36Sopenharmony_ci c.niqflint_niq = cpu_to_be32(FW_PFVF_CMD_NIQFLINT_V(rxqi) | 758862306a36Sopenharmony_ci FW_PFVF_CMD_NIQ_V(rxq)); 758962306a36Sopenharmony_ci c.type_to_neq = cpu_to_be32(FW_PFVF_CMD_CMASK_V(cmask) | 759062306a36Sopenharmony_ci FW_PFVF_CMD_PMASK_V(pmask) | 759162306a36Sopenharmony_ci FW_PFVF_CMD_NEQ_V(txq)); 759262306a36Sopenharmony_ci c.tc_to_nexactf = cpu_to_be32(FW_PFVF_CMD_TC_V(tc) | 759362306a36Sopenharmony_ci FW_PFVF_CMD_NVI_V(vi) | 759462306a36Sopenharmony_ci FW_PFVF_CMD_NEXACTF_V(nexact)); 759562306a36Sopenharmony_ci c.r_caps_to_nethctrl = cpu_to_be32(FW_PFVF_CMD_R_CAPS_V(rcaps) | 759662306a36Sopenharmony_ci FW_PFVF_CMD_WX_CAPS_V(wxcaps) | 759762306a36Sopenharmony_ci FW_PFVF_CMD_NETHCTRL_V(txq_eth_ctrl)); 759862306a36Sopenharmony_ci return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 759962306a36Sopenharmony_ci} 760062306a36Sopenharmony_ci 760162306a36Sopenharmony_ci/** 760262306a36Sopenharmony_ci * t4_alloc_vi - allocate a virtual interface 760362306a36Sopenharmony_ci * @adap: the adapter 760462306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 760562306a36Sopenharmony_ci * @port: physical port associated with the VI 760662306a36Sopenharmony_ci * @pf: the PF owning the VI 760762306a36Sopenharmony_ci * @vf: the VF owning the VI 760862306a36Sopenharmony_ci * @nmac: number of MAC addresses needed (1 to 5) 760962306a36Sopenharmony_ci * @mac: the MAC addresses of the VI 761062306a36Sopenharmony_ci * @rss_size: size of RSS table slice associated with this VI 761162306a36Sopenharmony_ci * @vivld: the destination to store the VI Valid value. 761262306a36Sopenharmony_ci * @vin: the destination to store the VIN value. 761362306a36Sopenharmony_ci * 761462306a36Sopenharmony_ci * Allocates a virtual interface for the given physical port. If @mac is 761562306a36Sopenharmony_ci * not %NULL it contains the MAC addresses of the VI as assigned by FW. 761662306a36Sopenharmony_ci * @mac should be large enough to hold @nmac Ethernet addresses, they are 761762306a36Sopenharmony_ci * stored consecutively so the space needed is @nmac * 6 bytes. 761862306a36Sopenharmony_ci * Returns a negative error number or the non-negative VI id. 761962306a36Sopenharmony_ci */ 762062306a36Sopenharmony_ciint t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port, 762162306a36Sopenharmony_ci unsigned int pf, unsigned int vf, unsigned int nmac, u8 *mac, 762262306a36Sopenharmony_ci unsigned int *rss_size, u8 *vivld, u8 *vin) 762362306a36Sopenharmony_ci{ 762462306a36Sopenharmony_ci int ret; 762562306a36Sopenharmony_ci struct fw_vi_cmd c; 762662306a36Sopenharmony_ci 762762306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 762862306a36Sopenharmony_ci c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_VI_CMD) | FW_CMD_REQUEST_F | 762962306a36Sopenharmony_ci FW_CMD_WRITE_F | FW_CMD_EXEC_F | 763062306a36Sopenharmony_ci FW_VI_CMD_PFN_V(pf) | FW_VI_CMD_VFN_V(vf)); 763162306a36Sopenharmony_ci c.alloc_to_len16 = cpu_to_be32(FW_VI_CMD_ALLOC_F | FW_LEN16(c)); 763262306a36Sopenharmony_ci c.portid_pkd = FW_VI_CMD_PORTID_V(port); 763362306a36Sopenharmony_ci c.nmac = nmac - 1; 763462306a36Sopenharmony_ci 763562306a36Sopenharmony_ci ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); 763662306a36Sopenharmony_ci if (ret) 763762306a36Sopenharmony_ci return ret; 763862306a36Sopenharmony_ci 763962306a36Sopenharmony_ci if (mac) { 764062306a36Sopenharmony_ci memcpy(mac, c.mac, sizeof(c.mac)); 764162306a36Sopenharmony_ci switch (nmac) { 764262306a36Sopenharmony_ci case 5: 764362306a36Sopenharmony_ci memcpy(mac + 24, c.nmac3, sizeof(c.nmac3)); 764462306a36Sopenharmony_ci fallthrough; 764562306a36Sopenharmony_ci case 4: 764662306a36Sopenharmony_ci memcpy(mac + 18, c.nmac2, sizeof(c.nmac2)); 764762306a36Sopenharmony_ci fallthrough; 764862306a36Sopenharmony_ci case 3: 764962306a36Sopenharmony_ci memcpy(mac + 12, c.nmac1, sizeof(c.nmac1)); 765062306a36Sopenharmony_ci fallthrough; 765162306a36Sopenharmony_ci case 2: 765262306a36Sopenharmony_ci memcpy(mac + 6, c.nmac0, sizeof(c.nmac0)); 765362306a36Sopenharmony_ci } 765462306a36Sopenharmony_ci } 765562306a36Sopenharmony_ci if (rss_size) 765662306a36Sopenharmony_ci *rss_size = FW_VI_CMD_RSSSIZE_G(be16_to_cpu(c.rsssize_pkd)); 765762306a36Sopenharmony_ci 765862306a36Sopenharmony_ci if (vivld) 765962306a36Sopenharmony_ci *vivld = FW_VI_CMD_VFVLD_G(be32_to_cpu(c.alloc_to_len16)); 766062306a36Sopenharmony_ci 766162306a36Sopenharmony_ci if (vin) 766262306a36Sopenharmony_ci *vin = FW_VI_CMD_VIN_G(be32_to_cpu(c.alloc_to_len16)); 766362306a36Sopenharmony_ci 766462306a36Sopenharmony_ci return FW_VI_CMD_VIID_G(be16_to_cpu(c.type_viid)); 766562306a36Sopenharmony_ci} 766662306a36Sopenharmony_ci 766762306a36Sopenharmony_ci/** 766862306a36Sopenharmony_ci * t4_free_vi - free a virtual interface 766962306a36Sopenharmony_ci * @adap: the adapter 767062306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 767162306a36Sopenharmony_ci * @pf: the PF owning the VI 767262306a36Sopenharmony_ci * @vf: the VF owning the VI 767362306a36Sopenharmony_ci * @viid: virtual interface identifiler 767462306a36Sopenharmony_ci * 767562306a36Sopenharmony_ci * Free a previously allocated virtual interface. 767662306a36Sopenharmony_ci */ 767762306a36Sopenharmony_ciint t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf, 767862306a36Sopenharmony_ci unsigned int vf, unsigned int viid) 767962306a36Sopenharmony_ci{ 768062306a36Sopenharmony_ci struct fw_vi_cmd c; 768162306a36Sopenharmony_ci 768262306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 768362306a36Sopenharmony_ci c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_VI_CMD) | 768462306a36Sopenharmony_ci FW_CMD_REQUEST_F | 768562306a36Sopenharmony_ci FW_CMD_EXEC_F | 768662306a36Sopenharmony_ci FW_VI_CMD_PFN_V(pf) | 768762306a36Sopenharmony_ci FW_VI_CMD_VFN_V(vf)); 768862306a36Sopenharmony_ci c.alloc_to_len16 = cpu_to_be32(FW_VI_CMD_FREE_F | FW_LEN16(c)); 768962306a36Sopenharmony_ci c.type_viid = cpu_to_be16(FW_VI_CMD_VIID_V(viid)); 769062306a36Sopenharmony_ci 769162306a36Sopenharmony_ci return t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); 769262306a36Sopenharmony_ci} 769362306a36Sopenharmony_ci 769462306a36Sopenharmony_ci/** 769562306a36Sopenharmony_ci * t4_set_rxmode - set Rx properties of a virtual interface 769662306a36Sopenharmony_ci * @adap: the adapter 769762306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 769862306a36Sopenharmony_ci * @viid: the VI id 769962306a36Sopenharmony_ci * @viid_mirror: the mirror VI id 770062306a36Sopenharmony_ci * @mtu: the new MTU or -1 770162306a36Sopenharmony_ci * @promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change 770262306a36Sopenharmony_ci * @all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change 770362306a36Sopenharmony_ci * @bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change 770462306a36Sopenharmony_ci * @vlanex: 1 to enable HW VLAN extraction, 0 to disable it, -1 no change 770562306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 770662306a36Sopenharmony_ci * 770762306a36Sopenharmony_ci * Sets Rx properties of a virtual interface. 770862306a36Sopenharmony_ci */ 770962306a36Sopenharmony_ciint t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid, 771062306a36Sopenharmony_ci unsigned int viid_mirror, int mtu, int promisc, int all_multi, 771162306a36Sopenharmony_ci int bcast, int vlanex, bool sleep_ok) 771262306a36Sopenharmony_ci{ 771362306a36Sopenharmony_ci struct fw_vi_rxmode_cmd c, c_mirror; 771462306a36Sopenharmony_ci int ret; 771562306a36Sopenharmony_ci 771662306a36Sopenharmony_ci /* convert to FW values */ 771762306a36Sopenharmony_ci if (mtu < 0) 771862306a36Sopenharmony_ci mtu = FW_RXMODE_MTU_NO_CHG; 771962306a36Sopenharmony_ci if (promisc < 0) 772062306a36Sopenharmony_ci promisc = FW_VI_RXMODE_CMD_PROMISCEN_M; 772162306a36Sopenharmony_ci if (all_multi < 0) 772262306a36Sopenharmony_ci all_multi = FW_VI_RXMODE_CMD_ALLMULTIEN_M; 772362306a36Sopenharmony_ci if (bcast < 0) 772462306a36Sopenharmony_ci bcast = FW_VI_RXMODE_CMD_BROADCASTEN_M; 772562306a36Sopenharmony_ci if (vlanex < 0) 772662306a36Sopenharmony_ci vlanex = FW_VI_RXMODE_CMD_VLANEXEN_M; 772762306a36Sopenharmony_ci 772862306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 772962306a36Sopenharmony_ci c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_RXMODE_CMD) | 773062306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F | 773162306a36Sopenharmony_ci FW_VI_RXMODE_CMD_VIID_V(viid)); 773262306a36Sopenharmony_ci c.retval_len16 = cpu_to_be32(FW_LEN16(c)); 773362306a36Sopenharmony_ci c.mtu_to_vlanexen = 773462306a36Sopenharmony_ci cpu_to_be32(FW_VI_RXMODE_CMD_MTU_V(mtu) | 773562306a36Sopenharmony_ci FW_VI_RXMODE_CMD_PROMISCEN_V(promisc) | 773662306a36Sopenharmony_ci FW_VI_RXMODE_CMD_ALLMULTIEN_V(all_multi) | 773762306a36Sopenharmony_ci FW_VI_RXMODE_CMD_BROADCASTEN_V(bcast) | 773862306a36Sopenharmony_ci FW_VI_RXMODE_CMD_VLANEXEN_V(vlanex)); 773962306a36Sopenharmony_ci 774062306a36Sopenharmony_ci if (viid_mirror) { 774162306a36Sopenharmony_ci memcpy(&c_mirror, &c, sizeof(c_mirror)); 774262306a36Sopenharmony_ci c_mirror.op_to_viid = 774362306a36Sopenharmony_ci cpu_to_be32(FW_CMD_OP_V(FW_VI_RXMODE_CMD) | 774462306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F | 774562306a36Sopenharmony_ci FW_VI_RXMODE_CMD_VIID_V(viid_mirror)); 774662306a36Sopenharmony_ci } 774762306a36Sopenharmony_ci 774862306a36Sopenharmony_ci ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok); 774962306a36Sopenharmony_ci if (ret) 775062306a36Sopenharmony_ci return ret; 775162306a36Sopenharmony_ci 775262306a36Sopenharmony_ci if (viid_mirror) 775362306a36Sopenharmony_ci ret = t4_wr_mbox_meat(adap, mbox, &c_mirror, sizeof(c_mirror), 775462306a36Sopenharmony_ci NULL, sleep_ok); 775562306a36Sopenharmony_ci 775662306a36Sopenharmony_ci return ret; 775762306a36Sopenharmony_ci} 775862306a36Sopenharmony_ci 775962306a36Sopenharmony_ci/** 776062306a36Sopenharmony_ci * t4_free_encap_mac_filt - frees MPS entry at given index 776162306a36Sopenharmony_ci * @adap: the adapter 776262306a36Sopenharmony_ci * @viid: the VI id 776362306a36Sopenharmony_ci * @idx: index of MPS entry to be freed 776462306a36Sopenharmony_ci * @sleep_ok: call is allowed to sleep 776562306a36Sopenharmony_ci * 776662306a36Sopenharmony_ci * Frees the MPS entry at supplied index 776762306a36Sopenharmony_ci * 776862306a36Sopenharmony_ci * Returns a negative error number or zero on success 776962306a36Sopenharmony_ci */ 777062306a36Sopenharmony_ciint t4_free_encap_mac_filt(struct adapter *adap, unsigned int viid, 777162306a36Sopenharmony_ci int idx, bool sleep_ok) 777262306a36Sopenharmony_ci{ 777362306a36Sopenharmony_ci struct fw_vi_mac_exact *p; 777462306a36Sopenharmony_ci struct fw_vi_mac_cmd c; 777562306a36Sopenharmony_ci int ret = 0; 777662306a36Sopenharmony_ci u32 exact; 777762306a36Sopenharmony_ci 777862306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 777962306a36Sopenharmony_ci c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) | 778062306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F | 778162306a36Sopenharmony_ci FW_CMD_EXEC_V(0) | 778262306a36Sopenharmony_ci FW_VI_MAC_CMD_VIID_V(viid)); 778362306a36Sopenharmony_ci exact = FW_VI_MAC_CMD_ENTRY_TYPE_V(FW_VI_MAC_TYPE_EXACTMAC); 778462306a36Sopenharmony_ci c.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_FREEMACS_V(0) | 778562306a36Sopenharmony_ci exact | 778662306a36Sopenharmony_ci FW_CMD_LEN16_V(1)); 778762306a36Sopenharmony_ci p = c.u.exact; 778862306a36Sopenharmony_ci p->valid_to_idx = cpu_to_be16(FW_VI_MAC_CMD_VALID_F | 778962306a36Sopenharmony_ci FW_VI_MAC_CMD_IDX_V(idx)); 779062306a36Sopenharmony_ci eth_zero_addr(p->macaddr); 779162306a36Sopenharmony_ci ret = t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok); 779262306a36Sopenharmony_ci return ret; 779362306a36Sopenharmony_ci} 779462306a36Sopenharmony_ci 779562306a36Sopenharmony_ci/** 779662306a36Sopenharmony_ci * t4_free_raw_mac_filt - Frees a raw mac entry in mps tcam 779762306a36Sopenharmony_ci * @adap: the adapter 779862306a36Sopenharmony_ci * @viid: the VI id 779962306a36Sopenharmony_ci * @addr: the MAC address 780062306a36Sopenharmony_ci * @mask: the mask 780162306a36Sopenharmony_ci * @idx: index of the entry in mps tcam 780262306a36Sopenharmony_ci * @lookup_type: MAC address for inner (1) or outer (0) header 780362306a36Sopenharmony_ci * @port_id: the port index 780462306a36Sopenharmony_ci * @sleep_ok: call is allowed to sleep 780562306a36Sopenharmony_ci * 780662306a36Sopenharmony_ci * Removes the mac entry at the specified index using raw mac interface. 780762306a36Sopenharmony_ci * 780862306a36Sopenharmony_ci * Returns a negative error number on failure. 780962306a36Sopenharmony_ci */ 781062306a36Sopenharmony_ciint t4_free_raw_mac_filt(struct adapter *adap, unsigned int viid, 781162306a36Sopenharmony_ci const u8 *addr, const u8 *mask, unsigned int idx, 781262306a36Sopenharmony_ci u8 lookup_type, u8 port_id, bool sleep_ok) 781362306a36Sopenharmony_ci{ 781462306a36Sopenharmony_ci struct fw_vi_mac_cmd c; 781562306a36Sopenharmony_ci struct fw_vi_mac_raw *p = &c.u.raw; 781662306a36Sopenharmony_ci u32 val; 781762306a36Sopenharmony_ci 781862306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 781962306a36Sopenharmony_ci c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) | 782062306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F | 782162306a36Sopenharmony_ci FW_CMD_EXEC_V(0) | 782262306a36Sopenharmony_ci FW_VI_MAC_CMD_VIID_V(viid)); 782362306a36Sopenharmony_ci val = FW_CMD_LEN16_V(1) | 782462306a36Sopenharmony_ci FW_VI_MAC_CMD_ENTRY_TYPE_V(FW_VI_MAC_TYPE_RAW); 782562306a36Sopenharmony_ci c.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_FREEMACS_V(0) | 782662306a36Sopenharmony_ci FW_CMD_LEN16_V(val)); 782762306a36Sopenharmony_ci 782862306a36Sopenharmony_ci p->raw_idx_pkd = cpu_to_be32(FW_VI_MAC_CMD_RAW_IDX_V(idx) | 782962306a36Sopenharmony_ci FW_VI_MAC_ID_BASED_FREE); 783062306a36Sopenharmony_ci 783162306a36Sopenharmony_ci /* Lookup Type. Outer header: 0, Inner header: 1 */ 783262306a36Sopenharmony_ci p->data0_pkd = cpu_to_be32(DATALKPTYPE_V(lookup_type) | 783362306a36Sopenharmony_ci DATAPORTNUM_V(port_id)); 783462306a36Sopenharmony_ci /* Lookup mask and port mask */ 783562306a36Sopenharmony_ci p->data0m_pkd = cpu_to_be64(DATALKPTYPE_V(DATALKPTYPE_M) | 783662306a36Sopenharmony_ci DATAPORTNUM_V(DATAPORTNUM_M)); 783762306a36Sopenharmony_ci 783862306a36Sopenharmony_ci /* Copy the address and the mask */ 783962306a36Sopenharmony_ci memcpy((u8 *)&p->data1[0] + 2, addr, ETH_ALEN); 784062306a36Sopenharmony_ci memcpy((u8 *)&p->data1m[0] + 2, mask, ETH_ALEN); 784162306a36Sopenharmony_ci 784262306a36Sopenharmony_ci return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok); 784362306a36Sopenharmony_ci} 784462306a36Sopenharmony_ci 784562306a36Sopenharmony_ci/** 784662306a36Sopenharmony_ci * t4_alloc_encap_mac_filt - Adds a mac entry in mps tcam with VNI support 784762306a36Sopenharmony_ci * @adap: the adapter 784862306a36Sopenharmony_ci * @viid: the VI id 784962306a36Sopenharmony_ci * @addr: the MAC address 785062306a36Sopenharmony_ci * @mask: the mask 785162306a36Sopenharmony_ci * @vni: the VNI id for the tunnel protocol 785262306a36Sopenharmony_ci * @vni_mask: mask for the VNI id 785362306a36Sopenharmony_ci * @dip_hit: to enable DIP match for the MPS entry 785462306a36Sopenharmony_ci * @lookup_type: MAC address for inner (1) or outer (0) header 785562306a36Sopenharmony_ci * @sleep_ok: call is allowed to sleep 785662306a36Sopenharmony_ci * 785762306a36Sopenharmony_ci * Allocates an MPS entry with specified MAC address and VNI value. 785862306a36Sopenharmony_ci * 785962306a36Sopenharmony_ci * Returns a negative error number or the allocated index for this mac. 786062306a36Sopenharmony_ci */ 786162306a36Sopenharmony_ciint t4_alloc_encap_mac_filt(struct adapter *adap, unsigned int viid, 786262306a36Sopenharmony_ci const u8 *addr, const u8 *mask, unsigned int vni, 786362306a36Sopenharmony_ci unsigned int vni_mask, u8 dip_hit, u8 lookup_type, 786462306a36Sopenharmony_ci bool sleep_ok) 786562306a36Sopenharmony_ci{ 786662306a36Sopenharmony_ci struct fw_vi_mac_cmd c; 786762306a36Sopenharmony_ci struct fw_vi_mac_vni *p = c.u.exact_vni; 786862306a36Sopenharmony_ci int ret = 0; 786962306a36Sopenharmony_ci u32 val; 787062306a36Sopenharmony_ci 787162306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 787262306a36Sopenharmony_ci c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) | 787362306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F | 787462306a36Sopenharmony_ci FW_VI_MAC_CMD_VIID_V(viid)); 787562306a36Sopenharmony_ci val = FW_CMD_LEN16_V(1) | 787662306a36Sopenharmony_ci FW_VI_MAC_CMD_ENTRY_TYPE_V(FW_VI_MAC_TYPE_EXACTMAC_VNI); 787762306a36Sopenharmony_ci c.freemacs_to_len16 = cpu_to_be32(val); 787862306a36Sopenharmony_ci p->valid_to_idx = cpu_to_be16(FW_VI_MAC_CMD_VALID_F | 787962306a36Sopenharmony_ci FW_VI_MAC_CMD_IDX_V(FW_VI_MAC_ADD_MAC)); 788062306a36Sopenharmony_ci memcpy(p->macaddr, addr, sizeof(p->macaddr)); 788162306a36Sopenharmony_ci memcpy(p->macaddr_mask, mask, sizeof(p->macaddr_mask)); 788262306a36Sopenharmony_ci 788362306a36Sopenharmony_ci p->lookup_type_to_vni = 788462306a36Sopenharmony_ci cpu_to_be32(FW_VI_MAC_CMD_VNI_V(vni) | 788562306a36Sopenharmony_ci FW_VI_MAC_CMD_DIP_HIT_V(dip_hit) | 788662306a36Sopenharmony_ci FW_VI_MAC_CMD_LOOKUP_TYPE_V(lookup_type)); 788762306a36Sopenharmony_ci p->vni_mask_pkd = cpu_to_be32(FW_VI_MAC_CMD_VNI_MASK_V(vni_mask)); 788862306a36Sopenharmony_ci ret = t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok); 788962306a36Sopenharmony_ci if (ret == 0) 789062306a36Sopenharmony_ci ret = FW_VI_MAC_CMD_IDX_G(be16_to_cpu(p->valid_to_idx)); 789162306a36Sopenharmony_ci return ret; 789262306a36Sopenharmony_ci} 789362306a36Sopenharmony_ci 789462306a36Sopenharmony_ci/** 789562306a36Sopenharmony_ci * t4_alloc_raw_mac_filt - Adds a mac entry in mps tcam 789662306a36Sopenharmony_ci * @adap: the adapter 789762306a36Sopenharmony_ci * @viid: the VI id 789862306a36Sopenharmony_ci * @addr: the MAC address 789962306a36Sopenharmony_ci * @mask: the mask 790062306a36Sopenharmony_ci * @idx: index at which to add this entry 790162306a36Sopenharmony_ci * @lookup_type: MAC address for inner (1) or outer (0) header 790262306a36Sopenharmony_ci * @port_id: the port index 790362306a36Sopenharmony_ci * @sleep_ok: call is allowed to sleep 790462306a36Sopenharmony_ci * 790562306a36Sopenharmony_ci * Adds the mac entry at the specified index using raw mac interface. 790662306a36Sopenharmony_ci * 790762306a36Sopenharmony_ci * Returns a negative error number or the allocated index for this mac. 790862306a36Sopenharmony_ci */ 790962306a36Sopenharmony_ciint t4_alloc_raw_mac_filt(struct adapter *adap, unsigned int viid, 791062306a36Sopenharmony_ci const u8 *addr, const u8 *mask, unsigned int idx, 791162306a36Sopenharmony_ci u8 lookup_type, u8 port_id, bool sleep_ok) 791262306a36Sopenharmony_ci{ 791362306a36Sopenharmony_ci int ret = 0; 791462306a36Sopenharmony_ci struct fw_vi_mac_cmd c; 791562306a36Sopenharmony_ci struct fw_vi_mac_raw *p = &c.u.raw; 791662306a36Sopenharmony_ci u32 val; 791762306a36Sopenharmony_ci 791862306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 791962306a36Sopenharmony_ci c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) | 792062306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F | 792162306a36Sopenharmony_ci FW_VI_MAC_CMD_VIID_V(viid)); 792262306a36Sopenharmony_ci val = FW_CMD_LEN16_V(1) | 792362306a36Sopenharmony_ci FW_VI_MAC_CMD_ENTRY_TYPE_V(FW_VI_MAC_TYPE_RAW); 792462306a36Sopenharmony_ci c.freemacs_to_len16 = cpu_to_be32(val); 792562306a36Sopenharmony_ci 792662306a36Sopenharmony_ci /* Specify that this is an inner mac address */ 792762306a36Sopenharmony_ci p->raw_idx_pkd = cpu_to_be32(FW_VI_MAC_CMD_RAW_IDX_V(idx)); 792862306a36Sopenharmony_ci 792962306a36Sopenharmony_ci /* Lookup Type. Outer header: 0, Inner header: 1 */ 793062306a36Sopenharmony_ci p->data0_pkd = cpu_to_be32(DATALKPTYPE_V(lookup_type) | 793162306a36Sopenharmony_ci DATAPORTNUM_V(port_id)); 793262306a36Sopenharmony_ci /* Lookup mask and port mask */ 793362306a36Sopenharmony_ci p->data0m_pkd = cpu_to_be64(DATALKPTYPE_V(DATALKPTYPE_M) | 793462306a36Sopenharmony_ci DATAPORTNUM_V(DATAPORTNUM_M)); 793562306a36Sopenharmony_ci 793662306a36Sopenharmony_ci /* Copy the address and the mask */ 793762306a36Sopenharmony_ci memcpy((u8 *)&p->data1[0] + 2, addr, ETH_ALEN); 793862306a36Sopenharmony_ci memcpy((u8 *)&p->data1m[0] + 2, mask, ETH_ALEN); 793962306a36Sopenharmony_ci 794062306a36Sopenharmony_ci ret = t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok); 794162306a36Sopenharmony_ci if (ret == 0) { 794262306a36Sopenharmony_ci ret = FW_VI_MAC_CMD_RAW_IDX_G(be32_to_cpu(p->raw_idx_pkd)); 794362306a36Sopenharmony_ci if (ret != idx) 794462306a36Sopenharmony_ci ret = -ENOMEM; 794562306a36Sopenharmony_ci } 794662306a36Sopenharmony_ci 794762306a36Sopenharmony_ci return ret; 794862306a36Sopenharmony_ci} 794962306a36Sopenharmony_ci 795062306a36Sopenharmony_ci/** 795162306a36Sopenharmony_ci * t4_alloc_mac_filt - allocates exact-match filters for MAC addresses 795262306a36Sopenharmony_ci * @adap: the adapter 795362306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 795462306a36Sopenharmony_ci * @viid: the VI id 795562306a36Sopenharmony_ci * @free: if true any existing filters for this VI id are first removed 795662306a36Sopenharmony_ci * @naddr: the number of MAC addresses to allocate filters for (up to 7) 795762306a36Sopenharmony_ci * @addr: the MAC address(es) 795862306a36Sopenharmony_ci * @idx: where to store the index of each allocated filter 795962306a36Sopenharmony_ci * @hash: pointer to hash address filter bitmap 796062306a36Sopenharmony_ci * @sleep_ok: call is allowed to sleep 796162306a36Sopenharmony_ci * 796262306a36Sopenharmony_ci * Allocates an exact-match filter for each of the supplied addresses and 796362306a36Sopenharmony_ci * sets it to the corresponding address. If @idx is not %NULL it should 796462306a36Sopenharmony_ci * have at least @naddr entries, each of which will be set to the index of 796562306a36Sopenharmony_ci * the filter allocated for the corresponding MAC address. If a filter 796662306a36Sopenharmony_ci * could not be allocated for an address its index is set to 0xffff. 796762306a36Sopenharmony_ci * If @hash is not %NULL addresses that fail to allocate an exact filter 796862306a36Sopenharmony_ci * are hashed and update the hash filter bitmap pointed at by @hash. 796962306a36Sopenharmony_ci * 797062306a36Sopenharmony_ci * Returns a negative error number or the number of filters allocated. 797162306a36Sopenharmony_ci */ 797262306a36Sopenharmony_ciint t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox, 797362306a36Sopenharmony_ci unsigned int viid, bool free, unsigned int naddr, 797462306a36Sopenharmony_ci const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok) 797562306a36Sopenharmony_ci{ 797662306a36Sopenharmony_ci int offset, ret = 0; 797762306a36Sopenharmony_ci struct fw_vi_mac_cmd c; 797862306a36Sopenharmony_ci unsigned int nfilters = 0; 797962306a36Sopenharmony_ci unsigned int max_naddr = adap->params.arch.mps_tcam_size; 798062306a36Sopenharmony_ci unsigned int rem = naddr; 798162306a36Sopenharmony_ci 798262306a36Sopenharmony_ci if (naddr > max_naddr) 798362306a36Sopenharmony_ci return -EINVAL; 798462306a36Sopenharmony_ci 798562306a36Sopenharmony_ci for (offset = 0; offset < naddr ; /**/) { 798662306a36Sopenharmony_ci unsigned int fw_naddr = (rem < ARRAY_SIZE(c.u.exact) ? 798762306a36Sopenharmony_ci rem : ARRAY_SIZE(c.u.exact)); 798862306a36Sopenharmony_ci size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, 798962306a36Sopenharmony_ci u.exact[fw_naddr]), 16); 799062306a36Sopenharmony_ci struct fw_vi_mac_exact *p; 799162306a36Sopenharmony_ci int i; 799262306a36Sopenharmony_ci 799362306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 799462306a36Sopenharmony_ci c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) | 799562306a36Sopenharmony_ci FW_CMD_REQUEST_F | 799662306a36Sopenharmony_ci FW_CMD_WRITE_F | 799762306a36Sopenharmony_ci FW_CMD_EXEC_V(free) | 799862306a36Sopenharmony_ci FW_VI_MAC_CMD_VIID_V(viid)); 799962306a36Sopenharmony_ci c.freemacs_to_len16 = 800062306a36Sopenharmony_ci cpu_to_be32(FW_VI_MAC_CMD_FREEMACS_V(free) | 800162306a36Sopenharmony_ci FW_CMD_LEN16_V(len16)); 800262306a36Sopenharmony_ci 800362306a36Sopenharmony_ci for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) { 800462306a36Sopenharmony_ci p->valid_to_idx = 800562306a36Sopenharmony_ci cpu_to_be16(FW_VI_MAC_CMD_VALID_F | 800662306a36Sopenharmony_ci FW_VI_MAC_CMD_IDX_V( 800762306a36Sopenharmony_ci FW_VI_MAC_ADD_MAC)); 800862306a36Sopenharmony_ci memcpy(p->macaddr, addr[offset + i], 800962306a36Sopenharmony_ci sizeof(p->macaddr)); 801062306a36Sopenharmony_ci } 801162306a36Sopenharmony_ci 801262306a36Sopenharmony_ci /* It's okay if we run out of space in our MAC address arena. 801362306a36Sopenharmony_ci * Some of the addresses we submit may get stored so we need 801462306a36Sopenharmony_ci * to run through the reply to see what the results were ... 801562306a36Sopenharmony_ci */ 801662306a36Sopenharmony_ci ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok); 801762306a36Sopenharmony_ci if (ret && ret != -FW_ENOMEM) 801862306a36Sopenharmony_ci break; 801962306a36Sopenharmony_ci 802062306a36Sopenharmony_ci for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) { 802162306a36Sopenharmony_ci u16 index = FW_VI_MAC_CMD_IDX_G( 802262306a36Sopenharmony_ci be16_to_cpu(p->valid_to_idx)); 802362306a36Sopenharmony_ci 802462306a36Sopenharmony_ci if (idx) 802562306a36Sopenharmony_ci idx[offset + i] = (index >= max_naddr ? 802662306a36Sopenharmony_ci 0xffff : index); 802762306a36Sopenharmony_ci if (index < max_naddr) 802862306a36Sopenharmony_ci nfilters++; 802962306a36Sopenharmony_ci else if (hash) 803062306a36Sopenharmony_ci *hash |= (1ULL << 803162306a36Sopenharmony_ci hash_mac_addr(addr[offset + i])); 803262306a36Sopenharmony_ci } 803362306a36Sopenharmony_ci 803462306a36Sopenharmony_ci free = false; 803562306a36Sopenharmony_ci offset += fw_naddr; 803662306a36Sopenharmony_ci rem -= fw_naddr; 803762306a36Sopenharmony_ci } 803862306a36Sopenharmony_ci 803962306a36Sopenharmony_ci if (ret == 0 || ret == -FW_ENOMEM) 804062306a36Sopenharmony_ci ret = nfilters; 804162306a36Sopenharmony_ci return ret; 804262306a36Sopenharmony_ci} 804362306a36Sopenharmony_ci 804462306a36Sopenharmony_ci/** 804562306a36Sopenharmony_ci * t4_free_mac_filt - frees exact-match filters of given MAC addresses 804662306a36Sopenharmony_ci * @adap: the adapter 804762306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 804862306a36Sopenharmony_ci * @viid: the VI id 804962306a36Sopenharmony_ci * @naddr: the number of MAC addresses to allocate filters for (up to 7) 805062306a36Sopenharmony_ci * @addr: the MAC address(es) 805162306a36Sopenharmony_ci * @sleep_ok: call is allowed to sleep 805262306a36Sopenharmony_ci * 805362306a36Sopenharmony_ci * Frees the exact-match filter for each of the supplied addresses 805462306a36Sopenharmony_ci * 805562306a36Sopenharmony_ci * Returns a negative error number or the number of filters freed. 805662306a36Sopenharmony_ci */ 805762306a36Sopenharmony_ciint t4_free_mac_filt(struct adapter *adap, unsigned int mbox, 805862306a36Sopenharmony_ci unsigned int viid, unsigned int naddr, 805962306a36Sopenharmony_ci const u8 **addr, bool sleep_ok) 806062306a36Sopenharmony_ci{ 806162306a36Sopenharmony_ci int offset, ret = 0; 806262306a36Sopenharmony_ci struct fw_vi_mac_cmd c; 806362306a36Sopenharmony_ci unsigned int nfilters = 0; 806462306a36Sopenharmony_ci unsigned int max_naddr = is_t4(adap->params.chip) ? 806562306a36Sopenharmony_ci NUM_MPS_CLS_SRAM_L_INSTANCES : 806662306a36Sopenharmony_ci NUM_MPS_T5_CLS_SRAM_L_INSTANCES; 806762306a36Sopenharmony_ci unsigned int rem = naddr; 806862306a36Sopenharmony_ci 806962306a36Sopenharmony_ci if (naddr > max_naddr) 807062306a36Sopenharmony_ci return -EINVAL; 807162306a36Sopenharmony_ci 807262306a36Sopenharmony_ci for (offset = 0; offset < (int)naddr ; /**/) { 807362306a36Sopenharmony_ci unsigned int fw_naddr = (rem < ARRAY_SIZE(c.u.exact) 807462306a36Sopenharmony_ci ? rem 807562306a36Sopenharmony_ci : ARRAY_SIZE(c.u.exact)); 807662306a36Sopenharmony_ci size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, 807762306a36Sopenharmony_ci u.exact[fw_naddr]), 16); 807862306a36Sopenharmony_ci struct fw_vi_mac_exact *p; 807962306a36Sopenharmony_ci int i; 808062306a36Sopenharmony_ci 808162306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 808262306a36Sopenharmony_ci c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) | 808362306a36Sopenharmony_ci FW_CMD_REQUEST_F | 808462306a36Sopenharmony_ci FW_CMD_WRITE_F | 808562306a36Sopenharmony_ci FW_CMD_EXEC_V(0) | 808662306a36Sopenharmony_ci FW_VI_MAC_CMD_VIID_V(viid)); 808762306a36Sopenharmony_ci c.freemacs_to_len16 = 808862306a36Sopenharmony_ci cpu_to_be32(FW_VI_MAC_CMD_FREEMACS_V(0) | 808962306a36Sopenharmony_ci FW_CMD_LEN16_V(len16)); 809062306a36Sopenharmony_ci 809162306a36Sopenharmony_ci for (i = 0, p = c.u.exact; i < (int)fw_naddr; i++, p++) { 809262306a36Sopenharmony_ci p->valid_to_idx = cpu_to_be16( 809362306a36Sopenharmony_ci FW_VI_MAC_CMD_VALID_F | 809462306a36Sopenharmony_ci FW_VI_MAC_CMD_IDX_V(FW_VI_MAC_MAC_BASED_FREE)); 809562306a36Sopenharmony_ci memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr)); 809662306a36Sopenharmony_ci } 809762306a36Sopenharmony_ci 809862306a36Sopenharmony_ci ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok); 809962306a36Sopenharmony_ci if (ret) 810062306a36Sopenharmony_ci break; 810162306a36Sopenharmony_ci 810262306a36Sopenharmony_ci for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) { 810362306a36Sopenharmony_ci u16 index = FW_VI_MAC_CMD_IDX_G( 810462306a36Sopenharmony_ci be16_to_cpu(p->valid_to_idx)); 810562306a36Sopenharmony_ci 810662306a36Sopenharmony_ci if (index < max_naddr) 810762306a36Sopenharmony_ci nfilters++; 810862306a36Sopenharmony_ci } 810962306a36Sopenharmony_ci 811062306a36Sopenharmony_ci offset += fw_naddr; 811162306a36Sopenharmony_ci rem -= fw_naddr; 811262306a36Sopenharmony_ci } 811362306a36Sopenharmony_ci 811462306a36Sopenharmony_ci if (ret == 0) 811562306a36Sopenharmony_ci ret = nfilters; 811662306a36Sopenharmony_ci return ret; 811762306a36Sopenharmony_ci} 811862306a36Sopenharmony_ci 811962306a36Sopenharmony_ci/** 812062306a36Sopenharmony_ci * t4_change_mac - modifies the exact-match filter for a MAC address 812162306a36Sopenharmony_ci * @adap: the adapter 812262306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 812362306a36Sopenharmony_ci * @viid: the VI id 812462306a36Sopenharmony_ci * @idx: index of existing filter for old value of MAC address, or -1 812562306a36Sopenharmony_ci * @addr: the new MAC address value 812662306a36Sopenharmony_ci * @persist: whether a new MAC allocation should be persistent 812762306a36Sopenharmony_ci * @smt_idx: the destination to store the new SMT index. 812862306a36Sopenharmony_ci * 812962306a36Sopenharmony_ci * Modifies an exact-match filter and sets it to the new MAC address. 813062306a36Sopenharmony_ci * Note that in general it is not possible to modify the value of a given 813162306a36Sopenharmony_ci * filter so the generic way to modify an address filter is to free the one 813262306a36Sopenharmony_ci * being used by the old address value and allocate a new filter for the 813362306a36Sopenharmony_ci * new address value. @idx can be -1 if the address is a new addition. 813462306a36Sopenharmony_ci * 813562306a36Sopenharmony_ci * Returns a negative error number or the index of the filter with the new 813662306a36Sopenharmony_ci * MAC value. 813762306a36Sopenharmony_ci */ 813862306a36Sopenharmony_ciint t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid, 813962306a36Sopenharmony_ci int idx, const u8 *addr, bool persist, u8 *smt_idx) 814062306a36Sopenharmony_ci{ 814162306a36Sopenharmony_ci int ret, mode; 814262306a36Sopenharmony_ci struct fw_vi_mac_cmd c; 814362306a36Sopenharmony_ci struct fw_vi_mac_exact *p = c.u.exact; 814462306a36Sopenharmony_ci unsigned int max_mac_addr = adap->params.arch.mps_tcam_size; 814562306a36Sopenharmony_ci 814662306a36Sopenharmony_ci if (idx < 0) /* new allocation */ 814762306a36Sopenharmony_ci idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC; 814862306a36Sopenharmony_ci mode = smt_idx ? FW_VI_MAC_SMT_AND_MPSTCAM : FW_VI_MAC_MPS_TCAM_ENTRY; 814962306a36Sopenharmony_ci 815062306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 815162306a36Sopenharmony_ci c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) | 815262306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F | 815362306a36Sopenharmony_ci FW_VI_MAC_CMD_VIID_V(viid)); 815462306a36Sopenharmony_ci c.freemacs_to_len16 = cpu_to_be32(FW_CMD_LEN16_V(1)); 815562306a36Sopenharmony_ci p->valid_to_idx = cpu_to_be16(FW_VI_MAC_CMD_VALID_F | 815662306a36Sopenharmony_ci FW_VI_MAC_CMD_SMAC_RESULT_V(mode) | 815762306a36Sopenharmony_ci FW_VI_MAC_CMD_IDX_V(idx)); 815862306a36Sopenharmony_ci memcpy(p->macaddr, addr, sizeof(p->macaddr)); 815962306a36Sopenharmony_ci 816062306a36Sopenharmony_ci ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); 816162306a36Sopenharmony_ci if (ret == 0) { 816262306a36Sopenharmony_ci ret = FW_VI_MAC_CMD_IDX_G(be16_to_cpu(p->valid_to_idx)); 816362306a36Sopenharmony_ci if (ret >= max_mac_addr) 816462306a36Sopenharmony_ci ret = -ENOMEM; 816562306a36Sopenharmony_ci if (smt_idx) { 816662306a36Sopenharmony_ci if (adap->params.viid_smt_extn_support) { 816762306a36Sopenharmony_ci *smt_idx = FW_VI_MAC_CMD_SMTID_G 816862306a36Sopenharmony_ci (be32_to_cpu(c.op_to_viid)); 816962306a36Sopenharmony_ci } else { 817062306a36Sopenharmony_ci /* In T4/T5, SMT contains 256 SMAC entries 817162306a36Sopenharmony_ci * organized in 128 rows of 2 entries each. 817262306a36Sopenharmony_ci * In T6, SMT contains 256 SMAC entries in 817362306a36Sopenharmony_ci * 256 rows. 817462306a36Sopenharmony_ci */ 817562306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adap->params.chip) <= 817662306a36Sopenharmony_ci CHELSIO_T5) 817762306a36Sopenharmony_ci *smt_idx = (viid & FW_VIID_VIN_M) << 1; 817862306a36Sopenharmony_ci else 817962306a36Sopenharmony_ci *smt_idx = (viid & FW_VIID_VIN_M); 818062306a36Sopenharmony_ci } 818162306a36Sopenharmony_ci } 818262306a36Sopenharmony_ci } 818362306a36Sopenharmony_ci return ret; 818462306a36Sopenharmony_ci} 818562306a36Sopenharmony_ci 818662306a36Sopenharmony_ci/** 818762306a36Sopenharmony_ci * t4_set_addr_hash - program the MAC inexact-match hash filter 818862306a36Sopenharmony_ci * @adap: the adapter 818962306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 819062306a36Sopenharmony_ci * @viid: the VI id 819162306a36Sopenharmony_ci * @ucast: whether the hash filter should also match unicast addresses 819262306a36Sopenharmony_ci * @vec: the value to be written to the hash filter 819362306a36Sopenharmony_ci * @sleep_ok: call is allowed to sleep 819462306a36Sopenharmony_ci * 819562306a36Sopenharmony_ci * Sets the 64-bit inexact-match hash filter for a virtual interface. 819662306a36Sopenharmony_ci */ 819762306a36Sopenharmony_ciint t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid, 819862306a36Sopenharmony_ci bool ucast, u64 vec, bool sleep_ok) 819962306a36Sopenharmony_ci{ 820062306a36Sopenharmony_ci struct fw_vi_mac_cmd c; 820162306a36Sopenharmony_ci 820262306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 820362306a36Sopenharmony_ci c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) | 820462306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F | 820562306a36Sopenharmony_ci FW_VI_ENABLE_CMD_VIID_V(viid)); 820662306a36Sopenharmony_ci c.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_HASHVECEN_F | 820762306a36Sopenharmony_ci FW_VI_MAC_CMD_HASHUNIEN_V(ucast) | 820862306a36Sopenharmony_ci FW_CMD_LEN16_V(1)); 820962306a36Sopenharmony_ci c.u.hash.hashvec = cpu_to_be64(vec); 821062306a36Sopenharmony_ci return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok); 821162306a36Sopenharmony_ci} 821262306a36Sopenharmony_ci 821362306a36Sopenharmony_ci/** 821462306a36Sopenharmony_ci * t4_enable_vi_params - enable/disable a virtual interface 821562306a36Sopenharmony_ci * @adap: the adapter 821662306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 821762306a36Sopenharmony_ci * @viid: the VI id 821862306a36Sopenharmony_ci * @rx_en: 1=enable Rx, 0=disable Rx 821962306a36Sopenharmony_ci * @tx_en: 1=enable Tx, 0=disable Tx 822062306a36Sopenharmony_ci * @dcb_en: 1=enable delivery of Data Center Bridging messages. 822162306a36Sopenharmony_ci * 822262306a36Sopenharmony_ci * Enables/disables a virtual interface. Note that setting DCB Enable 822362306a36Sopenharmony_ci * only makes sense when enabling a Virtual Interface ... 822462306a36Sopenharmony_ci */ 822562306a36Sopenharmony_ciint t4_enable_vi_params(struct adapter *adap, unsigned int mbox, 822662306a36Sopenharmony_ci unsigned int viid, bool rx_en, bool tx_en, bool dcb_en) 822762306a36Sopenharmony_ci{ 822862306a36Sopenharmony_ci struct fw_vi_enable_cmd c; 822962306a36Sopenharmony_ci 823062306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 823162306a36Sopenharmony_ci c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_ENABLE_CMD) | 823262306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_EXEC_F | 823362306a36Sopenharmony_ci FW_VI_ENABLE_CMD_VIID_V(viid)); 823462306a36Sopenharmony_ci c.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_IEN_V(rx_en) | 823562306a36Sopenharmony_ci FW_VI_ENABLE_CMD_EEN_V(tx_en) | 823662306a36Sopenharmony_ci FW_VI_ENABLE_CMD_DCB_INFO_V(dcb_en) | 823762306a36Sopenharmony_ci FW_LEN16(c)); 823862306a36Sopenharmony_ci return t4_wr_mbox_ns(adap, mbox, &c, sizeof(c), NULL); 823962306a36Sopenharmony_ci} 824062306a36Sopenharmony_ci 824162306a36Sopenharmony_ci/** 824262306a36Sopenharmony_ci * t4_enable_vi - enable/disable a virtual interface 824362306a36Sopenharmony_ci * @adap: the adapter 824462306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 824562306a36Sopenharmony_ci * @viid: the VI id 824662306a36Sopenharmony_ci * @rx_en: 1=enable Rx, 0=disable Rx 824762306a36Sopenharmony_ci * @tx_en: 1=enable Tx, 0=disable Tx 824862306a36Sopenharmony_ci * 824962306a36Sopenharmony_ci * Enables/disables a virtual interface. 825062306a36Sopenharmony_ci */ 825162306a36Sopenharmony_ciint t4_enable_vi(struct adapter *adap, unsigned int mbox, unsigned int viid, 825262306a36Sopenharmony_ci bool rx_en, bool tx_en) 825362306a36Sopenharmony_ci{ 825462306a36Sopenharmony_ci return t4_enable_vi_params(adap, mbox, viid, rx_en, tx_en, 0); 825562306a36Sopenharmony_ci} 825662306a36Sopenharmony_ci 825762306a36Sopenharmony_ci/** 825862306a36Sopenharmony_ci * t4_enable_pi_params - enable/disable a Port's Virtual Interface 825962306a36Sopenharmony_ci * @adap: the adapter 826062306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 826162306a36Sopenharmony_ci * @pi: the Port Information structure 826262306a36Sopenharmony_ci * @rx_en: 1=enable Rx, 0=disable Rx 826362306a36Sopenharmony_ci * @tx_en: 1=enable Tx, 0=disable Tx 826462306a36Sopenharmony_ci * @dcb_en: 1=enable delivery of Data Center Bridging messages. 826562306a36Sopenharmony_ci * 826662306a36Sopenharmony_ci * Enables/disables a Port's Virtual Interface. Note that setting DCB 826762306a36Sopenharmony_ci * Enable only makes sense when enabling a Virtual Interface ... 826862306a36Sopenharmony_ci * If the Virtual Interface enable/disable operation is successful, 826962306a36Sopenharmony_ci * we notify the OS-specific code of a potential Link Status change 827062306a36Sopenharmony_ci * via the OS Contract API t4_os_link_changed(). 827162306a36Sopenharmony_ci */ 827262306a36Sopenharmony_ciint t4_enable_pi_params(struct adapter *adap, unsigned int mbox, 827362306a36Sopenharmony_ci struct port_info *pi, 827462306a36Sopenharmony_ci bool rx_en, bool tx_en, bool dcb_en) 827562306a36Sopenharmony_ci{ 827662306a36Sopenharmony_ci int ret = t4_enable_vi_params(adap, mbox, pi->viid, 827762306a36Sopenharmony_ci rx_en, tx_en, dcb_en); 827862306a36Sopenharmony_ci if (ret) 827962306a36Sopenharmony_ci return ret; 828062306a36Sopenharmony_ci t4_os_link_changed(adap, pi->port_id, 828162306a36Sopenharmony_ci rx_en && tx_en && pi->link_cfg.link_ok); 828262306a36Sopenharmony_ci return 0; 828362306a36Sopenharmony_ci} 828462306a36Sopenharmony_ci 828562306a36Sopenharmony_ci/** 828662306a36Sopenharmony_ci * t4_identify_port - identify a VI's port by blinking its LED 828762306a36Sopenharmony_ci * @adap: the adapter 828862306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 828962306a36Sopenharmony_ci * @viid: the VI id 829062306a36Sopenharmony_ci * @nblinks: how many times to blink LED at 2.5 Hz 829162306a36Sopenharmony_ci * 829262306a36Sopenharmony_ci * Identifies a VI's port by blinking its LED. 829362306a36Sopenharmony_ci */ 829462306a36Sopenharmony_ciint t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid, 829562306a36Sopenharmony_ci unsigned int nblinks) 829662306a36Sopenharmony_ci{ 829762306a36Sopenharmony_ci struct fw_vi_enable_cmd c; 829862306a36Sopenharmony_ci 829962306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 830062306a36Sopenharmony_ci c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_ENABLE_CMD) | 830162306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_EXEC_F | 830262306a36Sopenharmony_ci FW_VI_ENABLE_CMD_VIID_V(viid)); 830362306a36Sopenharmony_ci c.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_LED_F | FW_LEN16(c)); 830462306a36Sopenharmony_ci c.blinkdur = cpu_to_be16(nblinks); 830562306a36Sopenharmony_ci return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 830662306a36Sopenharmony_ci} 830762306a36Sopenharmony_ci 830862306a36Sopenharmony_ci/** 830962306a36Sopenharmony_ci * t4_iq_stop - stop an ingress queue and its FLs 831062306a36Sopenharmony_ci * @adap: the adapter 831162306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 831262306a36Sopenharmony_ci * @pf: the PF owning the queues 831362306a36Sopenharmony_ci * @vf: the VF owning the queues 831462306a36Sopenharmony_ci * @iqtype: the ingress queue type (FW_IQ_TYPE_FL_INT_CAP, etc.) 831562306a36Sopenharmony_ci * @iqid: ingress queue id 831662306a36Sopenharmony_ci * @fl0id: FL0 queue id or 0xffff if no attached FL0 831762306a36Sopenharmony_ci * @fl1id: FL1 queue id or 0xffff if no attached FL1 831862306a36Sopenharmony_ci * 831962306a36Sopenharmony_ci * Stops an ingress queue and its associated FLs, if any. This causes 832062306a36Sopenharmony_ci * any current or future data/messages destined for these queues to be 832162306a36Sopenharmony_ci * tossed. 832262306a36Sopenharmony_ci */ 832362306a36Sopenharmony_ciint t4_iq_stop(struct adapter *adap, unsigned int mbox, unsigned int pf, 832462306a36Sopenharmony_ci unsigned int vf, unsigned int iqtype, unsigned int iqid, 832562306a36Sopenharmony_ci unsigned int fl0id, unsigned int fl1id) 832662306a36Sopenharmony_ci{ 832762306a36Sopenharmony_ci struct fw_iq_cmd c; 832862306a36Sopenharmony_ci 832962306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 833062306a36Sopenharmony_ci c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_IQ_CMD) | FW_CMD_REQUEST_F | 833162306a36Sopenharmony_ci FW_CMD_EXEC_F | FW_IQ_CMD_PFN_V(pf) | 833262306a36Sopenharmony_ci FW_IQ_CMD_VFN_V(vf)); 833362306a36Sopenharmony_ci c.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_IQSTOP_F | FW_LEN16(c)); 833462306a36Sopenharmony_ci c.type_to_iqandstindex = cpu_to_be32(FW_IQ_CMD_TYPE_V(iqtype)); 833562306a36Sopenharmony_ci c.iqid = cpu_to_be16(iqid); 833662306a36Sopenharmony_ci c.fl0id = cpu_to_be16(fl0id); 833762306a36Sopenharmony_ci c.fl1id = cpu_to_be16(fl1id); 833862306a36Sopenharmony_ci return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 833962306a36Sopenharmony_ci} 834062306a36Sopenharmony_ci 834162306a36Sopenharmony_ci/** 834262306a36Sopenharmony_ci * t4_iq_free - free an ingress queue and its FLs 834362306a36Sopenharmony_ci * @adap: the adapter 834462306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 834562306a36Sopenharmony_ci * @pf: the PF owning the queues 834662306a36Sopenharmony_ci * @vf: the VF owning the queues 834762306a36Sopenharmony_ci * @iqtype: the ingress queue type 834862306a36Sopenharmony_ci * @iqid: ingress queue id 834962306a36Sopenharmony_ci * @fl0id: FL0 queue id or 0xffff if no attached FL0 835062306a36Sopenharmony_ci * @fl1id: FL1 queue id or 0xffff if no attached FL1 835162306a36Sopenharmony_ci * 835262306a36Sopenharmony_ci * Frees an ingress queue and its associated FLs, if any. 835362306a36Sopenharmony_ci */ 835462306a36Sopenharmony_ciint t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, 835562306a36Sopenharmony_ci unsigned int vf, unsigned int iqtype, unsigned int iqid, 835662306a36Sopenharmony_ci unsigned int fl0id, unsigned int fl1id) 835762306a36Sopenharmony_ci{ 835862306a36Sopenharmony_ci struct fw_iq_cmd c; 835962306a36Sopenharmony_ci 836062306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 836162306a36Sopenharmony_ci c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_IQ_CMD) | FW_CMD_REQUEST_F | 836262306a36Sopenharmony_ci FW_CMD_EXEC_F | FW_IQ_CMD_PFN_V(pf) | 836362306a36Sopenharmony_ci FW_IQ_CMD_VFN_V(vf)); 836462306a36Sopenharmony_ci c.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_FREE_F | FW_LEN16(c)); 836562306a36Sopenharmony_ci c.type_to_iqandstindex = cpu_to_be32(FW_IQ_CMD_TYPE_V(iqtype)); 836662306a36Sopenharmony_ci c.iqid = cpu_to_be16(iqid); 836762306a36Sopenharmony_ci c.fl0id = cpu_to_be16(fl0id); 836862306a36Sopenharmony_ci c.fl1id = cpu_to_be16(fl1id); 836962306a36Sopenharmony_ci return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 837062306a36Sopenharmony_ci} 837162306a36Sopenharmony_ci 837262306a36Sopenharmony_ci/** 837362306a36Sopenharmony_ci * t4_eth_eq_free - free an Ethernet egress queue 837462306a36Sopenharmony_ci * @adap: the adapter 837562306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 837662306a36Sopenharmony_ci * @pf: the PF owning the queue 837762306a36Sopenharmony_ci * @vf: the VF owning the queue 837862306a36Sopenharmony_ci * @eqid: egress queue id 837962306a36Sopenharmony_ci * 838062306a36Sopenharmony_ci * Frees an Ethernet egress queue. 838162306a36Sopenharmony_ci */ 838262306a36Sopenharmony_ciint t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, 838362306a36Sopenharmony_ci unsigned int vf, unsigned int eqid) 838462306a36Sopenharmony_ci{ 838562306a36Sopenharmony_ci struct fw_eq_eth_cmd c; 838662306a36Sopenharmony_ci 838762306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 838862306a36Sopenharmony_ci c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_EQ_ETH_CMD) | 838962306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_EXEC_F | 839062306a36Sopenharmony_ci FW_EQ_ETH_CMD_PFN_V(pf) | 839162306a36Sopenharmony_ci FW_EQ_ETH_CMD_VFN_V(vf)); 839262306a36Sopenharmony_ci c.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_FREE_F | FW_LEN16(c)); 839362306a36Sopenharmony_ci c.eqid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_EQID_V(eqid)); 839462306a36Sopenharmony_ci return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 839562306a36Sopenharmony_ci} 839662306a36Sopenharmony_ci 839762306a36Sopenharmony_ci/** 839862306a36Sopenharmony_ci * t4_ctrl_eq_free - free a control egress queue 839962306a36Sopenharmony_ci * @adap: the adapter 840062306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 840162306a36Sopenharmony_ci * @pf: the PF owning the queue 840262306a36Sopenharmony_ci * @vf: the VF owning the queue 840362306a36Sopenharmony_ci * @eqid: egress queue id 840462306a36Sopenharmony_ci * 840562306a36Sopenharmony_ci * Frees a control egress queue. 840662306a36Sopenharmony_ci */ 840762306a36Sopenharmony_ciint t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, 840862306a36Sopenharmony_ci unsigned int vf, unsigned int eqid) 840962306a36Sopenharmony_ci{ 841062306a36Sopenharmony_ci struct fw_eq_ctrl_cmd c; 841162306a36Sopenharmony_ci 841262306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 841362306a36Sopenharmony_ci c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_EQ_CTRL_CMD) | 841462306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_EXEC_F | 841562306a36Sopenharmony_ci FW_EQ_CTRL_CMD_PFN_V(pf) | 841662306a36Sopenharmony_ci FW_EQ_CTRL_CMD_VFN_V(vf)); 841762306a36Sopenharmony_ci c.alloc_to_len16 = cpu_to_be32(FW_EQ_CTRL_CMD_FREE_F | FW_LEN16(c)); 841862306a36Sopenharmony_ci c.cmpliqid_eqid = cpu_to_be32(FW_EQ_CTRL_CMD_EQID_V(eqid)); 841962306a36Sopenharmony_ci return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 842062306a36Sopenharmony_ci} 842162306a36Sopenharmony_ci 842262306a36Sopenharmony_ci/** 842362306a36Sopenharmony_ci * t4_ofld_eq_free - free an offload egress queue 842462306a36Sopenharmony_ci * @adap: the adapter 842562306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 842662306a36Sopenharmony_ci * @pf: the PF owning the queue 842762306a36Sopenharmony_ci * @vf: the VF owning the queue 842862306a36Sopenharmony_ci * @eqid: egress queue id 842962306a36Sopenharmony_ci * 843062306a36Sopenharmony_ci * Frees a control egress queue. 843162306a36Sopenharmony_ci */ 843262306a36Sopenharmony_ciint t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, 843362306a36Sopenharmony_ci unsigned int vf, unsigned int eqid) 843462306a36Sopenharmony_ci{ 843562306a36Sopenharmony_ci struct fw_eq_ofld_cmd c; 843662306a36Sopenharmony_ci 843762306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 843862306a36Sopenharmony_ci c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_EQ_OFLD_CMD) | 843962306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_EXEC_F | 844062306a36Sopenharmony_ci FW_EQ_OFLD_CMD_PFN_V(pf) | 844162306a36Sopenharmony_ci FW_EQ_OFLD_CMD_VFN_V(vf)); 844262306a36Sopenharmony_ci c.alloc_to_len16 = cpu_to_be32(FW_EQ_OFLD_CMD_FREE_F | FW_LEN16(c)); 844362306a36Sopenharmony_ci c.eqid_pkd = cpu_to_be32(FW_EQ_OFLD_CMD_EQID_V(eqid)); 844462306a36Sopenharmony_ci return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); 844562306a36Sopenharmony_ci} 844662306a36Sopenharmony_ci 844762306a36Sopenharmony_ci/** 844862306a36Sopenharmony_ci * t4_link_down_rc_str - return a string for a Link Down Reason Code 844962306a36Sopenharmony_ci * @link_down_rc: Link Down Reason Code 845062306a36Sopenharmony_ci * 845162306a36Sopenharmony_ci * Returns a string representation of the Link Down Reason Code. 845262306a36Sopenharmony_ci */ 845362306a36Sopenharmony_cistatic const char *t4_link_down_rc_str(unsigned char link_down_rc) 845462306a36Sopenharmony_ci{ 845562306a36Sopenharmony_ci static const char * const reason[] = { 845662306a36Sopenharmony_ci "Link Down", 845762306a36Sopenharmony_ci "Remote Fault", 845862306a36Sopenharmony_ci "Auto-negotiation Failure", 845962306a36Sopenharmony_ci "Reserved", 846062306a36Sopenharmony_ci "Insufficient Airflow", 846162306a36Sopenharmony_ci "Unable To Determine Reason", 846262306a36Sopenharmony_ci "No RX Signal Detected", 846362306a36Sopenharmony_ci "Reserved", 846462306a36Sopenharmony_ci }; 846562306a36Sopenharmony_ci 846662306a36Sopenharmony_ci if (link_down_rc >= ARRAY_SIZE(reason)) 846762306a36Sopenharmony_ci return "Bad Reason Code"; 846862306a36Sopenharmony_ci 846962306a36Sopenharmony_ci return reason[link_down_rc]; 847062306a36Sopenharmony_ci} 847162306a36Sopenharmony_ci 847262306a36Sopenharmony_ci/* Return the highest speed set in the port capabilities, in Mb/s. */ 847362306a36Sopenharmony_cistatic unsigned int fwcap_to_speed(fw_port_cap32_t caps) 847462306a36Sopenharmony_ci{ 847562306a36Sopenharmony_ci #define TEST_SPEED_RETURN(__caps_speed, __speed) \ 847662306a36Sopenharmony_ci do { \ 847762306a36Sopenharmony_ci if (caps & FW_PORT_CAP32_SPEED_##__caps_speed) \ 847862306a36Sopenharmony_ci return __speed; \ 847962306a36Sopenharmony_ci } while (0) 848062306a36Sopenharmony_ci 848162306a36Sopenharmony_ci TEST_SPEED_RETURN(400G, 400000); 848262306a36Sopenharmony_ci TEST_SPEED_RETURN(200G, 200000); 848362306a36Sopenharmony_ci TEST_SPEED_RETURN(100G, 100000); 848462306a36Sopenharmony_ci TEST_SPEED_RETURN(50G, 50000); 848562306a36Sopenharmony_ci TEST_SPEED_RETURN(40G, 40000); 848662306a36Sopenharmony_ci TEST_SPEED_RETURN(25G, 25000); 848762306a36Sopenharmony_ci TEST_SPEED_RETURN(10G, 10000); 848862306a36Sopenharmony_ci TEST_SPEED_RETURN(1G, 1000); 848962306a36Sopenharmony_ci TEST_SPEED_RETURN(100M, 100); 849062306a36Sopenharmony_ci 849162306a36Sopenharmony_ci #undef TEST_SPEED_RETURN 849262306a36Sopenharmony_ci 849362306a36Sopenharmony_ci return 0; 849462306a36Sopenharmony_ci} 849562306a36Sopenharmony_ci 849662306a36Sopenharmony_ci/** 849762306a36Sopenharmony_ci * fwcap_to_fwspeed - return highest speed in Port Capabilities 849862306a36Sopenharmony_ci * @acaps: advertised Port Capabilities 849962306a36Sopenharmony_ci * 850062306a36Sopenharmony_ci * Get the highest speed for the port from the advertised Port 850162306a36Sopenharmony_ci * Capabilities. It will be either the highest speed from the list of 850262306a36Sopenharmony_ci * speeds or whatever user has set using ethtool. 850362306a36Sopenharmony_ci */ 850462306a36Sopenharmony_cistatic fw_port_cap32_t fwcap_to_fwspeed(fw_port_cap32_t acaps) 850562306a36Sopenharmony_ci{ 850662306a36Sopenharmony_ci #define TEST_SPEED_RETURN(__caps_speed) \ 850762306a36Sopenharmony_ci do { \ 850862306a36Sopenharmony_ci if (acaps & FW_PORT_CAP32_SPEED_##__caps_speed) \ 850962306a36Sopenharmony_ci return FW_PORT_CAP32_SPEED_##__caps_speed; \ 851062306a36Sopenharmony_ci } while (0) 851162306a36Sopenharmony_ci 851262306a36Sopenharmony_ci TEST_SPEED_RETURN(400G); 851362306a36Sopenharmony_ci TEST_SPEED_RETURN(200G); 851462306a36Sopenharmony_ci TEST_SPEED_RETURN(100G); 851562306a36Sopenharmony_ci TEST_SPEED_RETURN(50G); 851662306a36Sopenharmony_ci TEST_SPEED_RETURN(40G); 851762306a36Sopenharmony_ci TEST_SPEED_RETURN(25G); 851862306a36Sopenharmony_ci TEST_SPEED_RETURN(10G); 851962306a36Sopenharmony_ci TEST_SPEED_RETURN(1G); 852062306a36Sopenharmony_ci TEST_SPEED_RETURN(100M); 852162306a36Sopenharmony_ci 852262306a36Sopenharmony_ci #undef TEST_SPEED_RETURN 852362306a36Sopenharmony_ci 852462306a36Sopenharmony_ci return 0; 852562306a36Sopenharmony_ci} 852662306a36Sopenharmony_ci 852762306a36Sopenharmony_ci/** 852862306a36Sopenharmony_ci * lstatus_to_fwcap - translate old lstatus to 32-bit Port Capabilities 852962306a36Sopenharmony_ci * @lstatus: old FW_PORT_ACTION_GET_PORT_INFO lstatus value 853062306a36Sopenharmony_ci * 853162306a36Sopenharmony_ci * Translates old FW_PORT_ACTION_GET_PORT_INFO lstatus field into new 853262306a36Sopenharmony_ci * 32-bit Port Capabilities value. 853362306a36Sopenharmony_ci */ 853462306a36Sopenharmony_cistatic fw_port_cap32_t lstatus_to_fwcap(u32 lstatus) 853562306a36Sopenharmony_ci{ 853662306a36Sopenharmony_ci fw_port_cap32_t linkattr = 0; 853762306a36Sopenharmony_ci 853862306a36Sopenharmony_ci /* Unfortunately the format of the Link Status in the old 853962306a36Sopenharmony_ci * 16-bit Port Information message isn't the same as the 854062306a36Sopenharmony_ci * 16-bit Port Capabilities bitfield used everywhere else ... 854162306a36Sopenharmony_ci */ 854262306a36Sopenharmony_ci if (lstatus & FW_PORT_CMD_RXPAUSE_F) 854362306a36Sopenharmony_ci linkattr |= FW_PORT_CAP32_FC_RX; 854462306a36Sopenharmony_ci if (lstatus & FW_PORT_CMD_TXPAUSE_F) 854562306a36Sopenharmony_ci linkattr |= FW_PORT_CAP32_FC_TX; 854662306a36Sopenharmony_ci if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M)) 854762306a36Sopenharmony_ci linkattr |= FW_PORT_CAP32_SPEED_100M; 854862306a36Sopenharmony_ci if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G)) 854962306a36Sopenharmony_ci linkattr |= FW_PORT_CAP32_SPEED_1G; 855062306a36Sopenharmony_ci if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G)) 855162306a36Sopenharmony_ci linkattr |= FW_PORT_CAP32_SPEED_10G; 855262306a36Sopenharmony_ci if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_25G)) 855362306a36Sopenharmony_ci linkattr |= FW_PORT_CAP32_SPEED_25G; 855462306a36Sopenharmony_ci if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G)) 855562306a36Sopenharmony_ci linkattr |= FW_PORT_CAP32_SPEED_40G; 855662306a36Sopenharmony_ci if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100G)) 855762306a36Sopenharmony_ci linkattr |= FW_PORT_CAP32_SPEED_100G; 855862306a36Sopenharmony_ci 855962306a36Sopenharmony_ci return linkattr; 856062306a36Sopenharmony_ci} 856162306a36Sopenharmony_ci 856262306a36Sopenharmony_ci/** 856362306a36Sopenharmony_ci * t4_handle_get_port_info - process a FW reply message 856462306a36Sopenharmony_ci * @pi: the port info 856562306a36Sopenharmony_ci * @rpl: start of the FW message 856662306a36Sopenharmony_ci * 856762306a36Sopenharmony_ci * Processes a GET_PORT_INFO FW reply message. 856862306a36Sopenharmony_ci */ 856962306a36Sopenharmony_civoid t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl) 857062306a36Sopenharmony_ci{ 857162306a36Sopenharmony_ci const struct fw_port_cmd *cmd = (const void *)rpl; 857262306a36Sopenharmony_ci fw_port_cap32_t pcaps, acaps, lpacaps, linkattr; 857362306a36Sopenharmony_ci struct link_config *lc = &pi->link_cfg; 857462306a36Sopenharmony_ci struct adapter *adapter = pi->adapter; 857562306a36Sopenharmony_ci unsigned int speed, fc, fec, adv_fc; 857662306a36Sopenharmony_ci enum fw_port_module_type mod_type; 857762306a36Sopenharmony_ci int action, link_ok, linkdnrc; 857862306a36Sopenharmony_ci enum fw_port_type port_type; 857962306a36Sopenharmony_ci 858062306a36Sopenharmony_ci /* Extract the various fields from the Port Information message. 858162306a36Sopenharmony_ci */ 858262306a36Sopenharmony_ci action = FW_PORT_CMD_ACTION_G(be32_to_cpu(cmd->action_to_len16)); 858362306a36Sopenharmony_ci switch (action) { 858462306a36Sopenharmony_ci case FW_PORT_ACTION_GET_PORT_INFO: { 858562306a36Sopenharmony_ci u32 lstatus = be32_to_cpu(cmd->u.info.lstatus_to_modtype); 858662306a36Sopenharmony_ci 858762306a36Sopenharmony_ci link_ok = (lstatus & FW_PORT_CMD_LSTATUS_F) != 0; 858862306a36Sopenharmony_ci linkdnrc = FW_PORT_CMD_LINKDNRC_G(lstatus); 858962306a36Sopenharmony_ci port_type = FW_PORT_CMD_PTYPE_G(lstatus); 859062306a36Sopenharmony_ci mod_type = FW_PORT_CMD_MODTYPE_G(lstatus); 859162306a36Sopenharmony_ci pcaps = fwcaps16_to_caps32(be16_to_cpu(cmd->u.info.pcap)); 859262306a36Sopenharmony_ci acaps = fwcaps16_to_caps32(be16_to_cpu(cmd->u.info.acap)); 859362306a36Sopenharmony_ci lpacaps = fwcaps16_to_caps32(be16_to_cpu(cmd->u.info.lpacap)); 859462306a36Sopenharmony_ci linkattr = lstatus_to_fwcap(lstatus); 859562306a36Sopenharmony_ci break; 859662306a36Sopenharmony_ci } 859762306a36Sopenharmony_ci 859862306a36Sopenharmony_ci case FW_PORT_ACTION_GET_PORT_INFO32: { 859962306a36Sopenharmony_ci u32 lstatus32; 860062306a36Sopenharmony_ci 860162306a36Sopenharmony_ci lstatus32 = be32_to_cpu(cmd->u.info32.lstatus32_to_cbllen32); 860262306a36Sopenharmony_ci link_ok = (lstatus32 & FW_PORT_CMD_LSTATUS32_F) != 0; 860362306a36Sopenharmony_ci linkdnrc = FW_PORT_CMD_LINKDNRC32_G(lstatus32); 860462306a36Sopenharmony_ci port_type = FW_PORT_CMD_PORTTYPE32_G(lstatus32); 860562306a36Sopenharmony_ci mod_type = FW_PORT_CMD_MODTYPE32_G(lstatus32); 860662306a36Sopenharmony_ci pcaps = be32_to_cpu(cmd->u.info32.pcaps32); 860762306a36Sopenharmony_ci acaps = be32_to_cpu(cmd->u.info32.acaps32); 860862306a36Sopenharmony_ci lpacaps = be32_to_cpu(cmd->u.info32.lpacaps32); 860962306a36Sopenharmony_ci linkattr = be32_to_cpu(cmd->u.info32.linkattr32); 861062306a36Sopenharmony_ci break; 861162306a36Sopenharmony_ci } 861262306a36Sopenharmony_ci 861362306a36Sopenharmony_ci default: 861462306a36Sopenharmony_ci dev_err(adapter->pdev_dev, "Handle Port Information: Bad Command/Action %#x\n", 861562306a36Sopenharmony_ci be32_to_cpu(cmd->action_to_len16)); 861662306a36Sopenharmony_ci return; 861762306a36Sopenharmony_ci } 861862306a36Sopenharmony_ci 861962306a36Sopenharmony_ci fec = fwcap_to_cc_fec(acaps); 862062306a36Sopenharmony_ci adv_fc = fwcap_to_cc_pause(acaps); 862162306a36Sopenharmony_ci fc = fwcap_to_cc_pause(linkattr); 862262306a36Sopenharmony_ci speed = fwcap_to_speed(linkattr); 862362306a36Sopenharmony_ci 862462306a36Sopenharmony_ci /* Reset state for communicating new Transceiver Module status and 862562306a36Sopenharmony_ci * whether the OS-dependent layer wants us to redo the current 862662306a36Sopenharmony_ci * "sticky" L1 Configure Link Parameters. 862762306a36Sopenharmony_ci */ 862862306a36Sopenharmony_ci lc->new_module = false; 862962306a36Sopenharmony_ci lc->redo_l1cfg = false; 863062306a36Sopenharmony_ci 863162306a36Sopenharmony_ci if (mod_type != pi->mod_type) { 863262306a36Sopenharmony_ci /* With the newer SFP28 and QSFP28 Transceiver Module Types, 863362306a36Sopenharmony_ci * various fundamental Port Capabilities which used to be 863462306a36Sopenharmony_ci * immutable can now change radically. We can now have 863562306a36Sopenharmony_ci * Speeds, Auto-Negotiation, Forward Error Correction, etc. 863662306a36Sopenharmony_ci * all change based on what Transceiver Module is inserted. 863762306a36Sopenharmony_ci * So we need to record the Physical "Port" Capabilities on 863862306a36Sopenharmony_ci * every Transceiver Module change. 863962306a36Sopenharmony_ci */ 864062306a36Sopenharmony_ci lc->pcaps = pcaps; 864162306a36Sopenharmony_ci 864262306a36Sopenharmony_ci /* When a new Transceiver Module is inserted, the Firmware 864362306a36Sopenharmony_ci * will examine its i2c EPROM to determine its type and 864462306a36Sopenharmony_ci * general operating parameters including things like Forward 864562306a36Sopenharmony_ci * Error Control, etc. Various IEEE 802.3 standards dictate 864662306a36Sopenharmony_ci * how to interpret these i2c values to determine default 864762306a36Sopenharmony_ci * "sutomatic" settings. We record these for future use when 864862306a36Sopenharmony_ci * the user explicitly requests these standards-based values. 864962306a36Sopenharmony_ci */ 865062306a36Sopenharmony_ci lc->def_acaps = acaps; 865162306a36Sopenharmony_ci 865262306a36Sopenharmony_ci /* Some versions of the early T6 Firmware "cheated" when 865362306a36Sopenharmony_ci * handling different Transceiver Modules by changing the 865462306a36Sopenharmony_ci * underlaying Port Type reported to the Host Drivers. As 865562306a36Sopenharmony_ci * such we need to capture whatever Port Type the Firmware 865662306a36Sopenharmony_ci * sends us and record it in case it's different from what we 865762306a36Sopenharmony_ci * were told earlier. Unfortunately, since Firmware is 865862306a36Sopenharmony_ci * forever, we'll need to keep this code here forever, but in 865962306a36Sopenharmony_ci * later T6 Firmware it should just be an assignment of the 866062306a36Sopenharmony_ci * same value already recorded. 866162306a36Sopenharmony_ci */ 866262306a36Sopenharmony_ci pi->port_type = port_type; 866362306a36Sopenharmony_ci 866462306a36Sopenharmony_ci /* Record new Module Type information. 866562306a36Sopenharmony_ci */ 866662306a36Sopenharmony_ci pi->mod_type = mod_type; 866762306a36Sopenharmony_ci 866862306a36Sopenharmony_ci /* Let the OS-dependent layer know if we have a new 866962306a36Sopenharmony_ci * Transceiver Module inserted. 867062306a36Sopenharmony_ci */ 867162306a36Sopenharmony_ci lc->new_module = t4_is_inserted_mod_type(mod_type); 867262306a36Sopenharmony_ci 867362306a36Sopenharmony_ci t4_os_portmod_changed(adapter, pi->port_id); 867462306a36Sopenharmony_ci } 867562306a36Sopenharmony_ci 867662306a36Sopenharmony_ci if (link_ok != lc->link_ok || speed != lc->speed || 867762306a36Sopenharmony_ci fc != lc->fc || adv_fc != lc->advertised_fc || 867862306a36Sopenharmony_ci fec != lc->fec) { 867962306a36Sopenharmony_ci /* something changed */ 868062306a36Sopenharmony_ci if (!link_ok && lc->link_ok) { 868162306a36Sopenharmony_ci lc->link_down_rc = linkdnrc; 868262306a36Sopenharmony_ci dev_warn_ratelimited(adapter->pdev_dev, 868362306a36Sopenharmony_ci "Port %d link down, reason: %s\n", 868462306a36Sopenharmony_ci pi->tx_chan, 868562306a36Sopenharmony_ci t4_link_down_rc_str(linkdnrc)); 868662306a36Sopenharmony_ci } 868762306a36Sopenharmony_ci lc->link_ok = link_ok; 868862306a36Sopenharmony_ci lc->speed = speed; 868962306a36Sopenharmony_ci lc->advertised_fc = adv_fc; 869062306a36Sopenharmony_ci lc->fc = fc; 869162306a36Sopenharmony_ci lc->fec = fec; 869262306a36Sopenharmony_ci 869362306a36Sopenharmony_ci lc->lpacaps = lpacaps; 869462306a36Sopenharmony_ci lc->acaps = acaps & ADVERT_MASK; 869562306a36Sopenharmony_ci 869662306a36Sopenharmony_ci /* If we're not physically capable of Auto-Negotiation, note 869762306a36Sopenharmony_ci * this as Auto-Negotiation disabled. Otherwise, we track 869862306a36Sopenharmony_ci * what Auto-Negotiation settings we have. Note parallel 869962306a36Sopenharmony_ci * structure in t4_link_l1cfg_core() and init_link_config(). 870062306a36Sopenharmony_ci */ 870162306a36Sopenharmony_ci if (!(lc->acaps & FW_PORT_CAP32_ANEG)) { 870262306a36Sopenharmony_ci lc->autoneg = AUTONEG_DISABLE; 870362306a36Sopenharmony_ci } else if (lc->acaps & FW_PORT_CAP32_ANEG) { 870462306a36Sopenharmony_ci lc->autoneg = AUTONEG_ENABLE; 870562306a36Sopenharmony_ci } else { 870662306a36Sopenharmony_ci /* When Autoneg is disabled, user needs to set 870762306a36Sopenharmony_ci * single speed. 870862306a36Sopenharmony_ci * Similar to cxgb4_ethtool.c: set_link_ksettings 870962306a36Sopenharmony_ci */ 871062306a36Sopenharmony_ci lc->acaps = 0; 871162306a36Sopenharmony_ci lc->speed_caps = fwcap_to_fwspeed(acaps); 871262306a36Sopenharmony_ci lc->autoneg = AUTONEG_DISABLE; 871362306a36Sopenharmony_ci } 871462306a36Sopenharmony_ci 871562306a36Sopenharmony_ci t4_os_link_changed(adapter, pi->port_id, link_ok); 871662306a36Sopenharmony_ci } 871762306a36Sopenharmony_ci 871862306a36Sopenharmony_ci /* If we have a new Transceiver Module and the OS-dependent code has 871962306a36Sopenharmony_ci * told us that it wants us to redo whatever "sticky" L1 Configuration 872062306a36Sopenharmony_ci * Link Parameters are set, do that now. 872162306a36Sopenharmony_ci */ 872262306a36Sopenharmony_ci if (lc->new_module && lc->redo_l1cfg) { 872362306a36Sopenharmony_ci struct link_config old_lc; 872462306a36Sopenharmony_ci int ret; 872562306a36Sopenharmony_ci 872662306a36Sopenharmony_ci /* Save the current L1 Configuration and restore it if an 872762306a36Sopenharmony_ci * error occurs. We probably should fix the l1_cfg*() 872862306a36Sopenharmony_ci * routines not to change the link_config when an error 872962306a36Sopenharmony_ci * occurs ... 873062306a36Sopenharmony_ci */ 873162306a36Sopenharmony_ci old_lc = *lc; 873262306a36Sopenharmony_ci ret = t4_link_l1cfg_ns(adapter, adapter->mbox, pi->lport, lc); 873362306a36Sopenharmony_ci if (ret) { 873462306a36Sopenharmony_ci *lc = old_lc; 873562306a36Sopenharmony_ci dev_warn(adapter->pdev_dev, 873662306a36Sopenharmony_ci "Attempt to update new Transceiver Module settings failed\n"); 873762306a36Sopenharmony_ci } 873862306a36Sopenharmony_ci } 873962306a36Sopenharmony_ci lc->new_module = false; 874062306a36Sopenharmony_ci lc->redo_l1cfg = false; 874162306a36Sopenharmony_ci} 874262306a36Sopenharmony_ci 874362306a36Sopenharmony_ci/** 874462306a36Sopenharmony_ci * t4_update_port_info - retrieve and update port information if changed 874562306a36Sopenharmony_ci * @pi: the port_info 874662306a36Sopenharmony_ci * 874762306a36Sopenharmony_ci * We issue a Get Port Information Command to the Firmware and, if 874862306a36Sopenharmony_ci * successful, we check to see if anything is different from what we 874962306a36Sopenharmony_ci * last recorded and update things accordingly. 875062306a36Sopenharmony_ci */ 875162306a36Sopenharmony_ciint t4_update_port_info(struct port_info *pi) 875262306a36Sopenharmony_ci{ 875362306a36Sopenharmony_ci unsigned int fw_caps = pi->adapter->params.fw_caps_support; 875462306a36Sopenharmony_ci struct fw_port_cmd port_cmd; 875562306a36Sopenharmony_ci int ret; 875662306a36Sopenharmony_ci 875762306a36Sopenharmony_ci memset(&port_cmd, 0, sizeof(port_cmd)); 875862306a36Sopenharmony_ci port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) | 875962306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_READ_F | 876062306a36Sopenharmony_ci FW_PORT_CMD_PORTID_V(pi->tx_chan)); 876162306a36Sopenharmony_ci port_cmd.action_to_len16 = cpu_to_be32( 876262306a36Sopenharmony_ci FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16 876362306a36Sopenharmony_ci ? FW_PORT_ACTION_GET_PORT_INFO 876462306a36Sopenharmony_ci : FW_PORT_ACTION_GET_PORT_INFO32) | 876562306a36Sopenharmony_ci FW_LEN16(port_cmd)); 876662306a36Sopenharmony_ci ret = t4_wr_mbox(pi->adapter, pi->adapter->mbox, 876762306a36Sopenharmony_ci &port_cmd, sizeof(port_cmd), &port_cmd); 876862306a36Sopenharmony_ci if (ret) 876962306a36Sopenharmony_ci return ret; 877062306a36Sopenharmony_ci 877162306a36Sopenharmony_ci t4_handle_get_port_info(pi, (__be64 *)&port_cmd); 877262306a36Sopenharmony_ci return 0; 877362306a36Sopenharmony_ci} 877462306a36Sopenharmony_ci 877562306a36Sopenharmony_ci/** 877662306a36Sopenharmony_ci * t4_get_link_params - retrieve basic link parameters for given port 877762306a36Sopenharmony_ci * @pi: the port 877862306a36Sopenharmony_ci * @link_okp: value return pointer for link up/down 877962306a36Sopenharmony_ci * @speedp: value return pointer for speed (Mb/s) 878062306a36Sopenharmony_ci * @mtup: value return pointer for mtu 878162306a36Sopenharmony_ci * 878262306a36Sopenharmony_ci * Retrieves basic link parameters for a port: link up/down, speed (Mb/s), 878362306a36Sopenharmony_ci * and MTU for a specified port. A negative error is returned on 878462306a36Sopenharmony_ci * failure; 0 on success. 878562306a36Sopenharmony_ci */ 878662306a36Sopenharmony_ciint t4_get_link_params(struct port_info *pi, unsigned int *link_okp, 878762306a36Sopenharmony_ci unsigned int *speedp, unsigned int *mtup) 878862306a36Sopenharmony_ci{ 878962306a36Sopenharmony_ci unsigned int fw_caps = pi->adapter->params.fw_caps_support; 879062306a36Sopenharmony_ci unsigned int action, link_ok, mtu; 879162306a36Sopenharmony_ci struct fw_port_cmd port_cmd; 879262306a36Sopenharmony_ci fw_port_cap32_t linkattr; 879362306a36Sopenharmony_ci int ret; 879462306a36Sopenharmony_ci 879562306a36Sopenharmony_ci memset(&port_cmd, 0, sizeof(port_cmd)); 879662306a36Sopenharmony_ci port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) | 879762306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_READ_F | 879862306a36Sopenharmony_ci FW_PORT_CMD_PORTID_V(pi->tx_chan)); 879962306a36Sopenharmony_ci action = (fw_caps == FW_CAPS16 880062306a36Sopenharmony_ci ? FW_PORT_ACTION_GET_PORT_INFO 880162306a36Sopenharmony_ci : FW_PORT_ACTION_GET_PORT_INFO32); 880262306a36Sopenharmony_ci port_cmd.action_to_len16 = cpu_to_be32( 880362306a36Sopenharmony_ci FW_PORT_CMD_ACTION_V(action) | 880462306a36Sopenharmony_ci FW_LEN16(port_cmd)); 880562306a36Sopenharmony_ci ret = t4_wr_mbox(pi->adapter, pi->adapter->mbox, 880662306a36Sopenharmony_ci &port_cmd, sizeof(port_cmd), &port_cmd); 880762306a36Sopenharmony_ci if (ret) 880862306a36Sopenharmony_ci return ret; 880962306a36Sopenharmony_ci 881062306a36Sopenharmony_ci if (action == FW_PORT_ACTION_GET_PORT_INFO) { 881162306a36Sopenharmony_ci u32 lstatus = be32_to_cpu(port_cmd.u.info.lstatus_to_modtype); 881262306a36Sopenharmony_ci 881362306a36Sopenharmony_ci link_ok = !!(lstatus & FW_PORT_CMD_LSTATUS_F); 881462306a36Sopenharmony_ci linkattr = lstatus_to_fwcap(lstatus); 881562306a36Sopenharmony_ci mtu = be16_to_cpu(port_cmd.u.info.mtu); 881662306a36Sopenharmony_ci } else { 881762306a36Sopenharmony_ci u32 lstatus32 = 881862306a36Sopenharmony_ci be32_to_cpu(port_cmd.u.info32.lstatus32_to_cbllen32); 881962306a36Sopenharmony_ci 882062306a36Sopenharmony_ci link_ok = !!(lstatus32 & FW_PORT_CMD_LSTATUS32_F); 882162306a36Sopenharmony_ci linkattr = be32_to_cpu(port_cmd.u.info32.linkattr32); 882262306a36Sopenharmony_ci mtu = FW_PORT_CMD_MTU32_G( 882362306a36Sopenharmony_ci be32_to_cpu(port_cmd.u.info32.auxlinfo32_mtu32)); 882462306a36Sopenharmony_ci } 882562306a36Sopenharmony_ci 882662306a36Sopenharmony_ci if (link_okp) 882762306a36Sopenharmony_ci *link_okp = link_ok; 882862306a36Sopenharmony_ci if (speedp) 882962306a36Sopenharmony_ci *speedp = fwcap_to_speed(linkattr); 883062306a36Sopenharmony_ci if (mtup) 883162306a36Sopenharmony_ci *mtup = mtu; 883262306a36Sopenharmony_ci 883362306a36Sopenharmony_ci return 0; 883462306a36Sopenharmony_ci} 883562306a36Sopenharmony_ci 883662306a36Sopenharmony_ci/** 883762306a36Sopenharmony_ci * t4_handle_fw_rpl - process a FW reply message 883862306a36Sopenharmony_ci * @adap: the adapter 883962306a36Sopenharmony_ci * @rpl: start of the FW message 884062306a36Sopenharmony_ci * 884162306a36Sopenharmony_ci * Processes a FW message, such as link state change messages. 884262306a36Sopenharmony_ci */ 884362306a36Sopenharmony_ciint t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl) 884462306a36Sopenharmony_ci{ 884562306a36Sopenharmony_ci u8 opcode = *(const u8 *)rpl; 884662306a36Sopenharmony_ci 884762306a36Sopenharmony_ci /* This might be a port command ... this simplifies the following 884862306a36Sopenharmony_ci * conditionals ... We can get away with pre-dereferencing 884962306a36Sopenharmony_ci * action_to_len16 because it's in the first 16 bytes and all messages 885062306a36Sopenharmony_ci * will be at least that long. 885162306a36Sopenharmony_ci */ 885262306a36Sopenharmony_ci const struct fw_port_cmd *p = (const void *)rpl; 885362306a36Sopenharmony_ci unsigned int action = 885462306a36Sopenharmony_ci FW_PORT_CMD_ACTION_G(be32_to_cpu(p->action_to_len16)); 885562306a36Sopenharmony_ci 885662306a36Sopenharmony_ci if (opcode == FW_PORT_CMD && 885762306a36Sopenharmony_ci (action == FW_PORT_ACTION_GET_PORT_INFO || 885862306a36Sopenharmony_ci action == FW_PORT_ACTION_GET_PORT_INFO32)) { 885962306a36Sopenharmony_ci int i; 886062306a36Sopenharmony_ci int chan = FW_PORT_CMD_PORTID_G(be32_to_cpu(p->op_to_portid)); 886162306a36Sopenharmony_ci struct port_info *pi = NULL; 886262306a36Sopenharmony_ci 886362306a36Sopenharmony_ci for_each_port(adap, i) { 886462306a36Sopenharmony_ci pi = adap2pinfo(adap, i); 886562306a36Sopenharmony_ci if (pi->tx_chan == chan) 886662306a36Sopenharmony_ci break; 886762306a36Sopenharmony_ci } 886862306a36Sopenharmony_ci 886962306a36Sopenharmony_ci t4_handle_get_port_info(pi, rpl); 887062306a36Sopenharmony_ci } else { 887162306a36Sopenharmony_ci dev_warn(adap->pdev_dev, "Unknown firmware reply %d\n", 887262306a36Sopenharmony_ci opcode); 887362306a36Sopenharmony_ci return -EINVAL; 887462306a36Sopenharmony_ci } 887562306a36Sopenharmony_ci return 0; 887662306a36Sopenharmony_ci} 887762306a36Sopenharmony_ci 887862306a36Sopenharmony_cistatic void get_pci_mode(struct adapter *adapter, struct pci_params *p) 887962306a36Sopenharmony_ci{ 888062306a36Sopenharmony_ci u16 val; 888162306a36Sopenharmony_ci 888262306a36Sopenharmony_ci if (pci_is_pcie(adapter->pdev)) { 888362306a36Sopenharmony_ci pcie_capability_read_word(adapter->pdev, PCI_EXP_LNKSTA, &val); 888462306a36Sopenharmony_ci p->speed = val & PCI_EXP_LNKSTA_CLS; 888562306a36Sopenharmony_ci p->width = (val & PCI_EXP_LNKSTA_NLW) >> 4; 888662306a36Sopenharmony_ci } 888762306a36Sopenharmony_ci} 888862306a36Sopenharmony_ci 888962306a36Sopenharmony_ci/** 889062306a36Sopenharmony_ci * init_link_config - initialize a link's SW state 889162306a36Sopenharmony_ci * @lc: pointer to structure holding the link state 889262306a36Sopenharmony_ci * @pcaps: link Port Capabilities 889362306a36Sopenharmony_ci * @acaps: link current Advertised Port Capabilities 889462306a36Sopenharmony_ci * 889562306a36Sopenharmony_ci * Initializes the SW state maintained for each link, including the link's 889662306a36Sopenharmony_ci * capabilities and default speed/flow-control/autonegotiation settings. 889762306a36Sopenharmony_ci */ 889862306a36Sopenharmony_cistatic void init_link_config(struct link_config *lc, fw_port_cap32_t pcaps, 889962306a36Sopenharmony_ci fw_port_cap32_t acaps) 890062306a36Sopenharmony_ci{ 890162306a36Sopenharmony_ci lc->pcaps = pcaps; 890262306a36Sopenharmony_ci lc->def_acaps = acaps; 890362306a36Sopenharmony_ci lc->lpacaps = 0; 890462306a36Sopenharmony_ci lc->speed_caps = 0; 890562306a36Sopenharmony_ci lc->speed = 0; 890662306a36Sopenharmony_ci lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; 890762306a36Sopenharmony_ci 890862306a36Sopenharmony_ci /* For Forward Error Control, we default to whatever the Firmware 890962306a36Sopenharmony_ci * tells us the Link is currently advertising. 891062306a36Sopenharmony_ci */ 891162306a36Sopenharmony_ci lc->requested_fec = FEC_AUTO; 891262306a36Sopenharmony_ci lc->fec = fwcap_to_cc_fec(lc->def_acaps); 891362306a36Sopenharmony_ci 891462306a36Sopenharmony_ci /* If the Port is capable of Auto-Negtotiation, initialize it as 891562306a36Sopenharmony_ci * "enabled" and copy over all of the Physical Port Capabilities 891662306a36Sopenharmony_ci * to the Advertised Port Capabilities. Otherwise mark it as 891762306a36Sopenharmony_ci * Auto-Negotiate disabled and select the highest supported speed 891862306a36Sopenharmony_ci * for the link. Note parallel structure in t4_link_l1cfg_core() 891962306a36Sopenharmony_ci * and t4_handle_get_port_info(). 892062306a36Sopenharmony_ci */ 892162306a36Sopenharmony_ci if (lc->pcaps & FW_PORT_CAP32_ANEG) { 892262306a36Sopenharmony_ci lc->acaps = lc->pcaps & ADVERT_MASK; 892362306a36Sopenharmony_ci lc->autoneg = AUTONEG_ENABLE; 892462306a36Sopenharmony_ci lc->requested_fc |= PAUSE_AUTONEG; 892562306a36Sopenharmony_ci } else { 892662306a36Sopenharmony_ci lc->acaps = 0; 892762306a36Sopenharmony_ci lc->autoneg = AUTONEG_DISABLE; 892862306a36Sopenharmony_ci lc->speed_caps = fwcap_to_fwspeed(acaps); 892962306a36Sopenharmony_ci } 893062306a36Sopenharmony_ci} 893162306a36Sopenharmony_ci 893262306a36Sopenharmony_ci#define CIM_PF_NOACCESS 0xeeeeeeee 893362306a36Sopenharmony_ci 893462306a36Sopenharmony_ciint t4_wait_dev_ready(void __iomem *regs) 893562306a36Sopenharmony_ci{ 893662306a36Sopenharmony_ci u32 whoami; 893762306a36Sopenharmony_ci 893862306a36Sopenharmony_ci whoami = readl(regs + PL_WHOAMI_A); 893962306a36Sopenharmony_ci if (whoami != 0xffffffff && whoami != CIM_PF_NOACCESS) 894062306a36Sopenharmony_ci return 0; 894162306a36Sopenharmony_ci 894262306a36Sopenharmony_ci msleep(500); 894362306a36Sopenharmony_ci whoami = readl(regs + PL_WHOAMI_A); 894462306a36Sopenharmony_ci return (whoami != 0xffffffff && whoami != CIM_PF_NOACCESS ? 0 : -EIO); 894562306a36Sopenharmony_ci} 894662306a36Sopenharmony_ci 894762306a36Sopenharmony_cistruct flash_desc { 894862306a36Sopenharmony_ci u32 vendor_and_model_id; 894962306a36Sopenharmony_ci u32 size_mb; 895062306a36Sopenharmony_ci}; 895162306a36Sopenharmony_ci 895262306a36Sopenharmony_cistatic int t4_get_flash_params(struct adapter *adap) 895362306a36Sopenharmony_ci{ 895462306a36Sopenharmony_ci /* Table for non-Numonix supported flash parts. Numonix parts are left 895562306a36Sopenharmony_ci * to the preexisting code. All flash parts have 64KB sectors. 895662306a36Sopenharmony_ci */ 895762306a36Sopenharmony_ci static struct flash_desc supported_flash[] = { 895862306a36Sopenharmony_ci { 0x150201, 4 << 20 }, /* Spansion 4MB S25FL032P */ 895962306a36Sopenharmony_ci }; 896062306a36Sopenharmony_ci 896162306a36Sopenharmony_ci unsigned int part, manufacturer; 896262306a36Sopenharmony_ci unsigned int density, size = 0; 896362306a36Sopenharmony_ci u32 flashid = 0; 896462306a36Sopenharmony_ci int ret; 896562306a36Sopenharmony_ci 896662306a36Sopenharmony_ci /* Issue a Read ID Command to the Flash part. We decode supported 896762306a36Sopenharmony_ci * Flash parts and their sizes from this. There's a newer Query 896862306a36Sopenharmony_ci * Command which can retrieve detailed geometry information but many 896962306a36Sopenharmony_ci * Flash parts don't support it. 897062306a36Sopenharmony_ci */ 897162306a36Sopenharmony_ci 897262306a36Sopenharmony_ci ret = sf1_write(adap, 1, 1, 0, SF_RD_ID); 897362306a36Sopenharmony_ci if (!ret) 897462306a36Sopenharmony_ci ret = sf1_read(adap, 3, 0, 1, &flashid); 897562306a36Sopenharmony_ci t4_write_reg(adap, SF_OP_A, 0); /* unlock SF */ 897662306a36Sopenharmony_ci if (ret) 897762306a36Sopenharmony_ci return ret; 897862306a36Sopenharmony_ci 897962306a36Sopenharmony_ci /* Check to see if it's one of our non-standard supported Flash parts. 898062306a36Sopenharmony_ci */ 898162306a36Sopenharmony_ci for (part = 0; part < ARRAY_SIZE(supported_flash); part++) 898262306a36Sopenharmony_ci if (supported_flash[part].vendor_and_model_id == flashid) { 898362306a36Sopenharmony_ci adap->params.sf_size = supported_flash[part].size_mb; 898462306a36Sopenharmony_ci adap->params.sf_nsec = 898562306a36Sopenharmony_ci adap->params.sf_size / SF_SEC_SIZE; 898662306a36Sopenharmony_ci goto found; 898762306a36Sopenharmony_ci } 898862306a36Sopenharmony_ci 898962306a36Sopenharmony_ci /* Decode Flash part size. The code below looks repetitive with 899062306a36Sopenharmony_ci * common encodings, but that's not guaranteed in the JEDEC 899162306a36Sopenharmony_ci * specification for the Read JEDEC ID command. The only thing that 899262306a36Sopenharmony_ci * we're guaranteed by the JEDEC specification is where the 899362306a36Sopenharmony_ci * Manufacturer ID is in the returned result. After that each 899462306a36Sopenharmony_ci * Manufacturer ~could~ encode things completely differently. 899562306a36Sopenharmony_ci * Note, all Flash parts must have 64KB sectors. 899662306a36Sopenharmony_ci */ 899762306a36Sopenharmony_ci manufacturer = flashid & 0xff; 899862306a36Sopenharmony_ci switch (manufacturer) { 899962306a36Sopenharmony_ci case 0x20: { /* Micron/Numonix */ 900062306a36Sopenharmony_ci /* This Density -> Size decoding table is taken from Micron 900162306a36Sopenharmony_ci * Data Sheets. 900262306a36Sopenharmony_ci */ 900362306a36Sopenharmony_ci density = (flashid >> 16) & 0xff; 900462306a36Sopenharmony_ci switch (density) { 900562306a36Sopenharmony_ci case 0x14: /* 1MB */ 900662306a36Sopenharmony_ci size = 1 << 20; 900762306a36Sopenharmony_ci break; 900862306a36Sopenharmony_ci case 0x15: /* 2MB */ 900962306a36Sopenharmony_ci size = 1 << 21; 901062306a36Sopenharmony_ci break; 901162306a36Sopenharmony_ci case 0x16: /* 4MB */ 901262306a36Sopenharmony_ci size = 1 << 22; 901362306a36Sopenharmony_ci break; 901462306a36Sopenharmony_ci case 0x17: /* 8MB */ 901562306a36Sopenharmony_ci size = 1 << 23; 901662306a36Sopenharmony_ci break; 901762306a36Sopenharmony_ci case 0x18: /* 16MB */ 901862306a36Sopenharmony_ci size = 1 << 24; 901962306a36Sopenharmony_ci break; 902062306a36Sopenharmony_ci case 0x19: /* 32MB */ 902162306a36Sopenharmony_ci size = 1 << 25; 902262306a36Sopenharmony_ci break; 902362306a36Sopenharmony_ci case 0x20: /* 64MB */ 902462306a36Sopenharmony_ci size = 1 << 26; 902562306a36Sopenharmony_ci break; 902662306a36Sopenharmony_ci case 0x21: /* 128MB */ 902762306a36Sopenharmony_ci size = 1 << 27; 902862306a36Sopenharmony_ci break; 902962306a36Sopenharmony_ci case 0x22: /* 256MB */ 903062306a36Sopenharmony_ci size = 1 << 28; 903162306a36Sopenharmony_ci break; 903262306a36Sopenharmony_ci } 903362306a36Sopenharmony_ci break; 903462306a36Sopenharmony_ci } 903562306a36Sopenharmony_ci case 0x9d: { /* ISSI -- Integrated Silicon Solution, Inc. */ 903662306a36Sopenharmony_ci /* This Density -> Size decoding table is taken from ISSI 903762306a36Sopenharmony_ci * Data Sheets. 903862306a36Sopenharmony_ci */ 903962306a36Sopenharmony_ci density = (flashid >> 16) & 0xff; 904062306a36Sopenharmony_ci switch (density) { 904162306a36Sopenharmony_ci case 0x16: /* 32 MB */ 904262306a36Sopenharmony_ci size = 1 << 25; 904362306a36Sopenharmony_ci break; 904462306a36Sopenharmony_ci case 0x17: /* 64MB */ 904562306a36Sopenharmony_ci size = 1 << 26; 904662306a36Sopenharmony_ci break; 904762306a36Sopenharmony_ci } 904862306a36Sopenharmony_ci break; 904962306a36Sopenharmony_ci } 905062306a36Sopenharmony_ci case 0xc2: { /* Macronix */ 905162306a36Sopenharmony_ci /* This Density -> Size decoding table is taken from Macronix 905262306a36Sopenharmony_ci * Data Sheets. 905362306a36Sopenharmony_ci */ 905462306a36Sopenharmony_ci density = (flashid >> 16) & 0xff; 905562306a36Sopenharmony_ci switch (density) { 905662306a36Sopenharmony_ci case 0x17: /* 8MB */ 905762306a36Sopenharmony_ci size = 1 << 23; 905862306a36Sopenharmony_ci break; 905962306a36Sopenharmony_ci case 0x18: /* 16MB */ 906062306a36Sopenharmony_ci size = 1 << 24; 906162306a36Sopenharmony_ci break; 906262306a36Sopenharmony_ci } 906362306a36Sopenharmony_ci break; 906462306a36Sopenharmony_ci } 906562306a36Sopenharmony_ci case 0xef: { /* Winbond */ 906662306a36Sopenharmony_ci /* This Density -> Size decoding table is taken from Winbond 906762306a36Sopenharmony_ci * Data Sheets. 906862306a36Sopenharmony_ci */ 906962306a36Sopenharmony_ci density = (flashid >> 16) & 0xff; 907062306a36Sopenharmony_ci switch (density) { 907162306a36Sopenharmony_ci case 0x17: /* 8MB */ 907262306a36Sopenharmony_ci size = 1 << 23; 907362306a36Sopenharmony_ci break; 907462306a36Sopenharmony_ci case 0x18: /* 16MB */ 907562306a36Sopenharmony_ci size = 1 << 24; 907662306a36Sopenharmony_ci break; 907762306a36Sopenharmony_ci } 907862306a36Sopenharmony_ci break; 907962306a36Sopenharmony_ci } 908062306a36Sopenharmony_ci } 908162306a36Sopenharmony_ci 908262306a36Sopenharmony_ci /* If we didn't recognize the FLASH part, that's no real issue: the 908362306a36Sopenharmony_ci * Hardware/Software contract says that Hardware will _*ALWAYS*_ 908462306a36Sopenharmony_ci * use a FLASH part which is at least 4MB in size and has 64KB 908562306a36Sopenharmony_ci * sectors. The unrecognized FLASH part is likely to be much larger 908662306a36Sopenharmony_ci * than 4MB, but that's all we really need. 908762306a36Sopenharmony_ci */ 908862306a36Sopenharmony_ci if (size == 0) { 908962306a36Sopenharmony_ci dev_warn(adap->pdev_dev, "Unknown Flash Part, ID = %#x, assuming 4MB\n", 909062306a36Sopenharmony_ci flashid); 909162306a36Sopenharmony_ci size = 1 << 22; 909262306a36Sopenharmony_ci } 909362306a36Sopenharmony_ci 909462306a36Sopenharmony_ci /* Store decoded Flash size and fall through into vetting code. */ 909562306a36Sopenharmony_ci adap->params.sf_size = size; 909662306a36Sopenharmony_ci adap->params.sf_nsec = size / SF_SEC_SIZE; 909762306a36Sopenharmony_ci 909862306a36Sopenharmony_cifound: 909962306a36Sopenharmony_ci if (adap->params.sf_size < FLASH_MIN_SIZE) 910062306a36Sopenharmony_ci dev_warn(adap->pdev_dev, "WARNING: Flash Part ID %#x, size %#x < %#x\n", 910162306a36Sopenharmony_ci flashid, adap->params.sf_size, FLASH_MIN_SIZE); 910262306a36Sopenharmony_ci return 0; 910362306a36Sopenharmony_ci} 910462306a36Sopenharmony_ci 910562306a36Sopenharmony_ci/** 910662306a36Sopenharmony_ci * t4_prep_adapter - prepare SW and HW for operation 910762306a36Sopenharmony_ci * @adapter: the adapter 910862306a36Sopenharmony_ci * 910962306a36Sopenharmony_ci * Initialize adapter SW state for the various HW modules, set initial 911062306a36Sopenharmony_ci * values for some adapter tunables, take PHYs out of reset, and 911162306a36Sopenharmony_ci * initialize the MDIO interface. 911262306a36Sopenharmony_ci */ 911362306a36Sopenharmony_ciint t4_prep_adapter(struct adapter *adapter) 911462306a36Sopenharmony_ci{ 911562306a36Sopenharmony_ci int ret, ver; 911662306a36Sopenharmony_ci uint16_t device_id; 911762306a36Sopenharmony_ci u32 pl_rev; 911862306a36Sopenharmony_ci 911962306a36Sopenharmony_ci get_pci_mode(adapter, &adapter->params.pci); 912062306a36Sopenharmony_ci pl_rev = REV_G(t4_read_reg(adapter, PL_REV_A)); 912162306a36Sopenharmony_ci 912262306a36Sopenharmony_ci ret = t4_get_flash_params(adapter); 912362306a36Sopenharmony_ci if (ret < 0) { 912462306a36Sopenharmony_ci dev_err(adapter->pdev_dev, "error %d identifying flash\n", ret); 912562306a36Sopenharmony_ci return ret; 912662306a36Sopenharmony_ci } 912762306a36Sopenharmony_ci 912862306a36Sopenharmony_ci /* Retrieve adapter's device ID 912962306a36Sopenharmony_ci */ 913062306a36Sopenharmony_ci pci_read_config_word(adapter->pdev, PCI_DEVICE_ID, &device_id); 913162306a36Sopenharmony_ci ver = device_id >> 12; 913262306a36Sopenharmony_ci adapter->params.chip = 0; 913362306a36Sopenharmony_ci switch (ver) { 913462306a36Sopenharmony_ci case CHELSIO_T4: 913562306a36Sopenharmony_ci adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T4, pl_rev); 913662306a36Sopenharmony_ci adapter->params.arch.sge_fl_db = DBPRIO_F; 913762306a36Sopenharmony_ci adapter->params.arch.mps_tcam_size = 913862306a36Sopenharmony_ci NUM_MPS_CLS_SRAM_L_INSTANCES; 913962306a36Sopenharmony_ci adapter->params.arch.mps_rplc_size = 128; 914062306a36Sopenharmony_ci adapter->params.arch.nchan = NCHAN; 914162306a36Sopenharmony_ci adapter->params.arch.pm_stats_cnt = PM_NSTATS; 914262306a36Sopenharmony_ci adapter->params.arch.vfcount = 128; 914362306a36Sopenharmony_ci /* Congestion map is for 4 channels so that 914462306a36Sopenharmony_ci * MPS can have 4 priority per port. 914562306a36Sopenharmony_ci */ 914662306a36Sopenharmony_ci adapter->params.arch.cng_ch_bits_log = 2; 914762306a36Sopenharmony_ci break; 914862306a36Sopenharmony_ci case CHELSIO_T5: 914962306a36Sopenharmony_ci adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T5, pl_rev); 915062306a36Sopenharmony_ci adapter->params.arch.sge_fl_db = DBPRIO_F | DBTYPE_F; 915162306a36Sopenharmony_ci adapter->params.arch.mps_tcam_size = 915262306a36Sopenharmony_ci NUM_MPS_T5_CLS_SRAM_L_INSTANCES; 915362306a36Sopenharmony_ci adapter->params.arch.mps_rplc_size = 128; 915462306a36Sopenharmony_ci adapter->params.arch.nchan = NCHAN; 915562306a36Sopenharmony_ci adapter->params.arch.pm_stats_cnt = PM_NSTATS; 915662306a36Sopenharmony_ci adapter->params.arch.vfcount = 128; 915762306a36Sopenharmony_ci adapter->params.arch.cng_ch_bits_log = 2; 915862306a36Sopenharmony_ci break; 915962306a36Sopenharmony_ci case CHELSIO_T6: 916062306a36Sopenharmony_ci adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T6, pl_rev); 916162306a36Sopenharmony_ci adapter->params.arch.sge_fl_db = 0; 916262306a36Sopenharmony_ci adapter->params.arch.mps_tcam_size = 916362306a36Sopenharmony_ci NUM_MPS_T5_CLS_SRAM_L_INSTANCES; 916462306a36Sopenharmony_ci adapter->params.arch.mps_rplc_size = 256; 916562306a36Sopenharmony_ci adapter->params.arch.nchan = 2; 916662306a36Sopenharmony_ci adapter->params.arch.pm_stats_cnt = T6_PM_NSTATS; 916762306a36Sopenharmony_ci adapter->params.arch.vfcount = 256; 916862306a36Sopenharmony_ci /* Congestion map will be for 2 channels so that 916962306a36Sopenharmony_ci * MPS can have 8 priority per port. 917062306a36Sopenharmony_ci */ 917162306a36Sopenharmony_ci adapter->params.arch.cng_ch_bits_log = 3; 917262306a36Sopenharmony_ci break; 917362306a36Sopenharmony_ci default: 917462306a36Sopenharmony_ci dev_err(adapter->pdev_dev, "Device %d is not supported\n", 917562306a36Sopenharmony_ci device_id); 917662306a36Sopenharmony_ci return -EINVAL; 917762306a36Sopenharmony_ci } 917862306a36Sopenharmony_ci 917962306a36Sopenharmony_ci adapter->params.cim_la_size = CIMLA_SIZE; 918062306a36Sopenharmony_ci init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd); 918162306a36Sopenharmony_ci 918262306a36Sopenharmony_ci /* 918362306a36Sopenharmony_ci * Default port for debugging in case we can't reach FW. 918462306a36Sopenharmony_ci */ 918562306a36Sopenharmony_ci adapter->params.nports = 1; 918662306a36Sopenharmony_ci adapter->params.portvec = 1; 918762306a36Sopenharmony_ci adapter->params.vpd.cclk = 50000; 918862306a36Sopenharmony_ci 918962306a36Sopenharmony_ci /* Set PCIe completion timeout to 4 seconds. */ 919062306a36Sopenharmony_ci pcie_capability_clear_and_set_word(adapter->pdev, PCI_EXP_DEVCTL2, 919162306a36Sopenharmony_ci PCI_EXP_DEVCTL2_COMP_TIMEOUT, 0xd); 919262306a36Sopenharmony_ci return 0; 919362306a36Sopenharmony_ci} 919462306a36Sopenharmony_ci 919562306a36Sopenharmony_ci/** 919662306a36Sopenharmony_ci * t4_shutdown_adapter - shut down adapter, host & wire 919762306a36Sopenharmony_ci * @adapter: the adapter 919862306a36Sopenharmony_ci * 919962306a36Sopenharmony_ci * Perform an emergency shutdown of the adapter and stop it from 920062306a36Sopenharmony_ci * continuing any further communication on the ports or DMA to the 920162306a36Sopenharmony_ci * host. This is typically used when the adapter and/or firmware 920262306a36Sopenharmony_ci * have crashed and we want to prevent any further accidental 920362306a36Sopenharmony_ci * communication with the rest of the world. This will also force 920462306a36Sopenharmony_ci * the port Link Status to go down -- if register writes work -- 920562306a36Sopenharmony_ci * which should help our peers figure out that we're down. 920662306a36Sopenharmony_ci */ 920762306a36Sopenharmony_ciint t4_shutdown_adapter(struct adapter *adapter) 920862306a36Sopenharmony_ci{ 920962306a36Sopenharmony_ci int port; 921062306a36Sopenharmony_ci 921162306a36Sopenharmony_ci t4_intr_disable(adapter); 921262306a36Sopenharmony_ci t4_write_reg(adapter, DBG_GPIO_EN_A, 0); 921362306a36Sopenharmony_ci for_each_port(adapter, port) { 921462306a36Sopenharmony_ci u32 a_port_cfg = is_t4(adapter->params.chip) ? 921562306a36Sopenharmony_ci PORT_REG(port, XGMAC_PORT_CFG_A) : 921662306a36Sopenharmony_ci T5_PORT_REG(port, MAC_PORT_CFG_A); 921762306a36Sopenharmony_ci 921862306a36Sopenharmony_ci t4_write_reg(adapter, a_port_cfg, 921962306a36Sopenharmony_ci t4_read_reg(adapter, a_port_cfg) 922062306a36Sopenharmony_ci & ~SIGNAL_DET_V(1)); 922162306a36Sopenharmony_ci } 922262306a36Sopenharmony_ci t4_set_reg_field(adapter, SGE_CONTROL_A, GLOBALENABLE_F, 0); 922362306a36Sopenharmony_ci 922462306a36Sopenharmony_ci return 0; 922562306a36Sopenharmony_ci} 922662306a36Sopenharmony_ci 922762306a36Sopenharmony_ci/** 922862306a36Sopenharmony_ci * t4_bar2_sge_qregs - return BAR2 SGE Queue register information 922962306a36Sopenharmony_ci * @adapter: the adapter 923062306a36Sopenharmony_ci * @qid: the Queue ID 923162306a36Sopenharmony_ci * @qtype: the Ingress or Egress type for @qid 923262306a36Sopenharmony_ci * @user: true if this request is for a user mode queue 923362306a36Sopenharmony_ci * @pbar2_qoffset: BAR2 Queue Offset 923462306a36Sopenharmony_ci * @pbar2_qid: BAR2 Queue ID or 0 for Queue ID inferred SGE Queues 923562306a36Sopenharmony_ci * 923662306a36Sopenharmony_ci * Returns the BAR2 SGE Queue Registers information associated with the 923762306a36Sopenharmony_ci * indicated Absolute Queue ID. These are passed back in return value 923862306a36Sopenharmony_ci * pointers. @qtype should be T4_BAR2_QTYPE_EGRESS for Egress Queue 923962306a36Sopenharmony_ci * and T4_BAR2_QTYPE_INGRESS for Ingress Queues. 924062306a36Sopenharmony_ci * 924162306a36Sopenharmony_ci * This may return an error which indicates that BAR2 SGE Queue 924262306a36Sopenharmony_ci * registers aren't available. If an error is not returned, then the 924362306a36Sopenharmony_ci * following values are returned: 924462306a36Sopenharmony_ci * 924562306a36Sopenharmony_ci * *@pbar2_qoffset: the BAR2 Offset of the @qid Registers 924662306a36Sopenharmony_ci * *@pbar2_qid: the BAR2 SGE Queue ID or 0 of @qid 924762306a36Sopenharmony_ci * 924862306a36Sopenharmony_ci * If the returned BAR2 Queue ID is 0, then BAR2 SGE registers which 924962306a36Sopenharmony_ci * require the "Inferred Queue ID" ability may be used. E.g. the 925062306a36Sopenharmony_ci * Write Combining Doorbell Buffer. If the BAR2 Queue ID is not 0, 925162306a36Sopenharmony_ci * then these "Inferred Queue ID" register may not be used. 925262306a36Sopenharmony_ci */ 925362306a36Sopenharmony_ciint t4_bar2_sge_qregs(struct adapter *adapter, 925462306a36Sopenharmony_ci unsigned int qid, 925562306a36Sopenharmony_ci enum t4_bar2_qtype qtype, 925662306a36Sopenharmony_ci int user, 925762306a36Sopenharmony_ci u64 *pbar2_qoffset, 925862306a36Sopenharmony_ci unsigned int *pbar2_qid) 925962306a36Sopenharmony_ci{ 926062306a36Sopenharmony_ci unsigned int page_shift, page_size, qpp_shift, qpp_mask; 926162306a36Sopenharmony_ci u64 bar2_page_offset, bar2_qoffset; 926262306a36Sopenharmony_ci unsigned int bar2_qid, bar2_qid_offset, bar2_qinferred; 926362306a36Sopenharmony_ci 926462306a36Sopenharmony_ci /* T4 doesn't support BAR2 SGE Queue registers for kernel mode queues */ 926562306a36Sopenharmony_ci if (!user && is_t4(adapter->params.chip)) 926662306a36Sopenharmony_ci return -EINVAL; 926762306a36Sopenharmony_ci 926862306a36Sopenharmony_ci /* Get our SGE Page Size parameters. 926962306a36Sopenharmony_ci */ 927062306a36Sopenharmony_ci page_shift = adapter->params.sge.hps + 10; 927162306a36Sopenharmony_ci page_size = 1 << page_shift; 927262306a36Sopenharmony_ci 927362306a36Sopenharmony_ci /* Get the right Queues per Page parameters for our Queue. 927462306a36Sopenharmony_ci */ 927562306a36Sopenharmony_ci qpp_shift = (qtype == T4_BAR2_QTYPE_EGRESS 927662306a36Sopenharmony_ci ? adapter->params.sge.eq_qpp 927762306a36Sopenharmony_ci : adapter->params.sge.iq_qpp); 927862306a36Sopenharmony_ci qpp_mask = (1 << qpp_shift) - 1; 927962306a36Sopenharmony_ci 928062306a36Sopenharmony_ci /* Calculate the basics of the BAR2 SGE Queue register area: 928162306a36Sopenharmony_ci * o The BAR2 page the Queue registers will be in. 928262306a36Sopenharmony_ci * o The BAR2 Queue ID. 928362306a36Sopenharmony_ci * o The BAR2 Queue ID Offset into the BAR2 page. 928462306a36Sopenharmony_ci */ 928562306a36Sopenharmony_ci bar2_page_offset = ((u64)(qid >> qpp_shift) << page_shift); 928662306a36Sopenharmony_ci bar2_qid = qid & qpp_mask; 928762306a36Sopenharmony_ci bar2_qid_offset = bar2_qid * SGE_UDB_SIZE; 928862306a36Sopenharmony_ci 928962306a36Sopenharmony_ci /* If the BAR2 Queue ID Offset is less than the Page Size, then the 929062306a36Sopenharmony_ci * hardware will infer the Absolute Queue ID simply from the writes to 929162306a36Sopenharmony_ci * the BAR2 Queue ID Offset within the BAR2 Page (and we need to use a 929262306a36Sopenharmony_ci * BAR2 Queue ID of 0 for those writes). Otherwise, we'll simply 929362306a36Sopenharmony_ci * write to the first BAR2 SGE Queue Area within the BAR2 Page with 929462306a36Sopenharmony_ci * the BAR2 Queue ID and the hardware will infer the Absolute Queue ID 929562306a36Sopenharmony_ci * from the BAR2 Page and BAR2 Queue ID. 929662306a36Sopenharmony_ci * 929762306a36Sopenharmony_ci * One important censequence of this is that some BAR2 SGE registers 929862306a36Sopenharmony_ci * have a "Queue ID" field and we can write the BAR2 SGE Queue ID 929962306a36Sopenharmony_ci * there. But other registers synthesize the SGE Queue ID purely 930062306a36Sopenharmony_ci * from the writes to the registers -- the Write Combined Doorbell 930162306a36Sopenharmony_ci * Buffer is a good example. These BAR2 SGE Registers are only 930262306a36Sopenharmony_ci * available for those BAR2 SGE Register areas where the SGE Absolute 930362306a36Sopenharmony_ci * Queue ID can be inferred from simple writes. 930462306a36Sopenharmony_ci */ 930562306a36Sopenharmony_ci bar2_qoffset = bar2_page_offset; 930662306a36Sopenharmony_ci bar2_qinferred = (bar2_qid_offset < page_size); 930762306a36Sopenharmony_ci if (bar2_qinferred) { 930862306a36Sopenharmony_ci bar2_qoffset += bar2_qid_offset; 930962306a36Sopenharmony_ci bar2_qid = 0; 931062306a36Sopenharmony_ci } 931162306a36Sopenharmony_ci 931262306a36Sopenharmony_ci *pbar2_qoffset = bar2_qoffset; 931362306a36Sopenharmony_ci *pbar2_qid = bar2_qid; 931462306a36Sopenharmony_ci return 0; 931562306a36Sopenharmony_ci} 931662306a36Sopenharmony_ci 931762306a36Sopenharmony_ci/** 931862306a36Sopenharmony_ci * t4_init_devlog_params - initialize adapter->params.devlog 931962306a36Sopenharmony_ci * @adap: the adapter 932062306a36Sopenharmony_ci * 932162306a36Sopenharmony_ci * Initialize various fields of the adapter's Firmware Device Log 932262306a36Sopenharmony_ci * Parameters structure. 932362306a36Sopenharmony_ci */ 932462306a36Sopenharmony_ciint t4_init_devlog_params(struct adapter *adap) 932562306a36Sopenharmony_ci{ 932662306a36Sopenharmony_ci struct devlog_params *dparams = &adap->params.devlog; 932762306a36Sopenharmony_ci u32 pf_dparams; 932862306a36Sopenharmony_ci unsigned int devlog_meminfo; 932962306a36Sopenharmony_ci struct fw_devlog_cmd devlog_cmd; 933062306a36Sopenharmony_ci int ret; 933162306a36Sopenharmony_ci 933262306a36Sopenharmony_ci /* If we're dealing with newer firmware, the Device Log Parameters 933362306a36Sopenharmony_ci * are stored in a designated register which allows us to access the 933462306a36Sopenharmony_ci * Device Log even if we can't talk to the firmware. 933562306a36Sopenharmony_ci */ 933662306a36Sopenharmony_ci pf_dparams = 933762306a36Sopenharmony_ci t4_read_reg(adap, PCIE_FW_REG(PCIE_FW_PF_A, PCIE_FW_PF_DEVLOG)); 933862306a36Sopenharmony_ci if (pf_dparams) { 933962306a36Sopenharmony_ci unsigned int nentries, nentries128; 934062306a36Sopenharmony_ci 934162306a36Sopenharmony_ci dparams->memtype = PCIE_FW_PF_DEVLOG_MEMTYPE_G(pf_dparams); 934262306a36Sopenharmony_ci dparams->start = PCIE_FW_PF_DEVLOG_ADDR16_G(pf_dparams) << 4; 934362306a36Sopenharmony_ci 934462306a36Sopenharmony_ci nentries128 = PCIE_FW_PF_DEVLOG_NENTRIES128_G(pf_dparams); 934562306a36Sopenharmony_ci nentries = (nentries128 + 1) * 128; 934662306a36Sopenharmony_ci dparams->size = nentries * sizeof(struct fw_devlog_e); 934762306a36Sopenharmony_ci 934862306a36Sopenharmony_ci return 0; 934962306a36Sopenharmony_ci } 935062306a36Sopenharmony_ci 935162306a36Sopenharmony_ci /* Otherwise, ask the firmware for it's Device Log Parameters. 935262306a36Sopenharmony_ci */ 935362306a36Sopenharmony_ci memset(&devlog_cmd, 0, sizeof(devlog_cmd)); 935462306a36Sopenharmony_ci devlog_cmd.op_to_write = cpu_to_be32(FW_CMD_OP_V(FW_DEVLOG_CMD) | 935562306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_READ_F); 935662306a36Sopenharmony_ci devlog_cmd.retval_len16 = cpu_to_be32(FW_LEN16(devlog_cmd)); 935762306a36Sopenharmony_ci ret = t4_wr_mbox(adap, adap->mbox, &devlog_cmd, sizeof(devlog_cmd), 935862306a36Sopenharmony_ci &devlog_cmd); 935962306a36Sopenharmony_ci if (ret) 936062306a36Sopenharmony_ci return ret; 936162306a36Sopenharmony_ci 936262306a36Sopenharmony_ci devlog_meminfo = 936362306a36Sopenharmony_ci be32_to_cpu(devlog_cmd.memtype_devlog_memaddr16_devlog); 936462306a36Sopenharmony_ci dparams->memtype = FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(devlog_meminfo); 936562306a36Sopenharmony_ci dparams->start = FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(devlog_meminfo) << 4; 936662306a36Sopenharmony_ci dparams->size = be32_to_cpu(devlog_cmd.memsize_devlog); 936762306a36Sopenharmony_ci 936862306a36Sopenharmony_ci return 0; 936962306a36Sopenharmony_ci} 937062306a36Sopenharmony_ci 937162306a36Sopenharmony_ci/** 937262306a36Sopenharmony_ci * t4_init_sge_params - initialize adap->params.sge 937362306a36Sopenharmony_ci * @adapter: the adapter 937462306a36Sopenharmony_ci * 937562306a36Sopenharmony_ci * Initialize various fields of the adapter's SGE Parameters structure. 937662306a36Sopenharmony_ci */ 937762306a36Sopenharmony_ciint t4_init_sge_params(struct adapter *adapter) 937862306a36Sopenharmony_ci{ 937962306a36Sopenharmony_ci struct sge_params *sge_params = &adapter->params.sge; 938062306a36Sopenharmony_ci u32 hps, qpp; 938162306a36Sopenharmony_ci unsigned int s_hps, s_qpp; 938262306a36Sopenharmony_ci 938362306a36Sopenharmony_ci /* Extract the SGE Page Size for our PF. 938462306a36Sopenharmony_ci */ 938562306a36Sopenharmony_ci hps = t4_read_reg(adapter, SGE_HOST_PAGE_SIZE_A); 938662306a36Sopenharmony_ci s_hps = (HOSTPAGESIZEPF0_S + 938762306a36Sopenharmony_ci (HOSTPAGESIZEPF1_S - HOSTPAGESIZEPF0_S) * adapter->pf); 938862306a36Sopenharmony_ci sge_params->hps = ((hps >> s_hps) & HOSTPAGESIZEPF0_M); 938962306a36Sopenharmony_ci 939062306a36Sopenharmony_ci /* Extract the SGE Egress and Ingess Queues Per Page for our PF. 939162306a36Sopenharmony_ci */ 939262306a36Sopenharmony_ci s_qpp = (QUEUESPERPAGEPF0_S + 939362306a36Sopenharmony_ci (QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * adapter->pf); 939462306a36Sopenharmony_ci qpp = t4_read_reg(adapter, SGE_EGRESS_QUEUES_PER_PAGE_PF_A); 939562306a36Sopenharmony_ci sge_params->eq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_M); 939662306a36Sopenharmony_ci qpp = t4_read_reg(adapter, SGE_INGRESS_QUEUES_PER_PAGE_PF_A); 939762306a36Sopenharmony_ci sge_params->iq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_M); 939862306a36Sopenharmony_ci 939962306a36Sopenharmony_ci return 0; 940062306a36Sopenharmony_ci} 940162306a36Sopenharmony_ci 940262306a36Sopenharmony_ci/** 940362306a36Sopenharmony_ci * t4_init_tp_params - initialize adap->params.tp 940462306a36Sopenharmony_ci * @adap: the adapter 940562306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 940662306a36Sopenharmony_ci * 940762306a36Sopenharmony_ci * Initialize various fields of the adapter's TP Parameters structure. 940862306a36Sopenharmony_ci */ 940962306a36Sopenharmony_ciint t4_init_tp_params(struct adapter *adap, bool sleep_ok) 941062306a36Sopenharmony_ci{ 941162306a36Sopenharmony_ci u32 param, val, v; 941262306a36Sopenharmony_ci int chan, ret; 941362306a36Sopenharmony_ci 941462306a36Sopenharmony_ci 941562306a36Sopenharmony_ci v = t4_read_reg(adap, TP_TIMER_RESOLUTION_A); 941662306a36Sopenharmony_ci adap->params.tp.tre = TIMERRESOLUTION_G(v); 941762306a36Sopenharmony_ci adap->params.tp.dack_re = DELAYEDACKRESOLUTION_G(v); 941862306a36Sopenharmony_ci 941962306a36Sopenharmony_ci /* MODQ_REQ_MAP defaults to setting queues 0-3 to chan 0-3 */ 942062306a36Sopenharmony_ci for (chan = 0; chan < NCHAN; chan++) 942162306a36Sopenharmony_ci adap->params.tp.tx_modq[chan] = chan; 942262306a36Sopenharmony_ci 942362306a36Sopenharmony_ci /* Cache the adapter's Compressed Filter Mode/Mask and global Ingress 942462306a36Sopenharmony_ci * Configuration. 942562306a36Sopenharmony_ci */ 942662306a36Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 942762306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_FILTER) | 942862306a36Sopenharmony_ci FW_PARAMS_PARAM_Y_V(FW_PARAM_DEV_FILTER_MODE_MASK)); 942962306a36Sopenharmony_ci 943062306a36Sopenharmony_ci /* Read current value */ 943162306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, 943262306a36Sopenharmony_ci ¶m, &val); 943362306a36Sopenharmony_ci if (ret == 0) { 943462306a36Sopenharmony_ci dev_info(adap->pdev_dev, 943562306a36Sopenharmony_ci "Current filter mode/mask 0x%x:0x%x\n", 943662306a36Sopenharmony_ci FW_PARAMS_PARAM_FILTER_MODE_G(val), 943762306a36Sopenharmony_ci FW_PARAMS_PARAM_FILTER_MASK_G(val)); 943862306a36Sopenharmony_ci adap->params.tp.vlan_pri_map = 943962306a36Sopenharmony_ci FW_PARAMS_PARAM_FILTER_MODE_G(val); 944062306a36Sopenharmony_ci adap->params.tp.filter_mask = 944162306a36Sopenharmony_ci FW_PARAMS_PARAM_FILTER_MASK_G(val); 944262306a36Sopenharmony_ci } else { 944362306a36Sopenharmony_ci dev_info(adap->pdev_dev, 944462306a36Sopenharmony_ci "Failed to read filter mode/mask via fw api, using indirect-reg-read\n"); 944562306a36Sopenharmony_ci 944662306a36Sopenharmony_ci /* Incase of older-fw (which doesn't expose the api 944762306a36Sopenharmony_ci * FW_PARAM_DEV_FILTER_MODE_MASK) and newer-driver (which uses 944862306a36Sopenharmony_ci * the fw api) combination, fall-back to older method of reading 944962306a36Sopenharmony_ci * the filter mode from indirect-register 945062306a36Sopenharmony_ci */ 945162306a36Sopenharmony_ci t4_tp_pio_read(adap, &adap->params.tp.vlan_pri_map, 1, 945262306a36Sopenharmony_ci TP_VLAN_PRI_MAP_A, sleep_ok); 945362306a36Sopenharmony_ci 945462306a36Sopenharmony_ci /* With the older-fw and newer-driver combination we might run 945562306a36Sopenharmony_ci * into an issue when user wants to use hash filter region but 945662306a36Sopenharmony_ci * the filter_mask is zero, in this case filter_mask validation 945762306a36Sopenharmony_ci * is tough. To avoid that we set the filter_mask same as filter 945862306a36Sopenharmony_ci * mode, which will behave exactly as the older way of ignoring 945962306a36Sopenharmony_ci * the filter mask validation. 946062306a36Sopenharmony_ci */ 946162306a36Sopenharmony_ci adap->params.tp.filter_mask = adap->params.tp.vlan_pri_map; 946262306a36Sopenharmony_ci } 946362306a36Sopenharmony_ci 946462306a36Sopenharmony_ci t4_tp_pio_read(adap, &adap->params.tp.ingress_config, 1, 946562306a36Sopenharmony_ci TP_INGRESS_CONFIG_A, sleep_ok); 946662306a36Sopenharmony_ci 946762306a36Sopenharmony_ci /* For T6, cache the adapter's compressed error vector 946862306a36Sopenharmony_ci * and passing outer header info for encapsulated packets. 946962306a36Sopenharmony_ci */ 947062306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) { 947162306a36Sopenharmony_ci v = t4_read_reg(adap, TP_OUT_CONFIG_A); 947262306a36Sopenharmony_ci adap->params.tp.rx_pkt_encap = (v & CRXPKTENC_F) ? 1 : 0; 947362306a36Sopenharmony_ci } 947462306a36Sopenharmony_ci 947562306a36Sopenharmony_ci /* Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field 947662306a36Sopenharmony_ci * shift positions of several elements of the Compressed Filter Tuple 947762306a36Sopenharmony_ci * for this adapter which we need frequently ... 947862306a36Sopenharmony_ci */ 947962306a36Sopenharmony_ci adap->params.tp.fcoe_shift = t4_filter_field_shift(adap, FCOE_F); 948062306a36Sopenharmony_ci adap->params.tp.port_shift = t4_filter_field_shift(adap, PORT_F); 948162306a36Sopenharmony_ci adap->params.tp.vnic_shift = t4_filter_field_shift(adap, VNIC_ID_F); 948262306a36Sopenharmony_ci adap->params.tp.vlan_shift = t4_filter_field_shift(adap, VLAN_F); 948362306a36Sopenharmony_ci adap->params.tp.tos_shift = t4_filter_field_shift(adap, TOS_F); 948462306a36Sopenharmony_ci adap->params.tp.protocol_shift = t4_filter_field_shift(adap, 948562306a36Sopenharmony_ci PROTOCOL_F); 948662306a36Sopenharmony_ci adap->params.tp.ethertype_shift = t4_filter_field_shift(adap, 948762306a36Sopenharmony_ci ETHERTYPE_F); 948862306a36Sopenharmony_ci adap->params.tp.macmatch_shift = t4_filter_field_shift(adap, 948962306a36Sopenharmony_ci MACMATCH_F); 949062306a36Sopenharmony_ci adap->params.tp.matchtype_shift = t4_filter_field_shift(adap, 949162306a36Sopenharmony_ci MPSHITTYPE_F); 949262306a36Sopenharmony_ci adap->params.tp.frag_shift = t4_filter_field_shift(adap, 949362306a36Sopenharmony_ci FRAGMENTATION_F); 949462306a36Sopenharmony_ci 949562306a36Sopenharmony_ci /* If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID 949662306a36Sopenharmony_ci * represents the presence of an Outer VLAN instead of a VNIC ID. 949762306a36Sopenharmony_ci */ 949862306a36Sopenharmony_ci if ((adap->params.tp.ingress_config & VNIC_F) == 0) 949962306a36Sopenharmony_ci adap->params.tp.vnic_shift = -1; 950062306a36Sopenharmony_ci 950162306a36Sopenharmony_ci v = t4_read_reg(adap, LE_3_DB_HASH_MASK_GEN_IPV4_T6_A); 950262306a36Sopenharmony_ci adap->params.tp.hash_filter_mask = v; 950362306a36Sopenharmony_ci v = t4_read_reg(adap, LE_4_DB_HASH_MASK_GEN_IPV4_T6_A); 950462306a36Sopenharmony_ci adap->params.tp.hash_filter_mask |= ((u64)v << 32); 950562306a36Sopenharmony_ci return 0; 950662306a36Sopenharmony_ci} 950762306a36Sopenharmony_ci 950862306a36Sopenharmony_ci/** 950962306a36Sopenharmony_ci * t4_filter_field_shift - calculate filter field shift 951062306a36Sopenharmony_ci * @adap: the adapter 951162306a36Sopenharmony_ci * @filter_sel: the desired field (from TP_VLAN_PRI_MAP bits) 951262306a36Sopenharmony_ci * 951362306a36Sopenharmony_ci * Return the shift position of a filter field within the Compressed 951462306a36Sopenharmony_ci * Filter Tuple. The filter field is specified via its selection bit 951562306a36Sopenharmony_ci * within TP_VLAN_PRI_MAL (filter mode). E.g. F_VLAN. 951662306a36Sopenharmony_ci */ 951762306a36Sopenharmony_ciint t4_filter_field_shift(const struct adapter *adap, int filter_sel) 951862306a36Sopenharmony_ci{ 951962306a36Sopenharmony_ci unsigned int filter_mode = adap->params.tp.vlan_pri_map; 952062306a36Sopenharmony_ci unsigned int sel; 952162306a36Sopenharmony_ci int field_shift; 952262306a36Sopenharmony_ci 952362306a36Sopenharmony_ci if ((filter_mode & filter_sel) == 0) 952462306a36Sopenharmony_ci return -1; 952562306a36Sopenharmony_ci 952662306a36Sopenharmony_ci for (sel = 1, field_shift = 0; sel < filter_sel; sel <<= 1) { 952762306a36Sopenharmony_ci switch (filter_mode & sel) { 952862306a36Sopenharmony_ci case FCOE_F: 952962306a36Sopenharmony_ci field_shift += FT_FCOE_W; 953062306a36Sopenharmony_ci break; 953162306a36Sopenharmony_ci case PORT_F: 953262306a36Sopenharmony_ci field_shift += FT_PORT_W; 953362306a36Sopenharmony_ci break; 953462306a36Sopenharmony_ci case VNIC_ID_F: 953562306a36Sopenharmony_ci field_shift += FT_VNIC_ID_W; 953662306a36Sopenharmony_ci break; 953762306a36Sopenharmony_ci case VLAN_F: 953862306a36Sopenharmony_ci field_shift += FT_VLAN_W; 953962306a36Sopenharmony_ci break; 954062306a36Sopenharmony_ci case TOS_F: 954162306a36Sopenharmony_ci field_shift += FT_TOS_W; 954262306a36Sopenharmony_ci break; 954362306a36Sopenharmony_ci case PROTOCOL_F: 954462306a36Sopenharmony_ci field_shift += FT_PROTOCOL_W; 954562306a36Sopenharmony_ci break; 954662306a36Sopenharmony_ci case ETHERTYPE_F: 954762306a36Sopenharmony_ci field_shift += FT_ETHERTYPE_W; 954862306a36Sopenharmony_ci break; 954962306a36Sopenharmony_ci case MACMATCH_F: 955062306a36Sopenharmony_ci field_shift += FT_MACMATCH_W; 955162306a36Sopenharmony_ci break; 955262306a36Sopenharmony_ci case MPSHITTYPE_F: 955362306a36Sopenharmony_ci field_shift += FT_MPSHITTYPE_W; 955462306a36Sopenharmony_ci break; 955562306a36Sopenharmony_ci case FRAGMENTATION_F: 955662306a36Sopenharmony_ci field_shift += FT_FRAGMENTATION_W; 955762306a36Sopenharmony_ci break; 955862306a36Sopenharmony_ci } 955962306a36Sopenharmony_ci } 956062306a36Sopenharmony_ci return field_shift; 956162306a36Sopenharmony_ci} 956262306a36Sopenharmony_ci 956362306a36Sopenharmony_ciint t4_init_rss_mode(struct adapter *adap, int mbox) 956462306a36Sopenharmony_ci{ 956562306a36Sopenharmony_ci int i, ret; 956662306a36Sopenharmony_ci struct fw_rss_vi_config_cmd rvc; 956762306a36Sopenharmony_ci 956862306a36Sopenharmony_ci memset(&rvc, 0, sizeof(rvc)); 956962306a36Sopenharmony_ci 957062306a36Sopenharmony_ci for_each_port(adap, i) { 957162306a36Sopenharmony_ci struct port_info *p = adap2pinfo(adap, i); 957262306a36Sopenharmony_ci 957362306a36Sopenharmony_ci rvc.op_to_viid = 957462306a36Sopenharmony_ci cpu_to_be32(FW_CMD_OP_V(FW_RSS_VI_CONFIG_CMD) | 957562306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_READ_F | 957662306a36Sopenharmony_ci FW_RSS_VI_CONFIG_CMD_VIID_V(p->viid)); 957762306a36Sopenharmony_ci rvc.retval_len16 = cpu_to_be32(FW_LEN16(rvc)); 957862306a36Sopenharmony_ci ret = t4_wr_mbox(adap, mbox, &rvc, sizeof(rvc), &rvc); 957962306a36Sopenharmony_ci if (ret) 958062306a36Sopenharmony_ci return ret; 958162306a36Sopenharmony_ci p->rss_mode = be32_to_cpu(rvc.u.basicvirtual.defaultq_to_udpen); 958262306a36Sopenharmony_ci } 958362306a36Sopenharmony_ci return 0; 958462306a36Sopenharmony_ci} 958562306a36Sopenharmony_ci 958662306a36Sopenharmony_ci/** 958762306a36Sopenharmony_ci * t4_init_portinfo - allocate a virtual interface and initialize port_info 958862306a36Sopenharmony_ci * @pi: the port_info 958962306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 959062306a36Sopenharmony_ci * @port: physical port associated with the VI 959162306a36Sopenharmony_ci * @pf: the PF owning the VI 959262306a36Sopenharmony_ci * @vf: the VF owning the VI 959362306a36Sopenharmony_ci * @mac: the MAC address of the VI 959462306a36Sopenharmony_ci * 959562306a36Sopenharmony_ci * Allocates a virtual interface for the given physical port. If @mac is 959662306a36Sopenharmony_ci * not %NULL it contains the MAC address of the VI as assigned by FW. 959762306a36Sopenharmony_ci * @mac should be large enough to hold an Ethernet address. 959862306a36Sopenharmony_ci * Returns < 0 on error. 959962306a36Sopenharmony_ci */ 960062306a36Sopenharmony_ciint t4_init_portinfo(struct port_info *pi, int mbox, 960162306a36Sopenharmony_ci int port, int pf, int vf, u8 mac[]) 960262306a36Sopenharmony_ci{ 960362306a36Sopenharmony_ci struct adapter *adapter = pi->adapter; 960462306a36Sopenharmony_ci unsigned int fw_caps = adapter->params.fw_caps_support; 960562306a36Sopenharmony_ci struct fw_port_cmd cmd; 960662306a36Sopenharmony_ci unsigned int rss_size; 960762306a36Sopenharmony_ci enum fw_port_type port_type; 960862306a36Sopenharmony_ci int mdio_addr; 960962306a36Sopenharmony_ci fw_port_cap32_t pcaps, acaps; 961062306a36Sopenharmony_ci u8 vivld = 0, vin = 0; 961162306a36Sopenharmony_ci int ret; 961262306a36Sopenharmony_ci 961362306a36Sopenharmony_ci /* If we haven't yet determined whether we're talking to Firmware 961462306a36Sopenharmony_ci * which knows the new 32-bit Port Capabilities, it's time to find 961562306a36Sopenharmony_ci * out now. This will also tell new Firmware to send us Port Status 961662306a36Sopenharmony_ci * Updates using the new 32-bit Port Capabilities version of the 961762306a36Sopenharmony_ci * Port Information message. 961862306a36Sopenharmony_ci */ 961962306a36Sopenharmony_ci if (fw_caps == FW_CAPS_UNKNOWN) { 962062306a36Sopenharmony_ci u32 param, val; 962162306a36Sopenharmony_ci 962262306a36Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) | 962362306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_PORT_CAPS32)); 962462306a36Sopenharmony_ci val = 1; 962562306a36Sopenharmony_ci ret = t4_set_params(adapter, mbox, pf, vf, 1, ¶m, &val); 962662306a36Sopenharmony_ci fw_caps = (ret == 0 ? FW_CAPS32 : FW_CAPS16); 962762306a36Sopenharmony_ci adapter->params.fw_caps_support = fw_caps; 962862306a36Sopenharmony_ci } 962962306a36Sopenharmony_ci 963062306a36Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 963162306a36Sopenharmony_ci cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) | 963262306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_READ_F | 963362306a36Sopenharmony_ci FW_PORT_CMD_PORTID_V(port)); 963462306a36Sopenharmony_ci cmd.action_to_len16 = cpu_to_be32( 963562306a36Sopenharmony_ci FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16 963662306a36Sopenharmony_ci ? FW_PORT_ACTION_GET_PORT_INFO 963762306a36Sopenharmony_ci : FW_PORT_ACTION_GET_PORT_INFO32) | 963862306a36Sopenharmony_ci FW_LEN16(cmd)); 963962306a36Sopenharmony_ci ret = t4_wr_mbox(pi->adapter, mbox, &cmd, sizeof(cmd), &cmd); 964062306a36Sopenharmony_ci if (ret) 964162306a36Sopenharmony_ci return ret; 964262306a36Sopenharmony_ci 964362306a36Sopenharmony_ci /* Extract the various fields from the Port Information message. 964462306a36Sopenharmony_ci */ 964562306a36Sopenharmony_ci if (fw_caps == FW_CAPS16) { 964662306a36Sopenharmony_ci u32 lstatus = be32_to_cpu(cmd.u.info.lstatus_to_modtype); 964762306a36Sopenharmony_ci 964862306a36Sopenharmony_ci port_type = FW_PORT_CMD_PTYPE_G(lstatus); 964962306a36Sopenharmony_ci mdio_addr = ((lstatus & FW_PORT_CMD_MDIOCAP_F) 965062306a36Sopenharmony_ci ? FW_PORT_CMD_MDIOADDR_G(lstatus) 965162306a36Sopenharmony_ci : -1); 965262306a36Sopenharmony_ci pcaps = fwcaps16_to_caps32(be16_to_cpu(cmd.u.info.pcap)); 965362306a36Sopenharmony_ci acaps = fwcaps16_to_caps32(be16_to_cpu(cmd.u.info.acap)); 965462306a36Sopenharmony_ci } else { 965562306a36Sopenharmony_ci u32 lstatus32 = be32_to_cpu(cmd.u.info32.lstatus32_to_cbllen32); 965662306a36Sopenharmony_ci 965762306a36Sopenharmony_ci port_type = FW_PORT_CMD_PORTTYPE32_G(lstatus32); 965862306a36Sopenharmony_ci mdio_addr = ((lstatus32 & FW_PORT_CMD_MDIOCAP32_F) 965962306a36Sopenharmony_ci ? FW_PORT_CMD_MDIOADDR32_G(lstatus32) 966062306a36Sopenharmony_ci : -1); 966162306a36Sopenharmony_ci pcaps = be32_to_cpu(cmd.u.info32.pcaps32); 966262306a36Sopenharmony_ci acaps = be32_to_cpu(cmd.u.info32.acaps32); 966362306a36Sopenharmony_ci } 966462306a36Sopenharmony_ci 966562306a36Sopenharmony_ci ret = t4_alloc_vi(pi->adapter, mbox, port, pf, vf, 1, mac, &rss_size, 966662306a36Sopenharmony_ci &vivld, &vin); 966762306a36Sopenharmony_ci if (ret < 0) 966862306a36Sopenharmony_ci return ret; 966962306a36Sopenharmony_ci 967062306a36Sopenharmony_ci pi->viid = ret; 967162306a36Sopenharmony_ci pi->tx_chan = port; 967262306a36Sopenharmony_ci pi->lport = port; 967362306a36Sopenharmony_ci pi->rss_size = rss_size; 967462306a36Sopenharmony_ci pi->rx_cchan = t4_get_tp_e2c_map(pi->adapter, port); 967562306a36Sopenharmony_ci 967662306a36Sopenharmony_ci /* If fw supports returning the VIN as part of FW_VI_CMD, 967762306a36Sopenharmony_ci * save the returned values. 967862306a36Sopenharmony_ci */ 967962306a36Sopenharmony_ci if (adapter->params.viid_smt_extn_support) { 968062306a36Sopenharmony_ci pi->vivld = vivld; 968162306a36Sopenharmony_ci pi->vin = vin; 968262306a36Sopenharmony_ci } else { 968362306a36Sopenharmony_ci /* Retrieve the values from VIID */ 968462306a36Sopenharmony_ci pi->vivld = FW_VIID_VIVLD_G(pi->viid); 968562306a36Sopenharmony_ci pi->vin = FW_VIID_VIN_G(pi->viid); 968662306a36Sopenharmony_ci } 968762306a36Sopenharmony_ci 968862306a36Sopenharmony_ci pi->port_type = port_type; 968962306a36Sopenharmony_ci pi->mdio_addr = mdio_addr; 969062306a36Sopenharmony_ci pi->mod_type = FW_PORT_MOD_TYPE_NA; 969162306a36Sopenharmony_ci 969262306a36Sopenharmony_ci init_link_config(&pi->link_cfg, pcaps, acaps); 969362306a36Sopenharmony_ci return 0; 969462306a36Sopenharmony_ci} 969562306a36Sopenharmony_ci 969662306a36Sopenharmony_ciint t4_port_init(struct adapter *adap, int mbox, int pf, int vf) 969762306a36Sopenharmony_ci{ 969862306a36Sopenharmony_ci u8 addr[6]; 969962306a36Sopenharmony_ci int ret, i, j = 0; 970062306a36Sopenharmony_ci 970162306a36Sopenharmony_ci for_each_port(adap, i) { 970262306a36Sopenharmony_ci struct port_info *pi = adap2pinfo(adap, i); 970362306a36Sopenharmony_ci 970462306a36Sopenharmony_ci while ((adap->params.portvec & (1 << j)) == 0) 970562306a36Sopenharmony_ci j++; 970662306a36Sopenharmony_ci 970762306a36Sopenharmony_ci ret = t4_init_portinfo(pi, mbox, j, pf, vf, addr); 970862306a36Sopenharmony_ci if (ret) 970962306a36Sopenharmony_ci return ret; 971062306a36Sopenharmony_ci 971162306a36Sopenharmony_ci eth_hw_addr_set(adap->port[i], addr); 971262306a36Sopenharmony_ci j++; 971362306a36Sopenharmony_ci } 971462306a36Sopenharmony_ci return 0; 971562306a36Sopenharmony_ci} 971662306a36Sopenharmony_ci 971762306a36Sopenharmony_ciint t4_init_port_mirror(struct port_info *pi, u8 mbox, u8 port, u8 pf, u8 vf, 971862306a36Sopenharmony_ci u16 *mirror_viid) 971962306a36Sopenharmony_ci{ 972062306a36Sopenharmony_ci int ret; 972162306a36Sopenharmony_ci 972262306a36Sopenharmony_ci ret = t4_alloc_vi(pi->adapter, mbox, port, pf, vf, 1, NULL, NULL, 972362306a36Sopenharmony_ci NULL, NULL); 972462306a36Sopenharmony_ci if (ret < 0) 972562306a36Sopenharmony_ci return ret; 972662306a36Sopenharmony_ci 972762306a36Sopenharmony_ci if (mirror_viid) 972862306a36Sopenharmony_ci *mirror_viid = ret; 972962306a36Sopenharmony_ci 973062306a36Sopenharmony_ci return 0; 973162306a36Sopenharmony_ci} 973262306a36Sopenharmony_ci 973362306a36Sopenharmony_ci/** 973462306a36Sopenharmony_ci * t4_read_cimq_cfg - read CIM queue configuration 973562306a36Sopenharmony_ci * @adap: the adapter 973662306a36Sopenharmony_ci * @base: holds the queue base addresses in bytes 973762306a36Sopenharmony_ci * @size: holds the queue sizes in bytes 973862306a36Sopenharmony_ci * @thres: holds the queue full thresholds in bytes 973962306a36Sopenharmony_ci * 974062306a36Sopenharmony_ci * Returns the current configuration of the CIM queues, starting with 974162306a36Sopenharmony_ci * the IBQs, then the OBQs. 974262306a36Sopenharmony_ci */ 974362306a36Sopenharmony_civoid t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres) 974462306a36Sopenharmony_ci{ 974562306a36Sopenharmony_ci unsigned int i, v; 974662306a36Sopenharmony_ci int cim_num_obq = is_t4(adap->params.chip) ? 974762306a36Sopenharmony_ci CIM_NUM_OBQ : CIM_NUM_OBQ_T5; 974862306a36Sopenharmony_ci 974962306a36Sopenharmony_ci for (i = 0; i < CIM_NUM_IBQ; i++) { 975062306a36Sopenharmony_ci t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, IBQSELECT_F | 975162306a36Sopenharmony_ci QUENUMSELECT_V(i)); 975262306a36Sopenharmony_ci v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A); 975362306a36Sopenharmony_ci /* value is in 256-byte units */ 975462306a36Sopenharmony_ci *base++ = CIMQBASE_G(v) * 256; 975562306a36Sopenharmony_ci *size++ = CIMQSIZE_G(v) * 256; 975662306a36Sopenharmony_ci *thres++ = QUEFULLTHRSH_G(v) * 8; /* 8-byte unit */ 975762306a36Sopenharmony_ci } 975862306a36Sopenharmony_ci for (i = 0; i < cim_num_obq; i++) { 975962306a36Sopenharmony_ci t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, OBQSELECT_F | 976062306a36Sopenharmony_ci QUENUMSELECT_V(i)); 976162306a36Sopenharmony_ci v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A); 976262306a36Sopenharmony_ci /* value is in 256-byte units */ 976362306a36Sopenharmony_ci *base++ = CIMQBASE_G(v) * 256; 976462306a36Sopenharmony_ci *size++ = CIMQSIZE_G(v) * 256; 976562306a36Sopenharmony_ci } 976662306a36Sopenharmony_ci} 976762306a36Sopenharmony_ci 976862306a36Sopenharmony_ci/** 976962306a36Sopenharmony_ci * t4_read_cim_ibq - read the contents of a CIM inbound queue 977062306a36Sopenharmony_ci * @adap: the adapter 977162306a36Sopenharmony_ci * @qid: the queue index 977262306a36Sopenharmony_ci * @data: where to store the queue contents 977362306a36Sopenharmony_ci * @n: capacity of @data in 32-bit words 977462306a36Sopenharmony_ci * 977562306a36Sopenharmony_ci * Reads the contents of the selected CIM queue starting at address 0 up 977662306a36Sopenharmony_ci * to the capacity of @data. @n must be a multiple of 4. Returns < 0 on 977762306a36Sopenharmony_ci * error and the number of 32-bit words actually read on success. 977862306a36Sopenharmony_ci */ 977962306a36Sopenharmony_ciint t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data, size_t n) 978062306a36Sopenharmony_ci{ 978162306a36Sopenharmony_ci int i, err, attempts; 978262306a36Sopenharmony_ci unsigned int addr; 978362306a36Sopenharmony_ci const unsigned int nwords = CIM_IBQ_SIZE * 4; 978462306a36Sopenharmony_ci 978562306a36Sopenharmony_ci if (qid > 5 || (n & 3)) 978662306a36Sopenharmony_ci return -EINVAL; 978762306a36Sopenharmony_ci 978862306a36Sopenharmony_ci addr = qid * nwords; 978962306a36Sopenharmony_ci if (n > nwords) 979062306a36Sopenharmony_ci n = nwords; 979162306a36Sopenharmony_ci 979262306a36Sopenharmony_ci /* It might take 3-10ms before the IBQ debug read access is allowed. 979362306a36Sopenharmony_ci * Wait for 1 Sec with a delay of 1 usec. 979462306a36Sopenharmony_ci */ 979562306a36Sopenharmony_ci attempts = 1000000; 979662306a36Sopenharmony_ci 979762306a36Sopenharmony_ci for (i = 0; i < n; i++, addr++) { 979862306a36Sopenharmony_ci t4_write_reg(adap, CIM_IBQ_DBG_CFG_A, IBQDBGADDR_V(addr) | 979962306a36Sopenharmony_ci IBQDBGEN_F); 980062306a36Sopenharmony_ci err = t4_wait_op_done(adap, CIM_IBQ_DBG_CFG_A, IBQDBGBUSY_F, 0, 980162306a36Sopenharmony_ci attempts, 1); 980262306a36Sopenharmony_ci if (err) 980362306a36Sopenharmony_ci return err; 980462306a36Sopenharmony_ci *data++ = t4_read_reg(adap, CIM_IBQ_DBG_DATA_A); 980562306a36Sopenharmony_ci } 980662306a36Sopenharmony_ci t4_write_reg(adap, CIM_IBQ_DBG_CFG_A, 0); 980762306a36Sopenharmony_ci return i; 980862306a36Sopenharmony_ci} 980962306a36Sopenharmony_ci 981062306a36Sopenharmony_ci/** 981162306a36Sopenharmony_ci * t4_read_cim_obq - read the contents of a CIM outbound queue 981262306a36Sopenharmony_ci * @adap: the adapter 981362306a36Sopenharmony_ci * @qid: the queue index 981462306a36Sopenharmony_ci * @data: where to store the queue contents 981562306a36Sopenharmony_ci * @n: capacity of @data in 32-bit words 981662306a36Sopenharmony_ci * 981762306a36Sopenharmony_ci * Reads the contents of the selected CIM queue starting at address 0 up 981862306a36Sopenharmony_ci * to the capacity of @data. @n must be a multiple of 4. Returns < 0 on 981962306a36Sopenharmony_ci * error and the number of 32-bit words actually read on success. 982062306a36Sopenharmony_ci */ 982162306a36Sopenharmony_ciint t4_read_cim_obq(struct adapter *adap, unsigned int qid, u32 *data, size_t n) 982262306a36Sopenharmony_ci{ 982362306a36Sopenharmony_ci int i, err; 982462306a36Sopenharmony_ci unsigned int addr, v, nwords; 982562306a36Sopenharmony_ci int cim_num_obq = is_t4(adap->params.chip) ? 982662306a36Sopenharmony_ci CIM_NUM_OBQ : CIM_NUM_OBQ_T5; 982762306a36Sopenharmony_ci 982862306a36Sopenharmony_ci if ((qid > (cim_num_obq - 1)) || (n & 3)) 982962306a36Sopenharmony_ci return -EINVAL; 983062306a36Sopenharmony_ci 983162306a36Sopenharmony_ci t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, OBQSELECT_F | 983262306a36Sopenharmony_ci QUENUMSELECT_V(qid)); 983362306a36Sopenharmony_ci v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A); 983462306a36Sopenharmony_ci 983562306a36Sopenharmony_ci addr = CIMQBASE_G(v) * 64; /* muliple of 256 -> muliple of 4 */ 983662306a36Sopenharmony_ci nwords = CIMQSIZE_G(v) * 64; /* same */ 983762306a36Sopenharmony_ci if (n > nwords) 983862306a36Sopenharmony_ci n = nwords; 983962306a36Sopenharmony_ci 984062306a36Sopenharmony_ci for (i = 0; i < n; i++, addr++) { 984162306a36Sopenharmony_ci t4_write_reg(adap, CIM_OBQ_DBG_CFG_A, OBQDBGADDR_V(addr) | 984262306a36Sopenharmony_ci OBQDBGEN_F); 984362306a36Sopenharmony_ci err = t4_wait_op_done(adap, CIM_OBQ_DBG_CFG_A, OBQDBGBUSY_F, 0, 984462306a36Sopenharmony_ci 2, 1); 984562306a36Sopenharmony_ci if (err) 984662306a36Sopenharmony_ci return err; 984762306a36Sopenharmony_ci *data++ = t4_read_reg(adap, CIM_OBQ_DBG_DATA_A); 984862306a36Sopenharmony_ci } 984962306a36Sopenharmony_ci t4_write_reg(adap, CIM_OBQ_DBG_CFG_A, 0); 985062306a36Sopenharmony_ci return i; 985162306a36Sopenharmony_ci} 985262306a36Sopenharmony_ci 985362306a36Sopenharmony_ci/** 985462306a36Sopenharmony_ci * t4_cim_read - read a block from CIM internal address space 985562306a36Sopenharmony_ci * @adap: the adapter 985662306a36Sopenharmony_ci * @addr: the start address within the CIM address space 985762306a36Sopenharmony_ci * @n: number of words to read 985862306a36Sopenharmony_ci * @valp: where to store the result 985962306a36Sopenharmony_ci * 986062306a36Sopenharmony_ci * Reads a block of 4-byte words from the CIM intenal address space. 986162306a36Sopenharmony_ci */ 986262306a36Sopenharmony_ciint t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n, 986362306a36Sopenharmony_ci unsigned int *valp) 986462306a36Sopenharmony_ci{ 986562306a36Sopenharmony_ci int ret = 0; 986662306a36Sopenharmony_ci 986762306a36Sopenharmony_ci if (t4_read_reg(adap, CIM_HOST_ACC_CTRL_A) & HOSTBUSY_F) 986862306a36Sopenharmony_ci return -EBUSY; 986962306a36Sopenharmony_ci 987062306a36Sopenharmony_ci for ( ; !ret && n--; addr += 4) { 987162306a36Sopenharmony_ci t4_write_reg(adap, CIM_HOST_ACC_CTRL_A, addr); 987262306a36Sopenharmony_ci ret = t4_wait_op_done(adap, CIM_HOST_ACC_CTRL_A, HOSTBUSY_F, 987362306a36Sopenharmony_ci 0, 5, 2); 987462306a36Sopenharmony_ci if (!ret) 987562306a36Sopenharmony_ci *valp++ = t4_read_reg(adap, CIM_HOST_ACC_DATA_A); 987662306a36Sopenharmony_ci } 987762306a36Sopenharmony_ci return ret; 987862306a36Sopenharmony_ci} 987962306a36Sopenharmony_ci 988062306a36Sopenharmony_ci/** 988162306a36Sopenharmony_ci * t4_cim_write - write a block into CIM internal address space 988262306a36Sopenharmony_ci * @adap: the adapter 988362306a36Sopenharmony_ci * @addr: the start address within the CIM address space 988462306a36Sopenharmony_ci * @n: number of words to write 988562306a36Sopenharmony_ci * @valp: set of values to write 988662306a36Sopenharmony_ci * 988762306a36Sopenharmony_ci * Writes a block of 4-byte words into the CIM intenal address space. 988862306a36Sopenharmony_ci */ 988962306a36Sopenharmony_ciint t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n, 989062306a36Sopenharmony_ci const unsigned int *valp) 989162306a36Sopenharmony_ci{ 989262306a36Sopenharmony_ci int ret = 0; 989362306a36Sopenharmony_ci 989462306a36Sopenharmony_ci if (t4_read_reg(adap, CIM_HOST_ACC_CTRL_A) & HOSTBUSY_F) 989562306a36Sopenharmony_ci return -EBUSY; 989662306a36Sopenharmony_ci 989762306a36Sopenharmony_ci for ( ; !ret && n--; addr += 4) { 989862306a36Sopenharmony_ci t4_write_reg(adap, CIM_HOST_ACC_DATA_A, *valp++); 989962306a36Sopenharmony_ci t4_write_reg(adap, CIM_HOST_ACC_CTRL_A, addr | HOSTWRITE_F); 990062306a36Sopenharmony_ci ret = t4_wait_op_done(adap, CIM_HOST_ACC_CTRL_A, HOSTBUSY_F, 990162306a36Sopenharmony_ci 0, 5, 2); 990262306a36Sopenharmony_ci } 990362306a36Sopenharmony_ci return ret; 990462306a36Sopenharmony_ci} 990562306a36Sopenharmony_ci 990662306a36Sopenharmony_cistatic int t4_cim_write1(struct adapter *adap, unsigned int addr, 990762306a36Sopenharmony_ci unsigned int val) 990862306a36Sopenharmony_ci{ 990962306a36Sopenharmony_ci return t4_cim_write(adap, addr, 1, &val); 991062306a36Sopenharmony_ci} 991162306a36Sopenharmony_ci 991262306a36Sopenharmony_ci/** 991362306a36Sopenharmony_ci * t4_cim_read_la - read CIM LA capture buffer 991462306a36Sopenharmony_ci * @adap: the adapter 991562306a36Sopenharmony_ci * @la_buf: where to store the LA data 991662306a36Sopenharmony_ci * @wrptr: the HW write pointer within the capture buffer 991762306a36Sopenharmony_ci * 991862306a36Sopenharmony_ci * Reads the contents of the CIM LA buffer with the most recent entry at 991962306a36Sopenharmony_ci * the end of the returned data and with the entry at @wrptr first. 992062306a36Sopenharmony_ci * We try to leave the LA in the running state we find it in. 992162306a36Sopenharmony_ci */ 992262306a36Sopenharmony_ciint t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr) 992362306a36Sopenharmony_ci{ 992462306a36Sopenharmony_ci int i, ret; 992562306a36Sopenharmony_ci unsigned int cfg, val, idx; 992662306a36Sopenharmony_ci 992762306a36Sopenharmony_ci ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &cfg); 992862306a36Sopenharmony_ci if (ret) 992962306a36Sopenharmony_ci return ret; 993062306a36Sopenharmony_ci 993162306a36Sopenharmony_ci if (cfg & UPDBGLAEN_F) { /* LA is running, freeze it */ 993262306a36Sopenharmony_ci ret = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A, 0); 993362306a36Sopenharmony_ci if (ret) 993462306a36Sopenharmony_ci return ret; 993562306a36Sopenharmony_ci } 993662306a36Sopenharmony_ci 993762306a36Sopenharmony_ci ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &val); 993862306a36Sopenharmony_ci if (ret) 993962306a36Sopenharmony_ci goto restart; 994062306a36Sopenharmony_ci 994162306a36Sopenharmony_ci idx = UPDBGLAWRPTR_G(val); 994262306a36Sopenharmony_ci if (wrptr) 994362306a36Sopenharmony_ci *wrptr = idx; 994462306a36Sopenharmony_ci 994562306a36Sopenharmony_ci for (i = 0; i < adap->params.cim_la_size; i++) { 994662306a36Sopenharmony_ci ret = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A, 994762306a36Sopenharmony_ci UPDBGLARDPTR_V(idx) | UPDBGLARDEN_F); 994862306a36Sopenharmony_ci if (ret) 994962306a36Sopenharmony_ci break; 995062306a36Sopenharmony_ci ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &val); 995162306a36Sopenharmony_ci if (ret) 995262306a36Sopenharmony_ci break; 995362306a36Sopenharmony_ci if (val & UPDBGLARDEN_F) { 995462306a36Sopenharmony_ci ret = -ETIMEDOUT; 995562306a36Sopenharmony_ci break; 995662306a36Sopenharmony_ci } 995762306a36Sopenharmony_ci ret = t4_cim_read(adap, UP_UP_DBG_LA_DATA_A, 1, &la_buf[i]); 995862306a36Sopenharmony_ci if (ret) 995962306a36Sopenharmony_ci break; 996062306a36Sopenharmony_ci 996162306a36Sopenharmony_ci /* Bits 0-3 of UpDbgLaRdPtr can be between 0000 to 1001 to 996262306a36Sopenharmony_ci * identify the 32-bit portion of the full 312-bit data 996362306a36Sopenharmony_ci */ 996462306a36Sopenharmony_ci if (is_t6(adap->params.chip) && (idx & 0xf) >= 9) 996562306a36Sopenharmony_ci idx = (idx & 0xff0) + 0x10; 996662306a36Sopenharmony_ci else 996762306a36Sopenharmony_ci idx++; 996862306a36Sopenharmony_ci /* address can't exceed 0xfff */ 996962306a36Sopenharmony_ci idx &= UPDBGLARDPTR_M; 997062306a36Sopenharmony_ci } 997162306a36Sopenharmony_cirestart: 997262306a36Sopenharmony_ci if (cfg & UPDBGLAEN_F) { 997362306a36Sopenharmony_ci int r = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A, 997462306a36Sopenharmony_ci cfg & ~UPDBGLARDEN_F); 997562306a36Sopenharmony_ci if (!ret) 997662306a36Sopenharmony_ci ret = r; 997762306a36Sopenharmony_ci } 997862306a36Sopenharmony_ci return ret; 997962306a36Sopenharmony_ci} 998062306a36Sopenharmony_ci 998162306a36Sopenharmony_ci/** 998262306a36Sopenharmony_ci * t4_tp_read_la - read TP LA capture buffer 998362306a36Sopenharmony_ci * @adap: the adapter 998462306a36Sopenharmony_ci * @la_buf: where to store the LA data 998562306a36Sopenharmony_ci * @wrptr: the HW write pointer within the capture buffer 998662306a36Sopenharmony_ci * 998762306a36Sopenharmony_ci * Reads the contents of the TP LA buffer with the most recent entry at 998862306a36Sopenharmony_ci * the end of the returned data and with the entry at @wrptr first. 998962306a36Sopenharmony_ci * We leave the LA in the running state we find it in. 999062306a36Sopenharmony_ci */ 999162306a36Sopenharmony_civoid t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr) 999262306a36Sopenharmony_ci{ 999362306a36Sopenharmony_ci bool last_incomplete; 999462306a36Sopenharmony_ci unsigned int i, cfg, val, idx; 999562306a36Sopenharmony_ci 999662306a36Sopenharmony_ci cfg = t4_read_reg(adap, TP_DBG_LA_CONFIG_A) & 0xffff; 999762306a36Sopenharmony_ci if (cfg & DBGLAENABLE_F) /* freeze LA */ 999862306a36Sopenharmony_ci t4_write_reg(adap, TP_DBG_LA_CONFIG_A, 999962306a36Sopenharmony_ci adap->params.tp.la_mask | (cfg ^ DBGLAENABLE_F)); 1000062306a36Sopenharmony_ci 1000162306a36Sopenharmony_ci val = t4_read_reg(adap, TP_DBG_LA_CONFIG_A); 1000262306a36Sopenharmony_ci idx = DBGLAWPTR_G(val); 1000362306a36Sopenharmony_ci last_incomplete = DBGLAMODE_G(val) >= 2 && (val & DBGLAWHLF_F) == 0; 1000462306a36Sopenharmony_ci if (last_incomplete) 1000562306a36Sopenharmony_ci idx = (idx + 1) & DBGLARPTR_M; 1000662306a36Sopenharmony_ci if (wrptr) 1000762306a36Sopenharmony_ci *wrptr = idx; 1000862306a36Sopenharmony_ci 1000962306a36Sopenharmony_ci val &= 0xffff; 1001062306a36Sopenharmony_ci val &= ~DBGLARPTR_V(DBGLARPTR_M); 1001162306a36Sopenharmony_ci val |= adap->params.tp.la_mask; 1001262306a36Sopenharmony_ci 1001362306a36Sopenharmony_ci for (i = 0; i < TPLA_SIZE; i++) { 1001462306a36Sopenharmony_ci t4_write_reg(adap, TP_DBG_LA_CONFIG_A, DBGLARPTR_V(idx) | val); 1001562306a36Sopenharmony_ci la_buf[i] = t4_read_reg64(adap, TP_DBG_LA_DATAL_A); 1001662306a36Sopenharmony_ci idx = (idx + 1) & DBGLARPTR_M; 1001762306a36Sopenharmony_ci } 1001862306a36Sopenharmony_ci 1001962306a36Sopenharmony_ci /* Wipe out last entry if it isn't valid */ 1002062306a36Sopenharmony_ci if (last_incomplete) 1002162306a36Sopenharmony_ci la_buf[TPLA_SIZE - 1] = ~0ULL; 1002262306a36Sopenharmony_ci 1002362306a36Sopenharmony_ci if (cfg & DBGLAENABLE_F) /* restore running state */ 1002462306a36Sopenharmony_ci t4_write_reg(adap, TP_DBG_LA_CONFIG_A, 1002562306a36Sopenharmony_ci cfg | adap->params.tp.la_mask); 1002662306a36Sopenharmony_ci} 1002762306a36Sopenharmony_ci 1002862306a36Sopenharmony_ci/* SGE Hung Ingress DMA Warning Threshold time and Warning Repeat Rate (in 1002962306a36Sopenharmony_ci * seconds). If we find one of the SGE Ingress DMA State Machines in the same 1003062306a36Sopenharmony_ci * state for more than the Warning Threshold then we'll issue a warning about 1003162306a36Sopenharmony_ci * a potential hang. We'll repeat the warning as the SGE Ingress DMA Channel 1003262306a36Sopenharmony_ci * appears to be hung every Warning Repeat second till the situation clears. 1003362306a36Sopenharmony_ci * If the situation clears, we'll note that as well. 1003462306a36Sopenharmony_ci */ 1003562306a36Sopenharmony_ci#define SGE_IDMA_WARN_THRESH 1 1003662306a36Sopenharmony_ci#define SGE_IDMA_WARN_REPEAT 300 1003762306a36Sopenharmony_ci 1003862306a36Sopenharmony_ci/** 1003962306a36Sopenharmony_ci * t4_idma_monitor_init - initialize SGE Ingress DMA Monitor 1004062306a36Sopenharmony_ci * @adapter: the adapter 1004162306a36Sopenharmony_ci * @idma: the adapter IDMA Monitor state 1004262306a36Sopenharmony_ci * 1004362306a36Sopenharmony_ci * Initialize the state of an SGE Ingress DMA Monitor. 1004462306a36Sopenharmony_ci */ 1004562306a36Sopenharmony_civoid t4_idma_monitor_init(struct adapter *adapter, 1004662306a36Sopenharmony_ci struct sge_idma_monitor_state *idma) 1004762306a36Sopenharmony_ci{ 1004862306a36Sopenharmony_ci /* Initialize the state variables for detecting an SGE Ingress DMA 1004962306a36Sopenharmony_ci * hang. The SGE has internal counters which count up on each clock 1005062306a36Sopenharmony_ci * tick whenever the SGE finds its Ingress DMA State Engines in the 1005162306a36Sopenharmony_ci * same state they were on the previous clock tick. The clock used is 1005262306a36Sopenharmony_ci * the Core Clock so we have a limit on the maximum "time" they can 1005362306a36Sopenharmony_ci * record; typically a very small number of seconds. For instance, 1005462306a36Sopenharmony_ci * with a 600MHz Core Clock, we can only count up to a bit more than 1005562306a36Sopenharmony_ci * 7s. So we'll synthesize a larger counter in order to not run the 1005662306a36Sopenharmony_ci * risk of having the "timers" overflow and give us the flexibility to 1005762306a36Sopenharmony_ci * maintain a Hung SGE State Machine of our own which operates across 1005862306a36Sopenharmony_ci * a longer time frame. 1005962306a36Sopenharmony_ci */ 1006062306a36Sopenharmony_ci idma->idma_1s_thresh = core_ticks_per_usec(adapter) * 1000000; /* 1s */ 1006162306a36Sopenharmony_ci idma->idma_stalled[0] = 0; 1006262306a36Sopenharmony_ci idma->idma_stalled[1] = 0; 1006362306a36Sopenharmony_ci} 1006462306a36Sopenharmony_ci 1006562306a36Sopenharmony_ci/** 1006662306a36Sopenharmony_ci * t4_idma_monitor - monitor SGE Ingress DMA state 1006762306a36Sopenharmony_ci * @adapter: the adapter 1006862306a36Sopenharmony_ci * @idma: the adapter IDMA Monitor state 1006962306a36Sopenharmony_ci * @hz: number of ticks/second 1007062306a36Sopenharmony_ci * @ticks: number of ticks since the last IDMA Monitor call 1007162306a36Sopenharmony_ci */ 1007262306a36Sopenharmony_civoid t4_idma_monitor(struct adapter *adapter, 1007362306a36Sopenharmony_ci struct sge_idma_monitor_state *idma, 1007462306a36Sopenharmony_ci int hz, int ticks) 1007562306a36Sopenharmony_ci{ 1007662306a36Sopenharmony_ci int i, idma_same_state_cnt[2]; 1007762306a36Sopenharmony_ci 1007862306a36Sopenharmony_ci /* Read the SGE Debug Ingress DMA Same State Count registers. These 1007962306a36Sopenharmony_ci * are counters inside the SGE which count up on each clock when the 1008062306a36Sopenharmony_ci * SGE finds its Ingress DMA State Engines in the same states they 1008162306a36Sopenharmony_ci * were in the previous clock. The counters will peg out at 1008262306a36Sopenharmony_ci * 0xffffffff without wrapping around so once they pass the 1s 1008362306a36Sopenharmony_ci * threshold they'll stay above that till the IDMA state changes. 1008462306a36Sopenharmony_ci */ 1008562306a36Sopenharmony_ci t4_write_reg(adapter, SGE_DEBUG_INDEX_A, 13); 1008662306a36Sopenharmony_ci idma_same_state_cnt[0] = t4_read_reg(adapter, SGE_DEBUG_DATA_HIGH_A); 1008762306a36Sopenharmony_ci idma_same_state_cnt[1] = t4_read_reg(adapter, SGE_DEBUG_DATA_LOW_A); 1008862306a36Sopenharmony_ci 1008962306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 1009062306a36Sopenharmony_ci u32 debug0, debug11; 1009162306a36Sopenharmony_ci 1009262306a36Sopenharmony_ci /* If the Ingress DMA Same State Counter ("timer") is less 1009362306a36Sopenharmony_ci * than 1s, then we can reset our synthesized Stall Timer and 1009462306a36Sopenharmony_ci * continue. If we have previously emitted warnings about a 1009562306a36Sopenharmony_ci * potential stalled Ingress Queue, issue a note indicating 1009662306a36Sopenharmony_ci * that the Ingress Queue has resumed forward progress. 1009762306a36Sopenharmony_ci */ 1009862306a36Sopenharmony_ci if (idma_same_state_cnt[i] < idma->idma_1s_thresh) { 1009962306a36Sopenharmony_ci if (idma->idma_stalled[i] >= SGE_IDMA_WARN_THRESH * hz) 1010062306a36Sopenharmony_ci dev_warn(adapter->pdev_dev, "SGE idma%d, queue %u, " 1010162306a36Sopenharmony_ci "resumed after %d seconds\n", 1010262306a36Sopenharmony_ci i, idma->idma_qid[i], 1010362306a36Sopenharmony_ci idma->idma_stalled[i] / hz); 1010462306a36Sopenharmony_ci idma->idma_stalled[i] = 0; 1010562306a36Sopenharmony_ci continue; 1010662306a36Sopenharmony_ci } 1010762306a36Sopenharmony_ci 1010862306a36Sopenharmony_ci /* Synthesize an SGE Ingress DMA Same State Timer in the Hz 1010962306a36Sopenharmony_ci * domain. The first time we get here it'll be because we 1011062306a36Sopenharmony_ci * passed the 1s Threshold; each additional time it'll be 1011162306a36Sopenharmony_ci * because the RX Timer Callback is being fired on its regular 1011262306a36Sopenharmony_ci * schedule. 1011362306a36Sopenharmony_ci * 1011462306a36Sopenharmony_ci * If the stall is below our Potential Hung Ingress Queue 1011562306a36Sopenharmony_ci * Warning Threshold, continue. 1011662306a36Sopenharmony_ci */ 1011762306a36Sopenharmony_ci if (idma->idma_stalled[i] == 0) { 1011862306a36Sopenharmony_ci idma->idma_stalled[i] = hz; 1011962306a36Sopenharmony_ci idma->idma_warn[i] = 0; 1012062306a36Sopenharmony_ci } else { 1012162306a36Sopenharmony_ci idma->idma_stalled[i] += ticks; 1012262306a36Sopenharmony_ci idma->idma_warn[i] -= ticks; 1012362306a36Sopenharmony_ci } 1012462306a36Sopenharmony_ci 1012562306a36Sopenharmony_ci if (idma->idma_stalled[i] < SGE_IDMA_WARN_THRESH * hz) 1012662306a36Sopenharmony_ci continue; 1012762306a36Sopenharmony_ci 1012862306a36Sopenharmony_ci /* We'll issue a warning every SGE_IDMA_WARN_REPEAT seconds. 1012962306a36Sopenharmony_ci */ 1013062306a36Sopenharmony_ci if (idma->idma_warn[i] > 0) 1013162306a36Sopenharmony_ci continue; 1013262306a36Sopenharmony_ci idma->idma_warn[i] = SGE_IDMA_WARN_REPEAT * hz; 1013362306a36Sopenharmony_ci 1013462306a36Sopenharmony_ci /* Read and save the SGE IDMA State and Queue ID information. 1013562306a36Sopenharmony_ci * We do this every time in case it changes across time ... 1013662306a36Sopenharmony_ci * can't be too careful ... 1013762306a36Sopenharmony_ci */ 1013862306a36Sopenharmony_ci t4_write_reg(adapter, SGE_DEBUG_INDEX_A, 0); 1013962306a36Sopenharmony_ci debug0 = t4_read_reg(adapter, SGE_DEBUG_DATA_LOW_A); 1014062306a36Sopenharmony_ci idma->idma_state[i] = (debug0 >> (i * 9)) & 0x3f; 1014162306a36Sopenharmony_ci 1014262306a36Sopenharmony_ci t4_write_reg(adapter, SGE_DEBUG_INDEX_A, 11); 1014362306a36Sopenharmony_ci debug11 = t4_read_reg(adapter, SGE_DEBUG_DATA_LOW_A); 1014462306a36Sopenharmony_ci idma->idma_qid[i] = (debug11 >> (i * 16)) & 0xffff; 1014562306a36Sopenharmony_ci 1014662306a36Sopenharmony_ci dev_warn(adapter->pdev_dev, "SGE idma%u, queue %u, potentially stuck in " 1014762306a36Sopenharmony_ci "state %u for %d seconds (debug0=%#x, debug11=%#x)\n", 1014862306a36Sopenharmony_ci i, idma->idma_qid[i], idma->idma_state[i], 1014962306a36Sopenharmony_ci idma->idma_stalled[i] / hz, 1015062306a36Sopenharmony_ci debug0, debug11); 1015162306a36Sopenharmony_ci t4_sge_decode_idma_state(adapter, idma->idma_state[i]); 1015262306a36Sopenharmony_ci } 1015362306a36Sopenharmony_ci} 1015462306a36Sopenharmony_ci 1015562306a36Sopenharmony_ci/** 1015662306a36Sopenharmony_ci * t4_load_cfg - download config file 1015762306a36Sopenharmony_ci * @adap: the adapter 1015862306a36Sopenharmony_ci * @cfg_data: the cfg text file to write 1015962306a36Sopenharmony_ci * @size: text file size 1016062306a36Sopenharmony_ci * 1016162306a36Sopenharmony_ci * Write the supplied config text file to the card's serial flash. 1016262306a36Sopenharmony_ci */ 1016362306a36Sopenharmony_ciint t4_load_cfg(struct adapter *adap, const u8 *cfg_data, unsigned int size) 1016462306a36Sopenharmony_ci{ 1016562306a36Sopenharmony_ci int ret, i, n, cfg_addr; 1016662306a36Sopenharmony_ci unsigned int addr; 1016762306a36Sopenharmony_ci unsigned int flash_cfg_start_sec; 1016862306a36Sopenharmony_ci unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; 1016962306a36Sopenharmony_ci 1017062306a36Sopenharmony_ci cfg_addr = t4_flash_cfg_addr(adap); 1017162306a36Sopenharmony_ci if (cfg_addr < 0) 1017262306a36Sopenharmony_ci return cfg_addr; 1017362306a36Sopenharmony_ci 1017462306a36Sopenharmony_ci addr = cfg_addr; 1017562306a36Sopenharmony_ci flash_cfg_start_sec = addr / SF_SEC_SIZE; 1017662306a36Sopenharmony_ci 1017762306a36Sopenharmony_ci if (size > FLASH_CFG_MAX_SIZE) { 1017862306a36Sopenharmony_ci dev_err(adap->pdev_dev, "cfg file too large, max is %u bytes\n", 1017962306a36Sopenharmony_ci FLASH_CFG_MAX_SIZE); 1018062306a36Sopenharmony_ci return -EFBIG; 1018162306a36Sopenharmony_ci } 1018262306a36Sopenharmony_ci 1018362306a36Sopenharmony_ci i = DIV_ROUND_UP(FLASH_CFG_MAX_SIZE, /* # of sectors spanned */ 1018462306a36Sopenharmony_ci sf_sec_size); 1018562306a36Sopenharmony_ci ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec, 1018662306a36Sopenharmony_ci flash_cfg_start_sec + i - 1); 1018762306a36Sopenharmony_ci /* If size == 0 then we're simply erasing the FLASH sectors associated 1018862306a36Sopenharmony_ci * with the on-adapter Firmware Configuration File. 1018962306a36Sopenharmony_ci */ 1019062306a36Sopenharmony_ci if (ret || size == 0) 1019162306a36Sopenharmony_ci goto out; 1019262306a36Sopenharmony_ci 1019362306a36Sopenharmony_ci /* this will write to the flash up to SF_PAGE_SIZE at a time */ 1019462306a36Sopenharmony_ci for (i = 0; i < size; i += SF_PAGE_SIZE) { 1019562306a36Sopenharmony_ci if ((size - i) < SF_PAGE_SIZE) 1019662306a36Sopenharmony_ci n = size - i; 1019762306a36Sopenharmony_ci else 1019862306a36Sopenharmony_ci n = SF_PAGE_SIZE; 1019962306a36Sopenharmony_ci ret = t4_write_flash(adap, addr, n, cfg_data, true); 1020062306a36Sopenharmony_ci if (ret) 1020162306a36Sopenharmony_ci goto out; 1020262306a36Sopenharmony_ci 1020362306a36Sopenharmony_ci addr += SF_PAGE_SIZE; 1020462306a36Sopenharmony_ci cfg_data += SF_PAGE_SIZE; 1020562306a36Sopenharmony_ci } 1020662306a36Sopenharmony_ci 1020762306a36Sopenharmony_ciout: 1020862306a36Sopenharmony_ci if (ret) 1020962306a36Sopenharmony_ci dev_err(adap->pdev_dev, "config file %s failed %d\n", 1021062306a36Sopenharmony_ci (size == 0 ? "clear" : "download"), ret); 1021162306a36Sopenharmony_ci return ret; 1021262306a36Sopenharmony_ci} 1021362306a36Sopenharmony_ci 1021462306a36Sopenharmony_ci/** 1021562306a36Sopenharmony_ci * t4_set_vf_mac_acl - Set MAC address for the specified VF 1021662306a36Sopenharmony_ci * @adapter: The adapter 1021762306a36Sopenharmony_ci * @vf: one of the VFs instantiated by the specified PF 1021862306a36Sopenharmony_ci * @naddr: the number of MAC addresses 1021962306a36Sopenharmony_ci * @addr: the MAC address(es) to be set to the specified VF 1022062306a36Sopenharmony_ci */ 1022162306a36Sopenharmony_ciint t4_set_vf_mac_acl(struct adapter *adapter, unsigned int vf, 1022262306a36Sopenharmony_ci unsigned int naddr, u8 *addr) 1022362306a36Sopenharmony_ci{ 1022462306a36Sopenharmony_ci struct fw_acl_mac_cmd cmd; 1022562306a36Sopenharmony_ci 1022662306a36Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 1022762306a36Sopenharmony_ci cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_ACL_MAC_CMD) | 1022862306a36Sopenharmony_ci FW_CMD_REQUEST_F | 1022962306a36Sopenharmony_ci FW_CMD_WRITE_F | 1023062306a36Sopenharmony_ci FW_ACL_MAC_CMD_PFN_V(adapter->pf) | 1023162306a36Sopenharmony_ci FW_ACL_MAC_CMD_VFN_V(vf)); 1023262306a36Sopenharmony_ci 1023362306a36Sopenharmony_ci /* Note: Do not enable the ACL */ 1023462306a36Sopenharmony_ci cmd.en_to_len16 = cpu_to_be32((unsigned int)FW_LEN16(cmd)); 1023562306a36Sopenharmony_ci cmd.nmac = naddr; 1023662306a36Sopenharmony_ci 1023762306a36Sopenharmony_ci switch (adapter->pf) { 1023862306a36Sopenharmony_ci case 3: 1023962306a36Sopenharmony_ci memcpy(cmd.macaddr3, addr, sizeof(cmd.macaddr3)); 1024062306a36Sopenharmony_ci break; 1024162306a36Sopenharmony_ci case 2: 1024262306a36Sopenharmony_ci memcpy(cmd.macaddr2, addr, sizeof(cmd.macaddr2)); 1024362306a36Sopenharmony_ci break; 1024462306a36Sopenharmony_ci case 1: 1024562306a36Sopenharmony_ci memcpy(cmd.macaddr1, addr, sizeof(cmd.macaddr1)); 1024662306a36Sopenharmony_ci break; 1024762306a36Sopenharmony_ci case 0: 1024862306a36Sopenharmony_ci memcpy(cmd.macaddr0, addr, sizeof(cmd.macaddr0)); 1024962306a36Sopenharmony_ci break; 1025062306a36Sopenharmony_ci } 1025162306a36Sopenharmony_ci 1025262306a36Sopenharmony_ci return t4_wr_mbox(adapter, adapter->mbox, &cmd, sizeof(cmd), &cmd); 1025362306a36Sopenharmony_ci} 1025462306a36Sopenharmony_ci 1025562306a36Sopenharmony_ci/** 1025662306a36Sopenharmony_ci * t4_read_pace_tbl - read the pace table 1025762306a36Sopenharmony_ci * @adap: the adapter 1025862306a36Sopenharmony_ci * @pace_vals: holds the returned values 1025962306a36Sopenharmony_ci * 1026062306a36Sopenharmony_ci * Returns the values of TP's pace table in microseconds. 1026162306a36Sopenharmony_ci */ 1026262306a36Sopenharmony_civoid t4_read_pace_tbl(struct adapter *adap, unsigned int pace_vals[NTX_SCHED]) 1026362306a36Sopenharmony_ci{ 1026462306a36Sopenharmony_ci unsigned int i, v; 1026562306a36Sopenharmony_ci 1026662306a36Sopenharmony_ci for (i = 0; i < NTX_SCHED; i++) { 1026762306a36Sopenharmony_ci t4_write_reg(adap, TP_PACE_TABLE_A, 0xffff0000 + i); 1026862306a36Sopenharmony_ci v = t4_read_reg(adap, TP_PACE_TABLE_A); 1026962306a36Sopenharmony_ci pace_vals[i] = dack_ticks_to_usec(adap, v); 1027062306a36Sopenharmony_ci } 1027162306a36Sopenharmony_ci} 1027262306a36Sopenharmony_ci 1027362306a36Sopenharmony_ci/** 1027462306a36Sopenharmony_ci * t4_get_tx_sched - get the configuration of a Tx HW traffic scheduler 1027562306a36Sopenharmony_ci * @adap: the adapter 1027662306a36Sopenharmony_ci * @sched: the scheduler index 1027762306a36Sopenharmony_ci * @kbps: the byte rate in Kbps 1027862306a36Sopenharmony_ci * @ipg: the interpacket delay in tenths of nanoseconds 1027962306a36Sopenharmony_ci * @sleep_ok: if true we may sleep while awaiting command completion 1028062306a36Sopenharmony_ci * 1028162306a36Sopenharmony_ci * Return the current configuration of a HW Tx scheduler. 1028262306a36Sopenharmony_ci */ 1028362306a36Sopenharmony_civoid t4_get_tx_sched(struct adapter *adap, unsigned int sched, 1028462306a36Sopenharmony_ci unsigned int *kbps, unsigned int *ipg, bool sleep_ok) 1028562306a36Sopenharmony_ci{ 1028662306a36Sopenharmony_ci unsigned int v, addr, bpt, cpt; 1028762306a36Sopenharmony_ci 1028862306a36Sopenharmony_ci if (kbps) { 1028962306a36Sopenharmony_ci addr = TP_TX_MOD_Q1_Q0_RATE_LIMIT_A - sched / 2; 1029062306a36Sopenharmony_ci t4_tp_tm_pio_read(adap, &v, 1, addr, sleep_ok); 1029162306a36Sopenharmony_ci if (sched & 1) 1029262306a36Sopenharmony_ci v >>= 16; 1029362306a36Sopenharmony_ci bpt = (v >> 8) & 0xff; 1029462306a36Sopenharmony_ci cpt = v & 0xff; 1029562306a36Sopenharmony_ci if (!cpt) { 1029662306a36Sopenharmony_ci *kbps = 0; /* scheduler disabled */ 1029762306a36Sopenharmony_ci } else { 1029862306a36Sopenharmony_ci v = (adap->params.vpd.cclk * 1000) / cpt; /* ticks/s */ 1029962306a36Sopenharmony_ci *kbps = (v * bpt) / 125; 1030062306a36Sopenharmony_ci } 1030162306a36Sopenharmony_ci } 1030262306a36Sopenharmony_ci if (ipg) { 1030362306a36Sopenharmony_ci addr = TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR_A - sched / 2; 1030462306a36Sopenharmony_ci t4_tp_tm_pio_read(adap, &v, 1, addr, sleep_ok); 1030562306a36Sopenharmony_ci if (sched & 1) 1030662306a36Sopenharmony_ci v >>= 16; 1030762306a36Sopenharmony_ci v &= 0xffff; 1030862306a36Sopenharmony_ci *ipg = (10000 * v) / core_ticks_per_usec(adap); 1030962306a36Sopenharmony_ci } 1031062306a36Sopenharmony_ci} 1031162306a36Sopenharmony_ci 1031262306a36Sopenharmony_ci/* t4_sge_ctxt_rd - read an SGE context through FW 1031362306a36Sopenharmony_ci * @adap: the adapter 1031462306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 1031562306a36Sopenharmony_ci * @cid: the context id 1031662306a36Sopenharmony_ci * @ctype: the context type 1031762306a36Sopenharmony_ci * @data: where to store the context data 1031862306a36Sopenharmony_ci * 1031962306a36Sopenharmony_ci * Issues a FW command through the given mailbox to read an SGE context. 1032062306a36Sopenharmony_ci */ 1032162306a36Sopenharmony_ciint t4_sge_ctxt_rd(struct adapter *adap, unsigned int mbox, unsigned int cid, 1032262306a36Sopenharmony_ci enum ctxt_type ctype, u32 *data) 1032362306a36Sopenharmony_ci{ 1032462306a36Sopenharmony_ci struct fw_ldst_cmd c; 1032562306a36Sopenharmony_ci int ret; 1032662306a36Sopenharmony_ci 1032762306a36Sopenharmony_ci if (ctype == CTXT_FLM) 1032862306a36Sopenharmony_ci ret = FW_LDST_ADDRSPC_SGE_FLMC; 1032962306a36Sopenharmony_ci else 1033062306a36Sopenharmony_ci ret = FW_LDST_ADDRSPC_SGE_CONMC; 1033162306a36Sopenharmony_ci 1033262306a36Sopenharmony_ci memset(&c, 0, sizeof(c)); 1033362306a36Sopenharmony_ci c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) | 1033462306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_READ_F | 1033562306a36Sopenharmony_ci FW_LDST_CMD_ADDRSPACE_V(ret)); 1033662306a36Sopenharmony_ci c.cycles_to_len16 = cpu_to_be32(FW_LEN16(c)); 1033762306a36Sopenharmony_ci c.u.idctxt.physid = cpu_to_be32(cid); 1033862306a36Sopenharmony_ci 1033962306a36Sopenharmony_ci ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); 1034062306a36Sopenharmony_ci if (ret == 0) { 1034162306a36Sopenharmony_ci data[0] = be32_to_cpu(c.u.idctxt.ctxt_data0); 1034262306a36Sopenharmony_ci data[1] = be32_to_cpu(c.u.idctxt.ctxt_data1); 1034362306a36Sopenharmony_ci data[2] = be32_to_cpu(c.u.idctxt.ctxt_data2); 1034462306a36Sopenharmony_ci data[3] = be32_to_cpu(c.u.idctxt.ctxt_data3); 1034562306a36Sopenharmony_ci data[4] = be32_to_cpu(c.u.idctxt.ctxt_data4); 1034662306a36Sopenharmony_ci data[5] = be32_to_cpu(c.u.idctxt.ctxt_data5); 1034762306a36Sopenharmony_ci } 1034862306a36Sopenharmony_ci return ret; 1034962306a36Sopenharmony_ci} 1035062306a36Sopenharmony_ci 1035162306a36Sopenharmony_ci/** 1035262306a36Sopenharmony_ci * t4_sge_ctxt_rd_bd - read an SGE context bypassing FW 1035362306a36Sopenharmony_ci * @adap: the adapter 1035462306a36Sopenharmony_ci * @cid: the context id 1035562306a36Sopenharmony_ci * @ctype: the context type 1035662306a36Sopenharmony_ci * @data: where to store the context data 1035762306a36Sopenharmony_ci * 1035862306a36Sopenharmony_ci * Reads an SGE context directly, bypassing FW. This is only for 1035962306a36Sopenharmony_ci * debugging when FW is unavailable. 1036062306a36Sopenharmony_ci */ 1036162306a36Sopenharmony_ciint t4_sge_ctxt_rd_bd(struct adapter *adap, unsigned int cid, 1036262306a36Sopenharmony_ci enum ctxt_type ctype, u32 *data) 1036362306a36Sopenharmony_ci{ 1036462306a36Sopenharmony_ci int i, ret; 1036562306a36Sopenharmony_ci 1036662306a36Sopenharmony_ci t4_write_reg(adap, SGE_CTXT_CMD_A, CTXTQID_V(cid) | CTXTTYPE_V(ctype)); 1036762306a36Sopenharmony_ci ret = t4_wait_op_done(adap, SGE_CTXT_CMD_A, BUSY_F, 0, 3, 1); 1036862306a36Sopenharmony_ci if (!ret) 1036962306a36Sopenharmony_ci for (i = SGE_CTXT_DATA0_A; i <= SGE_CTXT_DATA5_A; i += 4) 1037062306a36Sopenharmony_ci *data++ = t4_read_reg(adap, i); 1037162306a36Sopenharmony_ci return ret; 1037262306a36Sopenharmony_ci} 1037362306a36Sopenharmony_ci 1037462306a36Sopenharmony_ciint t4_sched_params(struct adapter *adapter, u8 type, u8 level, u8 mode, 1037562306a36Sopenharmony_ci u8 rateunit, u8 ratemode, u8 channel, u8 class, 1037662306a36Sopenharmony_ci u32 minrate, u32 maxrate, u16 weight, u16 pktsize, 1037762306a36Sopenharmony_ci u16 burstsize) 1037862306a36Sopenharmony_ci{ 1037962306a36Sopenharmony_ci struct fw_sched_cmd cmd; 1038062306a36Sopenharmony_ci 1038162306a36Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 1038262306a36Sopenharmony_ci cmd.op_to_write = cpu_to_be32(FW_CMD_OP_V(FW_SCHED_CMD) | 1038362306a36Sopenharmony_ci FW_CMD_REQUEST_F | 1038462306a36Sopenharmony_ci FW_CMD_WRITE_F); 1038562306a36Sopenharmony_ci cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); 1038662306a36Sopenharmony_ci 1038762306a36Sopenharmony_ci cmd.u.params.sc = FW_SCHED_SC_PARAMS; 1038862306a36Sopenharmony_ci cmd.u.params.type = type; 1038962306a36Sopenharmony_ci cmd.u.params.level = level; 1039062306a36Sopenharmony_ci cmd.u.params.mode = mode; 1039162306a36Sopenharmony_ci cmd.u.params.ch = channel; 1039262306a36Sopenharmony_ci cmd.u.params.cl = class; 1039362306a36Sopenharmony_ci cmd.u.params.unit = rateunit; 1039462306a36Sopenharmony_ci cmd.u.params.rate = ratemode; 1039562306a36Sopenharmony_ci cmd.u.params.min = cpu_to_be32(minrate); 1039662306a36Sopenharmony_ci cmd.u.params.max = cpu_to_be32(maxrate); 1039762306a36Sopenharmony_ci cmd.u.params.weight = cpu_to_be16(weight); 1039862306a36Sopenharmony_ci cmd.u.params.pktsize = cpu_to_be16(pktsize); 1039962306a36Sopenharmony_ci cmd.u.params.burstsize = cpu_to_be16(burstsize); 1040062306a36Sopenharmony_ci 1040162306a36Sopenharmony_ci return t4_wr_mbox_meat(adapter, adapter->mbox, &cmd, sizeof(cmd), 1040262306a36Sopenharmony_ci NULL, 1); 1040362306a36Sopenharmony_ci} 1040462306a36Sopenharmony_ci 1040562306a36Sopenharmony_ci/** 1040662306a36Sopenharmony_ci * t4_i2c_rd - read I2C data from adapter 1040762306a36Sopenharmony_ci * @adap: the adapter 1040862306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 1040962306a36Sopenharmony_ci * @port: Port number if per-port device; <0 if not 1041062306a36Sopenharmony_ci * @devid: per-port device ID or absolute device ID 1041162306a36Sopenharmony_ci * @offset: byte offset into device I2C space 1041262306a36Sopenharmony_ci * @len: byte length of I2C space data 1041362306a36Sopenharmony_ci * @buf: buffer in which to return I2C data 1041462306a36Sopenharmony_ci * 1041562306a36Sopenharmony_ci * Reads the I2C data from the indicated device and location. 1041662306a36Sopenharmony_ci */ 1041762306a36Sopenharmony_ciint t4_i2c_rd(struct adapter *adap, unsigned int mbox, int port, 1041862306a36Sopenharmony_ci unsigned int devid, unsigned int offset, 1041962306a36Sopenharmony_ci unsigned int len, u8 *buf) 1042062306a36Sopenharmony_ci{ 1042162306a36Sopenharmony_ci struct fw_ldst_cmd ldst_cmd, ldst_rpl; 1042262306a36Sopenharmony_ci unsigned int i2c_max = sizeof(ldst_cmd.u.i2c.data); 1042362306a36Sopenharmony_ci int ret = 0; 1042462306a36Sopenharmony_ci 1042562306a36Sopenharmony_ci if (len > I2C_PAGE_SIZE) 1042662306a36Sopenharmony_ci return -EINVAL; 1042762306a36Sopenharmony_ci 1042862306a36Sopenharmony_ci /* Dont allow reads that spans multiple pages */ 1042962306a36Sopenharmony_ci if (offset < I2C_PAGE_SIZE && offset + len > I2C_PAGE_SIZE) 1043062306a36Sopenharmony_ci return -EINVAL; 1043162306a36Sopenharmony_ci 1043262306a36Sopenharmony_ci memset(&ldst_cmd, 0, sizeof(ldst_cmd)); 1043362306a36Sopenharmony_ci ldst_cmd.op_to_addrspace = 1043462306a36Sopenharmony_ci cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) | 1043562306a36Sopenharmony_ci FW_CMD_REQUEST_F | 1043662306a36Sopenharmony_ci FW_CMD_READ_F | 1043762306a36Sopenharmony_ci FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_I2C)); 1043862306a36Sopenharmony_ci ldst_cmd.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst_cmd)); 1043962306a36Sopenharmony_ci ldst_cmd.u.i2c.pid = (port < 0 ? 0xff : port); 1044062306a36Sopenharmony_ci ldst_cmd.u.i2c.did = devid; 1044162306a36Sopenharmony_ci 1044262306a36Sopenharmony_ci while (len > 0) { 1044362306a36Sopenharmony_ci unsigned int i2c_len = (len < i2c_max) ? len : i2c_max; 1044462306a36Sopenharmony_ci 1044562306a36Sopenharmony_ci ldst_cmd.u.i2c.boffset = offset; 1044662306a36Sopenharmony_ci ldst_cmd.u.i2c.blen = i2c_len; 1044762306a36Sopenharmony_ci 1044862306a36Sopenharmony_ci ret = t4_wr_mbox(adap, mbox, &ldst_cmd, sizeof(ldst_cmd), 1044962306a36Sopenharmony_ci &ldst_rpl); 1045062306a36Sopenharmony_ci if (ret) 1045162306a36Sopenharmony_ci break; 1045262306a36Sopenharmony_ci 1045362306a36Sopenharmony_ci memcpy(buf, ldst_rpl.u.i2c.data, i2c_len); 1045462306a36Sopenharmony_ci offset += i2c_len; 1045562306a36Sopenharmony_ci buf += i2c_len; 1045662306a36Sopenharmony_ci len -= i2c_len; 1045762306a36Sopenharmony_ci } 1045862306a36Sopenharmony_ci 1045962306a36Sopenharmony_ci return ret; 1046062306a36Sopenharmony_ci} 1046162306a36Sopenharmony_ci 1046262306a36Sopenharmony_ci/** 1046362306a36Sopenharmony_ci * t4_set_vlan_acl - Set a VLAN id for the specified VF 1046462306a36Sopenharmony_ci * @adap: the adapter 1046562306a36Sopenharmony_ci * @mbox: mailbox to use for the FW command 1046662306a36Sopenharmony_ci * @vf: one of the VFs instantiated by the specified PF 1046762306a36Sopenharmony_ci * @vlan: The vlanid to be set 1046862306a36Sopenharmony_ci */ 1046962306a36Sopenharmony_ciint t4_set_vlan_acl(struct adapter *adap, unsigned int mbox, unsigned int vf, 1047062306a36Sopenharmony_ci u16 vlan) 1047162306a36Sopenharmony_ci{ 1047262306a36Sopenharmony_ci struct fw_acl_vlan_cmd vlan_cmd; 1047362306a36Sopenharmony_ci unsigned int enable; 1047462306a36Sopenharmony_ci 1047562306a36Sopenharmony_ci enable = (vlan ? FW_ACL_VLAN_CMD_EN_F : 0); 1047662306a36Sopenharmony_ci memset(&vlan_cmd, 0, sizeof(vlan_cmd)); 1047762306a36Sopenharmony_ci vlan_cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_ACL_VLAN_CMD) | 1047862306a36Sopenharmony_ci FW_CMD_REQUEST_F | 1047962306a36Sopenharmony_ci FW_CMD_WRITE_F | 1048062306a36Sopenharmony_ci FW_CMD_EXEC_F | 1048162306a36Sopenharmony_ci FW_ACL_VLAN_CMD_PFN_V(adap->pf) | 1048262306a36Sopenharmony_ci FW_ACL_VLAN_CMD_VFN_V(vf)); 1048362306a36Sopenharmony_ci vlan_cmd.en_to_len16 = cpu_to_be32(enable | FW_LEN16(vlan_cmd)); 1048462306a36Sopenharmony_ci /* Drop all packets that donot match vlan id */ 1048562306a36Sopenharmony_ci vlan_cmd.dropnovlan_fm = (enable 1048662306a36Sopenharmony_ci ? (FW_ACL_VLAN_CMD_DROPNOVLAN_F | 1048762306a36Sopenharmony_ci FW_ACL_VLAN_CMD_FM_F) : 0); 1048862306a36Sopenharmony_ci if (enable != 0) { 1048962306a36Sopenharmony_ci vlan_cmd.nvlan = 1; 1049062306a36Sopenharmony_ci vlan_cmd.vlanid[0] = cpu_to_be16(vlan); 1049162306a36Sopenharmony_ci } 1049262306a36Sopenharmony_ci 1049362306a36Sopenharmony_ci return t4_wr_mbox(adap, adap->mbox, &vlan_cmd, sizeof(vlan_cmd), NULL); 1049462306a36Sopenharmony_ci} 1049562306a36Sopenharmony_ci 1049662306a36Sopenharmony_ci/** 1049762306a36Sopenharmony_ci * modify_device_id - Modifies the device ID of the Boot BIOS image 1049862306a36Sopenharmony_ci * @device_id: the device ID to write. 1049962306a36Sopenharmony_ci * @boot_data: the boot image to modify. 1050062306a36Sopenharmony_ci * 1050162306a36Sopenharmony_ci * Write the supplied device ID to the boot BIOS image. 1050262306a36Sopenharmony_ci */ 1050362306a36Sopenharmony_cistatic void modify_device_id(int device_id, u8 *boot_data) 1050462306a36Sopenharmony_ci{ 1050562306a36Sopenharmony_ci struct cxgb4_pcir_data *pcir_header; 1050662306a36Sopenharmony_ci struct legacy_pci_rom_hdr *header; 1050762306a36Sopenharmony_ci u8 *cur_header = boot_data; 1050862306a36Sopenharmony_ci u16 pcir_offset; 1050962306a36Sopenharmony_ci 1051062306a36Sopenharmony_ci /* Loop through all chained images and change the device ID's */ 1051162306a36Sopenharmony_ci do { 1051262306a36Sopenharmony_ci header = (struct legacy_pci_rom_hdr *)cur_header; 1051362306a36Sopenharmony_ci pcir_offset = le16_to_cpu(header->pcir_offset); 1051462306a36Sopenharmony_ci pcir_header = (struct cxgb4_pcir_data *)(cur_header + 1051562306a36Sopenharmony_ci pcir_offset); 1051662306a36Sopenharmony_ci 1051762306a36Sopenharmony_ci /** 1051862306a36Sopenharmony_ci * Only modify the Device ID if code type is Legacy or HP. 1051962306a36Sopenharmony_ci * 0x00: Okay to modify 1052062306a36Sopenharmony_ci * 0x01: FCODE. Do not modify 1052162306a36Sopenharmony_ci * 0x03: Okay to modify 1052262306a36Sopenharmony_ci * 0x04-0xFF: Do not modify 1052362306a36Sopenharmony_ci */ 1052462306a36Sopenharmony_ci if (pcir_header->code_type == CXGB4_HDR_CODE1) { 1052562306a36Sopenharmony_ci u8 csum = 0; 1052662306a36Sopenharmony_ci int i; 1052762306a36Sopenharmony_ci 1052862306a36Sopenharmony_ci /** 1052962306a36Sopenharmony_ci * Modify Device ID to match current adatper 1053062306a36Sopenharmony_ci */ 1053162306a36Sopenharmony_ci pcir_header->device_id = cpu_to_le16(device_id); 1053262306a36Sopenharmony_ci 1053362306a36Sopenharmony_ci /** 1053462306a36Sopenharmony_ci * Set checksum temporarily to 0. 1053562306a36Sopenharmony_ci * We will recalculate it later. 1053662306a36Sopenharmony_ci */ 1053762306a36Sopenharmony_ci header->cksum = 0x0; 1053862306a36Sopenharmony_ci 1053962306a36Sopenharmony_ci /** 1054062306a36Sopenharmony_ci * Calculate and update checksum 1054162306a36Sopenharmony_ci */ 1054262306a36Sopenharmony_ci for (i = 0; i < (header->size512 * 512); i++) 1054362306a36Sopenharmony_ci csum += cur_header[i]; 1054462306a36Sopenharmony_ci 1054562306a36Sopenharmony_ci /** 1054662306a36Sopenharmony_ci * Invert summed value to create the checksum 1054762306a36Sopenharmony_ci * Writing new checksum value directly to the boot data 1054862306a36Sopenharmony_ci */ 1054962306a36Sopenharmony_ci cur_header[7] = -csum; 1055062306a36Sopenharmony_ci 1055162306a36Sopenharmony_ci } else if (pcir_header->code_type == CXGB4_HDR_CODE2) { 1055262306a36Sopenharmony_ci /** 1055362306a36Sopenharmony_ci * Modify Device ID to match current adatper 1055462306a36Sopenharmony_ci */ 1055562306a36Sopenharmony_ci pcir_header->device_id = cpu_to_le16(device_id); 1055662306a36Sopenharmony_ci } 1055762306a36Sopenharmony_ci 1055862306a36Sopenharmony_ci /** 1055962306a36Sopenharmony_ci * Move header pointer up to the next image in the ROM. 1056062306a36Sopenharmony_ci */ 1056162306a36Sopenharmony_ci cur_header += header->size512 * 512; 1056262306a36Sopenharmony_ci } while (!(pcir_header->indicator & CXGB4_HDR_INDI)); 1056362306a36Sopenharmony_ci} 1056462306a36Sopenharmony_ci 1056562306a36Sopenharmony_ci/** 1056662306a36Sopenharmony_ci * t4_load_boot - download boot flash 1056762306a36Sopenharmony_ci * @adap: the adapter 1056862306a36Sopenharmony_ci * @boot_data: the boot image to write 1056962306a36Sopenharmony_ci * @boot_addr: offset in flash to write boot_data 1057062306a36Sopenharmony_ci * @size: image size 1057162306a36Sopenharmony_ci * 1057262306a36Sopenharmony_ci * Write the supplied boot image to the card's serial flash. 1057362306a36Sopenharmony_ci * The boot image has the following sections: a 28-byte header and the 1057462306a36Sopenharmony_ci * boot image. 1057562306a36Sopenharmony_ci */ 1057662306a36Sopenharmony_ciint t4_load_boot(struct adapter *adap, u8 *boot_data, 1057762306a36Sopenharmony_ci unsigned int boot_addr, unsigned int size) 1057862306a36Sopenharmony_ci{ 1057962306a36Sopenharmony_ci unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; 1058062306a36Sopenharmony_ci unsigned int boot_sector = (boot_addr * 1024); 1058162306a36Sopenharmony_ci struct cxgb4_pci_exp_rom_header *header; 1058262306a36Sopenharmony_ci struct cxgb4_pcir_data *pcir_header; 1058362306a36Sopenharmony_ci int pcir_offset; 1058462306a36Sopenharmony_ci unsigned int i; 1058562306a36Sopenharmony_ci u16 device_id; 1058662306a36Sopenharmony_ci int ret, addr; 1058762306a36Sopenharmony_ci 1058862306a36Sopenharmony_ci /** 1058962306a36Sopenharmony_ci * Make sure the boot image does not encroach on the firmware region 1059062306a36Sopenharmony_ci */ 1059162306a36Sopenharmony_ci if ((boot_sector + size) >> 16 > FLASH_FW_START_SEC) { 1059262306a36Sopenharmony_ci dev_err(adap->pdev_dev, "boot image encroaching on firmware region\n"); 1059362306a36Sopenharmony_ci return -EFBIG; 1059462306a36Sopenharmony_ci } 1059562306a36Sopenharmony_ci 1059662306a36Sopenharmony_ci /* Get boot header */ 1059762306a36Sopenharmony_ci header = (struct cxgb4_pci_exp_rom_header *)boot_data; 1059862306a36Sopenharmony_ci pcir_offset = le16_to_cpu(header->pcir_offset); 1059962306a36Sopenharmony_ci /* PCIR Data Structure */ 1060062306a36Sopenharmony_ci pcir_header = (struct cxgb4_pcir_data *)&boot_data[pcir_offset]; 1060162306a36Sopenharmony_ci 1060262306a36Sopenharmony_ci /** 1060362306a36Sopenharmony_ci * Perform some primitive sanity testing to avoid accidentally 1060462306a36Sopenharmony_ci * writing garbage over the boot sectors. We ought to check for 1060562306a36Sopenharmony_ci * more but it's not worth it for now ... 1060662306a36Sopenharmony_ci */ 1060762306a36Sopenharmony_ci if (size < BOOT_MIN_SIZE || size > BOOT_MAX_SIZE) { 1060862306a36Sopenharmony_ci dev_err(adap->pdev_dev, "boot image too small/large\n"); 1060962306a36Sopenharmony_ci return -EFBIG; 1061062306a36Sopenharmony_ci } 1061162306a36Sopenharmony_ci 1061262306a36Sopenharmony_ci if (le16_to_cpu(header->signature) != BOOT_SIGNATURE) { 1061362306a36Sopenharmony_ci dev_err(adap->pdev_dev, "Boot image missing signature\n"); 1061462306a36Sopenharmony_ci return -EINVAL; 1061562306a36Sopenharmony_ci } 1061662306a36Sopenharmony_ci 1061762306a36Sopenharmony_ci /* Check PCI header signature */ 1061862306a36Sopenharmony_ci if (le32_to_cpu(pcir_header->signature) != PCIR_SIGNATURE) { 1061962306a36Sopenharmony_ci dev_err(adap->pdev_dev, "PCI header missing signature\n"); 1062062306a36Sopenharmony_ci return -EINVAL; 1062162306a36Sopenharmony_ci } 1062262306a36Sopenharmony_ci 1062362306a36Sopenharmony_ci /* Check Vendor ID matches Chelsio ID*/ 1062462306a36Sopenharmony_ci if (le16_to_cpu(pcir_header->vendor_id) != PCI_VENDOR_ID_CHELSIO) { 1062562306a36Sopenharmony_ci dev_err(adap->pdev_dev, "Vendor ID missing signature\n"); 1062662306a36Sopenharmony_ci return -EINVAL; 1062762306a36Sopenharmony_ci } 1062862306a36Sopenharmony_ci 1062962306a36Sopenharmony_ci /** 1063062306a36Sopenharmony_ci * The boot sector is comprised of the Expansion-ROM boot, iSCSI boot, 1063162306a36Sopenharmony_ci * and Boot configuration data sections. These 3 boot sections span 1063262306a36Sopenharmony_ci * sectors 0 to 7 in flash and live right before the FW image location. 1063362306a36Sopenharmony_ci */ 1063462306a36Sopenharmony_ci i = DIV_ROUND_UP(size ? size : FLASH_FW_START, sf_sec_size); 1063562306a36Sopenharmony_ci ret = t4_flash_erase_sectors(adap, boot_sector >> 16, 1063662306a36Sopenharmony_ci (boot_sector >> 16) + i - 1); 1063762306a36Sopenharmony_ci 1063862306a36Sopenharmony_ci /** 1063962306a36Sopenharmony_ci * If size == 0 then we're simply erasing the FLASH sectors associated 1064062306a36Sopenharmony_ci * with the on-adapter option ROM file 1064162306a36Sopenharmony_ci */ 1064262306a36Sopenharmony_ci if (ret || size == 0) 1064362306a36Sopenharmony_ci goto out; 1064462306a36Sopenharmony_ci /* Retrieve adapter's device ID */ 1064562306a36Sopenharmony_ci pci_read_config_word(adap->pdev, PCI_DEVICE_ID, &device_id); 1064662306a36Sopenharmony_ci /* Want to deal with PF 0 so I strip off PF 4 indicator */ 1064762306a36Sopenharmony_ci device_id = device_id & 0xf0ff; 1064862306a36Sopenharmony_ci 1064962306a36Sopenharmony_ci /* Check PCIE Device ID */ 1065062306a36Sopenharmony_ci if (le16_to_cpu(pcir_header->device_id) != device_id) { 1065162306a36Sopenharmony_ci /** 1065262306a36Sopenharmony_ci * Change the device ID in the Boot BIOS image to match 1065362306a36Sopenharmony_ci * the Device ID of the current adapter. 1065462306a36Sopenharmony_ci */ 1065562306a36Sopenharmony_ci modify_device_id(device_id, boot_data); 1065662306a36Sopenharmony_ci } 1065762306a36Sopenharmony_ci 1065862306a36Sopenharmony_ci /** 1065962306a36Sopenharmony_ci * Skip over the first SF_PAGE_SIZE worth of data and write it after 1066062306a36Sopenharmony_ci * we finish copying the rest of the boot image. This will ensure 1066162306a36Sopenharmony_ci * that the BIOS boot header will only be written if the boot image 1066262306a36Sopenharmony_ci * was written in full. 1066362306a36Sopenharmony_ci */ 1066462306a36Sopenharmony_ci addr = boot_sector; 1066562306a36Sopenharmony_ci for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { 1066662306a36Sopenharmony_ci addr += SF_PAGE_SIZE; 1066762306a36Sopenharmony_ci boot_data += SF_PAGE_SIZE; 1066862306a36Sopenharmony_ci ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, boot_data, 1066962306a36Sopenharmony_ci false); 1067062306a36Sopenharmony_ci if (ret) 1067162306a36Sopenharmony_ci goto out; 1067262306a36Sopenharmony_ci } 1067362306a36Sopenharmony_ci 1067462306a36Sopenharmony_ci ret = t4_write_flash(adap, boot_sector, SF_PAGE_SIZE, 1067562306a36Sopenharmony_ci (const u8 *)header, false); 1067662306a36Sopenharmony_ci 1067762306a36Sopenharmony_ciout: 1067862306a36Sopenharmony_ci if (ret) 1067962306a36Sopenharmony_ci dev_err(adap->pdev_dev, "boot image load failed, error %d\n", 1068062306a36Sopenharmony_ci ret); 1068162306a36Sopenharmony_ci return ret; 1068262306a36Sopenharmony_ci} 1068362306a36Sopenharmony_ci 1068462306a36Sopenharmony_ci/** 1068562306a36Sopenharmony_ci * t4_flash_bootcfg_addr - return the address of the flash 1068662306a36Sopenharmony_ci * optionrom configuration 1068762306a36Sopenharmony_ci * @adapter: the adapter 1068862306a36Sopenharmony_ci * 1068962306a36Sopenharmony_ci * Return the address within the flash where the OptionROM Configuration 1069062306a36Sopenharmony_ci * is stored, or an error if the device FLASH is too small to contain 1069162306a36Sopenharmony_ci * a OptionROM Configuration. 1069262306a36Sopenharmony_ci */ 1069362306a36Sopenharmony_cistatic int t4_flash_bootcfg_addr(struct adapter *adapter) 1069462306a36Sopenharmony_ci{ 1069562306a36Sopenharmony_ci /** 1069662306a36Sopenharmony_ci * If the device FLASH isn't large enough to hold a Firmware 1069762306a36Sopenharmony_ci * Configuration File, return an error. 1069862306a36Sopenharmony_ci */ 1069962306a36Sopenharmony_ci if (adapter->params.sf_size < 1070062306a36Sopenharmony_ci FLASH_BOOTCFG_START + FLASH_BOOTCFG_MAX_SIZE) 1070162306a36Sopenharmony_ci return -ENOSPC; 1070262306a36Sopenharmony_ci 1070362306a36Sopenharmony_ci return FLASH_BOOTCFG_START; 1070462306a36Sopenharmony_ci} 1070562306a36Sopenharmony_ci 1070662306a36Sopenharmony_ciint t4_load_bootcfg(struct adapter *adap, const u8 *cfg_data, unsigned int size) 1070762306a36Sopenharmony_ci{ 1070862306a36Sopenharmony_ci unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; 1070962306a36Sopenharmony_ci struct cxgb4_bootcfg_data *header; 1071062306a36Sopenharmony_ci unsigned int flash_cfg_start_sec; 1071162306a36Sopenharmony_ci unsigned int addr, npad; 1071262306a36Sopenharmony_ci int ret, i, n, cfg_addr; 1071362306a36Sopenharmony_ci 1071462306a36Sopenharmony_ci cfg_addr = t4_flash_bootcfg_addr(adap); 1071562306a36Sopenharmony_ci if (cfg_addr < 0) 1071662306a36Sopenharmony_ci return cfg_addr; 1071762306a36Sopenharmony_ci 1071862306a36Sopenharmony_ci addr = cfg_addr; 1071962306a36Sopenharmony_ci flash_cfg_start_sec = addr / SF_SEC_SIZE; 1072062306a36Sopenharmony_ci 1072162306a36Sopenharmony_ci if (size > FLASH_BOOTCFG_MAX_SIZE) { 1072262306a36Sopenharmony_ci dev_err(adap->pdev_dev, "bootcfg file too large, max is %u bytes\n", 1072362306a36Sopenharmony_ci FLASH_BOOTCFG_MAX_SIZE); 1072462306a36Sopenharmony_ci return -EFBIG; 1072562306a36Sopenharmony_ci } 1072662306a36Sopenharmony_ci 1072762306a36Sopenharmony_ci header = (struct cxgb4_bootcfg_data *)cfg_data; 1072862306a36Sopenharmony_ci if (le16_to_cpu(header->signature) != BOOT_CFG_SIG) { 1072962306a36Sopenharmony_ci dev_err(adap->pdev_dev, "Wrong bootcfg signature\n"); 1073062306a36Sopenharmony_ci ret = -EINVAL; 1073162306a36Sopenharmony_ci goto out; 1073262306a36Sopenharmony_ci } 1073362306a36Sopenharmony_ci 1073462306a36Sopenharmony_ci i = DIV_ROUND_UP(FLASH_BOOTCFG_MAX_SIZE, 1073562306a36Sopenharmony_ci sf_sec_size); 1073662306a36Sopenharmony_ci ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec, 1073762306a36Sopenharmony_ci flash_cfg_start_sec + i - 1); 1073862306a36Sopenharmony_ci 1073962306a36Sopenharmony_ci /** 1074062306a36Sopenharmony_ci * If size == 0 then we're simply erasing the FLASH sectors associated 1074162306a36Sopenharmony_ci * with the on-adapter OptionROM Configuration File. 1074262306a36Sopenharmony_ci */ 1074362306a36Sopenharmony_ci if (ret || size == 0) 1074462306a36Sopenharmony_ci goto out; 1074562306a36Sopenharmony_ci 1074662306a36Sopenharmony_ci /* this will write to the flash up to SF_PAGE_SIZE at a time */ 1074762306a36Sopenharmony_ci for (i = 0; i < size; i += SF_PAGE_SIZE) { 1074862306a36Sopenharmony_ci n = min_t(u32, size - i, SF_PAGE_SIZE); 1074962306a36Sopenharmony_ci 1075062306a36Sopenharmony_ci ret = t4_write_flash(adap, addr, n, cfg_data, false); 1075162306a36Sopenharmony_ci if (ret) 1075262306a36Sopenharmony_ci goto out; 1075362306a36Sopenharmony_ci 1075462306a36Sopenharmony_ci addr += SF_PAGE_SIZE; 1075562306a36Sopenharmony_ci cfg_data += SF_PAGE_SIZE; 1075662306a36Sopenharmony_ci } 1075762306a36Sopenharmony_ci 1075862306a36Sopenharmony_ci npad = ((size + 4 - 1) & ~3) - size; 1075962306a36Sopenharmony_ci for (i = 0; i < npad; i++) { 1076062306a36Sopenharmony_ci u8 data = 0; 1076162306a36Sopenharmony_ci 1076262306a36Sopenharmony_ci ret = t4_write_flash(adap, cfg_addr + size + i, 1, &data, 1076362306a36Sopenharmony_ci false); 1076462306a36Sopenharmony_ci if (ret) 1076562306a36Sopenharmony_ci goto out; 1076662306a36Sopenharmony_ci } 1076762306a36Sopenharmony_ci 1076862306a36Sopenharmony_ciout: 1076962306a36Sopenharmony_ci if (ret) 1077062306a36Sopenharmony_ci dev_err(adap->pdev_dev, "boot config data %s failed %d\n", 1077162306a36Sopenharmony_ci (size == 0 ? "clear" : "download"), ret); 1077262306a36Sopenharmony_ci return ret; 1077362306a36Sopenharmony_ci} 10774