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			      &param, &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				 &param, &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				    &param, &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, &param, &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, &param, &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			      &param, &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, &param, &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