18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
58c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
118c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
128c2ecf20Sopenharmony_ci *     conditions are met:
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
158c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
168c2ecf20Sopenharmony_ci *        disclaimer.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
198c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
208c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
218c2ecf20Sopenharmony_ci *        provided with the distribution.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
308c2ecf20Sopenharmony_ci * SOFTWARE.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci#include "common.h"
338c2ecf20Sopenharmony_ci#include "regs.h"
348c2ecf20Sopenharmony_ci#include "sge_defs.h"
358c2ecf20Sopenharmony_ci#include "firmware_exports.h"
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic void t3_port_intr_clear(struct adapter *adapter, int idx);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/**
408c2ecf20Sopenharmony_ci *	t3_wait_op_done_val - wait until an operation is completed
418c2ecf20Sopenharmony_ci *	@adapter: the adapter performing the operation
428c2ecf20Sopenharmony_ci *	@reg: the register to check for completion
438c2ecf20Sopenharmony_ci *	@mask: a single-bit field within @reg that indicates completion
448c2ecf20Sopenharmony_ci *	@polarity: the value of the field when the operation is completed
458c2ecf20Sopenharmony_ci *	@attempts: number of check iterations
468c2ecf20Sopenharmony_ci *	@delay: delay in usecs between iterations
478c2ecf20Sopenharmony_ci *	@valp: where to store the value of the register at completion time
488c2ecf20Sopenharmony_ci *
498c2ecf20Sopenharmony_ci *	Wait until an operation is completed by checking a bit in a register
508c2ecf20Sopenharmony_ci *	up to @attempts times.  If @valp is not NULL the value of the register
518c2ecf20Sopenharmony_ci *	at the time it indicated completion is stored there.  Returns 0 if the
528c2ecf20Sopenharmony_ci *	operation completes and -EAGAIN otherwise.
538c2ecf20Sopenharmony_ci */
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ciint t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
568c2ecf20Sopenharmony_ci			int polarity, int attempts, int delay, u32 *valp)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	while (1) {
598c2ecf20Sopenharmony_ci		u32 val = t3_read_reg(adapter, reg);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci		if (!!(val & mask) == polarity) {
628c2ecf20Sopenharmony_ci			if (valp)
638c2ecf20Sopenharmony_ci				*valp = val;
648c2ecf20Sopenharmony_ci			return 0;
658c2ecf20Sopenharmony_ci		}
668c2ecf20Sopenharmony_ci		if (--attempts == 0)
678c2ecf20Sopenharmony_ci			return -EAGAIN;
688c2ecf20Sopenharmony_ci		if (delay)
698c2ecf20Sopenharmony_ci			udelay(delay);
708c2ecf20Sopenharmony_ci	}
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/**
748c2ecf20Sopenharmony_ci *	t3_write_regs - write a bunch of registers
758c2ecf20Sopenharmony_ci *	@adapter: the adapter to program
768c2ecf20Sopenharmony_ci *	@p: an array of register address/register value pairs
778c2ecf20Sopenharmony_ci *	@n: the number of address/value pairs
788c2ecf20Sopenharmony_ci *	@offset: register address offset
798c2ecf20Sopenharmony_ci *
808c2ecf20Sopenharmony_ci *	Takes an array of register address/register value pairs and writes each
818c2ecf20Sopenharmony_ci *	value to the corresponding register.  Register addresses are adjusted
828c2ecf20Sopenharmony_ci *	by the supplied offset.
838c2ecf20Sopenharmony_ci */
848c2ecf20Sopenharmony_civoid t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p,
858c2ecf20Sopenharmony_ci		   int n, unsigned int offset)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	while (n--) {
888c2ecf20Sopenharmony_ci		t3_write_reg(adapter, p->reg_addr + offset, p->val);
898c2ecf20Sopenharmony_ci		p++;
908c2ecf20Sopenharmony_ci	}
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci/**
948c2ecf20Sopenharmony_ci *	t3_set_reg_field - set a register field to a value
958c2ecf20Sopenharmony_ci *	@adapter: the adapter to program
968c2ecf20Sopenharmony_ci *	@addr: the register address
978c2ecf20Sopenharmony_ci *	@mask: specifies the portion of the register to modify
988c2ecf20Sopenharmony_ci *	@val: the new value for the register field
998c2ecf20Sopenharmony_ci *
1008c2ecf20Sopenharmony_ci *	Sets a register field specified by the supplied mask to the
1018c2ecf20Sopenharmony_ci *	given value.
1028c2ecf20Sopenharmony_ci */
1038c2ecf20Sopenharmony_civoid t3_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask,
1048c2ecf20Sopenharmony_ci		      u32 val)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	u32 v = t3_read_reg(adapter, addr) & ~mask;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	t3_write_reg(adapter, addr, v | val);
1098c2ecf20Sopenharmony_ci	t3_read_reg(adapter, addr);	/* flush */
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/**
1138c2ecf20Sopenharmony_ci *	t3_read_indirect - read indirectly addressed registers
1148c2ecf20Sopenharmony_ci *	@adap: the adapter
1158c2ecf20Sopenharmony_ci *	@addr_reg: register holding the indirect address
1168c2ecf20Sopenharmony_ci *	@data_reg: register holding the value of the indirect register
1178c2ecf20Sopenharmony_ci *	@vals: where the read register values are stored
1188c2ecf20Sopenharmony_ci *	@start_idx: index of first indirect register to read
1198c2ecf20Sopenharmony_ci *	@nregs: how many indirect registers to read
1208c2ecf20Sopenharmony_ci *
1218c2ecf20Sopenharmony_ci *	Reads registers that are accessed indirectly through an address/data
1228c2ecf20Sopenharmony_ci *	register pair.
1238c2ecf20Sopenharmony_ci */
1248c2ecf20Sopenharmony_cistatic void t3_read_indirect(struct adapter *adap, unsigned int addr_reg,
1258c2ecf20Sopenharmony_ci			     unsigned int data_reg, u32 *vals,
1268c2ecf20Sopenharmony_ci			     unsigned int nregs, unsigned int start_idx)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	while (nregs--) {
1298c2ecf20Sopenharmony_ci		t3_write_reg(adap, addr_reg, start_idx);
1308c2ecf20Sopenharmony_ci		*vals++ = t3_read_reg(adap, data_reg);
1318c2ecf20Sopenharmony_ci		start_idx++;
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci/**
1368c2ecf20Sopenharmony_ci *	t3_mc7_bd_read - read from MC7 through backdoor accesses
1378c2ecf20Sopenharmony_ci *	@mc7: identifies MC7 to read from
1388c2ecf20Sopenharmony_ci *	@start: index of first 64-bit word to read
1398c2ecf20Sopenharmony_ci *	@n: number of 64-bit words to read
1408c2ecf20Sopenharmony_ci *	@buf: where to store the read result
1418c2ecf20Sopenharmony_ci *
1428c2ecf20Sopenharmony_ci *	Read n 64-bit words from MC7 starting at word start, using backdoor
1438c2ecf20Sopenharmony_ci *	accesses.
1448c2ecf20Sopenharmony_ci */
1458c2ecf20Sopenharmony_ciint t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
1468c2ecf20Sopenharmony_ci		   u64 *buf)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	static const int shift[] = { 0, 0, 16, 24 };
1498c2ecf20Sopenharmony_ci	static const int step[] = { 0, 32, 16, 8 };
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	unsigned int size64 = mc7->size / 8;	/* # of 64-bit words */
1528c2ecf20Sopenharmony_ci	struct adapter *adap = mc7->adapter;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	if (start >= size64 || start + n > size64)
1558c2ecf20Sopenharmony_ci		return -EINVAL;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	start *= (8 << mc7->width);
1588c2ecf20Sopenharmony_ci	while (n--) {
1598c2ecf20Sopenharmony_ci		int i;
1608c2ecf20Sopenharmony_ci		u64 val64 = 0;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci		for (i = (1 << mc7->width) - 1; i >= 0; --i) {
1638c2ecf20Sopenharmony_ci			int attempts = 10;
1648c2ecf20Sopenharmony_ci			u32 val;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci			t3_write_reg(adap, mc7->offset + A_MC7_BD_ADDR, start);
1678c2ecf20Sopenharmony_ci			t3_write_reg(adap, mc7->offset + A_MC7_BD_OP, 0);
1688c2ecf20Sopenharmony_ci			val = t3_read_reg(adap, mc7->offset + A_MC7_BD_OP);
1698c2ecf20Sopenharmony_ci			while ((val & F_BUSY) && attempts--)
1708c2ecf20Sopenharmony_ci				val = t3_read_reg(adap,
1718c2ecf20Sopenharmony_ci						  mc7->offset + A_MC7_BD_OP);
1728c2ecf20Sopenharmony_ci			if (val & F_BUSY)
1738c2ecf20Sopenharmony_ci				return -EIO;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci			val = t3_read_reg(adap, mc7->offset + A_MC7_BD_DATA1);
1768c2ecf20Sopenharmony_ci			if (mc7->width == 0) {
1778c2ecf20Sopenharmony_ci				val64 = t3_read_reg(adap,
1788c2ecf20Sopenharmony_ci						    mc7->offset +
1798c2ecf20Sopenharmony_ci						    A_MC7_BD_DATA0);
1808c2ecf20Sopenharmony_ci				val64 |= (u64) val << 32;
1818c2ecf20Sopenharmony_ci			} else {
1828c2ecf20Sopenharmony_ci				if (mc7->width > 1)
1838c2ecf20Sopenharmony_ci					val >>= shift[mc7->width];
1848c2ecf20Sopenharmony_ci				val64 |= (u64) val << (step[mc7->width] * i);
1858c2ecf20Sopenharmony_ci			}
1868c2ecf20Sopenharmony_ci			start += 8;
1878c2ecf20Sopenharmony_ci		}
1888c2ecf20Sopenharmony_ci		*buf++ = val64;
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci	return 0;
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci/*
1948c2ecf20Sopenharmony_ci * Initialize MI1.
1958c2ecf20Sopenharmony_ci */
1968c2ecf20Sopenharmony_cistatic void mi1_init(struct adapter *adap, const struct adapter_info *ai)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1;
1998c2ecf20Sopenharmony_ci	u32 val = F_PREEN | V_CLKDIV(clkdiv);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_MI1_CFG, val);
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci#define MDIO_ATTEMPTS 20
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci/*
2078c2ecf20Sopenharmony_ci * MI1 read/write operations for clause 22 PHYs.
2088c2ecf20Sopenharmony_ci */
2098c2ecf20Sopenharmony_cistatic int t3_mi1_read(struct net_device *dev, int phy_addr, int mmd_addr,
2108c2ecf20Sopenharmony_ci		       u16 reg_addr)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
2138c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
2148c2ecf20Sopenharmony_ci	int ret;
2158c2ecf20Sopenharmony_ci	u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	mutex_lock(&adapter->mdio_lock);
2188c2ecf20Sopenharmony_ci	t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1));
2198c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_MI1_ADDR, addr);
2208c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2));
2218c2ecf20Sopenharmony_ci	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10);
2228c2ecf20Sopenharmony_ci	if (!ret)
2238c2ecf20Sopenharmony_ci		ret = t3_read_reg(adapter, A_MI1_DATA);
2248c2ecf20Sopenharmony_ci	mutex_unlock(&adapter->mdio_lock);
2258c2ecf20Sopenharmony_ci	return ret;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic int t3_mi1_write(struct net_device *dev, int phy_addr, int mmd_addr,
2298c2ecf20Sopenharmony_ci			u16 reg_addr, u16 val)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
2328c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
2338c2ecf20Sopenharmony_ci	int ret;
2348c2ecf20Sopenharmony_ci	u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	mutex_lock(&adapter->mdio_lock);
2378c2ecf20Sopenharmony_ci	t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1));
2388c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_MI1_ADDR, addr);
2398c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_MI1_DATA, val);
2408c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
2418c2ecf20Sopenharmony_ci	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10);
2428c2ecf20Sopenharmony_ci	mutex_unlock(&adapter->mdio_lock);
2438c2ecf20Sopenharmony_ci	return ret;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic const struct mdio_ops mi1_mdio_ops = {
2478c2ecf20Sopenharmony_ci	.read = t3_mi1_read,
2488c2ecf20Sopenharmony_ci	.write = t3_mi1_write,
2498c2ecf20Sopenharmony_ci	.mode_support = MDIO_SUPPORTS_C22
2508c2ecf20Sopenharmony_ci};
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci/*
2538c2ecf20Sopenharmony_ci * Performs the address cycle for clause 45 PHYs.
2548c2ecf20Sopenharmony_ci * Must be called with the MDIO_LOCK held.
2558c2ecf20Sopenharmony_ci */
2568c2ecf20Sopenharmony_cistatic int mi1_wr_addr(struct adapter *adapter, int phy_addr, int mmd_addr,
2578c2ecf20Sopenharmony_ci		       int reg_addr)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), 0);
2628c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_MI1_ADDR, addr);
2638c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_MI1_DATA, reg_addr);
2648c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
2658c2ecf20Sopenharmony_ci	return t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
2668c2ecf20Sopenharmony_ci			       MDIO_ATTEMPTS, 10);
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci/*
2708c2ecf20Sopenharmony_ci * MI1 read/write operations for indirect-addressed PHYs.
2718c2ecf20Sopenharmony_ci */
2728c2ecf20Sopenharmony_cistatic int mi1_ext_read(struct net_device *dev, int phy_addr, int mmd_addr,
2738c2ecf20Sopenharmony_ci			u16 reg_addr)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
2768c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
2778c2ecf20Sopenharmony_ci	int ret;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	mutex_lock(&adapter->mdio_lock);
2808c2ecf20Sopenharmony_ci	ret = mi1_wr_addr(adapter, phy_addr, mmd_addr, reg_addr);
2818c2ecf20Sopenharmony_ci	if (!ret) {
2828c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3));
2838c2ecf20Sopenharmony_ci		ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
2848c2ecf20Sopenharmony_ci				      MDIO_ATTEMPTS, 10);
2858c2ecf20Sopenharmony_ci		if (!ret)
2868c2ecf20Sopenharmony_ci			ret = t3_read_reg(adapter, A_MI1_DATA);
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci	mutex_unlock(&adapter->mdio_lock);
2898c2ecf20Sopenharmony_ci	return ret;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic int mi1_ext_write(struct net_device *dev, int phy_addr, int mmd_addr,
2938c2ecf20Sopenharmony_ci			 u16 reg_addr, u16 val)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
2968c2ecf20Sopenharmony_ci	struct adapter *adapter = pi->adapter;
2978c2ecf20Sopenharmony_ci	int ret;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	mutex_lock(&adapter->mdio_lock);
3008c2ecf20Sopenharmony_ci	ret = mi1_wr_addr(adapter, phy_addr, mmd_addr, reg_addr);
3018c2ecf20Sopenharmony_ci	if (!ret) {
3028c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_MI1_DATA, val);
3038c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
3048c2ecf20Sopenharmony_ci		ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
3058c2ecf20Sopenharmony_ci				      MDIO_ATTEMPTS, 10);
3068c2ecf20Sopenharmony_ci	}
3078c2ecf20Sopenharmony_ci	mutex_unlock(&adapter->mdio_lock);
3088c2ecf20Sopenharmony_ci	return ret;
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic const struct mdio_ops mi1_mdio_ext_ops = {
3128c2ecf20Sopenharmony_ci	.read = mi1_ext_read,
3138c2ecf20Sopenharmony_ci	.write = mi1_ext_write,
3148c2ecf20Sopenharmony_ci	.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22
3158c2ecf20Sopenharmony_ci};
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci/**
3188c2ecf20Sopenharmony_ci *	t3_mdio_change_bits - modify the value of a PHY register
3198c2ecf20Sopenharmony_ci *	@phy: the PHY to operate on
3208c2ecf20Sopenharmony_ci *	@mmd: the device address
3218c2ecf20Sopenharmony_ci *	@reg: the register address
3228c2ecf20Sopenharmony_ci *	@clear: what part of the register value to mask off
3238c2ecf20Sopenharmony_ci *	@set: what part of the register value to set
3248c2ecf20Sopenharmony_ci *
3258c2ecf20Sopenharmony_ci *	Changes the value of a PHY register by applying a mask to its current
3268c2ecf20Sopenharmony_ci *	value and ORing the result with a new value.
3278c2ecf20Sopenharmony_ci */
3288c2ecf20Sopenharmony_ciint t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear,
3298c2ecf20Sopenharmony_ci			unsigned int set)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	int ret;
3328c2ecf20Sopenharmony_ci	unsigned int val;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	ret = t3_mdio_read(phy, mmd, reg, &val);
3358c2ecf20Sopenharmony_ci	if (!ret) {
3368c2ecf20Sopenharmony_ci		val &= ~clear;
3378c2ecf20Sopenharmony_ci		ret = t3_mdio_write(phy, mmd, reg, val | set);
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci	return ret;
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci/**
3438c2ecf20Sopenharmony_ci *	t3_phy_reset - reset a PHY block
3448c2ecf20Sopenharmony_ci *	@phy: the PHY to operate on
3458c2ecf20Sopenharmony_ci *	@mmd: the device address of the PHY block to reset
3468c2ecf20Sopenharmony_ci *	@wait: how long to wait for the reset to complete in 1ms increments
3478c2ecf20Sopenharmony_ci *
3488c2ecf20Sopenharmony_ci *	Resets a PHY block and optionally waits for the reset to complete.
3498c2ecf20Sopenharmony_ci *	@mmd should be 0 for 10/100/1000 PHYs and the device address to reset
3508c2ecf20Sopenharmony_ci *	for 10G PHYs.
3518c2ecf20Sopenharmony_ci */
3528c2ecf20Sopenharmony_ciint t3_phy_reset(struct cphy *phy, int mmd, int wait)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	int err;
3558c2ecf20Sopenharmony_ci	unsigned int ctl;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	err = t3_mdio_change_bits(phy, mmd, MDIO_CTRL1, MDIO_CTRL1_LPOWER,
3588c2ecf20Sopenharmony_ci				  MDIO_CTRL1_RESET);
3598c2ecf20Sopenharmony_ci	if (err || !wait)
3608c2ecf20Sopenharmony_ci		return err;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	do {
3638c2ecf20Sopenharmony_ci		err = t3_mdio_read(phy, mmd, MDIO_CTRL1, &ctl);
3648c2ecf20Sopenharmony_ci		if (err)
3658c2ecf20Sopenharmony_ci			return err;
3668c2ecf20Sopenharmony_ci		ctl &= MDIO_CTRL1_RESET;
3678c2ecf20Sopenharmony_ci		if (ctl)
3688c2ecf20Sopenharmony_ci			msleep(1);
3698c2ecf20Sopenharmony_ci	} while (ctl && --wait);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	return ctl ? -1 : 0;
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci/**
3758c2ecf20Sopenharmony_ci *	t3_phy_advertise - set the PHY advertisement registers for autoneg
3768c2ecf20Sopenharmony_ci *	@phy: the PHY to operate on
3778c2ecf20Sopenharmony_ci *	@advert: bitmap of capabilities the PHY should advertise
3788c2ecf20Sopenharmony_ci *
3798c2ecf20Sopenharmony_ci *	Sets a 10/100/1000 PHY's advertisement registers to advertise the
3808c2ecf20Sopenharmony_ci *	requested capabilities.
3818c2ecf20Sopenharmony_ci */
3828c2ecf20Sopenharmony_ciint t3_phy_advertise(struct cphy *phy, unsigned int advert)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	int err;
3858c2ecf20Sopenharmony_ci	unsigned int val = 0;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	err = t3_mdio_read(phy, MDIO_DEVAD_NONE, MII_CTRL1000, &val);
3888c2ecf20Sopenharmony_ci	if (err)
3898c2ecf20Sopenharmony_ci		return err;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
3928c2ecf20Sopenharmony_ci	if (advert & ADVERTISED_1000baseT_Half)
3938c2ecf20Sopenharmony_ci		val |= ADVERTISE_1000HALF;
3948c2ecf20Sopenharmony_ci	if (advert & ADVERTISED_1000baseT_Full)
3958c2ecf20Sopenharmony_ci		val |= ADVERTISE_1000FULL;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	err = t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_CTRL1000, val);
3988c2ecf20Sopenharmony_ci	if (err)
3998c2ecf20Sopenharmony_ci		return err;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	val = 1;
4028c2ecf20Sopenharmony_ci	if (advert & ADVERTISED_10baseT_Half)
4038c2ecf20Sopenharmony_ci		val |= ADVERTISE_10HALF;
4048c2ecf20Sopenharmony_ci	if (advert & ADVERTISED_10baseT_Full)
4058c2ecf20Sopenharmony_ci		val |= ADVERTISE_10FULL;
4068c2ecf20Sopenharmony_ci	if (advert & ADVERTISED_100baseT_Half)
4078c2ecf20Sopenharmony_ci		val |= ADVERTISE_100HALF;
4088c2ecf20Sopenharmony_ci	if (advert & ADVERTISED_100baseT_Full)
4098c2ecf20Sopenharmony_ci		val |= ADVERTISE_100FULL;
4108c2ecf20Sopenharmony_ci	if (advert & ADVERTISED_Pause)
4118c2ecf20Sopenharmony_ci		val |= ADVERTISE_PAUSE_CAP;
4128c2ecf20Sopenharmony_ci	if (advert & ADVERTISED_Asym_Pause)
4138c2ecf20Sopenharmony_ci		val |= ADVERTISE_PAUSE_ASYM;
4148c2ecf20Sopenharmony_ci	return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_ADVERTISE, val);
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci/**
4188c2ecf20Sopenharmony_ci *	t3_phy_advertise_fiber - set fiber PHY advertisement register
4198c2ecf20Sopenharmony_ci *	@phy: the PHY to operate on
4208c2ecf20Sopenharmony_ci *	@advert: bitmap of capabilities the PHY should advertise
4218c2ecf20Sopenharmony_ci *
4228c2ecf20Sopenharmony_ci *	Sets a fiber PHY's advertisement register to advertise the
4238c2ecf20Sopenharmony_ci *	requested capabilities.
4248c2ecf20Sopenharmony_ci */
4258c2ecf20Sopenharmony_ciint t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	unsigned int val = 0;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	if (advert & ADVERTISED_1000baseT_Half)
4308c2ecf20Sopenharmony_ci		val |= ADVERTISE_1000XHALF;
4318c2ecf20Sopenharmony_ci	if (advert & ADVERTISED_1000baseT_Full)
4328c2ecf20Sopenharmony_ci		val |= ADVERTISE_1000XFULL;
4338c2ecf20Sopenharmony_ci	if (advert & ADVERTISED_Pause)
4348c2ecf20Sopenharmony_ci		val |= ADVERTISE_1000XPAUSE;
4358c2ecf20Sopenharmony_ci	if (advert & ADVERTISED_Asym_Pause)
4368c2ecf20Sopenharmony_ci		val |= ADVERTISE_1000XPSE_ASYM;
4378c2ecf20Sopenharmony_ci	return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_ADVERTISE, val);
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci/**
4418c2ecf20Sopenharmony_ci *	t3_set_phy_speed_duplex - force PHY speed and duplex
4428c2ecf20Sopenharmony_ci *	@phy: the PHY to operate on
4438c2ecf20Sopenharmony_ci *	@speed: requested PHY speed
4448c2ecf20Sopenharmony_ci *	@duplex: requested PHY duplex
4458c2ecf20Sopenharmony_ci *
4468c2ecf20Sopenharmony_ci *	Force a 10/100/1000 PHY's speed and duplex.  This also disables
4478c2ecf20Sopenharmony_ci *	auto-negotiation except for GigE, where auto-negotiation is mandatory.
4488c2ecf20Sopenharmony_ci */
4498c2ecf20Sopenharmony_ciint t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	int err;
4528c2ecf20Sopenharmony_ci	unsigned int ctl;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	err = t3_mdio_read(phy, MDIO_DEVAD_NONE, MII_BMCR, &ctl);
4558c2ecf20Sopenharmony_ci	if (err)
4568c2ecf20Sopenharmony_ci		return err;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	if (speed >= 0) {
4598c2ecf20Sopenharmony_ci		ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
4608c2ecf20Sopenharmony_ci		if (speed == SPEED_100)
4618c2ecf20Sopenharmony_ci			ctl |= BMCR_SPEED100;
4628c2ecf20Sopenharmony_ci		else if (speed == SPEED_1000)
4638c2ecf20Sopenharmony_ci			ctl |= BMCR_SPEED1000;
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci	if (duplex >= 0) {
4668c2ecf20Sopenharmony_ci		ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
4678c2ecf20Sopenharmony_ci		if (duplex == DUPLEX_FULL)
4688c2ecf20Sopenharmony_ci			ctl |= BMCR_FULLDPLX;
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci	if (ctl & BMCR_SPEED1000) /* auto-negotiation required for GigE */
4718c2ecf20Sopenharmony_ci		ctl |= BMCR_ANENABLE;
4728c2ecf20Sopenharmony_ci	return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_BMCR, ctl);
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ciint t3_phy_lasi_intr_enable(struct cphy *phy)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	return t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL,
4788c2ecf20Sopenharmony_ci			     MDIO_PMA_LASI_LSALARM);
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ciint t3_phy_lasi_intr_disable(struct cphy *phy)
4828c2ecf20Sopenharmony_ci{
4838c2ecf20Sopenharmony_ci	return t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, 0);
4848c2ecf20Sopenharmony_ci}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ciint t3_phy_lasi_intr_clear(struct cphy *phy)
4878c2ecf20Sopenharmony_ci{
4888c2ecf20Sopenharmony_ci	u32 val;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	return t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val);
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ciint t3_phy_lasi_intr_handler(struct cphy *phy)
4948c2ecf20Sopenharmony_ci{
4958c2ecf20Sopenharmony_ci	unsigned int status;
4968c2ecf20Sopenharmony_ci	int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT,
4978c2ecf20Sopenharmony_ci			       &status);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (err)
5008c2ecf20Sopenharmony_ci		return err;
5018c2ecf20Sopenharmony_ci	return (status & MDIO_PMA_LASI_LSALARM) ? cphy_cause_link_change : 0;
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic const struct adapter_info t3_adap_info[] = {
5058c2ecf20Sopenharmony_ci	{1, 1, 0,
5068c2ecf20Sopenharmony_ci	 F_GPIO2_OEN | F_GPIO4_OEN |
5078c2ecf20Sopenharmony_ci	 F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0,
5088c2ecf20Sopenharmony_ci	 &mi1_mdio_ops, "Chelsio PE9000"},
5098c2ecf20Sopenharmony_ci	{1, 1, 0,
5108c2ecf20Sopenharmony_ci	 F_GPIO2_OEN | F_GPIO4_OEN |
5118c2ecf20Sopenharmony_ci	 F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0,
5128c2ecf20Sopenharmony_ci	 &mi1_mdio_ops, "Chelsio T302"},
5138c2ecf20Sopenharmony_ci	{1, 0, 0,
5148c2ecf20Sopenharmony_ci	 F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN |
5158c2ecf20Sopenharmony_ci	 F_GPIO11_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
5168c2ecf20Sopenharmony_ci	 { 0 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
5178c2ecf20Sopenharmony_ci	 &mi1_mdio_ext_ops, "Chelsio T310"},
5188c2ecf20Sopenharmony_ci	{1, 1, 0,
5198c2ecf20Sopenharmony_ci	 F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN |
5208c2ecf20Sopenharmony_ci	 F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL |
5218c2ecf20Sopenharmony_ci	 F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
5228c2ecf20Sopenharmony_ci	 { S_GPIO9, S_GPIO3 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
5238c2ecf20Sopenharmony_ci	 &mi1_mdio_ext_ops, "Chelsio T320"},
5248c2ecf20Sopenharmony_ci	{},
5258c2ecf20Sopenharmony_ci	{},
5268c2ecf20Sopenharmony_ci	{1, 0, 0,
5278c2ecf20Sopenharmony_ci	 F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO6_OEN | F_GPIO7_OEN |
5288c2ecf20Sopenharmony_ci	 F_GPIO10_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
5298c2ecf20Sopenharmony_ci	 { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
5308c2ecf20Sopenharmony_ci	 &mi1_mdio_ext_ops, "Chelsio T310" },
5318c2ecf20Sopenharmony_ci	{1, 0, 0,
5328c2ecf20Sopenharmony_ci	 F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN |
5338c2ecf20Sopenharmony_ci	 F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL,
5348c2ecf20Sopenharmony_ci	 { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
5358c2ecf20Sopenharmony_ci	 &mi1_mdio_ext_ops, "Chelsio N320E-G2" },
5368c2ecf20Sopenharmony_ci};
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci/*
5398c2ecf20Sopenharmony_ci * Return the adapter_info structure with a given index.  Out-of-range indices
5408c2ecf20Sopenharmony_ci * return NULL.
5418c2ecf20Sopenharmony_ci */
5428c2ecf20Sopenharmony_ciconst struct adapter_info *t3_get_adapter_info(unsigned int id)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL;
5458c2ecf20Sopenharmony_ci}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_cistruct port_type_info {
5488c2ecf20Sopenharmony_ci	int (*phy_prep)(struct cphy *phy, struct adapter *adapter,
5498c2ecf20Sopenharmony_ci			int phy_addr, const struct mdio_ops *ops);
5508c2ecf20Sopenharmony_ci};
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_cistatic const struct port_type_info port_types[] = {
5538c2ecf20Sopenharmony_ci	{ NULL },
5548c2ecf20Sopenharmony_ci	{ t3_ael1002_phy_prep },
5558c2ecf20Sopenharmony_ci	{ t3_vsc8211_phy_prep },
5568c2ecf20Sopenharmony_ci	{ NULL},
5578c2ecf20Sopenharmony_ci	{ t3_xaui_direct_phy_prep },
5588c2ecf20Sopenharmony_ci	{ t3_ael2005_phy_prep },
5598c2ecf20Sopenharmony_ci	{ t3_qt2045_phy_prep },
5608c2ecf20Sopenharmony_ci	{ t3_ael1006_phy_prep },
5618c2ecf20Sopenharmony_ci	{ NULL },
5628c2ecf20Sopenharmony_ci	{ t3_aq100x_phy_prep },
5638c2ecf20Sopenharmony_ci	{ t3_ael2020_phy_prep },
5648c2ecf20Sopenharmony_ci};
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci#define VPD_ENTRY(name, len) \
5678c2ecf20Sopenharmony_ci	u8 name##_kword[2]; u8 name##_len; u8 name##_data[len]
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci/*
5708c2ecf20Sopenharmony_ci * Partial EEPROM Vital Product Data structure.  Includes only the ID and
5718c2ecf20Sopenharmony_ci * VPD-R sections.
5728c2ecf20Sopenharmony_ci */
5738c2ecf20Sopenharmony_cistruct t3_vpd {
5748c2ecf20Sopenharmony_ci	u8 id_tag;
5758c2ecf20Sopenharmony_ci	u8 id_len[2];
5768c2ecf20Sopenharmony_ci	u8 id_data[16];
5778c2ecf20Sopenharmony_ci	u8 vpdr_tag;
5788c2ecf20Sopenharmony_ci	u8 vpdr_len[2];
5798c2ecf20Sopenharmony_ci	VPD_ENTRY(pn, 16);	/* part number */
5808c2ecf20Sopenharmony_ci	VPD_ENTRY(ec, 16);	/* EC level */
5818c2ecf20Sopenharmony_ci	VPD_ENTRY(sn, SERNUM_LEN); /* serial number */
5828c2ecf20Sopenharmony_ci	VPD_ENTRY(na, 12);	/* MAC address base */
5838c2ecf20Sopenharmony_ci	VPD_ENTRY(cclk, 6);	/* core clock */
5848c2ecf20Sopenharmony_ci	VPD_ENTRY(mclk, 6);	/* mem clock */
5858c2ecf20Sopenharmony_ci	VPD_ENTRY(uclk, 6);	/* uP clk */
5868c2ecf20Sopenharmony_ci	VPD_ENTRY(mdc, 6);	/* MDIO clk */
5878c2ecf20Sopenharmony_ci	VPD_ENTRY(mt, 2);	/* mem timing */
5888c2ecf20Sopenharmony_ci	VPD_ENTRY(xaui0cfg, 6);	/* XAUI0 config */
5898c2ecf20Sopenharmony_ci	VPD_ENTRY(xaui1cfg, 6);	/* XAUI1 config */
5908c2ecf20Sopenharmony_ci	VPD_ENTRY(port0, 2);	/* PHY0 complex */
5918c2ecf20Sopenharmony_ci	VPD_ENTRY(port1, 2);	/* PHY1 complex */
5928c2ecf20Sopenharmony_ci	VPD_ENTRY(port2, 2);	/* PHY2 complex */
5938c2ecf20Sopenharmony_ci	VPD_ENTRY(port3, 2);	/* PHY3 complex */
5948c2ecf20Sopenharmony_ci	VPD_ENTRY(rv, 1);	/* csum */
5958c2ecf20Sopenharmony_ci	u32 pad;		/* for multiple-of-4 sizing and alignment */
5968c2ecf20Sopenharmony_ci};
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci#define EEPROM_MAX_POLL   40
5998c2ecf20Sopenharmony_ci#define EEPROM_STAT_ADDR  0x4000
6008c2ecf20Sopenharmony_ci#define VPD_BASE          0xc00
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci/**
6038c2ecf20Sopenharmony_ci *	t3_seeprom_read - read a VPD EEPROM location
6048c2ecf20Sopenharmony_ci *	@adapter: adapter to read
6058c2ecf20Sopenharmony_ci *	@addr: EEPROM address
6068c2ecf20Sopenharmony_ci *	@data: where to store the read data
6078c2ecf20Sopenharmony_ci *
6088c2ecf20Sopenharmony_ci *	Read a 32-bit word from a location in VPD EEPROM using the card's PCI
6098c2ecf20Sopenharmony_ci *	VPD ROM capability.  A zero is written to the flag bit when the
6108c2ecf20Sopenharmony_ci *	address is written to the control register.  The hardware device will
6118c2ecf20Sopenharmony_ci *	set the flag to 1 when 4 bytes have been read into the data register.
6128c2ecf20Sopenharmony_ci */
6138c2ecf20Sopenharmony_ciint t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data)
6148c2ecf20Sopenharmony_ci{
6158c2ecf20Sopenharmony_ci	u16 val;
6168c2ecf20Sopenharmony_ci	int attempts = EEPROM_MAX_POLL;
6178c2ecf20Sopenharmony_ci	u32 v;
6188c2ecf20Sopenharmony_ci	unsigned int base = adapter->params.pci.vpd_cap_addr;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
6218c2ecf20Sopenharmony_ci		return -EINVAL;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	pci_write_config_word(adapter->pdev, base + PCI_VPD_ADDR, addr);
6248c2ecf20Sopenharmony_ci	do {
6258c2ecf20Sopenharmony_ci		udelay(10);
6268c2ecf20Sopenharmony_ci		pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
6278c2ecf20Sopenharmony_ci	} while (!(val & PCI_VPD_ADDR_F) && --attempts);
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	if (!(val & PCI_VPD_ADDR_F)) {
6308c2ecf20Sopenharmony_ci		CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr);
6318c2ecf20Sopenharmony_ci		return -EIO;
6328c2ecf20Sopenharmony_ci	}
6338c2ecf20Sopenharmony_ci	pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, &v);
6348c2ecf20Sopenharmony_ci	*data = cpu_to_le32(v);
6358c2ecf20Sopenharmony_ci	return 0;
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci/**
6398c2ecf20Sopenharmony_ci *	t3_seeprom_write - write a VPD EEPROM location
6408c2ecf20Sopenharmony_ci *	@adapter: adapter to write
6418c2ecf20Sopenharmony_ci *	@addr: EEPROM address
6428c2ecf20Sopenharmony_ci *	@data: value to write
6438c2ecf20Sopenharmony_ci *
6448c2ecf20Sopenharmony_ci *	Write a 32-bit word to a location in VPD EEPROM using the card's PCI
6458c2ecf20Sopenharmony_ci *	VPD ROM capability.
6468c2ecf20Sopenharmony_ci */
6478c2ecf20Sopenharmony_ciint t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data)
6488c2ecf20Sopenharmony_ci{
6498c2ecf20Sopenharmony_ci	u16 val;
6508c2ecf20Sopenharmony_ci	int attempts = EEPROM_MAX_POLL;
6518c2ecf20Sopenharmony_ci	unsigned int base = adapter->params.pci.vpd_cap_addr;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
6548c2ecf20Sopenharmony_ci		return -EINVAL;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	pci_write_config_dword(adapter->pdev, base + PCI_VPD_DATA,
6578c2ecf20Sopenharmony_ci			       le32_to_cpu(data));
6588c2ecf20Sopenharmony_ci	pci_write_config_word(adapter->pdev,base + PCI_VPD_ADDR,
6598c2ecf20Sopenharmony_ci			      addr | PCI_VPD_ADDR_F);
6608c2ecf20Sopenharmony_ci	do {
6618c2ecf20Sopenharmony_ci		msleep(1);
6628c2ecf20Sopenharmony_ci		pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
6638c2ecf20Sopenharmony_ci	} while ((val & PCI_VPD_ADDR_F) && --attempts);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	if (val & PCI_VPD_ADDR_F) {
6668c2ecf20Sopenharmony_ci		CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr);
6678c2ecf20Sopenharmony_ci		return -EIO;
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci	return 0;
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci/**
6738c2ecf20Sopenharmony_ci *	t3_seeprom_wp - enable/disable EEPROM write protection
6748c2ecf20Sopenharmony_ci *	@adapter: the adapter
6758c2ecf20Sopenharmony_ci *	@enable: 1 to enable write protection, 0 to disable it
6768c2ecf20Sopenharmony_ci *
6778c2ecf20Sopenharmony_ci *	Enables or disables write protection on the serial EEPROM.
6788c2ecf20Sopenharmony_ci */
6798c2ecf20Sopenharmony_ciint t3_seeprom_wp(struct adapter *adapter, int enable)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_cistatic int vpdstrtouint(char *s, u8 len, unsigned int base, unsigned int *val)
6858c2ecf20Sopenharmony_ci{
6868c2ecf20Sopenharmony_ci	char tok[256];
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	memcpy(tok, s, len);
6898c2ecf20Sopenharmony_ci	tok[len] = 0;
6908c2ecf20Sopenharmony_ci	return kstrtouint(strim(tok), base, val);
6918c2ecf20Sopenharmony_ci}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_cistatic int vpdstrtou16(char *s, u8 len, unsigned int base, u16 *val)
6948c2ecf20Sopenharmony_ci{
6958c2ecf20Sopenharmony_ci	char tok[256];
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	memcpy(tok, s, len);
6988c2ecf20Sopenharmony_ci	tok[len] = 0;
6998c2ecf20Sopenharmony_ci	return kstrtou16(strim(tok), base, val);
7008c2ecf20Sopenharmony_ci}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci/**
7038c2ecf20Sopenharmony_ci *	get_vpd_params - read VPD parameters from VPD EEPROM
7048c2ecf20Sopenharmony_ci *	@adapter: adapter to read
7058c2ecf20Sopenharmony_ci *	@p: where to store the parameters
7068c2ecf20Sopenharmony_ci *
7078c2ecf20Sopenharmony_ci *	Reads card parameters stored in VPD EEPROM.
7088c2ecf20Sopenharmony_ci */
7098c2ecf20Sopenharmony_cistatic int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
7108c2ecf20Sopenharmony_ci{
7118c2ecf20Sopenharmony_ci	int i, addr, ret;
7128c2ecf20Sopenharmony_ci	struct t3_vpd vpd;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	/*
7158c2ecf20Sopenharmony_ci	 * Card information is normally at VPD_BASE but some early cards had
7168c2ecf20Sopenharmony_ci	 * it at 0.
7178c2ecf20Sopenharmony_ci	 */
7188c2ecf20Sopenharmony_ci	ret = t3_seeprom_read(adapter, VPD_BASE, (__le32 *)&vpd);
7198c2ecf20Sopenharmony_ci	if (ret)
7208c2ecf20Sopenharmony_ci		return ret;
7218c2ecf20Sopenharmony_ci	addr = vpd.id_tag == 0x82 ? VPD_BASE : 0;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	for (i = 0; i < sizeof(vpd); i += 4) {
7248c2ecf20Sopenharmony_ci		ret = t3_seeprom_read(adapter, addr + i,
7258c2ecf20Sopenharmony_ci				      (__le32 *)((u8 *)&vpd + i));
7268c2ecf20Sopenharmony_ci		if (ret)
7278c2ecf20Sopenharmony_ci			return ret;
7288c2ecf20Sopenharmony_ci	}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	ret = vpdstrtouint(vpd.cclk_data, vpd.cclk_len, 10, &p->cclk);
7318c2ecf20Sopenharmony_ci	if (ret)
7328c2ecf20Sopenharmony_ci		return ret;
7338c2ecf20Sopenharmony_ci	ret = vpdstrtouint(vpd.mclk_data, vpd.mclk_len, 10, &p->mclk);
7348c2ecf20Sopenharmony_ci	if (ret)
7358c2ecf20Sopenharmony_ci		return ret;
7368c2ecf20Sopenharmony_ci	ret = vpdstrtouint(vpd.uclk_data, vpd.uclk_len, 10, &p->uclk);
7378c2ecf20Sopenharmony_ci	if (ret)
7388c2ecf20Sopenharmony_ci		return ret;
7398c2ecf20Sopenharmony_ci	ret = vpdstrtouint(vpd.mdc_data, vpd.mdc_len, 10, &p->mdc);
7408c2ecf20Sopenharmony_ci	if (ret)
7418c2ecf20Sopenharmony_ci		return ret;
7428c2ecf20Sopenharmony_ci	ret = vpdstrtouint(vpd.mt_data, vpd.mt_len, 10, &p->mem_timing);
7438c2ecf20Sopenharmony_ci	if (ret)
7448c2ecf20Sopenharmony_ci		return ret;
7458c2ecf20Sopenharmony_ci	memcpy(p->sn, vpd.sn_data, SERNUM_LEN);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	/* Old eeproms didn't have port information */
7488c2ecf20Sopenharmony_ci	if (adapter->params.rev == 0 && !vpd.port0_data[0]) {
7498c2ecf20Sopenharmony_ci		p->port_type[0] = uses_xaui(adapter) ? 1 : 2;
7508c2ecf20Sopenharmony_ci		p->port_type[1] = uses_xaui(adapter) ? 6 : 2;
7518c2ecf20Sopenharmony_ci	} else {
7528c2ecf20Sopenharmony_ci		p->port_type[0] = hex_to_bin(vpd.port0_data[0]);
7538c2ecf20Sopenharmony_ci		p->port_type[1] = hex_to_bin(vpd.port1_data[0]);
7548c2ecf20Sopenharmony_ci		ret = vpdstrtou16(vpd.xaui0cfg_data, vpd.xaui0cfg_len, 16,
7558c2ecf20Sopenharmony_ci				  &p->xauicfg[0]);
7568c2ecf20Sopenharmony_ci		if (ret)
7578c2ecf20Sopenharmony_ci			return ret;
7588c2ecf20Sopenharmony_ci		ret = vpdstrtou16(vpd.xaui1cfg_data, vpd.xaui1cfg_len, 16,
7598c2ecf20Sopenharmony_ci				  &p->xauicfg[1]);
7608c2ecf20Sopenharmony_ci		if (ret)
7618c2ecf20Sopenharmony_ci			return ret;
7628c2ecf20Sopenharmony_ci	}
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	ret = hex2bin(p->eth_base, vpd.na_data, 6);
7658c2ecf20Sopenharmony_ci	if (ret < 0)
7668c2ecf20Sopenharmony_ci		return -EINVAL;
7678c2ecf20Sopenharmony_ci	return 0;
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci/* serial flash and firmware constants */
7718c2ecf20Sopenharmony_cienum {
7728c2ecf20Sopenharmony_ci	SF_ATTEMPTS = 5,	/* max retries for SF1 operations */
7738c2ecf20Sopenharmony_ci	SF_SEC_SIZE = 64 * 1024,	/* serial flash sector size */
7748c2ecf20Sopenharmony_ci	SF_SIZE = SF_SEC_SIZE * 8,	/* serial flash size */
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	/* flash command opcodes */
7778c2ecf20Sopenharmony_ci	SF_PROG_PAGE = 2,	/* program page */
7788c2ecf20Sopenharmony_ci	SF_WR_DISABLE = 4,	/* disable writes */
7798c2ecf20Sopenharmony_ci	SF_RD_STATUS = 5,	/* read status register */
7808c2ecf20Sopenharmony_ci	SF_WR_ENABLE = 6,	/* enable writes */
7818c2ecf20Sopenharmony_ci	SF_RD_DATA_FAST = 0xb,	/* read flash */
7828c2ecf20Sopenharmony_ci	SF_ERASE_SECTOR = 0xd8,	/* erase sector */
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	FW_FLASH_BOOT_ADDR = 0x70000,	/* start address of FW in flash */
7858c2ecf20Sopenharmony_ci	FW_VERS_ADDR = 0x7fffc,    /* flash address holding FW version */
7868c2ecf20Sopenharmony_ci	FW_MIN_SIZE = 8            /* at least version and csum */
7878c2ecf20Sopenharmony_ci};
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci/**
7908c2ecf20Sopenharmony_ci *	sf1_read - read data from the serial flash
7918c2ecf20Sopenharmony_ci *	@adapter: the adapter
7928c2ecf20Sopenharmony_ci *	@byte_cnt: number of bytes to read
7938c2ecf20Sopenharmony_ci *	@cont: whether another operation will be chained
7948c2ecf20Sopenharmony_ci *	@valp: where to store the read data
7958c2ecf20Sopenharmony_ci *
7968c2ecf20Sopenharmony_ci *	Reads up to 4 bytes of data from the serial flash.  The location of
7978c2ecf20Sopenharmony_ci *	the read needs to be specified prior to calling this by issuing the
7988c2ecf20Sopenharmony_ci *	appropriate commands to the serial flash.
7998c2ecf20Sopenharmony_ci */
8008c2ecf20Sopenharmony_cistatic int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont,
8018c2ecf20Sopenharmony_ci		    u32 *valp)
8028c2ecf20Sopenharmony_ci{
8038c2ecf20Sopenharmony_ci	int ret;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	if (!byte_cnt || byte_cnt > 4)
8068c2ecf20Sopenharmony_ci		return -EINVAL;
8078c2ecf20Sopenharmony_ci	if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
8088c2ecf20Sopenharmony_ci		return -EBUSY;
8098c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SF_OP, V_CONT(cont) | V_BYTECNT(byte_cnt - 1));
8108c2ecf20Sopenharmony_ci	ret = t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
8118c2ecf20Sopenharmony_ci	if (!ret)
8128c2ecf20Sopenharmony_ci		*valp = t3_read_reg(adapter, A_SF_DATA);
8138c2ecf20Sopenharmony_ci	return ret;
8148c2ecf20Sopenharmony_ci}
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci/**
8178c2ecf20Sopenharmony_ci *	sf1_write - write data to the serial flash
8188c2ecf20Sopenharmony_ci *	@adapter: the adapter
8198c2ecf20Sopenharmony_ci *	@byte_cnt: number of bytes to write
8208c2ecf20Sopenharmony_ci *	@cont: whether another operation will be chained
8218c2ecf20Sopenharmony_ci *	@val: value to write
8228c2ecf20Sopenharmony_ci *
8238c2ecf20Sopenharmony_ci *	Writes up to 4 bytes of data to the serial flash.  The location of
8248c2ecf20Sopenharmony_ci *	the write needs to be specified prior to calling this by issuing the
8258c2ecf20Sopenharmony_ci *	appropriate commands to the serial flash.
8268c2ecf20Sopenharmony_ci */
8278c2ecf20Sopenharmony_cistatic int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont,
8288c2ecf20Sopenharmony_ci		     u32 val)
8298c2ecf20Sopenharmony_ci{
8308c2ecf20Sopenharmony_ci	if (!byte_cnt || byte_cnt > 4)
8318c2ecf20Sopenharmony_ci		return -EINVAL;
8328c2ecf20Sopenharmony_ci	if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
8338c2ecf20Sopenharmony_ci		return -EBUSY;
8348c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SF_DATA, val);
8358c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SF_OP,
8368c2ecf20Sopenharmony_ci		     V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1));
8378c2ecf20Sopenharmony_ci	return t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
8388c2ecf20Sopenharmony_ci}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci/**
8418c2ecf20Sopenharmony_ci *	flash_wait_op - wait for a flash operation to complete
8428c2ecf20Sopenharmony_ci *	@adapter: the adapter
8438c2ecf20Sopenharmony_ci *	@attempts: max number of polls of the status register
8448c2ecf20Sopenharmony_ci *	@delay: delay between polls in ms
8458c2ecf20Sopenharmony_ci *
8468c2ecf20Sopenharmony_ci *	Wait for a flash operation to complete by polling the status register.
8478c2ecf20Sopenharmony_ci */
8488c2ecf20Sopenharmony_cistatic int flash_wait_op(struct adapter *adapter, int attempts, int delay)
8498c2ecf20Sopenharmony_ci{
8508c2ecf20Sopenharmony_ci	int ret;
8518c2ecf20Sopenharmony_ci	u32 status;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	while (1) {
8548c2ecf20Sopenharmony_ci		if ((ret = sf1_write(adapter, 1, 1, SF_RD_STATUS)) != 0 ||
8558c2ecf20Sopenharmony_ci		    (ret = sf1_read(adapter, 1, 0, &status)) != 0)
8568c2ecf20Sopenharmony_ci			return ret;
8578c2ecf20Sopenharmony_ci		if (!(status & 1))
8588c2ecf20Sopenharmony_ci			return 0;
8598c2ecf20Sopenharmony_ci		if (--attempts == 0)
8608c2ecf20Sopenharmony_ci			return -EAGAIN;
8618c2ecf20Sopenharmony_ci		if (delay)
8628c2ecf20Sopenharmony_ci			msleep(delay);
8638c2ecf20Sopenharmony_ci	}
8648c2ecf20Sopenharmony_ci}
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci/**
8678c2ecf20Sopenharmony_ci *	t3_read_flash - read words from serial flash
8688c2ecf20Sopenharmony_ci *	@adapter: the adapter
8698c2ecf20Sopenharmony_ci *	@addr: the start address for the read
8708c2ecf20Sopenharmony_ci *	@nwords: how many 32-bit words to read
8718c2ecf20Sopenharmony_ci *	@data: where to store the read data
8728c2ecf20Sopenharmony_ci *	@byte_oriented: whether to store data as bytes or as words
8738c2ecf20Sopenharmony_ci *
8748c2ecf20Sopenharmony_ci *	Read the specified number of 32-bit words from the serial flash.
8758c2ecf20Sopenharmony_ci *	If @byte_oriented is set the read data is stored as a byte array
8768c2ecf20Sopenharmony_ci *	(i.e., big-endian), otherwise as 32-bit words in the platform's
8778c2ecf20Sopenharmony_ci *	natural endianness.
8788c2ecf20Sopenharmony_ci */
8798c2ecf20Sopenharmony_cistatic int t3_read_flash(struct adapter *adapter, unsigned int addr,
8808c2ecf20Sopenharmony_ci			 unsigned int nwords, u32 *data, int byte_oriented)
8818c2ecf20Sopenharmony_ci{
8828c2ecf20Sopenharmony_ci	int ret;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3))
8858c2ecf20Sopenharmony_ci		return -EINVAL;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	addr = swab32(addr) | SF_RD_DATA_FAST;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	if ((ret = sf1_write(adapter, 4, 1, addr)) != 0 ||
8908c2ecf20Sopenharmony_ci	    (ret = sf1_read(adapter, 1, 1, data)) != 0)
8918c2ecf20Sopenharmony_ci		return ret;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	for (; nwords; nwords--, data++) {
8948c2ecf20Sopenharmony_ci		ret = sf1_read(adapter, 4, nwords > 1, data);
8958c2ecf20Sopenharmony_ci		if (ret)
8968c2ecf20Sopenharmony_ci			return ret;
8978c2ecf20Sopenharmony_ci		if (byte_oriented)
8988c2ecf20Sopenharmony_ci			*data = htonl(*data);
8998c2ecf20Sopenharmony_ci	}
9008c2ecf20Sopenharmony_ci	return 0;
9018c2ecf20Sopenharmony_ci}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci/**
9048c2ecf20Sopenharmony_ci *	t3_write_flash - write up to a page of data to the serial flash
9058c2ecf20Sopenharmony_ci *	@adapter: the adapter
9068c2ecf20Sopenharmony_ci *	@addr: the start address to write
9078c2ecf20Sopenharmony_ci *	@n: length of data to write
9088c2ecf20Sopenharmony_ci *	@data: the data to write
9098c2ecf20Sopenharmony_ci *
9108c2ecf20Sopenharmony_ci *	Writes up to a page of data (256 bytes) to the serial flash starting
9118c2ecf20Sopenharmony_ci *	at the given address.
9128c2ecf20Sopenharmony_ci */
9138c2ecf20Sopenharmony_cistatic int t3_write_flash(struct adapter *adapter, unsigned int addr,
9148c2ecf20Sopenharmony_ci			  unsigned int n, const u8 *data)
9158c2ecf20Sopenharmony_ci{
9168c2ecf20Sopenharmony_ci	int ret;
9178c2ecf20Sopenharmony_ci	u32 buf[64];
9188c2ecf20Sopenharmony_ci	unsigned int i, c, left, val, offset = addr & 0xff;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	if (addr + n > SF_SIZE || offset + n > 256)
9218c2ecf20Sopenharmony_ci		return -EINVAL;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	val = swab32(addr) | SF_PROG_PAGE;
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
9268c2ecf20Sopenharmony_ci	    (ret = sf1_write(adapter, 4, 1, val)) != 0)
9278c2ecf20Sopenharmony_ci		return ret;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	for (left = n; left; left -= c) {
9308c2ecf20Sopenharmony_ci		c = min(left, 4U);
9318c2ecf20Sopenharmony_ci		for (val = 0, i = 0; i < c; ++i)
9328c2ecf20Sopenharmony_ci			val = (val << 8) + *data++;
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci		ret = sf1_write(adapter, c, c != left, val);
9358c2ecf20Sopenharmony_ci		if (ret)
9368c2ecf20Sopenharmony_ci			return ret;
9378c2ecf20Sopenharmony_ci	}
9388c2ecf20Sopenharmony_ci	if ((ret = flash_wait_op(adapter, 5, 1)) != 0)
9398c2ecf20Sopenharmony_ci		return ret;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	/* Read the page to verify the write succeeded */
9428c2ecf20Sopenharmony_ci	ret = t3_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1);
9438c2ecf20Sopenharmony_ci	if (ret)
9448c2ecf20Sopenharmony_ci		return ret;
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	if (memcmp(data - n, (u8 *) buf + offset, n))
9478c2ecf20Sopenharmony_ci		return -EIO;
9488c2ecf20Sopenharmony_ci	return 0;
9498c2ecf20Sopenharmony_ci}
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci/**
9528c2ecf20Sopenharmony_ci *	t3_get_tp_version - read the tp sram version
9538c2ecf20Sopenharmony_ci *	@adapter: the adapter
9548c2ecf20Sopenharmony_ci *	@vers: where to place the version
9558c2ecf20Sopenharmony_ci *
9568c2ecf20Sopenharmony_ci *	Reads the protocol sram version from sram.
9578c2ecf20Sopenharmony_ci */
9588c2ecf20Sopenharmony_ciint t3_get_tp_version(struct adapter *adapter, u32 *vers)
9598c2ecf20Sopenharmony_ci{
9608c2ecf20Sopenharmony_ci	int ret;
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	/* Get version loaded in SRAM */
9638c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_TP_EMBED_OP_FIELD0, 0);
9648c2ecf20Sopenharmony_ci	ret = t3_wait_op_done(adapter, A_TP_EMBED_OP_FIELD0,
9658c2ecf20Sopenharmony_ci			      1, 1, 5, 1);
9668c2ecf20Sopenharmony_ci	if (ret)
9678c2ecf20Sopenharmony_ci		return ret;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	*vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1);
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	return 0;
9728c2ecf20Sopenharmony_ci}
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci/**
9758c2ecf20Sopenharmony_ci *	t3_check_tpsram_version - read the tp sram version
9768c2ecf20Sopenharmony_ci *	@adapter: the adapter
9778c2ecf20Sopenharmony_ci *
9788c2ecf20Sopenharmony_ci *	Reads the protocol sram version from flash.
9798c2ecf20Sopenharmony_ci */
9808c2ecf20Sopenharmony_ciint t3_check_tpsram_version(struct adapter *adapter)
9818c2ecf20Sopenharmony_ci{
9828c2ecf20Sopenharmony_ci	int ret;
9838c2ecf20Sopenharmony_ci	u32 vers;
9848c2ecf20Sopenharmony_ci	unsigned int major, minor;
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	if (adapter->params.rev == T3_REV_A)
9878c2ecf20Sopenharmony_ci		return 0;
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	ret = t3_get_tp_version(adapter, &vers);
9918c2ecf20Sopenharmony_ci	if (ret)
9928c2ecf20Sopenharmony_ci		return ret;
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	major = G_TP_VERSION_MAJOR(vers);
9958c2ecf20Sopenharmony_ci	minor = G_TP_VERSION_MINOR(vers);
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR)
9988c2ecf20Sopenharmony_ci		return 0;
9998c2ecf20Sopenharmony_ci	else {
10008c2ecf20Sopenharmony_ci		CH_ERR(adapter, "found wrong TP version (%u.%u), "
10018c2ecf20Sopenharmony_ci		       "driver compiled for version %d.%d\n", major, minor,
10028c2ecf20Sopenharmony_ci		       TP_VERSION_MAJOR, TP_VERSION_MINOR);
10038c2ecf20Sopenharmony_ci	}
10048c2ecf20Sopenharmony_ci	return -EINVAL;
10058c2ecf20Sopenharmony_ci}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci/**
10088c2ecf20Sopenharmony_ci *	t3_check_tpsram - check if provided protocol SRAM
10098c2ecf20Sopenharmony_ci *			  is compatible with this driver
10108c2ecf20Sopenharmony_ci *	@adapter: the adapter
10118c2ecf20Sopenharmony_ci *	@tp_sram: the firmware image to write
10128c2ecf20Sopenharmony_ci *	@size: image size
10138c2ecf20Sopenharmony_ci *
10148c2ecf20Sopenharmony_ci *	Checks if an adapter's tp sram is compatible with the driver.
10158c2ecf20Sopenharmony_ci *	Returns 0 if the versions are compatible, a negative error otherwise.
10168c2ecf20Sopenharmony_ci */
10178c2ecf20Sopenharmony_ciint t3_check_tpsram(struct adapter *adapter, const u8 *tp_sram,
10188c2ecf20Sopenharmony_ci		    unsigned int size)
10198c2ecf20Sopenharmony_ci{
10208c2ecf20Sopenharmony_ci	u32 csum;
10218c2ecf20Sopenharmony_ci	unsigned int i;
10228c2ecf20Sopenharmony_ci	const __be32 *p = (const __be32 *)tp_sram;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	/* Verify checksum */
10258c2ecf20Sopenharmony_ci	for (csum = 0, i = 0; i < size / sizeof(csum); i++)
10268c2ecf20Sopenharmony_ci		csum += ntohl(p[i]);
10278c2ecf20Sopenharmony_ci	if (csum != 0xffffffff) {
10288c2ecf20Sopenharmony_ci		CH_ERR(adapter, "corrupted protocol SRAM image, checksum %u\n",
10298c2ecf20Sopenharmony_ci		       csum);
10308c2ecf20Sopenharmony_ci		return -EINVAL;
10318c2ecf20Sopenharmony_ci	}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	return 0;
10348c2ecf20Sopenharmony_ci}
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_cienum fw_version_type {
10378c2ecf20Sopenharmony_ci	FW_VERSION_N3,
10388c2ecf20Sopenharmony_ci	FW_VERSION_T3
10398c2ecf20Sopenharmony_ci};
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci/**
10428c2ecf20Sopenharmony_ci *	t3_get_fw_version - read the firmware version
10438c2ecf20Sopenharmony_ci *	@adapter: the adapter
10448c2ecf20Sopenharmony_ci *	@vers: where to place the version
10458c2ecf20Sopenharmony_ci *
10468c2ecf20Sopenharmony_ci *	Reads the FW version from flash.
10478c2ecf20Sopenharmony_ci */
10488c2ecf20Sopenharmony_ciint t3_get_fw_version(struct adapter *adapter, u32 *vers)
10498c2ecf20Sopenharmony_ci{
10508c2ecf20Sopenharmony_ci	return t3_read_flash(adapter, FW_VERS_ADDR, 1, vers, 0);
10518c2ecf20Sopenharmony_ci}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci/**
10548c2ecf20Sopenharmony_ci *	t3_check_fw_version - check if the FW is compatible with this driver
10558c2ecf20Sopenharmony_ci *	@adapter: the adapter
10568c2ecf20Sopenharmony_ci *
10578c2ecf20Sopenharmony_ci *	Checks if an adapter's FW is compatible with the driver.  Returns 0
10588c2ecf20Sopenharmony_ci *	if the versions are compatible, a negative error otherwise.
10598c2ecf20Sopenharmony_ci */
10608c2ecf20Sopenharmony_ciint t3_check_fw_version(struct adapter *adapter)
10618c2ecf20Sopenharmony_ci{
10628c2ecf20Sopenharmony_ci	int ret;
10638c2ecf20Sopenharmony_ci	u32 vers;
10648c2ecf20Sopenharmony_ci	unsigned int type, major, minor;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	ret = t3_get_fw_version(adapter, &vers);
10678c2ecf20Sopenharmony_ci	if (ret)
10688c2ecf20Sopenharmony_ci		return ret;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	type = G_FW_VERSION_TYPE(vers);
10718c2ecf20Sopenharmony_ci	major = G_FW_VERSION_MAJOR(vers);
10728c2ecf20Sopenharmony_ci	minor = G_FW_VERSION_MINOR(vers);
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	if (type == FW_VERSION_T3 && major == FW_VERSION_MAJOR &&
10758c2ecf20Sopenharmony_ci	    minor == FW_VERSION_MINOR)
10768c2ecf20Sopenharmony_ci		return 0;
10778c2ecf20Sopenharmony_ci	else if (major != FW_VERSION_MAJOR || minor < FW_VERSION_MINOR)
10788c2ecf20Sopenharmony_ci		CH_WARN(adapter, "found old FW minor version(%u.%u), "
10798c2ecf20Sopenharmony_ci		        "driver compiled for version %u.%u\n", major, minor,
10808c2ecf20Sopenharmony_ci			FW_VERSION_MAJOR, FW_VERSION_MINOR);
10818c2ecf20Sopenharmony_ci	else {
10828c2ecf20Sopenharmony_ci		CH_WARN(adapter, "found newer FW version(%u.%u), "
10838c2ecf20Sopenharmony_ci		        "driver compiled for version %u.%u\n", major, minor,
10848c2ecf20Sopenharmony_ci			FW_VERSION_MAJOR, FW_VERSION_MINOR);
10858c2ecf20Sopenharmony_ci		return 0;
10868c2ecf20Sopenharmony_ci	}
10878c2ecf20Sopenharmony_ci	return -EINVAL;
10888c2ecf20Sopenharmony_ci}
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci/**
10918c2ecf20Sopenharmony_ci *	t3_flash_erase_sectors - erase a range of flash sectors
10928c2ecf20Sopenharmony_ci *	@adapter: the adapter
10938c2ecf20Sopenharmony_ci *	@start: the first sector to erase
10948c2ecf20Sopenharmony_ci *	@end: the last sector to erase
10958c2ecf20Sopenharmony_ci *
10968c2ecf20Sopenharmony_ci *	Erases the sectors in the given range.
10978c2ecf20Sopenharmony_ci */
10988c2ecf20Sopenharmony_cistatic int t3_flash_erase_sectors(struct adapter *adapter, int start, int end)
10998c2ecf20Sopenharmony_ci{
11008c2ecf20Sopenharmony_ci	while (start <= end) {
11018c2ecf20Sopenharmony_ci		int ret;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci		if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
11048c2ecf20Sopenharmony_ci		    (ret = sf1_write(adapter, 4, 0,
11058c2ecf20Sopenharmony_ci				     SF_ERASE_SECTOR | (start << 8))) != 0 ||
11068c2ecf20Sopenharmony_ci		    (ret = flash_wait_op(adapter, 5, 500)) != 0)
11078c2ecf20Sopenharmony_ci			return ret;
11088c2ecf20Sopenharmony_ci		start++;
11098c2ecf20Sopenharmony_ci	}
11108c2ecf20Sopenharmony_ci	return 0;
11118c2ecf20Sopenharmony_ci}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci/**
11148c2ecf20Sopenharmony_ci *	t3_load_fw - download firmware
11158c2ecf20Sopenharmony_ci *	@adapter: the adapter
11168c2ecf20Sopenharmony_ci *	@fw_data: the firmware image to write
11178c2ecf20Sopenharmony_ci *	@size: image size
11188c2ecf20Sopenharmony_ci *
11198c2ecf20Sopenharmony_ci *	Write the supplied firmware image to the card's serial flash.
11208c2ecf20Sopenharmony_ci *	The FW image has the following sections: @size - 8 bytes of code and
11218c2ecf20Sopenharmony_ci *	data, followed by 4 bytes of FW version, followed by the 32-bit
11228c2ecf20Sopenharmony_ci *	1's complement checksum of the whole image.
11238c2ecf20Sopenharmony_ci */
11248c2ecf20Sopenharmony_ciint t3_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size)
11258c2ecf20Sopenharmony_ci{
11268c2ecf20Sopenharmony_ci	u32 csum;
11278c2ecf20Sopenharmony_ci	unsigned int i;
11288c2ecf20Sopenharmony_ci	const __be32 *p = (const __be32 *)fw_data;
11298c2ecf20Sopenharmony_ci	int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16;
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	if ((size & 3) || size < FW_MIN_SIZE)
11328c2ecf20Sopenharmony_ci		return -EINVAL;
11338c2ecf20Sopenharmony_ci	if (size > FW_VERS_ADDR + 8 - FW_FLASH_BOOT_ADDR)
11348c2ecf20Sopenharmony_ci		return -EFBIG;
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	for (csum = 0, i = 0; i < size / sizeof(csum); i++)
11378c2ecf20Sopenharmony_ci		csum += ntohl(p[i]);
11388c2ecf20Sopenharmony_ci	if (csum != 0xffffffff) {
11398c2ecf20Sopenharmony_ci		CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
11408c2ecf20Sopenharmony_ci		       csum);
11418c2ecf20Sopenharmony_ci		return -EINVAL;
11428c2ecf20Sopenharmony_ci	}
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	ret = t3_flash_erase_sectors(adapter, fw_sector, fw_sector);
11458c2ecf20Sopenharmony_ci	if (ret)
11468c2ecf20Sopenharmony_ci		goto out;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	size -= 8;		/* trim off version and checksum */
11498c2ecf20Sopenharmony_ci	for (addr = FW_FLASH_BOOT_ADDR; size;) {
11508c2ecf20Sopenharmony_ci		unsigned int chunk_size = min(size, 256U);
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci		ret = t3_write_flash(adapter, addr, chunk_size, fw_data);
11538c2ecf20Sopenharmony_ci		if (ret)
11548c2ecf20Sopenharmony_ci			goto out;
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci		addr += chunk_size;
11578c2ecf20Sopenharmony_ci		fw_data += chunk_size;
11588c2ecf20Sopenharmony_ci		size -= chunk_size;
11598c2ecf20Sopenharmony_ci	}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	ret = t3_write_flash(adapter, FW_VERS_ADDR, 4, fw_data);
11628c2ecf20Sopenharmony_ciout:
11638c2ecf20Sopenharmony_ci	if (ret)
11648c2ecf20Sopenharmony_ci		CH_ERR(adapter, "firmware download failed, error %d\n", ret);
11658c2ecf20Sopenharmony_ci	return ret;
11668c2ecf20Sopenharmony_ci}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci#define CIM_CTL_BASE 0x2000
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci/**
11718c2ecf20Sopenharmony_ci *      t3_cim_ctl_blk_read - read a block from CIM control region
11728c2ecf20Sopenharmony_ci *
11738c2ecf20Sopenharmony_ci *      @adap: the adapter
11748c2ecf20Sopenharmony_ci *      @addr: the start address within the CIM control region
11758c2ecf20Sopenharmony_ci *      @n: number of words to read
11768c2ecf20Sopenharmony_ci *      @valp: where to store the result
11778c2ecf20Sopenharmony_ci *
11788c2ecf20Sopenharmony_ci *      Reads a block of 4-byte words from the CIM control region.
11798c2ecf20Sopenharmony_ci */
11808c2ecf20Sopenharmony_ciint t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr,
11818c2ecf20Sopenharmony_ci			unsigned int n, unsigned int *valp)
11828c2ecf20Sopenharmony_ci{
11838c2ecf20Sopenharmony_ci	int ret = 0;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	if (t3_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY)
11868c2ecf20Sopenharmony_ci		return -EBUSY;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	for ( ; !ret && n--; addr += 4) {
11898c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_CIM_HOST_ACC_CTRL, CIM_CTL_BASE + addr);
11908c2ecf20Sopenharmony_ci		ret = t3_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY,
11918c2ecf20Sopenharmony_ci				      0, 5, 2);
11928c2ecf20Sopenharmony_ci		if (!ret)
11938c2ecf20Sopenharmony_ci			*valp++ = t3_read_reg(adap, A_CIM_HOST_ACC_DATA);
11948c2ecf20Sopenharmony_ci	}
11958c2ecf20Sopenharmony_ci	return ret;
11968c2ecf20Sopenharmony_ci}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_cistatic void t3_gate_rx_traffic(struct cmac *mac, u32 *rx_cfg,
11998c2ecf20Sopenharmony_ci			       u32 *rx_hash_high, u32 *rx_hash_low)
12008c2ecf20Sopenharmony_ci{
12018c2ecf20Sopenharmony_ci	/* stop Rx unicast traffic */
12028c2ecf20Sopenharmony_ci	t3_mac_disable_exact_filters(mac);
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	/* stop broadcast, multicast, promiscuous mode traffic */
12058c2ecf20Sopenharmony_ci	*rx_cfg = t3_read_reg(mac->adapter, A_XGM_RX_CFG);
12068c2ecf20Sopenharmony_ci	t3_set_reg_field(mac->adapter, A_XGM_RX_CFG,
12078c2ecf20Sopenharmony_ci			 F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES,
12088c2ecf20Sopenharmony_ci			 F_DISBCAST);
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	*rx_hash_high = t3_read_reg(mac->adapter, A_XGM_RX_HASH_HIGH);
12118c2ecf20Sopenharmony_ci	t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH, 0);
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	*rx_hash_low = t3_read_reg(mac->adapter, A_XGM_RX_HASH_LOW);
12148c2ecf20Sopenharmony_ci	t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW, 0);
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	/* Leave time to drain max RX fifo */
12178c2ecf20Sopenharmony_ci	msleep(1);
12188c2ecf20Sopenharmony_ci}
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_cistatic void t3_open_rx_traffic(struct cmac *mac, u32 rx_cfg,
12218c2ecf20Sopenharmony_ci			       u32 rx_hash_high, u32 rx_hash_low)
12228c2ecf20Sopenharmony_ci{
12238c2ecf20Sopenharmony_ci	t3_mac_enable_exact_filters(mac);
12248c2ecf20Sopenharmony_ci	t3_set_reg_field(mac->adapter, A_XGM_RX_CFG,
12258c2ecf20Sopenharmony_ci			 F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES,
12268c2ecf20Sopenharmony_ci			 rx_cfg);
12278c2ecf20Sopenharmony_ci	t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH, rx_hash_high);
12288c2ecf20Sopenharmony_ci	t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW, rx_hash_low);
12298c2ecf20Sopenharmony_ci}
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci/**
12328c2ecf20Sopenharmony_ci *	t3_link_changed - handle interface link changes
12338c2ecf20Sopenharmony_ci *	@adapter: the adapter
12348c2ecf20Sopenharmony_ci *	@port_id: the port index that changed link state
12358c2ecf20Sopenharmony_ci *
12368c2ecf20Sopenharmony_ci *	Called when a port's link settings change to propagate the new values
12378c2ecf20Sopenharmony_ci *	to the associated PHY and MAC.  After performing the common tasks it
12388c2ecf20Sopenharmony_ci *	invokes an OS-specific handler.
12398c2ecf20Sopenharmony_ci */
12408c2ecf20Sopenharmony_civoid t3_link_changed(struct adapter *adapter, int port_id)
12418c2ecf20Sopenharmony_ci{
12428c2ecf20Sopenharmony_ci	int link_ok, speed, duplex, fc;
12438c2ecf20Sopenharmony_ci	struct port_info *pi = adap2pinfo(adapter, port_id);
12448c2ecf20Sopenharmony_ci	struct cphy *phy = &pi->phy;
12458c2ecf20Sopenharmony_ci	struct cmac *mac = &pi->mac;
12468c2ecf20Sopenharmony_ci	struct link_config *lc = &pi->link_config;
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	if (!lc->link_ok && link_ok) {
12518c2ecf20Sopenharmony_ci		u32 rx_cfg, rx_hash_high, rx_hash_low;
12528c2ecf20Sopenharmony_ci		u32 status;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci		t3_xgm_intr_enable(adapter, port_id);
12558c2ecf20Sopenharmony_ci		t3_gate_rx_traffic(mac, &rx_cfg, &rx_hash_high, &rx_hash_low);
12568c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0);
12578c2ecf20Sopenharmony_ci		t3_mac_enable(mac, MAC_DIRECTION_RX);
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci		status = t3_read_reg(adapter, A_XGM_INT_STATUS + mac->offset);
12608c2ecf20Sopenharmony_ci		if (status & F_LINKFAULTCHANGE) {
12618c2ecf20Sopenharmony_ci			mac->stats.link_faults++;
12628c2ecf20Sopenharmony_ci			pi->link_fault = 1;
12638c2ecf20Sopenharmony_ci		}
12648c2ecf20Sopenharmony_ci		t3_open_rx_traffic(mac, rx_cfg, rx_hash_high, rx_hash_low);
12658c2ecf20Sopenharmony_ci	}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	if (lc->requested_fc & PAUSE_AUTONEG)
12688c2ecf20Sopenharmony_ci		fc &= lc->requested_fc;
12698c2ecf20Sopenharmony_ci	else
12708c2ecf20Sopenharmony_ci		fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	if (link_ok == lc->link_ok && speed == lc->speed &&
12738c2ecf20Sopenharmony_ci	    duplex == lc->duplex && fc == lc->fc)
12748c2ecf20Sopenharmony_ci		return;                            /* nothing changed */
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	if (link_ok != lc->link_ok && adapter->params.rev > 0 &&
12778c2ecf20Sopenharmony_ci	    uses_xaui(adapter)) {
12788c2ecf20Sopenharmony_ci		if (link_ok)
12798c2ecf20Sopenharmony_ci			t3b_pcs_reset(mac);
12808c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
12818c2ecf20Sopenharmony_ci			     link_ok ? F_TXACTENABLE | F_RXEN : 0);
12828c2ecf20Sopenharmony_ci	}
12838c2ecf20Sopenharmony_ci	lc->link_ok = link_ok;
12848c2ecf20Sopenharmony_ci	lc->speed = speed < 0 ? SPEED_INVALID : speed;
12858c2ecf20Sopenharmony_ci	lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) {
12888c2ecf20Sopenharmony_ci		/* Set MAC speed, duplex, and flow control to match PHY. */
12898c2ecf20Sopenharmony_ci		t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc);
12908c2ecf20Sopenharmony_ci		lc->fc = fc;
12918c2ecf20Sopenharmony_ci	}
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	t3_os_link_changed(adapter, port_id, link_ok && !pi->link_fault,
12948c2ecf20Sopenharmony_ci			   speed, duplex, fc);
12958c2ecf20Sopenharmony_ci}
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_civoid t3_link_fault(struct adapter *adapter, int port_id)
12988c2ecf20Sopenharmony_ci{
12998c2ecf20Sopenharmony_ci	struct port_info *pi = adap2pinfo(adapter, port_id);
13008c2ecf20Sopenharmony_ci	struct cmac *mac = &pi->mac;
13018c2ecf20Sopenharmony_ci	struct cphy *phy = &pi->phy;
13028c2ecf20Sopenharmony_ci	struct link_config *lc = &pi->link_config;
13038c2ecf20Sopenharmony_ci	int link_ok, speed, duplex, fc, link_fault;
13048c2ecf20Sopenharmony_ci	u32 rx_cfg, rx_hash_high, rx_hash_low;
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	t3_gate_rx_traffic(mac, &rx_cfg, &rx_hash_high, &rx_hash_low);
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	if (adapter->params.rev > 0 && uses_xaui(adapter))
13098c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, 0);
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0);
13128c2ecf20Sopenharmony_ci	t3_mac_enable(mac, MAC_DIRECTION_RX);
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	t3_open_rx_traffic(mac, rx_cfg, rx_hash_high, rx_hash_low);
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	link_fault = t3_read_reg(adapter,
13178c2ecf20Sopenharmony_ci				 A_XGM_INT_STATUS + mac->offset);
13188c2ecf20Sopenharmony_ci	link_fault &= F_LINKFAULTCHANGE;
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	link_ok = lc->link_ok;
13218c2ecf20Sopenharmony_ci	speed = lc->speed;
13228c2ecf20Sopenharmony_ci	duplex = lc->duplex;
13238c2ecf20Sopenharmony_ci	fc = lc->fc;
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	if (link_fault) {
13288c2ecf20Sopenharmony_ci		lc->link_ok = 0;
13298c2ecf20Sopenharmony_ci		lc->speed = SPEED_INVALID;
13308c2ecf20Sopenharmony_ci		lc->duplex = DUPLEX_INVALID;
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci		t3_os_link_fault(adapter, port_id, 0);
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci		/* Account link faults only when the phy reports a link up */
13358c2ecf20Sopenharmony_ci		if (link_ok)
13368c2ecf20Sopenharmony_ci			mac->stats.link_faults++;
13378c2ecf20Sopenharmony_ci	} else {
13388c2ecf20Sopenharmony_ci		if (link_ok)
13398c2ecf20Sopenharmony_ci			t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
13408c2ecf20Sopenharmony_ci				     F_TXACTENABLE | F_RXEN);
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci		pi->link_fault = 0;
13438c2ecf20Sopenharmony_ci		lc->link_ok = (unsigned char)link_ok;
13448c2ecf20Sopenharmony_ci		lc->speed = speed < 0 ? SPEED_INVALID : speed;
13458c2ecf20Sopenharmony_ci		lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
13468c2ecf20Sopenharmony_ci		t3_os_link_fault(adapter, port_id, link_ok);
13478c2ecf20Sopenharmony_ci	}
13488c2ecf20Sopenharmony_ci}
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci/**
13518c2ecf20Sopenharmony_ci *	t3_link_start - apply link configuration to MAC/PHY
13528c2ecf20Sopenharmony_ci *	@phy: the PHY to setup
13538c2ecf20Sopenharmony_ci *	@mac: the MAC to setup
13548c2ecf20Sopenharmony_ci *	@lc: the requested link configuration
13558c2ecf20Sopenharmony_ci *
13568c2ecf20Sopenharmony_ci *	Set up a port's MAC and PHY according to a desired link configuration.
13578c2ecf20Sopenharmony_ci *	- If the PHY can auto-negotiate first decide what to advertise, then
13588c2ecf20Sopenharmony_ci *	  enable/disable auto-negotiation as desired, and reset.
13598c2ecf20Sopenharmony_ci *	- If the PHY does not auto-negotiate just reset it.
13608c2ecf20Sopenharmony_ci *	- If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
13618c2ecf20Sopenharmony_ci *	  otherwise do it later based on the outcome of auto-negotiation.
13628c2ecf20Sopenharmony_ci */
13638c2ecf20Sopenharmony_ciint t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
13648c2ecf20Sopenharmony_ci{
13658c2ecf20Sopenharmony_ci	unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	lc->link_ok = 0;
13688c2ecf20Sopenharmony_ci	if (lc->supported & SUPPORTED_Autoneg) {
13698c2ecf20Sopenharmony_ci		lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause);
13708c2ecf20Sopenharmony_ci		if (fc) {
13718c2ecf20Sopenharmony_ci			lc->advertising |= ADVERTISED_Asym_Pause;
13728c2ecf20Sopenharmony_ci			if (fc & PAUSE_RX)
13738c2ecf20Sopenharmony_ci				lc->advertising |= ADVERTISED_Pause;
13748c2ecf20Sopenharmony_ci		}
13758c2ecf20Sopenharmony_ci		phy->ops->advertise(phy, lc->advertising);
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci		if (lc->autoneg == AUTONEG_DISABLE) {
13788c2ecf20Sopenharmony_ci			lc->speed = lc->requested_speed;
13798c2ecf20Sopenharmony_ci			lc->duplex = lc->requested_duplex;
13808c2ecf20Sopenharmony_ci			lc->fc = (unsigned char)fc;
13818c2ecf20Sopenharmony_ci			t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex,
13828c2ecf20Sopenharmony_ci						   fc);
13838c2ecf20Sopenharmony_ci			/* Also disables autoneg */
13848c2ecf20Sopenharmony_ci			phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
13858c2ecf20Sopenharmony_ci		} else
13868c2ecf20Sopenharmony_ci			phy->ops->autoneg_enable(phy);
13878c2ecf20Sopenharmony_ci	} else {
13888c2ecf20Sopenharmony_ci		t3_mac_set_speed_duplex_fc(mac, -1, -1, fc);
13898c2ecf20Sopenharmony_ci		lc->fc = (unsigned char)fc;
13908c2ecf20Sopenharmony_ci		phy->ops->reset(phy, 0);
13918c2ecf20Sopenharmony_ci	}
13928c2ecf20Sopenharmony_ci	return 0;
13938c2ecf20Sopenharmony_ci}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci/**
13968c2ecf20Sopenharmony_ci *	t3_set_vlan_accel - control HW VLAN extraction
13978c2ecf20Sopenharmony_ci *	@adapter: the adapter
13988c2ecf20Sopenharmony_ci *	@ports: bitmap of adapter ports to operate on
13998c2ecf20Sopenharmony_ci *	@on: enable (1) or disable (0) HW VLAN extraction
14008c2ecf20Sopenharmony_ci *
14018c2ecf20Sopenharmony_ci *	Enables or disables HW extraction of VLAN tags for the given port.
14028c2ecf20Sopenharmony_ci */
14038c2ecf20Sopenharmony_civoid t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on)
14048c2ecf20Sopenharmony_ci{
14058c2ecf20Sopenharmony_ci	t3_set_reg_field(adapter, A_TP_OUT_CONFIG,
14068c2ecf20Sopenharmony_ci			 ports << S_VLANEXTRACTIONENABLE,
14078c2ecf20Sopenharmony_ci			 on ? (ports << S_VLANEXTRACTIONENABLE) : 0);
14088c2ecf20Sopenharmony_ci}
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_cistruct intr_info {
14118c2ecf20Sopenharmony_ci	unsigned int mask;	/* bits to check in interrupt status */
14128c2ecf20Sopenharmony_ci	const char *msg;	/* message to print or NULL */
14138c2ecf20Sopenharmony_ci	short stat_idx;		/* stat counter to increment or -1 */
14148c2ecf20Sopenharmony_ci	unsigned short fatal;	/* whether the condition reported is fatal */
14158c2ecf20Sopenharmony_ci};
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci/**
14188c2ecf20Sopenharmony_ci *	t3_handle_intr_status - table driven interrupt handler
14198c2ecf20Sopenharmony_ci *	@adapter: the adapter that generated the interrupt
14208c2ecf20Sopenharmony_ci *	@reg: the interrupt status register to process
14218c2ecf20Sopenharmony_ci *	@mask: a mask to apply to the interrupt status
14228c2ecf20Sopenharmony_ci *	@acts: table of interrupt actions
14238c2ecf20Sopenharmony_ci *	@stats: statistics counters tracking interrupt occurrences
14248c2ecf20Sopenharmony_ci *
14258c2ecf20Sopenharmony_ci *	A table driven interrupt handler that applies a set of masks to an
14268c2ecf20Sopenharmony_ci *	interrupt status word and performs the corresponding actions if the
14278c2ecf20Sopenharmony_ci *	interrupts described by the mask have occurred.  The actions include
14288c2ecf20Sopenharmony_ci *	optionally printing a warning or alert message, and optionally
14298c2ecf20Sopenharmony_ci *	incrementing a stat counter.  The table is terminated by an entry
14308c2ecf20Sopenharmony_ci *	specifying mask 0.  Returns the number of fatal interrupt conditions.
14318c2ecf20Sopenharmony_ci */
14328c2ecf20Sopenharmony_cistatic int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
14338c2ecf20Sopenharmony_ci				 unsigned int mask,
14348c2ecf20Sopenharmony_ci				 const struct intr_info *acts,
14358c2ecf20Sopenharmony_ci				 unsigned long *stats)
14368c2ecf20Sopenharmony_ci{
14378c2ecf20Sopenharmony_ci	int fatal = 0;
14388c2ecf20Sopenharmony_ci	unsigned int status = t3_read_reg(adapter, reg) & mask;
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	for (; acts->mask; ++acts) {
14418c2ecf20Sopenharmony_ci		if (!(status & acts->mask))
14428c2ecf20Sopenharmony_ci			continue;
14438c2ecf20Sopenharmony_ci		if (acts->fatal) {
14448c2ecf20Sopenharmony_ci			fatal++;
14458c2ecf20Sopenharmony_ci			CH_ALERT(adapter, "%s (0x%x)\n",
14468c2ecf20Sopenharmony_ci				 acts->msg, status & acts->mask);
14478c2ecf20Sopenharmony_ci			status &= ~acts->mask;
14488c2ecf20Sopenharmony_ci		} else if (acts->msg)
14498c2ecf20Sopenharmony_ci			CH_WARN(adapter, "%s (0x%x)\n",
14508c2ecf20Sopenharmony_ci				acts->msg, status & acts->mask);
14518c2ecf20Sopenharmony_ci		if (acts->stat_idx >= 0)
14528c2ecf20Sopenharmony_ci			stats[acts->stat_idx]++;
14538c2ecf20Sopenharmony_ci	}
14548c2ecf20Sopenharmony_ci	if (status)		/* clear processed interrupts */
14558c2ecf20Sopenharmony_ci		t3_write_reg(adapter, reg, status);
14568c2ecf20Sopenharmony_ci	return fatal;
14578c2ecf20Sopenharmony_ci}
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci#define SGE_INTR_MASK (F_RSPQDISABLED | \
14608c2ecf20Sopenharmony_ci		       F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR | \
14618c2ecf20Sopenharmony_ci		       F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \
14628c2ecf20Sopenharmony_ci		       F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \
14638c2ecf20Sopenharmony_ci		       V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \
14648c2ecf20Sopenharmony_ci		       F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \
14658c2ecf20Sopenharmony_ci		       F_HIRCQPARITYERROR | F_LOPRIORITYDBFULL | \
14668c2ecf20Sopenharmony_ci		       F_HIPRIORITYDBFULL | F_LOPRIORITYDBEMPTY | \
14678c2ecf20Sopenharmony_ci		       F_HIPRIORITYDBEMPTY | F_HIPIODRBDROPERR | \
14688c2ecf20Sopenharmony_ci		       F_LOPIODRBDROPERR)
14698c2ecf20Sopenharmony_ci#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \
14708c2ecf20Sopenharmony_ci		       F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \
14718c2ecf20Sopenharmony_ci		       F_NFASRCHFAIL)
14728c2ecf20Sopenharmony_ci#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE))
14738c2ecf20Sopenharmony_ci#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
14748c2ecf20Sopenharmony_ci		       V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \
14758c2ecf20Sopenharmony_ci		       F_TXFIFO_UNDERRUN)
14768c2ecf20Sopenharmony_ci#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \
14778c2ecf20Sopenharmony_ci			F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \
14788c2ecf20Sopenharmony_ci			F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \
14798c2ecf20Sopenharmony_ci			F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \
14808c2ecf20Sopenharmony_ci			V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \
14818c2ecf20Sopenharmony_ci			V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */)
14828c2ecf20Sopenharmony_ci#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\
14838c2ecf20Sopenharmony_ci			F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \
14848c2ecf20Sopenharmony_ci			/* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \
14858c2ecf20Sopenharmony_ci			F_RETRYBUFPARERR | F_RETRYLUTPARERR | F_RXPARERR | \
14868c2ecf20Sopenharmony_ci			F_TXPARERR | V_BISTERR(M_BISTERR))
14878c2ecf20Sopenharmony_ci#define ULPRX_INTR_MASK (F_PARERRDATA | F_PARERRPCMD | F_ARBPF1PERR | \
14888c2ecf20Sopenharmony_ci			 F_ARBPF0PERR | F_ARBFPERR | F_PCMDMUXPERR | \
14898c2ecf20Sopenharmony_ci			 F_DATASELFRAMEERR1 | F_DATASELFRAMEERR0)
14908c2ecf20Sopenharmony_ci#define ULPTX_INTR_MASK 0xfc
14918c2ecf20Sopenharmony_ci#define CPLSW_INTR_MASK (F_CIM_OP_MAP_PERR | F_TP_FRAMING_ERROR | \
14928c2ecf20Sopenharmony_ci			 F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \
14938c2ecf20Sopenharmony_ci			 F_ZERO_SWITCH_ERROR)
14948c2ecf20Sopenharmony_ci#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \
14958c2ecf20Sopenharmony_ci		       F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \
14968c2ecf20Sopenharmony_ci		       F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \
14978c2ecf20Sopenharmony_ci	 	       F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT | \
14988c2ecf20Sopenharmony_ci		       F_DRAMPARERR | F_ICACHEPARERR | F_DCACHEPARERR | \
14998c2ecf20Sopenharmony_ci		       F_OBQSGEPARERR | F_OBQULPHIPARERR | F_OBQULPLOPARERR | \
15008c2ecf20Sopenharmony_ci		       F_IBQSGELOPARERR | F_IBQSGEHIPARERR | F_IBQULPPARERR | \
15018c2ecf20Sopenharmony_ci		       F_IBQTPPARERR | F_ITAGPARERR | F_DTAGPARERR)
15028c2ecf20Sopenharmony_ci#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \
15038c2ecf20Sopenharmony_ci			V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \
15048c2ecf20Sopenharmony_ci			V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR))
15058c2ecf20Sopenharmony_ci#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \
15068c2ecf20Sopenharmony_ci			V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \
15078c2ecf20Sopenharmony_ci			V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR))
15088c2ecf20Sopenharmony_ci#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \
15098c2ecf20Sopenharmony_ci		       V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \
15108c2ecf20Sopenharmony_ci		       V_RXTPPARERRENB(M_RXTPPARERRENB) | \
15118c2ecf20Sopenharmony_ci		       V_MCAPARERRENB(M_MCAPARERRENB))
15128c2ecf20Sopenharmony_ci#define XGM_EXTRA_INTR_MASK (F_LINKFAULTCHANGE)
15138c2ecf20Sopenharmony_ci#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \
15148c2ecf20Sopenharmony_ci		      F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \
15158c2ecf20Sopenharmony_ci		      F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \
15168c2ecf20Sopenharmony_ci		      F_MPS0 | F_CPL_SWITCH)
15178c2ecf20Sopenharmony_ci/*
15188c2ecf20Sopenharmony_ci * Interrupt handler for the PCIX1 module.
15198c2ecf20Sopenharmony_ci */
15208c2ecf20Sopenharmony_cistatic void pci_intr_handler(struct adapter *adapter)
15218c2ecf20Sopenharmony_ci{
15228c2ecf20Sopenharmony_ci	static const struct intr_info pcix1_intr_info[] = {
15238c2ecf20Sopenharmony_ci		{F_MSTDETPARERR, "PCI master detected parity error", -1, 1},
15248c2ecf20Sopenharmony_ci		{F_SIGTARABT, "PCI signaled target abort", -1, 1},
15258c2ecf20Sopenharmony_ci		{F_RCVTARABT, "PCI received target abort", -1, 1},
15268c2ecf20Sopenharmony_ci		{F_RCVMSTABT, "PCI received master abort", -1, 1},
15278c2ecf20Sopenharmony_ci		{F_SIGSYSERR, "PCI signaled system error", -1, 1},
15288c2ecf20Sopenharmony_ci		{F_DETPARERR, "PCI detected parity error", -1, 1},
15298c2ecf20Sopenharmony_ci		{F_SPLCMPDIS, "PCI split completion discarded", -1, 1},
15308c2ecf20Sopenharmony_ci		{F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1},
15318c2ecf20Sopenharmony_ci		{F_RCVSPLCMPERR, "PCI received split completion error", -1,
15328c2ecf20Sopenharmony_ci		 1},
15338c2ecf20Sopenharmony_ci		{F_DETCORECCERR, "PCI correctable ECC error",
15348c2ecf20Sopenharmony_ci		 STAT_PCI_CORR_ECC, 0},
15358c2ecf20Sopenharmony_ci		{F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1},
15368c2ecf20Sopenharmony_ci		{F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1},
15378c2ecf20Sopenharmony_ci		{V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1,
15388c2ecf20Sopenharmony_ci		 1},
15398c2ecf20Sopenharmony_ci		{V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1,
15408c2ecf20Sopenharmony_ci		 1},
15418c2ecf20Sopenharmony_ci		{V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1,
15428c2ecf20Sopenharmony_ci		 1},
15438c2ecf20Sopenharmony_ci		{V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity "
15448c2ecf20Sopenharmony_ci		 "error", -1, 1},
15458c2ecf20Sopenharmony_ci		{0}
15468c2ecf20Sopenharmony_ci	};
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK,
15498c2ecf20Sopenharmony_ci				  pcix1_intr_info, adapter->irq_stats))
15508c2ecf20Sopenharmony_ci		t3_fatal_err(adapter);
15518c2ecf20Sopenharmony_ci}
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci/*
15548c2ecf20Sopenharmony_ci * Interrupt handler for the PCIE module.
15558c2ecf20Sopenharmony_ci */
15568c2ecf20Sopenharmony_cistatic void pcie_intr_handler(struct adapter *adapter)
15578c2ecf20Sopenharmony_ci{
15588c2ecf20Sopenharmony_ci	static const struct intr_info pcie_intr_info[] = {
15598c2ecf20Sopenharmony_ci		{F_PEXERR, "PCI PEX error", -1, 1},
15608c2ecf20Sopenharmony_ci		{F_UNXSPLCPLERRR,
15618c2ecf20Sopenharmony_ci		 "PCI unexpected split completion DMA read error", -1, 1},
15628c2ecf20Sopenharmony_ci		{F_UNXSPLCPLERRC,
15638c2ecf20Sopenharmony_ci		 "PCI unexpected split completion DMA command error", -1, 1},
15648c2ecf20Sopenharmony_ci		{F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1},
15658c2ecf20Sopenharmony_ci		{F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1},
15668c2ecf20Sopenharmony_ci		{F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1},
15678c2ecf20Sopenharmony_ci		{F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1},
15688c2ecf20Sopenharmony_ci		{V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR),
15698c2ecf20Sopenharmony_ci		 "PCI MSI-X table/PBA parity error", -1, 1},
15708c2ecf20Sopenharmony_ci		{F_RETRYBUFPARERR, "PCI retry buffer parity error", -1, 1},
15718c2ecf20Sopenharmony_ci		{F_RETRYLUTPARERR, "PCI retry LUT parity error", -1, 1},
15728c2ecf20Sopenharmony_ci		{F_RXPARERR, "PCI Rx parity error", -1, 1},
15738c2ecf20Sopenharmony_ci		{F_TXPARERR, "PCI Tx parity error", -1, 1},
15748c2ecf20Sopenharmony_ci		{V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1},
15758c2ecf20Sopenharmony_ci		{0}
15768c2ecf20Sopenharmony_ci	};
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	if (t3_read_reg(adapter, A_PCIE_INT_CAUSE) & F_PEXERR)
15798c2ecf20Sopenharmony_ci		CH_ALERT(adapter, "PEX error code 0x%x\n",
15808c2ecf20Sopenharmony_ci			 t3_read_reg(adapter, A_PCIE_PEX_ERR));
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci	if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK,
15838c2ecf20Sopenharmony_ci				  pcie_intr_info, adapter->irq_stats))
15848c2ecf20Sopenharmony_ci		t3_fatal_err(adapter);
15858c2ecf20Sopenharmony_ci}
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci/*
15888c2ecf20Sopenharmony_ci * TP interrupt handler.
15898c2ecf20Sopenharmony_ci */
15908c2ecf20Sopenharmony_cistatic void tp_intr_handler(struct adapter *adapter)
15918c2ecf20Sopenharmony_ci{
15928c2ecf20Sopenharmony_ci	static const struct intr_info tp_intr_info[] = {
15938c2ecf20Sopenharmony_ci		{0xffffff, "TP parity error", -1, 1},
15948c2ecf20Sopenharmony_ci		{0x1000000, "TP out of Rx pages", -1, 1},
15958c2ecf20Sopenharmony_ci		{0x2000000, "TP out of Tx pages", -1, 1},
15968c2ecf20Sopenharmony_ci		{0}
15978c2ecf20Sopenharmony_ci	};
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	static const struct intr_info tp_intr_info_t3c[] = {
16008c2ecf20Sopenharmony_ci		{0x1fffffff, "TP parity error", -1, 1},
16018c2ecf20Sopenharmony_ci		{F_FLMRXFLSTEMPTY, "TP out of Rx pages", -1, 1},
16028c2ecf20Sopenharmony_ci		{F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1},
16038c2ecf20Sopenharmony_ci		{0}
16048c2ecf20Sopenharmony_ci	};
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff,
16078c2ecf20Sopenharmony_ci				  adapter->params.rev < T3_REV_C ?
16088c2ecf20Sopenharmony_ci				  tp_intr_info : tp_intr_info_t3c, NULL))
16098c2ecf20Sopenharmony_ci		t3_fatal_err(adapter);
16108c2ecf20Sopenharmony_ci}
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci/*
16138c2ecf20Sopenharmony_ci * CIM interrupt handler.
16148c2ecf20Sopenharmony_ci */
16158c2ecf20Sopenharmony_cistatic void cim_intr_handler(struct adapter *adapter)
16168c2ecf20Sopenharmony_ci{
16178c2ecf20Sopenharmony_ci	static const struct intr_info cim_intr_info[] = {
16188c2ecf20Sopenharmony_ci		{F_RSVDSPACEINT, "CIM reserved space write", -1, 1},
16198c2ecf20Sopenharmony_ci		{F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1},
16208c2ecf20Sopenharmony_ci		{F_FLASHRANGEINT, "CIM flash address out of range", -1, 1},
16218c2ecf20Sopenharmony_ci		{F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1},
16228c2ecf20Sopenharmony_ci		{F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1},
16238c2ecf20Sopenharmony_ci		{F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1},
16248c2ecf20Sopenharmony_ci		{F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1},
16258c2ecf20Sopenharmony_ci		{F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1},
16268c2ecf20Sopenharmony_ci		{F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1},
16278c2ecf20Sopenharmony_ci		{F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1},
16288c2ecf20Sopenharmony_ci		{F_BLKRDPLINT, "CIM block read from PL space", -1, 1},
16298c2ecf20Sopenharmony_ci		{F_BLKWRPLINT, "CIM block write to PL space", -1, 1},
16308c2ecf20Sopenharmony_ci		{F_DRAMPARERR, "CIM DRAM parity error", -1, 1},
16318c2ecf20Sopenharmony_ci		{F_ICACHEPARERR, "CIM icache parity error", -1, 1},
16328c2ecf20Sopenharmony_ci		{F_DCACHEPARERR, "CIM dcache parity error", -1, 1},
16338c2ecf20Sopenharmony_ci		{F_OBQSGEPARERR, "CIM OBQ SGE parity error", -1, 1},
16348c2ecf20Sopenharmony_ci		{F_OBQULPHIPARERR, "CIM OBQ ULPHI parity error", -1, 1},
16358c2ecf20Sopenharmony_ci		{F_OBQULPLOPARERR, "CIM OBQ ULPLO parity error", -1, 1},
16368c2ecf20Sopenharmony_ci		{F_IBQSGELOPARERR, "CIM IBQ SGELO parity error", -1, 1},
16378c2ecf20Sopenharmony_ci		{F_IBQSGEHIPARERR, "CIM IBQ SGEHI parity error", -1, 1},
16388c2ecf20Sopenharmony_ci		{F_IBQULPPARERR, "CIM IBQ ULP parity error", -1, 1},
16398c2ecf20Sopenharmony_ci		{F_IBQTPPARERR, "CIM IBQ TP parity error", -1, 1},
16408c2ecf20Sopenharmony_ci		{F_ITAGPARERR, "CIM itag parity error", -1, 1},
16418c2ecf20Sopenharmony_ci		{F_DTAGPARERR, "CIM dtag parity error", -1, 1},
16428c2ecf20Sopenharmony_ci		{0}
16438c2ecf20Sopenharmony_ci	};
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, 0xffffffff,
16468c2ecf20Sopenharmony_ci				  cim_intr_info, NULL))
16478c2ecf20Sopenharmony_ci		t3_fatal_err(adapter);
16488c2ecf20Sopenharmony_ci}
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ci/*
16518c2ecf20Sopenharmony_ci * ULP RX interrupt handler.
16528c2ecf20Sopenharmony_ci */
16538c2ecf20Sopenharmony_cistatic void ulprx_intr_handler(struct adapter *adapter)
16548c2ecf20Sopenharmony_ci{
16558c2ecf20Sopenharmony_ci	static const struct intr_info ulprx_intr_info[] = {
16568c2ecf20Sopenharmony_ci		{F_PARERRDATA, "ULP RX data parity error", -1, 1},
16578c2ecf20Sopenharmony_ci		{F_PARERRPCMD, "ULP RX command parity error", -1, 1},
16588c2ecf20Sopenharmony_ci		{F_ARBPF1PERR, "ULP RX ArbPF1 parity error", -1, 1},
16598c2ecf20Sopenharmony_ci		{F_ARBPF0PERR, "ULP RX ArbPF0 parity error", -1, 1},
16608c2ecf20Sopenharmony_ci		{F_ARBFPERR, "ULP RX ArbF parity error", -1, 1},
16618c2ecf20Sopenharmony_ci		{F_PCMDMUXPERR, "ULP RX PCMDMUX parity error", -1, 1},
16628c2ecf20Sopenharmony_ci		{F_DATASELFRAMEERR1, "ULP RX frame error", -1, 1},
16638c2ecf20Sopenharmony_ci		{F_DATASELFRAMEERR0, "ULP RX frame error", -1, 1},
16648c2ecf20Sopenharmony_ci		{0}
16658c2ecf20Sopenharmony_ci	};
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff,
16688c2ecf20Sopenharmony_ci				  ulprx_intr_info, NULL))
16698c2ecf20Sopenharmony_ci		t3_fatal_err(adapter);
16708c2ecf20Sopenharmony_ci}
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci/*
16738c2ecf20Sopenharmony_ci * ULP TX interrupt handler.
16748c2ecf20Sopenharmony_ci */
16758c2ecf20Sopenharmony_cistatic void ulptx_intr_handler(struct adapter *adapter)
16768c2ecf20Sopenharmony_ci{
16778c2ecf20Sopenharmony_ci	static const struct intr_info ulptx_intr_info[] = {
16788c2ecf20Sopenharmony_ci		{F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds",
16798c2ecf20Sopenharmony_ci		 STAT_ULP_CH0_PBL_OOB, 0},
16808c2ecf20Sopenharmony_ci		{F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds",
16818c2ecf20Sopenharmony_ci		 STAT_ULP_CH1_PBL_OOB, 0},
16828c2ecf20Sopenharmony_ci		{0xfc, "ULP TX parity error", -1, 1},
16838c2ecf20Sopenharmony_ci		{0}
16848c2ecf20Sopenharmony_ci	};
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff,
16878c2ecf20Sopenharmony_ci				  ulptx_intr_info, adapter->irq_stats))
16888c2ecf20Sopenharmony_ci		t3_fatal_err(adapter);
16898c2ecf20Sopenharmony_ci}
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \
16928c2ecf20Sopenharmony_ci	F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \
16938c2ecf20Sopenharmony_ci	F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \
16948c2ecf20Sopenharmony_ci	F_ICSPI1_TX_FRAMING_ERROR)
16958c2ecf20Sopenharmony_ci#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \
16968c2ecf20Sopenharmony_ci	F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \
16978c2ecf20Sopenharmony_ci	F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \
16988c2ecf20Sopenharmony_ci	F_OESPI1_OFIFO2X_TX_FRAMING_ERROR)
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci/*
17018c2ecf20Sopenharmony_ci * PM TX interrupt handler.
17028c2ecf20Sopenharmony_ci */
17038c2ecf20Sopenharmony_cistatic void pmtx_intr_handler(struct adapter *adapter)
17048c2ecf20Sopenharmony_ci{
17058c2ecf20Sopenharmony_ci	static const struct intr_info pmtx_intr_info[] = {
17068c2ecf20Sopenharmony_ci		{F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1},
17078c2ecf20Sopenharmony_ci		{ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1},
17088c2ecf20Sopenharmony_ci		{OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1},
17098c2ecf20Sopenharmony_ci		{V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR),
17108c2ecf20Sopenharmony_ci		 "PMTX ispi parity error", -1, 1},
17118c2ecf20Sopenharmony_ci		{V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR),
17128c2ecf20Sopenharmony_ci		 "PMTX ospi parity error", -1, 1},
17138c2ecf20Sopenharmony_ci		{0}
17148c2ecf20Sopenharmony_ci	};
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci	if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff,
17178c2ecf20Sopenharmony_ci				  pmtx_intr_info, NULL))
17188c2ecf20Sopenharmony_ci		t3_fatal_err(adapter);
17198c2ecf20Sopenharmony_ci}
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \
17228c2ecf20Sopenharmony_ci	F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \
17238c2ecf20Sopenharmony_ci	F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \
17248c2ecf20Sopenharmony_ci	F_IESPI1_TX_FRAMING_ERROR)
17258c2ecf20Sopenharmony_ci#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \
17268c2ecf20Sopenharmony_ci	F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \
17278c2ecf20Sopenharmony_ci	F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \
17288c2ecf20Sopenharmony_ci	F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR)
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci/*
17318c2ecf20Sopenharmony_ci * PM RX interrupt handler.
17328c2ecf20Sopenharmony_ci */
17338c2ecf20Sopenharmony_cistatic void pmrx_intr_handler(struct adapter *adapter)
17348c2ecf20Sopenharmony_ci{
17358c2ecf20Sopenharmony_ci	static const struct intr_info pmrx_intr_info[] = {
17368c2ecf20Sopenharmony_ci		{F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1},
17378c2ecf20Sopenharmony_ci		{IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1},
17388c2ecf20Sopenharmony_ci		{OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1},
17398c2ecf20Sopenharmony_ci		{V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR),
17408c2ecf20Sopenharmony_ci		 "PMRX ispi parity error", -1, 1},
17418c2ecf20Sopenharmony_ci		{V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR),
17428c2ecf20Sopenharmony_ci		 "PMRX ospi parity error", -1, 1},
17438c2ecf20Sopenharmony_ci		{0}
17448c2ecf20Sopenharmony_ci	};
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff,
17478c2ecf20Sopenharmony_ci				  pmrx_intr_info, NULL))
17488c2ecf20Sopenharmony_ci		t3_fatal_err(adapter);
17498c2ecf20Sopenharmony_ci}
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci/*
17528c2ecf20Sopenharmony_ci * CPL switch interrupt handler.
17538c2ecf20Sopenharmony_ci */
17548c2ecf20Sopenharmony_cistatic void cplsw_intr_handler(struct adapter *adapter)
17558c2ecf20Sopenharmony_ci{
17568c2ecf20Sopenharmony_ci	static const struct intr_info cplsw_intr_info[] = {
17578c2ecf20Sopenharmony_ci		{F_CIM_OP_MAP_PERR, "CPL switch CIM parity error", -1, 1},
17588c2ecf20Sopenharmony_ci		{F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1},
17598c2ecf20Sopenharmony_ci		{F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1},
17608c2ecf20Sopenharmony_ci		{F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1},
17618c2ecf20Sopenharmony_ci		{F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1},
17628c2ecf20Sopenharmony_ci		{F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1},
17638c2ecf20Sopenharmony_ci		{0}
17648c2ecf20Sopenharmony_ci	};
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci	if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff,
17678c2ecf20Sopenharmony_ci				  cplsw_intr_info, NULL))
17688c2ecf20Sopenharmony_ci		t3_fatal_err(adapter);
17698c2ecf20Sopenharmony_ci}
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci/*
17728c2ecf20Sopenharmony_ci * MPS interrupt handler.
17738c2ecf20Sopenharmony_ci */
17748c2ecf20Sopenharmony_cistatic void mps_intr_handler(struct adapter *adapter)
17758c2ecf20Sopenharmony_ci{
17768c2ecf20Sopenharmony_ci	static const struct intr_info mps_intr_info[] = {
17778c2ecf20Sopenharmony_ci		{0x1ff, "MPS parity error", -1, 1},
17788c2ecf20Sopenharmony_ci		{0}
17798c2ecf20Sopenharmony_ci	};
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci	if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff,
17828c2ecf20Sopenharmony_ci				  mps_intr_info, NULL))
17838c2ecf20Sopenharmony_ci		t3_fatal_err(adapter);
17848c2ecf20Sopenharmony_ci}
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE)
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci/*
17898c2ecf20Sopenharmony_ci * MC7 interrupt handler.
17908c2ecf20Sopenharmony_ci */
17918c2ecf20Sopenharmony_cistatic void mc7_intr_handler(struct mc7 *mc7)
17928c2ecf20Sopenharmony_ci{
17938c2ecf20Sopenharmony_ci	struct adapter *adapter = mc7->adapter;
17948c2ecf20Sopenharmony_ci	u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE);
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_ci	if (cause & F_CE) {
17978c2ecf20Sopenharmony_ci		mc7->stats.corr_err++;
17988c2ecf20Sopenharmony_ci		CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, "
17998c2ecf20Sopenharmony_ci			"data 0x%x 0x%x 0x%x\n", mc7->name,
18008c2ecf20Sopenharmony_ci			t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR),
18018c2ecf20Sopenharmony_ci			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0),
18028c2ecf20Sopenharmony_ci			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1),
18038c2ecf20Sopenharmony_ci			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2));
18048c2ecf20Sopenharmony_ci	}
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	if (cause & F_UE) {
18078c2ecf20Sopenharmony_ci		mc7->stats.uncorr_err++;
18088c2ecf20Sopenharmony_ci		CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, "
18098c2ecf20Sopenharmony_ci			 "data 0x%x 0x%x 0x%x\n", mc7->name,
18108c2ecf20Sopenharmony_ci			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR),
18118c2ecf20Sopenharmony_ci			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0),
18128c2ecf20Sopenharmony_ci			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1),
18138c2ecf20Sopenharmony_ci			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2));
18148c2ecf20Sopenharmony_ci	}
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci	if (G_PE(cause)) {
18178c2ecf20Sopenharmony_ci		mc7->stats.parity_err++;
18188c2ecf20Sopenharmony_ci		CH_ALERT(adapter, "%s MC7 parity error 0x%x\n",
18198c2ecf20Sopenharmony_ci			 mc7->name, G_PE(cause));
18208c2ecf20Sopenharmony_ci	}
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	if (cause & F_AE) {
18238c2ecf20Sopenharmony_ci		u32 addr = 0;
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci		if (adapter->params.rev > 0)
18268c2ecf20Sopenharmony_ci			addr = t3_read_reg(adapter,
18278c2ecf20Sopenharmony_ci					   mc7->offset + A_MC7_ERR_ADDR);
18288c2ecf20Sopenharmony_ci		mc7->stats.addr_err++;
18298c2ecf20Sopenharmony_ci		CH_ALERT(adapter, "%s MC7 address error: 0x%x\n",
18308c2ecf20Sopenharmony_ci			 mc7->name, addr);
18318c2ecf20Sopenharmony_ci	}
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	if (cause & MC7_INTR_FATAL)
18348c2ecf20Sopenharmony_ci		t3_fatal_err(adapter);
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci	t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause);
18378c2ecf20Sopenharmony_ci}
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
18408c2ecf20Sopenharmony_ci			V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR))
18418c2ecf20Sopenharmony_ci/*
18428c2ecf20Sopenharmony_ci * XGMAC interrupt handler.
18438c2ecf20Sopenharmony_ci */
18448c2ecf20Sopenharmony_cistatic int mac_intr_handler(struct adapter *adap, unsigned int idx)
18458c2ecf20Sopenharmony_ci{
18468c2ecf20Sopenharmony_ci	struct cmac *mac = &adap2pinfo(adap, idx)->mac;
18478c2ecf20Sopenharmony_ci	/*
18488c2ecf20Sopenharmony_ci	 * We mask out interrupt causes for which we're not taking interrupts.
18498c2ecf20Sopenharmony_ci	 * This allows us to use polling logic to monitor some of the other
18508c2ecf20Sopenharmony_ci	 * conditions when taking interrupts would impose too much load on the
18518c2ecf20Sopenharmony_ci	 * system.
18528c2ecf20Sopenharmony_ci	 */
18538c2ecf20Sopenharmony_ci	u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset) &
18548c2ecf20Sopenharmony_ci		    ~F_RXFIFO_OVERFLOW;
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) {
18578c2ecf20Sopenharmony_ci		mac->stats.tx_fifo_parity_err++;
18588c2ecf20Sopenharmony_ci		CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx);
18598c2ecf20Sopenharmony_ci	}
18608c2ecf20Sopenharmony_ci	if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) {
18618c2ecf20Sopenharmony_ci		mac->stats.rx_fifo_parity_err++;
18628c2ecf20Sopenharmony_ci		CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx);
18638c2ecf20Sopenharmony_ci	}
18648c2ecf20Sopenharmony_ci	if (cause & F_TXFIFO_UNDERRUN)
18658c2ecf20Sopenharmony_ci		mac->stats.tx_fifo_urun++;
18668c2ecf20Sopenharmony_ci	if (cause & F_RXFIFO_OVERFLOW)
18678c2ecf20Sopenharmony_ci		mac->stats.rx_fifo_ovfl++;
18688c2ecf20Sopenharmony_ci	if (cause & V_SERDES_LOS(M_SERDES_LOS))
18698c2ecf20Sopenharmony_ci		mac->stats.serdes_signal_loss++;
18708c2ecf20Sopenharmony_ci	if (cause & F_XAUIPCSCTCERR)
18718c2ecf20Sopenharmony_ci		mac->stats.xaui_pcs_ctc_err++;
18728c2ecf20Sopenharmony_ci	if (cause & F_XAUIPCSALIGNCHANGE)
18738c2ecf20Sopenharmony_ci		mac->stats.xaui_pcs_align_change++;
18748c2ecf20Sopenharmony_ci	if (cause & F_XGM_INT) {
18758c2ecf20Sopenharmony_ci		t3_set_reg_field(adap,
18768c2ecf20Sopenharmony_ci				 A_XGM_INT_ENABLE + mac->offset,
18778c2ecf20Sopenharmony_ci				 F_XGM_INT, 0);
18788c2ecf20Sopenharmony_ci		mac->stats.link_faults++;
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ci		t3_os_link_fault_handler(adap, idx);
18818c2ecf20Sopenharmony_ci	}
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci	if (cause & XGM_INTR_FATAL)
18848c2ecf20Sopenharmony_ci		t3_fatal_err(adap);
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
18878c2ecf20Sopenharmony_ci	return cause != 0;
18888c2ecf20Sopenharmony_ci}
18898c2ecf20Sopenharmony_ci
18908c2ecf20Sopenharmony_ci/*
18918c2ecf20Sopenharmony_ci * Interrupt handler for PHY events.
18928c2ecf20Sopenharmony_ci */
18938c2ecf20Sopenharmony_ciint t3_phy_intr_handler(struct adapter *adapter)
18948c2ecf20Sopenharmony_ci{
18958c2ecf20Sopenharmony_ci	u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE);
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci	for_each_port(adapter, i) {
18988c2ecf20Sopenharmony_ci		struct port_info *p = adap2pinfo(adapter, i);
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci		if (!(p->phy.caps & SUPPORTED_IRQ))
19018c2ecf20Sopenharmony_ci			continue;
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci		if (cause & (1 << adapter_info(adapter)->gpio_intr[i])) {
19048c2ecf20Sopenharmony_ci			int phy_cause = p->phy.ops->intr_handler(&p->phy);
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ci			if (phy_cause & cphy_cause_link_change)
19078c2ecf20Sopenharmony_ci				t3_link_changed(adapter, i);
19088c2ecf20Sopenharmony_ci			if (phy_cause & cphy_cause_fifo_error)
19098c2ecf20Sopenharmony_ci				p->phy.fifo_errors++;
19108c2ecf20Sopenharmony_ci			if (phy_cause & cphy_cause_module_change)
19118c2ecf20Sopenharmony_ci				t3_os_phymod_changed(adapter, i);
19128c2ecf20Sopenharmony_ci		}
19138c2ecf20Sopenharmony_ci	}
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause);
19168c2ecf20Sopenharmony_ci	return 0;
19178c2ecf20Sopenharmony_ci}
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci/*
19208c2ecf20Sopenharmony_ci * T3 slow path (non-data) interrupt handler.
19218c2ecf20Sopenharmony_ci */
19228c2ecf20Sopenharmony_ciint t3_slow_intr_handler(struct adapter *adapter)
19238c2ecf20Sopenharmony_ci{
19248c2ecf20Sopenharmony_ci	u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0);
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci	cause &= adapter->slow_intr_mask;
19278c2ecf20Sopenharmony_ci	if (!cause)
19288c2ecf20Sopenharmony_ci		return 0;
19298c2ecf20Sopenharmony_ci	if (cause & F_PCIM0) {
19308c2ecf20Sopenharmony_ci		if (is_pcie(adapter))
19318c2ecf20Sopenharmony_ci			pcie_intr_handler(adapter);
19328c2ecf20Sopenharmony_ci		else
19338c2ecf20Sopenharmony_ci			pci_intr_handler(adapter);
19348c2ecf20Sopenharmony_ci	}
19358c2ecf20Sopenharmony_ci	if (cause & F_SGE3)
19368c2ecf20Sopenharmony_ci		t3_sge_err_intr_handler(adapter);
19378c2ecf20Sopenharmony_ci	if (cause & F_MC7_PMRX)
19388c2ecf20Sopenharmony_ci		mc7_intr_handler(&adapter->pmrx);
19398c2ecf20Sopenharmony_ci	if (cause & F_MC7_PMTX)
19408c2ecf20Sopenharmony_ci		mc7_intr_handler(&adapter->pmtx);
19418c2ecf20Sopenharmony_ci	if (cause & F_MC7_CM)
19428c2ecf20Sopenharmony_ci		mc7_intr_handler(&adapter->cm);
19438c2ecf20Sopenharmony_ci	if (cause & F_CIM)
19448c2ecf20Sopenharmony_ci		cim_intr_handler(adapter);
19458c2ecf20Sopenharmony_ci	if (cause & F_TP1)
19468c2ecf20Sopenharmony_ci		tp_intr_handler(adapter);
19478c2ecf20Sopenharmony_ci	if (cause & F_ULP2_RX)
19488c2ecf20Sopenharmony_ci		ulprx_intr_handler(adapter);
19498c2ecf20Sopenharmony_ci	if (cause & F_ULP2_TX)
19508c2ecf20Sopenharmony_ci		ulptx_intr_handler(adapter);
19518c2ecf20Sopenharmony_ci	if (cause & F_PM1_RX)
19528c2ecf20Sopenharmony_ci		pmrx_intr_handler(adapter);
19538c2ecf20Sopenharmony_ci	if (cause & F_PM1_TX)
19548c2ecf20Sopenharmony_ci		pmtx_intr_handler(adapter);
19558c2ecf20Sopenharmony_ci	if (cause & F_CPL_SWITCH)
19568c2ecf20Sopenharmony_ci		cplsw_intr_handler(adapter);
19578c2ecf20Sopenharmony_ci	if (cause & F_MPS0)
19588c2ecf20Sopenharmony_ci		mps_intr_handler(adapter);
19598c2ecf20Sopenharmony_ci	if (cause & F_MC5A)
19608c2ecf20Sopenharmony_ci		t3_mc5_intr_handler(&adapter->mc5);
19618c2ecf20Sopenharmony_ci	if (cause & F_XGMAC0_0)
19628c2ecf20Sopenharmony_ci		mac_intr_handler(adapter, 0);
19638c2ecf20Sopenharmony_ci	if (cause & F_XGMAC0_1)
19648c2ecf20Sopenharmony_ci		mac_intr_handler(adapter, 1);
19658c2ecf20Sopenharmony_ci	if (cause & F_T3DBG)
19668c2ecf20Sopenharmony_ci		t3_os_ext_intr_handler(adapter);
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_ci	/* Clear the interrupts just processed. */
19698c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_PL_INT_CAUSE0, cause);
19708c2ecf20Sopenharmony_ci	t3_read_reg(adapter, A_PL_INT_CAUSE0);	/* flush */
19718c2ecf20Sopenharmony_ci	return 1;
19728c2ecf20Sopenharmony_ci}
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_cistatic unsigned int calc_gpio_intr(struct adapter *adap)
19758c2ecf20Sopenharmony_ci{
19768c2ecf20Sopenharmony_ci	unsigned int i, gpi_intr = 0;
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	for_each_port(adap, i)
19798c2ecf20Sopenharmony_ci		if ((adap2pinfo(adap, i)->phy.caps & SUPPORTED_IRQ) &&
19808c2ecf20Sopenharmony_ci		    adapter_info(adap)->gpio_intr[i])
19818c2ecf20Sopenharmony_ci			gpi_intr |= 1 << adapter_info(adap)->gpio_intr[i];
19828c2ecf20Sopenharmony_ci	return gpi_intr;
19838c2ecf20Sopenharmony_ci}
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci/**
19868c2ecf20Sopenharmony_ci *	t3_intr_enable - enable interrupts
19878c2ecf20Sopenharmony_ci *	@adapter: the adapter whose interrupts should be enabled
19888c2ecf20Sopenharmony_ci *
19898c2ecf20Sopenharmony_ci *	Enable interrupts by setting the interrupt enable registers of the
19908c2ecf20Sopenharmony_ci *	various HW modules and then enabling the top-level interrupt
19918c2ecf20Sopenharmony_ci *	concentrator.
19928c2ecf20Sopenharmony_ci */
19938c2ecf20Sopenharmony_civoid t3_intr_enable(struct adapter *adapter)
19948c2ecf20Sopenharmony_ci{
19958c2ecf20Sopenharmony_ci	static const struct addr_val_pair intr_en_avp[] = {
19968c2ecf20Sopenharmony_ci		{A_SG_INT_ENABLE, SGE_INTR_MASK},
19978c2ecf20Sopenharmony_ci		{A_MC7_INT_ENABLE, MC7_INTR_MASK},
19988c2ecf20Sopenharmony_ci		{A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
19998c2ecf20Sopenharmony_ci		 MC7_INTR_MASK},
20008c2ecf20Sopenharmony_ci		{A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
20018c2ecf20Sopenharmony_ci		 MC7_INTR_MASK},
20028c2ecf20Sopenharmony_ci		{A_MC5_DB_INT_ENABLE, MC5_INTR_MASK},
20038c2ecf20Sopenharmony_ci		{A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK},
20048c2ecf20Sopenharmony_ci		{A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK},
20058c2ecf20Sopenharmony_ci		{A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK},
20068c2ecf20Sopenharmony_ci		{A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK},
20078c2ecf20Sopenharmony_ci		{A_MPS_INT_ENABLE, MPS_INTR_MASK},
20088c2ecf20Sopenharmony_ci	};
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci	adapter->slow_intr_mask = PL_INTR_MASK;
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci	t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0);
20138c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_TP_INT_ENABLE,
20148c2ecf20Sopenharmony_ci		     adapter->params.rev >= T3_REV_C ? 0x2bfffff : 0x3bfffff);
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	if (adapter->params.rev > 0) {
20178c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_CPL_INTR_ENABLE,
20188c2ecf20Sopenharmony_ci			     CPLSW_INTR_MASK | F_CIM_OVFL_ERROR);
20198c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_ULPTX_INT_ENABLE,
20208c2ecf20Sopenharmony_ci			     ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 |
20218c2ecf20Sopenharmony_ci			     F_PBL_BOUND_ERR_CH1);
20228c2ecf20Sopenharmony_ci	} else {
20238c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK);
20248c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK);
20258c2ecf20Sopenharmony_ci	}
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_T3DBG_INT_ENABLE, calc_gpio_intr(adapter));
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	if (is_pcie(adapter))
20308c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK);
20318c2ecf20Sopenharmony_ci	else
20328c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK);
20338c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask);
20348c2ecf20Sopenharmony_ci	t3_read_reg(adapter, A_PL_INT_ENABLE0);	/* flush */
20358c2ecf20Sopenharmony_ci}
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_ci/**
20388c2ecf20Sopenharmony_ci *	t3_intr_disable - disable a card's interrupts
20398c2ecf20Sopenharmony_ci *	@adapter: the adapter whose interrupts should be disabled
20408c2ecf20Sopenharmony_ci *
20418c2ecf20Sopenharmony_ci *	Disable interrupts.  We only disable the top-level interrupt
20428c2ecf20Sopenharmony_ci *	concentrator and the SGE data interrupts.
20438c2ecf20Sopenharmony_ci */
20448c2ecf20Sopenharmony_civoid t3_intr_disable(struct adapter *adapter)
20458c2ecf20Sopenharmony_ci{
20468c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_PL_INT_ENABLE0, 0);
20478c2ecf20Sopenharmony_ci	t3_read_reg(adapter, A_PL_INT_ENABLE0);	/* flush */
20488c2ecf20Sopenharmony_ci	adapter->slow_intr_mask = 0;
20498c2ecf20Sopenharmony_ci}
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci/**
20528c2ecf20Sopenharmony_ci *	t3_intr_clear - clear all interrupts
20538c2ecf20Sopenharmony_ci *	@adapter: the adapter whose interrupts should be cleared
20548c2ecf20Sopenharmony_ci *
20558c2ecf20Sopenharmony_ci *	Clears all interrupts.
20568c2ecf20Sopenharmony_ci */
20578c2ecf20Sopenharmony_civoid t3_intr_clear(struct adapter *adapter)
20588c2ecf20Sopenharmony_ci{
20598c2ecf20Sopenharmony_ci	static const unsigned int cause_reg_addr[] = {
20608c2ecf20Sopenharmony_ci		A_SG_INT_CAUSE,
20618c2ecf20Sopenharmony_ci		A_SG_RSPQ_FL_STATUS,
20628c2ecf20Sopenharmony_ci		A_PCIX_INT_CAUSE,
20638c2ecf20Sopenharmony_ci		A_MC7_INT_CAUSE,
20648c2ecf20Sopenharmony_ci		A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
20658c2ecf20Sopenharmony_ci		A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
20668c2ecf20Sopenharmony_ci		A_CIM_HOST_INT_CAUSE,
20678c2ecf20Sopenharmony_ci		A_TP_INT_CAUSE,
20688c2ecf20Sopenharmony_ci		A_MC5_DB_INT_CAUSE,
20698c2ecf20Sopenharmony_ci		A_ULPRX_INT_CAUSE,
20708c2ecf20Sopenharmony_ci		A_ULPTX_INT_CAUSE,
20718c2ecf20Sopenharmony_ci		A_CPL_INTR_CAUSE,
20728c2ecf20Sopenharmony_ci		A_PM1_TX_INT_CAUSE,
20738c2ecf20Sopenharmony_ci		A_PM1_RX_INT_CAUSE,
20748c2ecf20Sopenharmony_ci		A_MPS_INT_CAUSE,
20758c2ecf20Sopenharmony_ci		A_T3DBG_INT_CAUSE,
20768c2ecf20Sopenharmony_ci	};
20778c2ecf20Sopenharmony_ci	unsigned int i;
20788c2ecf20Sopenharmony_ci
20798c2ecf20Sopenharmony_ci	/* Clear PHY and MAC interrupts for each port. */
20808c2ecf20Sopenharmony_ci	for_each_port(adapter, i)
20818c2ecf20Sopenharmony_ci	    t3_port_intr_clear(adapter, i);
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i)
20848c2ecf20Sopenharmony_ci		t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff);
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_ci	if (is_pcie(adapter))
20878c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_PCIE_PEX_ERR, 0xffffffff);
20888c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff);
20898c2ecf20Sopenharmony_ci	t3_read_reg(adapter, A_PL_INT_CAUSE0);	/* flush */
20908c2ecf20Sopenharmony_ci}
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_civoid t3_xgm_intr_enable(struct adapter *adapter, int idx)
20938c2ecf20Sopenharmony_ci{
20948c2ecf20Sopenharmony_ci	struct port_info *pi = adap2pinfo(adapter, idx);
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_XGM_XGM_INT_ENABLE + pi->mac.offset,
20978c2ecf20Sopenharmony_ci		     XGM_EXTRA_INTR_MASK);
20988c2ecf20Sopenharmony_ci}
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_civoid t3_xgm_intr_disable(struct adapter *adapter, int idx)
21018c2ecf20Sopenharmony_ci{
21028c2ecf20Sopenharmony_ci	struct port_info *pi = adap2pinfo(adapter, idx);
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_XGM_XGM_INT_DISABLE + pi->mac.offset,
21058c2ecf20Sopenharmony_ci		     0x7ff);
21068c2ecf20Sopenharmony_ci}
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci/**
21098c2ecf20Sopenharmony_ci *	t3_port_intr_enable - enable port-specific interrupts
21108c2ecf20Sopenharmony_ci *	@adapter: associated adapter
21118c2ecf20Sopenharmony_ci *	@idx: index of port whose interrupts should be enabled
21128c2ecf20Sopenharmony_ci *
21138c2ecf20Sopenharmony_ci *	Enable port-specific (i.e., MAC and PHY) interrupts for the given
21148c2ecf20Sopenharmony_ci *	adapter port.
21158c2ecf20Sopenharmony_ci */
21168c2ecf20Sopenharmony_civoid t3_port_intr_enable(struct adapter *adapter, int idx)
21178c2ecf20Sopenharmony_ci{
21188c2ecf20Sopenharmony_ci	struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
21198c2ecf20Sopenharmony_ci
21208c2ecf20Sopenharmony_ci	t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), XGM_INTR_MASK);
21218c2ecf20Sopenharmony_ci	t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */
21228c2ecf20Sopenharmony_ci	phy->ops->intr_enable(phy);
21238c2ecf20Sopenharmony_ci}
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci/**
21268c2ecf20Sopenharmony_ci *	t3_port_intr_disable - disable port-specific interrupts
21278c2ecf20Sopenharmony_ci *	@adapter: associated adapter
21288c2ecf20Sopenharmony_ci *	@idx: index of port whose interrupts should be disabled
21298c2ecf20Sopenharmony_ci *
21308c2ecf20Sopenharmony_ci *	Disable port-specific (i.e., MAC and PHY) interrupts for the given
21318c2ecf20Sopenharmony_ci *	adapter port.
21328c2ecf20Sopenharmony_ci */
21338c2ecf20Sopenharmony_civoid t3_port_intr_disable(struct adapter *adapter, int idx)
21348c2ecf20Sopenharmony_ci{
21358c2ecf20Sopenharmony_ci	struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci	t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), 0);
21388c2ecf20Sopenharmony_ci	t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */
21398c2ecf20Sopenharmony_ci	phy->ops->intr_disable(phy);
21408c2ecf20Sopenharmony_ci}
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci/**
21438c2ecf20Sopenharmony_ci *	t3_port_intr_clear - clear port-specific interrupts
21448c2ecf20Sopenharmony_ci *	@adapter: associated adapter
21458c2ecf20Sopenharmony_ci *	@idx: index of port whose interrupts to clear
21468c2ecf20Sopenharmony_ci *
21478c2ecf20Sopenharmony_ci *	Clear port-specific (i.e., MAC and PHY) interrupts for the given
21488c2ecf20Sopenharmony_ci *	adapter port.
21498c2ecf20Sopenharmony_ci */
21508c2ecf20Sopenharmony_cistatic void t3_port_intr_clear(struct adapter *adapter, int idx)
21518c2ecf20Sopenharmony_ci{
21528c2ecf20Sopenharmony_ci	struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci	t3_write_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx), 0xffffffff);
21558c2ecf20Sopenharmony_ci	t3_read_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx)); /* flush */
21568c2ecf20Sopenharmony_ci	phy->ops->intr_clear(phy);
21578c2ecf20Sopenharmony_ci}
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci#define SG_CONTEXT_CMD_ATTEMPTS 100
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci/**
21628c2ecf20Sopenharmony_ci * 	t3_sge_write_context - write an SGE context
21638c2ecf20Sopenharmony_ci * 	@adapter: the adapter
21648c2ecf20Sopenharmony_ci * 	@id: the context id
21658c2ecf20Sopenharmony_ci * 	@type: the context type
21668c2ecf20Sopenharmony_ci *
21678c2ecf20Sopenharmony_ci * 	Program an SGE context with the values already loaded in the
21688c2ecf20Sopenharmony_ci * 	CONTEXT_DATA? registers.
21698c2ecf20Sopenharmony_ci */
21708c2ecf20Sopenharmony_cistatic int t3_sge_write_context(struct adapter *adapter, unsigned int id,
21718c2ecf20Sopenharmony_ci				unsigned int type)
21728c2ecf20Sopenharmony_ci{
21738c2ecf20Sopenharmony_ci	if (type == F_RESPONSEQ) {
21748c2ecf20Sopenharmony_ci		/*
21758c2ecf20Sopenharmony_ci		 * Can't write the Response Queue Context bits for
21768c2ecf20Sopenharmony_ci		 * Interrupt Armed or the Reserve bits after the chip
21778c2ecf20Sopenharmony_ci		 * has been initialized out of reset.  Writing to these
21788c2ecf20Sopenharmony_ci		 * bits can confuse the hardware.
21798c2ecf20Sopenharmony_ci		 */
21808c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff);
21818c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff);
21828c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0x17ffffff);
21838c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff);
21848c2ecf20Sopenharmony_ci	} else {
21858c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff);
21868c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff);
21878c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff);
21888c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff);
21898c2ecf20Sopenharmony_ci	}
21908c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
21918c2ecf20Sopenharmony_ci		     V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
21928c2ecf20Sopenharmony_ci	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
21938c2ecf20Sopenharmony_ci			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
21948c2ecf20Sopenharmony_ci}
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci/**
21978c2ecf20Sopenharmony_ci *	clear_sge_ctxt - completely clear an SGE context
21988c2ecf20Sopenharmony_ci *	@adap: the adapter
21998c2ecf20Sopenharmony_ci *	@id: the context id
22008c2ecf20Sopenharmony_ci *	@type: the context type
22018c2ecf20Sopenharmony_ci *
22028c2ecf20Sopenharmony_ci *	Completely clear an SGE context.  Used predominantly at post-reset
22038c2ecf20Sopenharmony_ci *	initialization.  Note in particular that we don't skip writing to any
22048c2ecf20Sopenharmony_ci *	"sensitive bits" in the contexts the way that t3_sge_write_context()
22058c2ecf20Sopenharmony_ci *	does ...
22068c2ecf20Sopenharmony_ci */
22078c2ecf20Sopenharmony_cistatic int clear_sge_ctxt(struct adapter *adap, unsigned int id,
22088c2ecf20Sopenharmony_ci			  unsigned int type)
22098c2ecf20Sopenharmony_ci{
22108c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_SG_CONTEXT_DATA0, 0);
22118c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_SG_CONTEXT_DATA1, 0);
22128c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_SG_CONTEXT_DATA2, 0);
22138c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_SG_CONTEXT_DATA3, 0);
22148c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_SG_CONTEXT_MASK0, 0xffffffff);
22158c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_SG_CONTEXT_MASK1, 0xffffffff);
22168c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_SG_CONTEXT_MASK2, 0xffffffff);
22178c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_SG_CONTEXT_MASK3, 0xffffffff);
22188c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_SG_CONTEXT_CMD,
22198c2ecf20Sopenharmony_ci		     V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
22208c2ecf20Sopenharmony_ci	return t3_wait_op_done(adap, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
22218c2ecf20Sopenharmony_ci			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
22228c2ecf20Sopenharmony_ci}
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_ci/**
22258c2ecf20Sopenharmony_ci *	t3_sge_init_ecntxt - initialize an SGE egress context
22268c2ecf20Sopenharmony_ci *	@adapter: the adapter to configure
22278c2ecf20Sopenharmony_ci *	@id: the context id
22288c2ecf20Sopenharmony_ci *	@gts_enable: whether to enable GTS for the context
22298c2ecf20Sopenharmony_ci *	@type: the egress context type
22308c2ecf20Sopenharmony_ci *	@respq: associated response queue
22318c2ecf20Sopenharmony_ci *	@base_addr: base address of queue
22328c2ecf20Sopenharmony_ci *	@size: number of queue entries
22338c2ecf20Sopenharmony_ci *	@token: uP token
22348c2ecf20Sopenharmony_ci *	@gen: initial generation value for the context
22358c2ecf20Sopenharmony_ci *	@cidx: consumer pointer
22368c2ecf20Sopenharmony_ci *
22378c2ecf20Sopenharmony_ci *	Initialize an SGE egress context and make it ready for use.  If the
22388c2ecf20Sopenharmony_ci *	platform allows concurrent context operations, the caller is
22398c2ecf20Sopenharmony_ci *	responsible for appropriate locking.
22408c2ecf20Sopenharmony_ci */
22418c2ecf20Sopenharmony_ciint t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable,
22428c2ecf20Sopenharmony_ci		       enum sge_context_type type, int respq, u64 base_addr,
22438c2ecf20Sopenharmony_ci		       unsigned int size, unsigned int token, int gen,
22448c2ecf20Sopenharmony_ci		       unsigned int cidx)
22458c2ecf20Sopenharmony_ci{
22468c2ecf20Sopenharmony_ci	unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM;
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci	if (base_addr & 0xfff)	/* must be 4K aligned */
22498c2ecf20Sopenharmony_ci		return -EINVAL;
22508c2ecf20Sopenharmony_ci	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
22518c2ecf20Sopenharmony_ci		return -EBUSY;
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_ci	base_addr >>= 12;
22548c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) |
22558c2ecf20Sopenharmony_ci		     V_EC_CREDITS(credits) | V_EC_GTS(gts_enable));
22568c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) |
22578c2ecf20Sopenharmony_ci		     V_EC_BASE_LO(base_addr & 0xffff));
22588c2ecf20Sopenharmony_ci	base_addr >>= 16;
22598c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, base_addr);
22608c2ecf20Sopenharmony_ci	base_addr >>= 32;
22618c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
22628c2ecf20Sopenharmony_ci		     V_EC_BASE_HI(base_addr & 0xf) | V_EC_RESPQ(respq) |
22638c2ecf20Sopenharmony_ci		     V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) |
22648c2ecf20Sopenharmony_ci		     F_EC_VALID);
22658c2ecf20Sopenharmony_ci	return t3_sge_write_context(adapter, id, F_EGRESS);
22668c2ecf20Sopenharmony_ci}
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci/**
22698c2ecf20Sopenharmony_ci *	t3_sge_init_flcntxt - initialize an SGE free-buffer list context
22708c2ecf20Sopenharmony_ci *	@adapter: the adapter to configure
22718c2ecf20Sopenharmony_ci *	@id: the context id
22728c2ecf20Sopenharmony_ci *	@gts_enable: whether to enable GTS for the context
22738c2ecf20Sopenharmony_ci *	@base_addr: base address of queue
22748c2ecf20Sopenharmony_ci *	@size: number of queue entries
22758c2ecf20Sopenharmony_ci *	@bsize: size of each buffer for this queue
22768c2ecf20Sopenharmony_ci *	@cong_thres: threshold to signal congestion to upstream producers
22778c2ecf20Sopenharmony_ci *	@gen: initial generation value for the context
22788c2ecf20Sopenharmony_ci *	@cidx: consumer pointer
22798c2ecf20Sopenharmony_ci *
22808c2ecf20Sopenharmony_ci *	Initialize an SGE free list context and make it ready for use.  The
22818c2ecf20Sopenharmony_ci *	caller is responsible for ensuring only one context operation occurs
22828c2ecf20Sopenharmony_ci *	at a time.
22838c2ecf20Sopenharmony_ci */
22848c2ecf20Sopenharmony_ciint t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id,
22858c2ecf20Sopenharmony_ci			int gts_enable, u64 base_addr, unsigned int size,
22868c2ecf20Sopenharmony_ci			unsigned int bsize, unsigned int cong_thres, int gen,
22878c2ecf20Sopenharmony_ci			unsigned int cidx)
22888c2ecf20Sopenharmony_ci{
22898c2ecf20Sopenharmony_ci	if (base_addr & 0xfff)	/* must be 4K aligned */
22908c2ecf20Sopenharmony_ci		return -EINVAL;
22918c2ecf20Sopenharmony_ci	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
22928c2ecf20Sopenharmony_ci		return -EBUSY;
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_ci	base_addr >>= 12;
22958c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, base_addr);
22968c2ecf20Sopenharmony_ci	base_addr >>= 32;
22978c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA1,
22988c2ecf20Sopenharmony_ci		     V_FL_BASE_HI((u32) base_addr) |
22998c2ecf20Sopenharmony_ci		     V_FL_INDEX_LO(cidx & M_FL_INDEX_LO));
23008c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) |
23018c2ecf20Sopenharmony_ci		     V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) |
23028c2ecf20Sopenharmony_ci		     V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO));
23038c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
23048c2ecf20Sopenharmony_ci		     V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) |
23058c2ecf20Sopenharmony_ci		     V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable));
23068c2ecf20Sopenharmony_ci	return t3_sge_write_context(adapter, id, F_FREELIST);
23078c2ecf20Sopenharmony_ci}
23088c2ecf20Sopenharmony_ci
23098c2ecf20Sopenharmony_ci/**
23108c2ecf20Sopenharmony_ci *	t3_sge_init_rspcntxt - initialize an SGE response queue context
23118c2ecf20Sopenharmony_ci *	@adapter: the adapter to configure
23128c2ecf20Sopenharmony_ci *	@id: the context id
23138c2ecf20Sopenharmony_ci *	@irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ
23148c2ecf20Sopenharmony_ci *	@base_addr: base address of queue
23158c2ecf20Sopenharmony_ci *	@size: number of queue entries
23168c2ecf20Sopenharmony_ci *	@fl_thres: threshold for selecting the normal or jumbo free list
23178c2ecf20Sopenharmony_ci *	@gen: initial generation value for the context
23188c2ecf20Sopenharmony_ci *	@cidx: consumer pointer
23198c2ecf20Sopenharmony_ci *
23208c2ecf20Sopenharmony_ci *	Initialize an SGE response queue context and make it ready for use.
23218c2ecf20Sopenharmony_ci *	The caller is responsible for ensuring only one context operation
23228c2ecf20Sopenharmony_ci *	occurs at a time.
23238c2ecf20Sopenharmony_ci */
23248c2ecf20Sopenharmony_ciint t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id,
23258c2ecf20Sopenharmony_ci			 int irq_vec_idx, u64 base_addr, unsigned int size,
23268c2ecf20Sopenharmony_ci			 unsigned int fl_thres, int gen, unsigned int cidx)
23278c2ecf20Sopenharmony_ci{
23288c2ecf20Sopenharmony_ci	unsigned int intr = 0;
23298c2ecf20Sopenharmony_ci
23308c2ecf20Sopenharmony_ci	if (base_addr & 0xfff)	/* must be 4K aligned */
23318c2ecf20Sopenharmony_ci		return -EINVAL;
23328c2ecf20Sopenharmony_ci	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
23338c2ecf20Sopenharmony_ci		return -EBUSY;
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_ci	base_addr >>= 12;
23368c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) |
23378c2ecf20Sopenharmony_ci		     V_CQ_INDEX(cidx));
23388c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr);
23398c2ecf20Sopenharmony_ci	base_addr >>= 32;
23408c2ecf20Sopenharmony_ci	if (irq_vec_idx >= 0)
23418c2ecf20Sopenharmony_ci		intr = V_RQ_MSI_VEC(irq_vec_idx) | F_RQ_INTR_EN;
23428c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
23438c2ecf20Sopenharmony_ci		     V_CQ_BASE_HI((u32) base_addr) | intr | V_RQ_GEN(gen));
23448c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres);
23458c2ecf20Sopenharmony_ci	return t3_sge_write_context(adapter, id, F_RESPONSEQ);
23468c2ecf20Sopenharmony_ci}
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci/**
23498c2ecf20Sopenharmony_ci *	t3_sge_init_cqcntxt - initialize an SGE completion queue context
23508c2ecf20Sopenharmony_ci *	@adapter: the adapter to configure
23518c2ecf20Sopenharmony_ci *	@id: the context id
23528c2ecf20Sopenharmony_ci *	@base_addr: base address of queue
23538c2ecf20Sopenharmony_ci *	@size: number of queue entries
23548c2ecf20Sopenharmony_ci *	@rspq: response queue for async notifications
23558c2ecf20Sopenharmony_ci *	@ovfl_mode: CQ overflow mode
23568c2ecf20Sopenharmony_ci *	@credits: completion queue credits
23578c2ecf20Sopenharmony_ci *	@credit_thres: the credit threshold
23588c2ecf20Sopenharmony_ci *
23598c2ecf20Sopenharmony_ci *	Initialize an SGE completion queue context and make it ready for use.
23608c2ecf20Sopenharmony_ci *	The caller is responsible for ensuring only one context operation
23618c2ecf20Sopenharmony_ci *	occurs at a time.
23628c2ecf20Sopenharmony_ci */
23638c2ecf20Sopenharmony_ciint t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr,
23648c2ecf20Sopenharmony_ci			unsigned int size, int rspq, int ovfl_mode,
23658c2ecf20Sopenharmony_ci			unsigned int credits, unsigned int credit_thres)
23668c2ecf20Sopenharmony_ci{
23678c2ecf20Sopenharmony_ci	if (base_addr & 0xfff)	/* must be 4K aligned */
23688c2ecf20Sopenharmony_ci		return -EINVAL;
23698c2ecf20Sopenharmony_ci	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
23708c2ecf20Sopenharmony_ci		return -EBUSY;
23718c2ecf20Sopenharmony_ci
23728c2ecf20Sopenharmony_ci	base_addr >>= 12;
23738c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size));
23748c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr);
23758c2ecf20Sopenharmony_ci	base_addr >>= 32;
23768c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
23778c2ecf20Sopenharmony_ci		     V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) |
23788c2ecf20Sopenharmony_ci		     V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode) |
23798c2ecf20Sopenharmony_ci		     V_CQ_ERR(ovfl_mode));
23808c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) |
23818c2ecf20Sopenharmony_ci		     V_CQ_CREDIT_THRES(credit_thres));
23828c2ecf20Sopenharmony_ci	return t3_sge_write_context(adapter, id, F_CQ);
23838c2ecf20Sopenharmony_ci}
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_ci/**
23868c2ecf20Sopenharmony_ci *	t3_sge_enable_ecntxt - enable/disable an SGE egress context
23878c2ecf20Sopenharmony_ci *	@adapter: the adapter
23888c2ecf20Sopenharmony_ci *	@id: the egress context id
23898c2ecf20Sopenharmony_ci *	@enable: enable (1) or disable (0) the context
23908c2ecf20Sopenharmony_ci *
23918c2ecf20Sopenharmony_ci *	Enable or disable an SGE egress context.  The caller is responsible for
23928c2ecf20Sopenharmony_ci *	ensuring only one context operation occurs at a time.
23938c2ecf20Sopenharmony_ci */
23948c2ecf20Sopenharmony_ciint t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable)
23958c2ecf20Sopenharmony_ci{
23968c2ecf20Sopenharmony_ci	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
23978c2ecf20Sopenharmony_ci		return -EBUSY;
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
24008c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
24018c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
24028c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID);
24038c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable));
24048c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
24058c2ecf20Sopenharmony_ci		     V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id));
24068c2ecf20Sopenharmony_ci	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
24078c2ecf20Sopenharmony_ci			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
24088c2ecf20Sopenharmony_ci}
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_ci/**
24118c2ecf20Sopenharmony_ci *	t3_sge_disable_fl - disable an SGE free-buffer list
24128c2ecf20Sopenharmony_ci *	@adapter: the adapter
24138c2ecf20Sopenharmony_ci *	@id: the free list context id
24148c2ecf20Sopenharmony_ci *
24158c2ecf20Sopenharmony_ci *	Disable an SGE free-buffer list.  The caller is responsible for
24168c2ecf20Sopenharmony_ci *	ensuring only one context operation occurs at a time.
24178c2ecf20Sopenharmony_ci */
24188c2ecf20Sopenharmony_ciint t3_sge_disable_fl(struct adapter *adapter, unsigned int id)
24198c2ecf20Sopenharmony_ci{
24208c2ecf20Sopenharmony_ci	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
24218c2ecf20Sopenharmony_ci		return -EBUSY;
24228c2ecf20Sopenharmony_ci
24238c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
24248c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
24258c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE));
24268c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
24278c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0);
24288c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
24298c2ecf20Sopenharmony_ci		     V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id));
24308c2ecf20Sopenharmony_ci	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
24318c2ecf20Sopenharmony_ci			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
24328c2ecf20Sopenharmony_ci}
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci/**
24358c2ecf20Sopenharmony_ci *	t3_sge_disable_rspcntxt - disable an SGE response queue
24368c2ecf20Sopenharmony_ci *	@adapter: the adapter
24378c2ecf20Sopenharmony_ci *	@id: the response queue context id
24388c2ecf20Sopenharmony_ci *
24398c2ecf20Sopenharmony_ci *	Disable an SGE response queue.  The caller is responsible for
24408c2ecf20Sopenharmony_ci *	ensuring only one context operation occurs at a time.
24418c2ecf20Sopenharmony_ci */
24428c2ecf20Sopenharmony_ciint t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id)
24438c2ecf20Sopenharmony_ci{
24448c2ecf20Sopenharmony_ci	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
24458c2ecf20Sopenharmony_ci		return -EBUSY;
24468c2ecf20Sopenharmony_ci
24478c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
24488c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
24498c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
24508c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
24518c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
24528c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
24538c2ecf20Sopenharmony_ci		     V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id));
24548c2ecf20Sopenharmony_ci	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
24558c2ecf20Sopenharmony_ci			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
24568c2ecf20Sopenharmony_ci}
24578c2ecf20Sopenharmony_ci
24588c2ecf20Sopenharmony_ci/**
24598c2ecf20Sopenharmony_ci *	t3_sge_disable_cqcntxt - disable an SGE completion queue
24608c2ecf20Sopenharmony_ci *	@adapter: the adapter
24618c2ecf20Sopenharmony_ci *	@id: the completion queue context id
24628c2ecf20Sopenharmony_ci *
24638c2ecf20Sopenharmony_ci *	Disable an SGE completion queue.  The caller is responsible for
24648c2ecf20Sopenharmony_ci *	ensuring only one context operation occurs at a time.
24658c2ecf20Sopenharmony_ci */
24668c2ecf20Sopenharmony_ciint t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id)
24678c2ecf20Sopenharmony_ci{
24688c2ecf20Sopenharmony_ci	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
24698c2ecf20Sopenharmony_ci		return -EBUSY;
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
24728c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
24738c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
24748c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
24758c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
24768c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
24778c2ecf20Sopenharmony_ci		     V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id));
24788c2ecf20Sopenharmony_ci	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
24798c2ecf20Sopenharmony_ci			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
24808c2ecf20Sopenharmony_ci}
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_ci/**
24838c2ecf20Sopenharmony_ci *	t3_sge_cqcntxt_op - perform an operation on a completion queue context
24848c2ecf20Sopenharmony_ci *	@adapter: the adapter
24858c2ecf20Sopenharmony_ci *	@id: the context id
24868c2ecf20Sopenharmony_ci *	@op: the operation to perform
24878c2ecf20Sopenharmony_ci *	@credits: credit value to write
24888c2ecf20Sopenharmony_ci *
24898c2ecf20Sopenharmony_ci *	Perform the selected operation on an SGE completion queue context.
24908c2ecf20Sopenharmony_ci *	The caller is responsible for ensuring only one context operation
24918c2ecf20Sopenharmony_ci *	occurs at a time.
24928c2ecf20Sopenharmony_ci */
24938c2ecf20Sopenharmony_ciint t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
24948c2ecf20Sopenharmony_ci		      unsigned int credits)
24958c2ecf20Sopenharmony_ci{
24968c2ecf20Sopenharmony_ci	u32 val;
24978c2ecf20Sopenharmony_ci
24988c2ecf20Sopenharmony_ci	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
24998c2ecf20Sopenharmony_ci		return -EBUSY;
25008c2ecf20Sopenharmony_ci
25018c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16);
25028c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) |
25038c2ecf20Sopenharmony_ci		     V_CONTEXT(id) | F_CQ);
25048c2ecf20Sopenharmony_ci	if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
25058c2ecf20Sopenharmony_ci				0, SG_CONTEXT_CMD_ATTEMPTS, 1, &val))
25068c2ecf20Sopenharmony_ci		return -EIO;
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_ci	if (op >= 2 && op < 7) {
25098c2ecf20Sopenharmony_ci		if (adapter->params.rev > 0)
25108c2ecf20Sopenharmony_ci			return G_CQ_INDEX(val);
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_SG_CONTEXT_CMD,
25138c2ecf20Sopenharmony_ci			     V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id));
25148c2ecf20Sopenharmony_ci		if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD,
25158c2ecf20Sopenharmony_ci				    F_CONTEXT_CMD_BUSY, 0,
25168c2ecf20Sopenharmony_ci				    SG_CONTEXT_CMD_ATTEMPTS, 1))
25178c2ecf20Sopenharmony_ci			return -EIO;
25188c2ecf20Sopenharmony_ci		return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0));
25198c2ecf20Sopenharmony_ci	}
25208c2ecf20Sopenharmony_ci	return 0;
25218c2ecf20Sopenharmony_ci}
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_ci/**
25248c2ecf20Sopenharmony_ci *	t3_config_rss - configure Rx packet steering
25258c2ecf20Sopenharmony_ci *	@adapter: the adapter
25268c2ecf20Sopenharmony_ci *	@rss_config: RSS settings (written to TP_RSS_CONFIG)
25278c2ecf20Sopenharmony_ci *	@cpus: values for the CPU lookup table (0xff terminated)
25288c2ecf20Sopenharmony_ci *	@rspq: values for the response queue lookup table (0xffff terminated)
25298c2ecf20Sopenharmony_ci *
25308c2ecf20Sopenharmony_ci *	Programs the receive packet steering logic.  @cpus and @rspq provide
25318c2ecf20Sopenharmony_ci *	the values for the CPU and response queue lookup tables.  If they
25328c2ecf20Sopenharmony_ci *	provide fewer values than the size of the tables the supplied values
25338c2ecf20Sopenharmony_ci *	are used repeatedly until the tables are fully populated.
25348c2ecf20Sopenharmony_ci */
25358c2ecf20Sopenharmony_civoid t3_config_rss(struct adapter *adapter, unsigned int rss_config,
25368c2ecf20Sopenharmony_ci		   const u8 * cpus, const u16 *rspq)
25378c2ecf20Sopenharmony_ci{
25388c2ecf20Sopenharmony_ci	int i, j, cpu_idx = 0, q_idx = 0;
25398c2ecf20Sopenharmony_ci
25408c2ecf20Sopenharmony_ci	if (cpus)
25418c2ecf20Sopenharmony_ci		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
25428c2ecf20Sopenharmony_ci			u32 val = i << 16;
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_ci			for (j = 0; j < 2; ++j) {
25458c2ecf20Sopenharmony_ci				val |= (cpus[cpu_idx++] & 0x3f) << (8 * j);
25468c2ecf20Sopenharmony_ci				if (cpus[cpu_idx] == 0xff)
25478c2ecf20Sopenharmony_ci					cpu_idx = 0;
25488c2ecf20Sopenharmony_ci			}
25498c2ecf20Sopenharmony_ci			t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val);
25508c2ecf20Sopenharmony_ci		}
25518c2ecf20Sopenharmony_ci
25528c2ecf20Sopenharmony_ci	if (rspq)
25538c2ecf20Sopenharmony_ci		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
25548c2ecf20Sopenharmony_ci			t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
25558c2ecf20Sopenharmony_ci				     (i << 16) | rspq[q_idx++]);
25568c2ecf20Sopenharmony_ci			if (rspq[q_idx] == 0xffff)
25578c2ecf20Sopenharmony_ci				q_idx = 0;
25588c2ecf20Sopenharmony_ci		}
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config);
25618c2ecf20Sopenharmony_ci}
25628c2ecf20Sopenharmony_ci
25638c2ecf20Sopenharmony_ci/**
25648c2ecf20Sopenharmony_ci *	t3_tp_set_offload_mode - put TP in NIC/offload mode
25658c2ecf20Sopenharmony_ci *	@adap: the adapter
25668c2ecf20Sopenharmony_ci *	@enable: 1 to select offload mode, 0 for regular NIC
25678c2ecf20Sopenharmony_ci *
25688c2ecf20Sopenharmony_ci *	Switches TP to NIC/offload mode.
25698c2ecf20Sopenharmony_ci */
25708c2ecf20Sopenharmony_civoid t3_tp_set_offload_mode(struct adapter *adap, int enable)
25718c2ecf20Sopenharmony_ci{
25728c2ecf20Sopenharmony_ci	if (is_offload(adap) || !enable)
25738c2ecf20Sopenharmony_ci		t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE,
25748c2ecf20Sopenharmony_ci				 V_NICMODE(!enable));
25758c2ecf20Sopenharmony_ci}
25768c2ecf20Sopenharmony_ci
25778c2ecf20Sopenharmony_ci/**
25788c2ecf20Sopenharmony_ci *	pm_num_pages - calculate the number of pages of the payload memory
25798c2ecf20Sopenharmony_ci *	@mem_size: the size of the payload memory
25808c2ecf20Sopenharmony_ci *	@pg_size: the size of each payload memory page
25818c2ecf20Sopenharmony_ci *
25828c2ecf20Sopenharmony_ci *	Calculate the number of pages, each of the given size, that fit in a
25838c2ecf20Sopenharmony_ci *	memory of the specified size, respecting the HW requirement that the
25848c2ecf20Sopenharmony_ci *	number of pages must be a multiple of 24.
25858c2ecf20Sopenharmony_ci */
25868c2ecf20Sopenharmony_cistatic inline unsigned int pm_num_pages(unsigned int mem_size,
25878c2ecf20Sopenharmony_ci					unsigned int pg_size)
25888c2ecf20Sopenharmony_ci{
25898c2ecf20Sopenharmony_ci	unsigned int n = mem_size / pg_size;
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_ci	return n - n % 24;
25928c2ecf20Sopenharmony_ci}
25938c2ecf20Sopenharmony_ci
25948c2ecf20Sopenharmony_ci#define mem_region(adap, start, size, reg) \
25958c2ecf20Sopenharmony_ci	t3_write_reg((adap), A_ ## reg, (start)); \
25968c2ecf20Sopenharmony_ci	start += size
25978c2ecf20Sopenharmony_ci
25988c2ecf20Sopenharmony_ci/**
25998c2ecf20Sopenharmony_ci *	partition_mem - partition memory and configure TP memory settings
26008c2ecf20Sopenharmony_ci *	@adap: the adapter
26018c2ecf20Sopenharmony_ci *	@p: the TP parameters
26028c2ecf20Sopenharmony_ci *
26038c2ecf20Sopenharmony_ci *	Partitions context and payload memory and configures TP's memory
26048c2ecf20Sopenharmony_ci *	registers.
26058c2ecf20Sopenharmony_ci */
26068c2ecf20Sopenharmony_cistatic void partition_mem(struct adapter *adap, const struct tp_params *p)
26078c2ecf20Sopenharmony_ci{
26088c2ecf20Sopenharmony_ci	unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5);
26098c2ecf20Sopenharmony_ci	unsigned int timers = 0, timers_shift = 22;
26108c2ecf20Sopenharmony_ci
26118c2ecf20Sopenharmony_ci	if (adap->params.rev > 0) {
26128c2ecf20Sopenharmony_ci		if (tids <= 16 * 1024) {
26138c2ecf20Sopenharmony_ci			timers = 1;
26148c2ecf20Sopenharmony_ci			timers_shift = 16;
26158c2ecf20Sopenharmony_ci		} else if (tids <= 64 * 1024) {
26168c2ecf20Sopenharmony_ci			timers = 2;
26178c2ecf20Sopenharmony_ci			timers_shift = 18;
26188c2ecf20Sopenharmony_ci		} else if (tids <= 256 * 1024) {
26198c2ecf20Sopenharmony_ci			timers = 3;
26208c2ecf20Sopenharmony_ci			timers_shift = 20;
26218c2ecf20Sopenharmony_ci		}
26228c2ecf20Sopenharmony_ci	}
26238c2ecf20Sopenharmony_ci
26248c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_PMM_SIZE,
26258c2ecf20Sopenharmony_ci		     p->chan_rx_size | (p->chan_tx_size >> 16));
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_PMM_TX_BASE, 0);
26288c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size);
26298c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs);
26308c2ecf20Sopenharmony_ci	t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX),
26318c2ecf20Sopenharmony_ci			 V_TXDATAACKIDX(fls(p->tx_pg_size) - 12));
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_PMM_RX_BASE, 0);
26348c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size);
26358c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs);
26368c2ecf20Sopenharmony_ci
26378c2ecf20Sopenharmony_ci	pstructs = p->rx_num_pgs + p->tx_num_pgs;
26388c2ecf20Sopenharmony_ci	/* Add a bit of headroom and make multiple of 24 */
26398c2ecf20Sopenharmony_ci	pstructs += 48;
26408c2ecf20Sopenharmony_ci	pstructs -= pstructs % 24;
26418c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs);
26428c2ecf20Sopenharmony_ci
26438c2ecf20Sopenharmony_ci	m = tids * TCB_SIZE;
26448c2ecf20Sopenharmony_ci	mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR);
26458c2ecf20Sopenharmony_ci	mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR);
26468c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m);
26478c2ecf20Sopenharmony_ci	m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22);
26488c2ecf20Sopenharmony_ci	mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE);
26498c2ecf20Sopenharmony_ci	mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE);
26508c2ecf20Sopenharmony_ci	mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE);
26518c2ecf20Sopenharmony_ci	mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE);
26528c2ecf20Sopenharmony_ci
26538c2ecf20Sopenharmony_ci	m = (m + 4095) & ~0xfff;
26548c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m);
26558c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m);
26568c2ecf20Sopenharmony_ci
26578c2ecf20Sopenharmony_ci	tids = (p->cm_size - m - (3 << 20)) / 3072 - 32;
26588c2ecf20Sopenharmony_ci	m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
26598c2ecf20Sopenharmony_ci	    adap->params.mc5.nfilters - adap->params.mc5.nroutes;
26608c2ecf20Sopenharmony_ci	if (tids < m)
26618c2ecf20Sopenharmony_ci		adap->params.mc5.nservers += m - tids;
26628c2ecf20Sopenharmony_ci}
26638c2ecf20Sopenharmony_ci
26648c2ecf20Sopenharmony_cistatic inline void tp_wr_indirect(struct adapter *adap, unsigned int addr,
26658c2ecf20Sopenharmony_ci				  u32 val)
26668c2ecf20Sopenharmony_ci{
26678c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_PIO_ADDR, addr);
26688c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_PIO_DATA, val);
26698c2ecf20Sopenharmony_ci}
26708c2ecf20Sopenharmony_ci
26718c2ecf20Sopenharmony_cistatic void tp_config(struct adapter *adap, const struct tp_params *p)
26728c2ecf20Sopenharmony_ci{
26738c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU |
26748c2ecf20Sopenharmony_ci		     F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD |
26758c2ecf20Sopenharmony_ci		     F_TCPCHECKSUMOFFLOAD | V_IPTTL(64));
26768c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) |
26778c2ecf20Sopenharmony_ci		     F_MTUENABLE | V_WINDOWSCALEMODE(1) |
26788c2ecf20Sopenharmony_ci		     V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1));
26798c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) |
26808c2ecf20Sopenharmony_ci		     V_AUTOSTATE2(1) | V_AUTOSTATE1(0) |
26818c2ecf20Sopenharmony_ci		     V_BYTETHRESHOLD(26880) | V_MSSTHRESHOLD(2) |
26828c2ecf20Sopenharmony_ci		     F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1));
26838c2ecf20Sopenharmony_ci	t3_set_reg_field(adap, A_TP_IN_CONFIG, F_RXFBARBPRIO | F_TXFBARBPRIO,
26848c2ecf20Sopenharmony_ci			 F_IPV6ENABLE | F_NICMODE);
26858c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814);
26868c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105);
26878c2ecf20Sopenharmony_ci	t3_set_reg_field(adap, A_TP_PARA_REG6, 0,
26888c2ecf20Sopenharmony_ci			 adap->params.rev > 0 ? F_ENABLEESND :
26898c2ecf20Sopenharmony_ci			 F_T3A_ENABLEESND);
26908c2ecf20Sopenharmony_ci
26918c2ecf20Sopenharmony_ci	t3_set_reg_field(adap, A_TP_PC_CONFIG,
26928c2ecf20Sopenharmony_ci			 F_ENABLEEPCMDAFULL,
26938c2ecf20Sopenharmony_ci			 F_ENABLEOCSPIFULL |F_TXDEFERENABLE | F_HEARBEATDACK |
26948c2ecf20Sopenharmony_ci			 F_TXCONGESTIONMODE | F_RXCONGESTIONMODE);
26958c2ecf20Sopenharmony_ci	t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL,
26968c2ecf20Sopenharmony_ci			 F_ENABLEIPV6RSS | F_ENABLENONOFDTNLSYN |
26978c2ecf20Sopenharmony_ci			 F_ENABLEARPMISS | F_DISBLEDAPARBIT0);
26988c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1080);
26998c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1000);
27008c2ecf20Sopenharmony_ci
27018c2ecf20Sopenharmony_ci	if (adap->params.rev > 0) {
27028c2ecf20Sopenharmony_ci		tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE);
27038c2ecf20Sopenharmony_ci		t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO,
27048c2ecf20Sopenharmony_ci				 F_TXPACEAUTO);
27058c2ecf20Sopenharmony_ci		t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID);
27068c2ecf20Sopenharmony_ci		t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEAUTOSTRICT);
27078c2ecf20Sopenharmony_ci	} else
27088c2ecf20Sopenharmony_ci		t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED);
27098c2ecf20Sopenharmony_ci
27108c2ecf20Sopenharmony_ci	if (adap->params.rev == T3_REV_C)
27118c2ecf20Sopenharmony_ci		t3_set_reg_field(adap, A_TP_PC_CONFIG,
27128c2ecf20Sopenharmony_ci				 V_TABLELATENCYDELTA(M_TABLELATENCYDELTA),
27138c2ecf20Sopenharmony_ci				 V_TABLELATENCYDELTA(4));
27148c2ecf20Sopenharmony_ci
27158c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0);
27168c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0);
27178c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0);
27188c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_MOD_RATE_LIMIT, 0xf2200000);
27198c2ecf20Sopenharmony_ci}
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci/* Desired TP timer resolution in usec */
27228c2ecf20Sopenharmony_ci#define TP_TMR_RES 50
27238c2ecf20Sopenharmony_ci
27248c2ecf20Sopenharmony_ci/* TCP timer values in ms */
27258c2ecf20Sopenharmony_ci#define TP_DACK_TIMER 50
27268c2ecf20Sopenharmony_ci#define TP_RTO_MIN    250
27278c2ecf20Sopenharmony_ci
27288c2ecf20Sopenharmony_ci/**
27298c2ecf20Sopenharmony_ci *	tp_set_timers - set TP timing parameters
27308c2ecf20Sopenharmony_ci *	@adap: the adapter to set
27318c2ecf20Sopenharmony_ci *	@core_clk: the core clock frequency in Hz
27328c2ecf20Sopenharmony_ci *
27338c2ecf20Sopenharmony_ci *	Set TP's timing parameters, such as the various timer resolutions and
27348c2ecf20Sopenharmony_ci *	the TCP timer values.
27358c2ecf20Sopenharmony_ci */
27368c2ecf20Sopenharmony_cistatic void tp_set_timers(struct adapter *adap, unsigned int core_clk)
27378c2ecf20Sopenharmony_ci{
27388c2ecf20Sopenharmony_ci	unsigned int tre = fls(core_clk / (1000000 / TP_TMR_RES)) - 1;
27398c2ecf20Sopenharmony_ci	unsigned int dack_re = fls(core_clk / 5000) - 1;	/* 200us */
27408c2ecf20Sopenharmony_ci	unsigned int tstamp_re = fls(core_clk / 1000);	/* 1ms, at least */
27418c2ecf20Sopenharmony_ci	unsigned int tps = core_clk >> tre;
27428c2ecf20Sopenharmony_ci
27438c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) |
27448c2ecf20Sopenharmony_ci		     V_DELAYEDACKRESOLUTION(dack_re) |
27458c2ecf20Sopenharmony_ci		     V_TIMESTAMPRESOLUTION(tstamp_re));
27468c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_DACK_TIMER,
27478c2ecf20Sopenharmony_ci		     (core_clk >> dack_re) / (1000 / TP_DACK_TIMER));
27488c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100);
27498c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504);
27508c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908);
27518c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c);
27528c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) |
27538c2ecf20Sopenharmony_ci		     V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) |
27548c2ecf20Sopenharmony_ci		     V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
27558c2ecf20Sopenharmony_ci		     V_KEEPALIVEMAX(9));
27568c2ecf20Sopenharmony_ci
27578c2ecf20Sopenharmony_ci#define SECONDS * tps
27588c2ecf20Sopenharmony_ci
27598c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_MSL, adap->params.rev > 0 ? 0 : 2 SECONDS);
27608c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN));
27618c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS);
27628c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS);
27638c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS);
27648c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS);
27658c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS);
27668c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS);
27678c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS);
27688c2ecf20Sopenharmony_ci
27698c2ecf20Sopenharmony_ci#undef SECONDS
27708c2ecf20Sopenharmony_ci}
27718c2ecf20Sopenharmony_ci
27728c2ecf20Sopenharmony_ci/**
27738c2ecf20Sopenharmony_ci *	t3_tp_set_coalescing_size - set receive coalescing size
27748c2ecf20Sopenharmony_ci *	@adap: the adapter
27758c2ecf20Sopenharmony_ci *	@size: the receive coalescing size
27768c2ecf20Sopenharmony_ci *	@psh: whether a set PSH bit should deliver coalesced data
27778c2ecf20Sopenharmony_ci *
27788c2ecf20Sopenharmony_ci *	Set the receive coalescing size and PSH bit handling.
27798c2ecf20Sopenharmony_ci */
27808c2ecf20Sopenharmony_cistatic int t3_tp_set_coalescing_size(struct adapter *adap,
27818c2ecf20Sopenharmony_ci				     unsigned int size, int psh)
27828c2ecf20Sopenharmony_ci{
27838c2ecf20Sopenharmony_ci	u32 val;
27848c2ecf20Sopenharmony_ci
27858c2ecf20Sopenharmony_ci	if (size > MAX_RX_COALESCING_LEN)
27868c2ecf20Sopenharmony_ci		return -EINVAL;
27878c2ecf20Sopenharmony_ci
27888c2ecf20Sopenharmony_ci	val = t3_read_reg(adap, A_TP_PARA_REG3);
27898c2ecf20Sopenharmony_ci	val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN);
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	if (size) {
27928c2ecf20Sopenharmony_ci		val |= F_RXCOALESCEENABLE;
27938c2ecf20Sopenharmony_ci		if (psh)
27948c2ecf20Sopenharmony_ci			val |= F_RXCOALESCEPSHEN;
27958c2ecf20Sopenharmony_ci		size = min(MAX_RX_COALESCING_LEN, size);
27968c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) |
27978c2ecf20Sopenharmony_ci			     V_MAXRXDATA(MAX_RX_COALESCING_LEN));
27988c2ecf20Sopenharmony_ci	}
27998c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_PARA_REG3, val);
28008c2ecf20Sopenharmony_ci	return 0;
28018c2ecf20Sopenharmony_ci}
28028c2ecf20Sopenharmony_ci
28038c2ecf20Sopenharmony_ci/**
28048c2ecf20Sopenharmony_ci *	t3_tp_set_max_rxsize - set the max receive size
28058c2ecf20Sopenharmony_ci *	@adap: the adapter
28068c2ecf20Sopenharmony_ci *	@size: the max receive size
28078c2ecf20Sopenharmony_ci *
28088c2ecf20Sopenharmony_ci *	Set TP's max receive size.  This is the limit that applies when
28098c2ecf20Sopenharmony_ci *	receive coalescing is disabled.
28108c2ecf20Sopenharmony_ci */
28118c2ecf20Sopenharmony_cistatic void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size)
28128c2ecf20Sopenharmony_ci{
28138c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_PARA_REG7,
28148c2ecf20Sopenharmony_ci		     V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size));
28158c2ecf20Sopenharmony_ci}
28168c2ecf20Sopenharmony_ci
28178c2ecf20Sopenharmony_cistatic void init_mtus(unsigned short mtus[])
28188c2ecf20Sopenharmony_ci{
28198c2ecf20Sopenharmony_ci	/*
28208c2ecf20Sopenharmony_ci	 * See draft-mathis-plpmtud-00.txt for the values.  The min is 88 so
28218c2ecf20Sopenharmony_ci	 * it can accommodate max size TCP/IP headers when SACK and timestamps
28228c2ecf20Sopenharmony_ci	 * are enabled and still have at least 8 bytes of payload.
28238c2ecf20Sopenharmony_ci	 */
28248c2ecf20Sopenharmony_ci	mtus[0] = 88;
28258c2ecf20Sopenharmony_ci	mtus[1] = 88;
28268c2ecf20Sopenharmony_ci	mtus[2] = 256;
28278c2ecf20Sopenharmony_ci	mtus[3] = 512;
28288c2ecf20Sopenharmony_ci	mtus[4] = 576;
28298c2ecf20Sopenharmony_ci	mtus[5] = 1024;
28308c2ecf20Sopenharmony_ci	mtus[6] = 1280;
28318c2ecf20Sopenharmony_ci	mtus[7] = 1492;
28328c2ecf20Sopenharmony_ci	mtus[8] = 1500;
28338c2ecf20Sopenharmony_ci	mtus[9] = 2002;
28348c2ecf20Sopenharmony_ci	mtus[10] = 2048;
28358c2ecf20Sopenharmony_ci	mtus[11] = 4096;
28368c2ecf20Sopenharmony_ci	mtus[12] = 4352;
28378c2ecf20Sopenharmony_ci	mtus[13] = 8192;
28388c2ecf20Sopenharmony_ci	mtus[14] = 9000;
28398c2ecf20Sopenharmony_ci	mtus[15] = 9600;
28408c2ecf20Sopenharmony_ci}
28418c2ecf20Sopenharmony_ci
28428c2ecf20Sopenharmony_ci/*
28438c2ecf20Sopenharmony_ci * Initial congestion control parameters.
28448c2ecf20Sopenharmony_ci */
28458c2ecf20Sopenharmony_cistatic void init_cong_ctrl(unsigned short *a, unsigned short *b)
28468c2ecf20Sopenharmony_ci{
28478c2ecf20Sopenharmony_ci	a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
28488c2ecf20Sopenharmony_ci	a[9] = 2;
28498c2ecf20Sopenharmony_ci	a[10] = 3;
28508c2ecf20Sopenharmony_ci	a[11] = 4;
28518c2ecf20Sopenharmony_ci	a[12] = 5;
28528c2ecf20Sopenharmony_ci	a[13] = 6;
28538c2ecf20Sopenharmony_ci	a[14] = 7;
28548c2ecf20Sopenharmony_ci	a[15] = 8;
28558c2ecf20Sopenharmony_ci	a[16] = 9;
28568c2ecf20Sopenharmony_ci	a[17] = 10;
28578c2ecf20Sopenharmony_ci	a[18] = 14;
28588c2ecf20Sopenharmony_ci	a[19] = 17;
28598c2ecf20Sopenharmony_ci	a[20] = 21;
28608c2ecf20Sopenharmony_ci	a[21] = 25;
28618c2ecf20Sopenharmony_ci	a[22] = 30;
28628c2ecf20Sopenharmony_ci	a[23] = 35;
28638c2ecf20Sopenharmony_ci	a[24] = 45;
28648c2ecf20Sopenharmony_ci	a[25] = 60;
28658c2ecf20Sopenharmony_ci	a[26] = 80;
28668c2ecf20Sopenharmony_ci	a[27] = 100;
28678c2ecf20Sopenharmony_ci	a[28] = 200;
28688c2ecf20Sopenharmony_ci	a[29] = 300;
28698c2ecf20Sopenharmony_ci	a[30] = 400;
28708c2ecf20Sopenharmony_ci	a[31] = 500;
28718c2ecf20Sopenharmony_ci
28728c2ecf20Sopenharmony_ci	b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0;
28738c2ecf20Sopenharmony_ci	b[9] = b[10] = 1;
28748c2ecf20Sopenharmony_ci	b[11] = b[12] = 2;
28758c2ecf20Sopenharmony_ci	b[13] = b[14] = b[15] = b[16] = 3;
28768c2ecf20Sopenharmony_ci	b[17] = b[18] = b[19] = b[20] = b[21] = 4;
28778c2ecf20Sopenharmony_ci	b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5;
28788c2ecf20Sopenharmony_ci	b[28] = b[29] = 6;
28798c2ecf20Sopenharmony_ci	b[30] = b[31] = 7;
28808c2ecf20Sopenharmony_ci}
28818c2ecf20Sopenharmony_ci
28828c2ecf20Sopenharmony_ci/* The minimum additive increment value for the congestion control table */
28838c2ecf20Sopenharmony_ci#define CC_MIN_INCR 2U
28848c2ecf20Sopenharmony_ci
28858c2ecf20Sopenharmony_ci/**
28868c2ecf20Sopenharmony_ci *	t3_load_mtus - write the MTU and congestion control HW tables
28878c2ecf20Sopenharmony_ci *	@adap: the adapter
28888c2ecf20Sopenharmony_ci *	@mtus: the unrestricted values for the MTU table
28898c2ecf20Sopenharmony_ci *	@alpha: the values for the congestion control alpha parameter
28908c2ecf20Sopenharmony_ci *	@beta: the values for the congestion control beta parameter
28918c2ecf20Sopenharmony_ci *	@mtu_cap: the maximum permitted effective MTU
28928c2ecf20Sopenharmony_ci *
28938c2ecf20Sopenharmony_ci *	Write the MTU table with the supplied MTUs capping each at &mtu_cap.
28948c2ecf20Sopenharmony_ci *	Update the high-speed congestion control table with the supplied alpha,
28958c2ecf20Sopenharmony_ci * 	beta, and MTUs.
28968c2ecf20Sopenharmony_ci */
28978c2ecf20Sopenharmony_civoid t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS],
28988c2ecf20Sopenharmony_ci		  unsigned short alpha[NCCTRL_WIN],
28998c2ecf20Sopenharmony_ci		  unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap)
29008c2ecf20Sopenharmony_ci{
29018c2ecf20Sopenharmony_ci	static const unsigned int avg_pkts[NCCTRL_WIN] = {
29028c2ecf20Sopenharmony_ci		2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640,
29038c2ecf20Sopenharmony_ci		896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480,
29048c2ecf20Sopenharmony_ci		28672, 40960, 57344, 81920, 114688, 163840, 229376
29058c2ecf20Sopenharmony_ci	};
29068c2ecf20Sopenharmony_ci
29078c2ecf20Sopenharmony_ci	unsigned int i, w;
29088c2ecf20Sopenharmony_ci
29098c2ecf20Sopenharmony_ci	for (i = 0; i < NMTUS; ++i) {
29108c2ecf20Sopenharmony_ci		unsigned int mtu = min(mtus[i], mtu_cap);
29118c2ecf20Sopenharmony_ci		unsigned int log2 = fls(mtu);
29128c2ecf20Sopenharmony_ci
29138c2ecf20Sopenharmony_ci		if (!(mtu & ((1 << log2) >> 2)))	/* round */
29148c2ecf20Sopenharmony_ci			log2--;
29158c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_TP_MTU_TABLE,
29168c2ecf20Sopenharmony_ci			     (i << 24) | (log2 << 16) | mtu);
29178c2ecf20Sopenharmony_ci
29188c2ecf20Sopenharmony_ci		for (w = 0; w < NCCTRL_WIN; ++w) {
29198c2ecf20Sopenharmony_ci			unsigned int inc;
29208c2ecf20Sopenharmony_ci
29218c2ecf20Sopenharmony_ci			inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w],
29228c2ecf20Sopenharmony_ci				  CC_MIN_INCR);
29238c2ecf20Sopenharmony_ci
29248c2ecf20Sopenharmony_ci			t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) |
29258c2ecf20Sopenharmony_ci				     (w << 16) | (beta[w] << 13) | inc);
29268c2ecf20Sopenharmony_ci		}
29278c2ecf20Sopenharmony_ci	}
29288c2ecf20Sopenharmony_ci}
29298c2ecf20Sopenharmony_ci
29308c2ecf20Sopenharmony_ci/**
29318c2ecf20Sopenharmony_ci *	t3_tp_get_mib_stats - read TP's MIB counters
29328c2ecf20Sopenharmony_ci *	@adap: the adapter
29338c2ecf20Sopenharmony_ci *	@tps: holds the returned counter values
29348c2ecf20Sopenharmony_ci *
29358c2ecf20Sopenharmony_ci *	Returns the values of TP's MIB counters.
29368c2ecf20Sopenharmony_ci */
29378c2ecf20Sopenharmony_civoid t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps)
29388c2ecf20Sopenharmony_ci{
29398c2ecf20Sopenharmony_ci	t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *) tps,
29408c2ecf20Sopenharmony_ci			 sizeof(*tps) / sizeof(u32), 0);
29418c2ecf20Sopenharmony_ci}
29428c2ecf20Sopenharmony_ci
29438c2ecf20Sopenharmony_ci#define ulp_region(adap, name, start, len) \
29448c2ecf20Sopenharmony_ci	t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \
29458c2ecf20Sopenharmony_ci	t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \
29468c2ecf20Sopenharmony_ci		     (start) + (len) - 1); \
29478c2ecf20Sopenharmony_ci	start += len
29488c2ecf20Sopenharmony_ci
29498c2ecf20Sopenharmony_ci#define ulptx_region(adap, name, start, len) \
29508c2ecf20Sopenharmony_ci	t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \
29518c2ecf20Sopenharmony_ci	t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \
29528c2ecf20Sopenharmony_ci		     (start) + (len) - 1)
29538c2ecf20Sopenharmony_ci
29548c2ecf20Sopenharmony_cistatic void ulp_config(struct adapter *adap, const struct tp_params *p)
29558c2ecf20Sopenharmony_ci{
29568c2ecf20Sopenharmony_ci	unsigned int m = p->chan_rx_size;
29578c2ecf20Sopenharmony_ci
29588c2ecf20Sopenharmony_ci	ulp_region(adap, ISCSI, m, p->chan_rx_size / 8);
29598c2ecf20Sopenharmony_ci	ulp_region(adap, TDDP, m, p->chan_rx_size / 8);
29608c2ecf20Sopenharmony_ci	ulptx_region(adap, TPT, m, p->chan_rx_size / 4);
29618c2ecf20Sopenharmony_ci	ulp_region(adap, STAG, m, p->chan_rx_size / 4);
29628c2ecf20Sopenharmony_ci	ulp_region(adap, RQ, m, p->chan_rx_size / 4);
29638c2ecf20Sopenharmony_ci	ulptx_region(adap, PBL, m, p->chan_rx_size / 4);
29648c2ecf20Sopenharmony_ci	ulp_region(adap, PBL, m, p->chan_rx_size / 4);
29658c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff);
29668c2ecf20Sopenharmony_ci}
29678c2ecf20Sopenharmony_ci
29688c2ecf20Sopenharmony_ci/**
29698c2ecf20Sopenharmony_ci *	t3_set_proto_sram - set the contents of the protocol sram
29708c2ecf20Sopenharmony_ci *	@adap: the adapter
29718c2ecf20Sopenharmony_ci *	@data: the protocol image
29728c2ecf20Sopenharmony_ci *
29738c2ecf20Sopenharmony_ci *	Write the contents of the protocol SRAM.
29748c2ecf20Sopenharmony_ci */
29758c2ecf20Sopenharmony_ciint t3_set_proto_sram(struct adapter *adap, const u8 *data)
29768c2ecf20Sopenharmony_ci{
29778c2ecf20Sopenharmony_ci	int i;
29788c2ecf20Sopenharmony_ci	const __be32 *buf = (const __be32 *)data;
29798c2ecf20Sopenharmony_ci
29808c2ecf20Sopenharmony_ci	for (i = 0; i < PROTO_SRAM_LINES; i++) {
29818c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, be32_to_cpu(*buf++));
29828c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, be32_to_cpu(*buf++));
29838c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, be32_to_cpu(*buf++));
29848c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, be32_to_cpu(*buf++));
29858c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, be32_to_cpu(*buf++));
29868c2ecf20Sopenharmony_ci
29878c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, i << 1 | 1 << 31);
29888c2ecf20Sopenharmony_ci		if (t3_wait_op_done(adap, A_TP_EMBED_OP_FIELD0, 1, 1, 5, 1))
29898c2ecf20Sopenharmony_ci			return -EIO;
29908c2ecf20Sopenharmony_ci	}
29918c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, 0);
29928c2ecf20Sopenharmony_ci
29938c2ecf20Sopenharmony_ci	return 0;
29948c2ecf20Sopenharmony_ci}
29958c2ecf20Sopenharmony_ci
29968c2ecf20Sopenharmony_civoid t3_config_trace_filter(struct adapter *adapter,
29978c2ecf20Sopenharmony_ci			    const struct trace_params *tp, int filter_index,
29988c2ecf20Sopenharmony_ci			    int invert, int enable)
29998c2ecf20Sopenharmony_ci{
30008c2ecf20Sopenharmony_ci	u32 addr, key[4], mask[4];
30018c2ecf20Sopenharmony_ci
30028c2ecf20Sopenharmony_ci	key[0] = tp->sport | (tp->sip << 16);
30038c2ecf20Sopenharmony_ci	key[1] = (tp->sip >> 16) | (tp->dport << 16);
30048c2ecf20Sopenharmony_ci	key[2] = tp->dip;
30058c2ecf20Sopenharmony_ci	key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20);
30068c2ecf20Sopenharmony_ci
30078c2ecf20Sopenharmony_ci	mask[0] = tp->sport_mask | (tp->sip_mask << 16);
30088c2ecf20Sopenharmony_ci	mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16);
30098c2ecf20Sopenharmony_ci	mask[2] = tp->dip_mask;
30108c2ecf20Sopenharmony_ci	mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20);
30118c2ecf20Sopenharmony_ci
30128c2ecf20Sopenharmony_ci	if (invert)
30138c2ecf20Sopenharmony_ci		key[3] |= (1 << 29);
30148c2ecf20Sopenharmony_ci	if (enable)
30158c2ecf20Sopenharmony_ci		key[3] |= (1 << 28);
30168c2ecf20Sopenharmony_ci
30178c2ecf20Sopenharmony_ci	addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0;
30188c2ecf20Sopenharmony_ci	tp_wr_indirect(adapter, addr++, key[0]);
30198c2ecf20Sopenharmony_ci	tp_wr_indirect(adapter, addr++, mask[0]);
30208c2ecf20Sopenharmony_ci	tp_wr_indirect(adapter, addr++, key[1]);
30218c2ecf20Sopenharmony_ci	tp_wr_indirect(adapter, addr++, mask[1]);
30228c2ecf20Sopenharmony_ci	tp_wr_indirect(adapter, addr++, key[2]);
30238c2ecf20Sopenharmony_ci	tp_wr_indirect(adapter, addr++, mask[2]);
30248c2ecf20Sopenharmony_ci	tp_wr_indirect(adapter, addr++, key[3]);
30258c2ecf20Sopenharmony_ci	tp_wr_indirect(adapter, addr, mask[3]);
30268c2ecf20Sopenharmony_ci	t3_read_reg(adapter, A_TP_PIO_DATA);
30278c2ecf20Sopenharmony_ci}
30288c2ecf20Sopenharmony_ci
30298c2ecf20Sopenharmony_ci/**
30308c2ecf20Sopenharmony_ci *	t3_config_sched - configure a HW traffic scheduler
30318c2ecf20Sopenharmony_ci *	@adap: the adapter
30328c2ecf20Sopenharmony_ci *	@kbps: target rate in Kbps
30338c2ecf20Sopenharmony_ci *	@sched: the scheduler index
30348c2ecf20Sopenharmony_ci *
30358c2ecf20Sopenharmony_ci *	Configure a HW scheduler for the target rate
30368c2ecf20Sopenharmony_ci */
30378c2ecf20Sopenharmony_ciint t3_config_sched(struct adapter *adap, unsigned int kbps, int sched)
30388c2ecf20Sopenharmony_ci{
30398c2ecf20Sopenharmony_ci	unsigned int v, tps, cpt, bpt, delta, mindelta = ~0;
30408c2ecf20Sopenharmony_ci	unsigned int clk = adap->params.vpd.cclk * 1000;
30418c2ecf20Sopenharmony_ci	unsigned int selected_cpt = 0, selected_bpt = 0;
30428c2ecf20Sopenharmony_ci
30438c2ecf20Sopenharmony_ci	if (kbps > 0) {
30448c2ecf20Sopenharmony_ci		kbps *= 125;	/* -> bytes */
30458c2ecf20Sopenharmony_ci		for (cpt = 1; cpt <= 255; cpt++) {
30468c2ecf20Sopenharmony_ci			tps = clk / cpt;
30478c2ecf20Sopenharmony_ci			bpt = (kbps + tps / 2) / tps;
30488c2ecf20Sopenharmony_ci			if (bpt > 0 && bpt <= 255) {
30498c2ecf20Sopenharmony_ci				v = bpt * tps;
30508c2ecf20Sopenharmony_ci				delta = v >= kbps ? v - kbps : kbps - v;
30518c2ecf20Sopenharmony_ci				if (delta <= mindelta) {
30528c2ecf20Sopenharmony_ci					mindelta = delta;
30538c2ecf20Sopenharmony_ci					selected_cpt = cpt;
30548c2ecf20Sopenharmony_ci					selected_bpt = bpt;
30558c2ecf20Sopenharmony_ci				}
30568c2ecf20Sopenharmony_ci			} else if (selected_cpt)
30578c2ecf20Sopenharmony_ci				break;
30588c2ecf20Sopenharmony_ci		}
30598c2ecf20Sopenharmony_ci		if (!selected_cpt)
30608c2ecf20Sopenharmony_ci			return -EINVAL;
30618c2ecf20Sopenharmony_ci	}
30628c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_TM_PIO_ADDR,
30638c2ecf20Sopenharmony_ci		     A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2);
30648c2ecf20Sopenharmony_ci	v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
30658c2ecf20Sopenharmony_ci	if (sched & 1)
30668c2ecf20Sopenharmony_ci		v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24);
30678c2ecf20Sopenharmony_ci	else
30688c2ecf20Sopenharmony_ci		v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8);
30698c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_TP_TM_PIO_DATA, v);
30708c2ecf20Sopenharmony_ci	return 0;
30718c2ecf20Sopenharmony_ci}
30728c2ecf20Sopenharmony_ci
30738c2ecf20Sopenharmony_cistatic int tp_init(struct adapter *adap, const struct tp_params *p)
30748c2ecf20Sopenharmony_ci{
30758c2ecf20Sopenharmony_ci	int busy = 0;
30768c2ecf20Sopenharmony_ci
30778c2ecf20Sopenharmony_ci	tp_config(adap, p);
30788c2ecf20Sopenharmony_ci	t3_set_vlan_accel(adap, 3, 0);
30798c2ecf20Sopenharmony_ci
30808c2ecf20Sopenharmony_ci	if (is_offload(adap)) {
30818c2ecf20Sopenharmony_ci		tp_set_timers(adap, adap->params.vpd.cclk * 1000);
30828c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE);
30838c2ecf20Sopenharmony_ci		busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE,
30848c2ecf20Sopenharmony_ci				       0, 1000, 5);
30858c2ecf20Sopenharmony_ci		if (busy)
30868c2ecf20Sopenharmony_ci			CH_ERR(adap, "TP initialization timed out\n");
30878c2ecf20Sopenharmony_ci	}
30888c2ecf20Sopenharmony_ci
30898c2ecf20Sopenharmony_ci	if (!busy)
30908c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_TP_RESET, F_TPRESET);
30918c2ecf20Sopenharmony_ci	return busy;
30928c2ecf20Sopenharmony_ci}
30938c2ecf20Sopenharmony_ci
30948c2ecf20Sopenharmony_ci/*
30958c2ecf20Sopenharmony_ci * Perform the bits of HW initialization that are dependent on the Tx
30968c2ecf20Sopenharmony_ci * channels being used.
30978c2ecf20Sopenharmony_ci */
30988c2ecf20Sopenharmony_cistatic void chan_init_hw(struct adapter *adap, unsigned int chan_map)
30998c2ecf20Sopenharmony_ci{
31008c2ecf20Sopenharmony_ci	int i;
31018c2ecf20Sopenharmony_ci
31028c2ecf20Sopenharmony_ci	if (chan_map != 3) {                                 /* one channel */
31038c2ecf20Sopenharmony_ci		t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0);
31048c2ecf20Sopenharmony_ci		t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0);
31058c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_ENFORCEPKT |
31068c2ecf20Sopenharmony_ci			     (chan_map == 1 ? F_TPTXPORT0EN | F_PORT0ACTIVE :
31078c2ecf20Sopenharmony_ci					      F_TPTXPORT1EN | F_PORT1ACTIVE));
31088c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_PM1_TX_CFG,
31098c2ecf20Sopenharmony_ci			     chan_map == 1 ? 0xffffffff : 0);
31108c2ecf20Sopenharmony_ci	} else {                                             /* two channels */
31118c2ecf20Sopenharmony_ci		t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN);
31128c2ecf20Sopenharmony_ci		t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB);
31138c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_ULPTX_DMA_WEIGHT,
31148c2ecf20Sopenharmony_ci			     V_D1_WEIGHT(16) | V_D0_WEIGHT(16));
31158c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN |
31168c2ecf20Sopenharmony_ci			     F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE |
31178c2ecf20Sopenharmony_ci			     F_ENFORCEPKT);
31188c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000);
31198c2ecf20Sopenharmony_ci		t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE);
31208c2ecf20Sopenharmony_ci		t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
31218c2ecf20Sopenharmony_ci			     V_TX_MOD_QUEUE_REQ_MAP(0xaa));
31228c2ecf20Sopenharmony_ci		for (i = 0; i < 16; i++)
31238c2ecf20Sopenharmony_ci			t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE,
31248c2ecf20Sopenharmony_ci				     (i << 16) | 0x1010);
31258c2ecf20Sopenharmony_ci	}
31268c2ecf20Sopenharmony_ci}
31278c2ecf20Sopenharmony_ci
31288c2ecf20Sopenharmony_cistatic int calibrate_xgm(struct adapter *adapter)
31298c2ecf20Sopenharmony_ci{
31308c2ecf20Sopenharmony_ci	if (uses_xaui(adapter)) {
31318c2ecf20Sopenharmony_ci		unsigned int v, i;
31328c2ecf20Sopenharmony_ci
31338c2ecf20Sopenharmony_ci		for (i = 0; i < 5; ++i) {
31348c2ecf20Sopenharmony_ci			t3_write_reg(adapter, A_XGM_XAUI_IMP, 0);
31358c2ecf20Sopenharmony_ci			t3_read_reg(adapter, A_XGM_XAUI_IMP);
31368c2ecf20Sopenharmony_ci			msleep(1);
31378c2ecf20Sopenharmony_ci			v = t3_read_reg(adapter, A_XGM_XAUI_IMP);
31388c2ecf20Sopenharmony_ci			if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) {
31398c2ecf20Sopenharmony_ci				t3_write_reg(adapter, A_XGM_XAUI_IMP,
31408c2ecf20Sopenharmony_ci					     V_XAUIIMP(G_CALIMP(v) >> 2));
31418c2ecf20Sopenharmony_ci				return 0;
31428c2ecf20Sopenharmony_ci			}
31438c2ecf20Sopenharmony_ci		}
31448c2ecf20Sopenharmony_ci		CH_ERR(adapter, "MAC calibration failed\n");
31458c2ecf20Sopenharmony_ci		return -1;
31468c2ecf20Sopenharmony_ci	} else {
31478c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_XGM_RGMII_IMP,
31488c2ecf20Sopenharmony_ci			     V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
31498c2ecf20Sopenharmony_ci		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
31508c2ecf20Sopenharmony_ci				 F_XGM_IMPSETUPDATE);
31518c2ecf20Sopenharmony_ci	}
31528c2ecf20Sopenharmony_ci	return 0;
31538c2ecf20Sopenharmony_ci}
31548c2ecf20Sopenharmony_ci
31558c2ecf20Sopenharmony_cistatic void calibrate_xgm_t3b(struct adapter *adapter)
31568c2ecf20Sopenharmony_ci{
31578c2ecf20Sopenharmony_ci	if (!uses_xaui(adapter)) {
31588c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET |
31598c2ecf20Sopenharmony_ci			     F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
31608c2ecf20Sopenharmony_ci		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0);
31618c2ecf20Sopenharmony_ci		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0,
31628c2ecf20Sopenharmony_ci				 F_XGM_IMPSETUPDATE);
31638c2ecf20Sopenharmony_ci		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
31648c2ecf20Sopenharmony_ci				 0);
31658c2ecf20Sopenharmony_ci		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0);
31668c2ecf20Sopenharmony_ci		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE);
31678c2ecf20Sopenharmony_ci	}
31688c2ecf20Sopenharmony_ci}
31698c2ecf20Sopenharmony_ci
31708c2ecf20Sopenharmony_cistruct mc7_timing_params {
31718c2ecf20Sopenharmony_ci	unsigned char ActToPreDly;
31728c2ecf20Sopenharmony_ci	unsigned char ActToRdWrDly;
31738c2ecf20Sopenharmony_ci	unsigned char PreCyc;
31748c2ecf20Sopenharmony_ci	unsigned char RefCyc[5];
31758c2ecf20Sopenharmony_ci	unsigned char BkCyc;
31768c2ecf20Sopenharmony_ci	unsigned char WrToRdDly;
31778c2ecf20Sopenharmony_ci	unsigned char RdToWrDly;
31788c2ecf20Sopenharmony_ci};
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_ci/*
31818c2ecf20Sopenharmony_ci * Write a value to a register and check that the write completed.  These
31828c2ecf20Sopenharmony_ci * writes normally complete in a cycle or two, so one read should suffice.
31838c2ecf20Sopenharmony_ci * The very first read exists to flush the posted write to the device.
31848c2ecf20Sopenharmony_ci */
31858c2ecf20Sopenharmony_cistatic int wrreg_wait(struct adapter *adapter, unsigned int addr, u32 val)
31868c2ecf20Sopenharmony_ci{
31878c2ecf20Sopenharmony_ci	t3_write_reg(adapter, addr, val);
31888c2ecf20Sopenharmony_ci	t3_read_reg(adapter, addr);	/* flush */
31898c2ecf20Sopenharmony_ci	if (!(t3_read_reg(adapter, addr) & F_BUSY))
31908c2ecf20Sopenharmony_ci		return 0;
31918c2ecf20Sopenharmony_ci	CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr);
31928c2ecf20Sopenharmony_ci	return -EIO;
31938c2ecf20Sopenharmony_ci}
31948c2ecf20Sopenharmony_ci
31958c2ecf20Sopenharmony_cistatic int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type)
31968c2ecf20Sopenharmony_ci{
31978c2ecf20Sopenharmony_ci	static const unsigned int mc7_mode[] = {
31988c2ecf20Sopenharmony_ci		0x632, 0x642, 0x652, 0x432, 0x442
31998c2ecf20Sopenharmony_ci	};
32008c2ecf20Sopenharmony_ci	static const struct mc7_timing_params mc7_timings[] = {
32018c2ecf20Sopenharmony_ci		{12, 3, 4, {20, 28, 34, 52, 0}, 15, 6, 4},
32028c2ecf20Sopenharmony_ci		{12, 4, 5, {20, 28, 34, 52, 0}, 16, 7, 4},
32038c2ecf20Sopenharmony_ci		{12, 5, 6, {20, 28, 34, 52, 0}, 17, 8, 4},
32048c2ecf20Sopenharmony_ci		{9, 3, 4, {15, 21, 26, 39, 0}, 12, 6, 4},
32058c2ecf20Sopenharmony_ci		{9, 4, 5, {15, 21, 26, 39, 0}, 13, 7, 4}
32068c2ecf20Sopenharmony_ci	};
32078c2ecf20Sopenharmony_ci
32088c2ecf20Sopenharmony_ci	u32 val;
32098c2ecf20Sopenharmony_ci	unsigned int width, density, slow, attempts;
32108c2ecf20Sopenharmony_ci	struct adapter *adapter = mc7->adapter;
32118c2ecf20Sopenharmony_ci	const struct mc7_timing_params *p = &mc7_timings[mem_type];
32128c2ecf20Sopenharmony_ci
32138c2ecf20Sopenharmony_ci	if (!mc7->size)
32148c2ecf20Sopenharmony_ci		return 0;
32158c2ecf20Sopenharmony_ci
32168c2ecf20Sopenharmony_ci	val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
32178c2ecf20Sopenharmony_ci	slow = val & F_SLOW;
32188c2ecf20Sopenharmony_ci	width = G_WIDTH(val);
32198c2ecf20Sopenharmony_ci	density = G_DEN(val);
32208c2ecf20Sopenharmony_ci
32218c2ecf20Sopenharmony_ci	t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN);
32228c2ecf20Sopenharmony_ci	val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);	/* flush */
32238c2ecf20Sopenharmony_ci	msleep(1);
32248c2ecf20Sopenharmony_ci
32258c2ecf20Sopenharmony_ci	if (!slow) {
32268c2ecf20Sopenharmony_ci		t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN);
32278c2ecf20Sopenharmony_ci		t3_read_reg(adapter, mc7->offset + A_MC7_CAL);
32288c2ecf20Sopenharmony_ci		msleep(1);
32298c2ecf20Sopenharmony_ci		if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) &
32308c2ecf20Sopenharmony_ci		    (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) {
32318c2ecf20Sopenharmony_ci			CH_ERR(adapter, "%s MC7 calibration timed out\n",
32328c2ecf20Sopenharmony_ci			       mc7->name);
32338c2ecf20Sopenharmony_ci			goto out_fail;
32348c2ecf20Sopenharmony_ci		}
32358c2ecf20Sopenharmony_ci	}
32368c2ecf20Sopenharmony_ci
32378c2ecf20Sopenharmony_ci	t3_write_reg(adapter, mc7->offset + A_MC7_PARM,
32388c2ecf20Sopenharmony_ci		     V_ACTTOPREDLY(p->ActToPreDly) |
32398c2ecf20Sopenharmony_ci		     V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) |
32408c2ecf20Sopenharmony_ci		     V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) |
32418c2ecf20Sopenharmony_ci		     V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly));
32428c2ecf20Sopenharmony_ci
32438c2ecf20Sopenharmony_ci	t3_write_reg(adapter, mc7->offset + A_MC7_CFG,
32448c2ecf20Sopenharmony_ci		     val | F_CLKEN | F_TERM150);
32458c2ecf20Sopenharmony_ci	t3_read_reg(adapter, mc7->offset + A_MC7_CFG);	/* flush */
32468c2ecf20Sopenharmony_ci
32478c2ecf20Sopenharmony_ci	if (!slow)
32488c2ecf20Sopenharmony_ci		t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB,
32498c2ecf20Sopenharmony_ci				 F_DLLENB);
32508c2ecf20Sopenharmony_ci	udelay(1);
32518c2ecf20Sopenharmony_ci
32528c2ecf20Sopenharmony_ci	val = slow ? 3 : 6;
32538c2ecf20Sopenharmony_ci	if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
32548c2ecf20Sopenharmony_ci	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) ||
32558c2ecf20Sopenharmony_ci	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) ||
32568c2ecf20Sopenharmony_ci	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
32578c2ecf20Sopenharmony_ci		goto out_fail;
32588c2ecf20Sopenharmony_ci
32598c2ecf20Sopenharmony_ci	if (!slow) {
32608c2ecf20Sopenharmony_ci		t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100);
32618c2ecf20Sopenharmony_ci		t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLRST, 0);
32628c2ecf20Sopenharmony_ci		udelay(5);
32638c2ecf20Sopenharmony_ci	}
32648c2ecf20Sopenharmony_ci
32658c2ecf20Sopenharmony_ci	if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
32668c2ecf20Sopenharmony_ci	    wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
32678c2ecf20Sopenharmony_ci	    wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
32688c2ecf20Sopenharmony_ci	    wrreg_wait(adapter, mc7->offset + A_MC7_MODE,
32698c2ecf20Sopenharmony_ci		       mc7_mode[mem_type]) ||
32708c2ecf20Sopenharmony_ci	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) ||
32718c2ecf20Sopenharmony_ci	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
32728c2ecf20Sopenharmony_ci		goto out_fail;
32738c2ecf20Sopenharmony_ci
32748c2ecf20Sopenharmony_ci	/* clock value is in KHz */
32758c2ecf20Sopenharmony_ci	mc7_clock = mc7_clock * 7812 + mc7_clock / 2;	/* ns */
32768c2ecf20Sopenharmony_ci	mc7_clock /= 1000000;	/* KHz->MHz, ns->us */
32778c2ecf20Sopenharmony_ci
32788c2ecf20Sopenharmony_ci	t3_write_reg(adapter, mc7->offset + A_MC7_REF,
32798c2ecf20Sopenharmony_ci		     F_PERREFEN | V_PREREFDIV(mc7_clock));
32808c2ecf20Sopenharmony_ci	t3_read_reg(adapter, mc7->offset + A_MC7_REF);	/* flush */
32818c2ecf20Sopenharmony_ci
32828c2ecf20Sopenharmony_ci	t3_write_reg(adapter, mc7->offset + A_MC7_ECC, F_ECCGENEN | F_ECCCHKEN);
32838c2ecf20Sopenharmony_ci	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0);
32848c2ecf20Sopenharmony_ci	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0);
32858c2ecf20Sopenharmony_ci	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END,
32868c2ecf20Sopenharmony_ci		     (mc7->size << width) - 1);
32878c2ecf20Sopenharmony_ci	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1));
32888c2ecf20Sopenharmony_ci	t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP);	/* flush */
32898c2ecf20Sopenharmony_ci
32908c2ecf20Sopenharmony_ci	attempts = 50;
32918c2ecf20Sopenharmony_ci	do {
32928c2ecf20Sopenharmony_ci		msleep(250);
32938c2ecf20Sopenharmony_ci		val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP);
32948c2ecf20Sopenharmony_ci	} while ((val & F_BUSY) && --attempts);
32958c2ecf20Sopenharmony_ci	if (val & F_BUSY) {
32968c2ecf20Sopenharmony_ci		CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name);
32978c2ecf20Sopenharmony_ci		goto out_fail;
32988c2ecf20Sopenharmony_ci	}
32998c2ecf20Sopenharmony_ci
33008c2ecf20Sopenharmony_ci	/* Enable normal memory accesses. */
33018c2ecf20Sopenharmony_ci	t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY);
33028c2ecf20Sopenharmony_ci	return 0;
33038c2ecf20Sopenharmony_ci
33048c2ecf20Sopenharmony_ciout_fail:
33058c2ecf20Sopenharmony_ci	return -1;
33068c2ecf20Sopenharmony_ci}
33078c2ecf20Sopenharmony_ci
33088c2ecf20Sopenharmony_cistatic void config_pcie(struct adapter *adap)
33098c2ecf20Sopenharmony_ci{
33108c2ecf20Sopenharmony_ci	static const u16 ack_lat[4][6] = {
33118c2ecf20Sopenharmony_ci		{237, 416, 559, 1071, 2095, 4143},
33128c2ecf20Sopenharmony_ci		{128, 217, 289, 545, 1057, 2081},
33138c2ecf20Sopenharmony_ci		{73, 118, 154, 282, 538, 1050},
33148c2ecf20Sopenharmony_ci		{67, 107, 86, 150, 278, 534}
33158c2ecf20Sopenharmony_ci	};
33168c2ecf20Sopenharmony_ci	static const u16 rpl_tmr[4][6] = {
33178c2ecf20Sopenharmony_ci		{711, 1248, 1677, 3213, 6285, 12429},
33188c2ecf20Sopenharmony_ci		{384, 651, 867, 1635, 3171, 6243},
33198c2ecf20Sopenharmony_ci		{219, 354, 462, 846, 1614, 3150},
33208c2ecf20Sopenharmony_ci		{201, 321, 258, 450, 834, 1602}
33218c2ecf20Sopenharmony_ci	};
33228c2ecf20Sopenharmony_ci
33238c2ecf20Sopenharmony_ci	u16 val, devid;
33248c2ecf20Sopenharmony_ci	unsigned int log2_width, pldsize;
33258c2ecf20Sopenharmony_ci	unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt;
33268c2ecf20Sopenharmony_ci
33278c2ecf20Sopenharmony_ci	pcie_capability_read_word(adap->pdev, PCI_EXP_DEVCTL, &val);
33288c2ecf20Sopenharmony_ci	pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
33298c2ecf20Sopenharmony_ci
33308c2ecf20Sopenharmony_ci	pci_read_config_word(adap->pdev, 0x2, &devid);
33318c2ecf20Sopenharmony_ci	if (devid == 0x37) {
33328c2ecf20Sopenharmony_ci		pcie_capability_write_word(adap->pdev, PCI_EXP_DEVCTL,
33338c2ecf20Sopenharmony_ci					   val & ~PCI_EXP_DEVCTL_READRQ &
33348c2ecf20Sopenharmony_ci					   ~PCI_EXP_DEVCTL_PAYLOAD);
33358c2ecf20Sopenharmony_ci		pldsize = 0;
33368c2ecf20Sopenharmony_ci	}
33378c2ecf20Sopenharmony_ci
33388c2ecf20Sopenharmony_ci	pcie_capability_read_word(adap->pdev, PCI_EXP_LNKCTL, &val);
33398c2ecf20Sopenharmony_ci
33408c2ecf20Sopenharmony_ci	fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0));
33418c2ecf20Sopenharmony_ci	fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx :
33428c2ecf20Sopenharmony_ci	    G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE));
33438c2ecf20Sopenharmony_ci	log2_width = fls(adap->params.pci.width) - 1;
33448c2ecf20Sopenharmony_ci	acklat = ack_lat[log2_width][pldsize];
33458c2ecf20Sopenharmony_ci	if (val & PCI_EXP_LNKCTL_ASPM_L0S)	/* check LOsEnable */
33468c2ecf20Sopenharmony_ci		acklat += fst_trn_tx * 4;
33478c2ecf20Sopenharmony_ci	rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4;
33488c2ecf20Sopenharmony_ci
33498c2ecf20Sopenharmony_ci	if (adap->params.rev == 0)
33508c2ecf20Sopenharmony_ci		t3_set_reg_field(adap, A_PCIE_PEX_CTRL1,
33518c2ecf20Sopenharmony_ci				 V_T3A_ACKLAT(M_T3A_ACKLAT),
33528c2ecf20Sopenharmony_ci				 V_T3A_ACKLAT(acklat));
33538c2ecf20Sopenharmony_ci	else
33548c2ecf20Sopenharmony_ci		t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT),
33558c2ecf20Sopenharmony_ci				 V_ACKLAT(acklat));
33568c2ecf20Sopenharmony_ci
33578c2ecf20Sopenharmony_ci	t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT),
33588c2ecf20Sopenharmony_ci			 V_REPLAYLMT(rpllmt));
33598c2ecf20Sopenharmony_ci
33608c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff);
33618c2ecf20Sopenharmony_ci	t3_set_reg_field(adap, A_PCIE_CFG, 0,
33628c2ecf20Sopenharmony_ci			 F_ENABLELINKDWNDRST | F_ENABLELINKDOWNRST |
33638c2ecf20Sopenharmony_ci			 F_PCIE_DMASTOPEN | F_PCIE_CLIDECEN);
33648c2ecf20Sopenharmony_ci}
33658c2ecf20Sopenharmony_ci
33668c2ecf20Sopenharmony_ci/*
33678c2ecf20Sopenharmony_ci * Initialize and configure T3 HW modules.  This performs the
33688c2ecf20Sopenharmony_ci * initialization steps that need to be done once after a card is reset.
33698c2ecf20Sopenharmony_ci * MAC and PHY initialization is handled separarely whenever a port is enabled.
33708c2ecf20Sopenharmony_ci *
33718c2ecf20Sopenharmony_ci * fw_params are passed to FW and their value is platform dependent.  Only the
33728c2ecf20Sopenharmony_ci * top 8 bits are available for use, the rest must be 0.
33738c2ecf20Sopenharmony_ci */
33748c2ecf20Sopenharmony_ciint t3_init_hw(struct adapter *adapter, u32 fw_params)
33758c2ecf20Sopenharmony_ci{
33768c2ecf20Sopenharmony_ci	int err = -EIO, attempts, i;
33778c2ecf20Sopenharmony_ci	const struct vpd_params *vpd = &adapter->params.vpd;
33788c2ecf20Sopenharmony_ci
33798c2ecf20Sopenharmony_ci	if (adapter->params.rev > 0)
33808c2ecf20Sopenharmony_ci		calibrate_xgm_t3b(adapter);
33818c2ecf20Sopenharmony_ci	else if (calibrate_xgm(adapter))
33828c2ecf20Sopenharmony_ci		goto out_err;
33838c2ecf20Sopenharmony_ci
33848c2ecf20Sopenharmony_ci	if (vpd->mclk) {
33858c2ecf20Sopenharmony_ci		partition_mem(adapter, &adapter->params.tp);
33868c2ecf20Sopenharmony_ci
33878c2ecf20Sopenharmony_ci		if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) ||
33888c2ecf20Sopenharmony_ci		    mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) ||
33898c2ecf20Sopenharmony_ci		    mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) ||
33908c2ecf20Sopenharmony_ci		    t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers,
33918c2ecf20Sopenharmony_ci				adapter->params.mc5.nfilters,
33928c2ecf20Sopenharmony_ci				adapter->params.mc5.nroutes))
33938c2ecf20Sopenharmony_ci			goto out_err;
33948c2ecf20Sopenharmony_ci
33958c2ecf20Sopenharmony_ci		for (i = 0; i < 32; i++)
33968c2ecf20Sopenharmony_ci			if (clear_sge_ctxt(adapter, i, F_CQ))
33978c2ecf20Sopenharmony_ci				goto out_err;
33988c2ecf20Sopenharmony_ci	}
33998c2ecf20Sopenharmony_ci
34008c2ecf20Sopenharmony_ci	if (tp_init(adapter, &adapter->params.tp))
34018c2ecf20Sopenharmony_ci		goto out_err;
34028c2ecf20Sopenharmony_ci
34038c2ecf20Sopenharmony_ci	t3_tp_set_coalescing_size(adapter,
34048c2ecf20Sopenharmony_ci				  min(adapter->params.sge.max_pkt_size,
34058c2ecf20Sopenharmony_ci				      MAX_RX_COALESCING_LEN), 1);
34068c2ecf20Sopenharmony_ci	t3_tp_set_max_rxsize(adapter,
34078c2ecf20Sopenharmony_ci			     min(adapter->params.sge.max_pkt_size, 16384U));
34088c2ecf20Sopenharmony_ci	ulp_config(adapter, &adapter->params.tp);
34098c2ecf20Sopenharmony_ci
34108c2ecf20Sopenharmony_ci	if (is_pcie(adapter))
34118c2ecf20Sopenharmony_ci		config_pcie(adapter);
34128c2ecf20Sopenharmony_ci	else
34138c2ecf20Sopenharmony_ci		t3_set_reg_field(adapter, A_PCIX_CFG, 0,
34148c2ecf20Sopenharmony_ci				 F_DMASTOPEN | F_CLIDECEN);
34158c2ecf20Sopenharmony_ci
34168c2ecf20Sopenharmony_ci	if (adapter->params.rev == T3_REV_C)
34178c2ecf20Sopenharmony_ci		t3_set_reg_field(adapter, A_ULPTX_CONFIG, 0,
34188c2ecf20Sopenharmony_ci				 F_CFG_CQE_SOP_MASK);
34198c2ecf20Sopenharmony_ci
34208c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff);
34218c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_PM1_RX_MODE, 0);
34228c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_PM1_TX_MODE, 0);
34238c2ecf20Sopenharmony_ci	chan_init_hw(adapter, adapter->params.chan_map);
34248c2ecf20Sopenharmony_ci	t3_sge_init(adapter, &adapter->params.sge);
34258c2ecf20Sopenharmony_ci	t3_set_reg_field(adapter, A_PL_RST, 0, F_FATALPERREN);
34268c2ecf20Sopenharmony_ci
34278c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, calc_gpio_intr(adapter));
34288c2ecf20Sopenharmony_ci
34298c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params);
34308c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_CIM_BOOT_CFG,
34318c2ecf20Sopenharmony_ci		     V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2));
34328c2ecf20Sopenharmony_ci	t3_read_reg(adapter, A_CIM_BOOT_CFG);	/* flush */
34338c2ecf20Sopenharmony_ci
34348c2ecf20Sopenharmony_ci	attempts = 100;
34358c2ecf20Sopenharmony_ci	do {			/* wait for uP to initialize */
34368c2ecf20Sopenharmony_ci		msleep(20);
34378c2ecf20Sopenharmony_ci	} while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts);
34388c2ecf20Sopenharmony_ci	if (!attempts) {
34398c2ecf20Sopenharmony_ci		CH_ERR(adapter, "uP initialization timed out\n");
34408c2ecf20Sopenharmony_ci		goto out_err;
34418c2ecf20Sopenharmony_ci	}
34428c2ecf20Sopenharmony_ci
34438c2ecf20Sopenharmony_ci	err = 0;
34448c2ecf20Sopenharmony_ciout_err:
34458c2ecf20Sopenharmony_ci	return err;
34468c2ecf20Sopenharmony_ci}
34478c2ecf20Sopenharmony_ci
34488c2ecf20Sopenharmony_ci/**
34498c2ecf20Sopenharmony_ci *	get_pci_mode - determine a card's PCI mode
34508c2ecf20Sopenharmony_ci *	@adapter: the adapter
34518c2ecf20Sopenharmony_ci *	@p: where to store the PCI settings
34528c2ecf20Sopenharmony_ci *
34538c2ecf20Sopenharmony_ci *	Determines a card's PCI mode and associated parameters, such as speed
34548c2ecf20Sopenharmony_ci *	and width.
34558c2ecf20Sopenharmony_ci */
34568c2ecf20Sopenharmony_cistatic void get_pci_mode(struct adapter *adapter, struct pci_params *p)
34578c2ecf20Sopenharmony_ci{
34588c2ecf20Sopenharmony_ci	static unsigned short speed_map[] = { 33, 66, 100, 133 };
34598c2ecf20Sopenharmony_ci	u32 pci_mode;
34608c2ecf20Sopenharmony_ci
34618c2ecf20Sopenharmony_ci	if (pci_is_pcie(adapter->pdev)) {
34628c2ecf20Sopenharmony_ci		u16 val;
34638c2ecf20Sopenharmony_ci
34648c2ecf20Sopenharmony_ci		p->variant = PCI_VARIANT_PCIE;
34658c2ecf20Sopenharmony_ci		pcie_capability_read_word(adapter->pdev, PCI_EXP_LNKSTA, &val);
34668c2ecf20Sopenharmony_ci		p->width = (val >> 4) & 0x3f;
34678c2ecf20Sopenharmony_ci		return;
34688c2ecf20Sopenharmony_ci	}
34698c2ecf20Sopenharmony_ci
34708c2ecf20Sopenharmony_ci	pci_mode = t3_read_reg(adapter, A_PCIX_MODE);
34718c2ecf20Sopenharmony_ci	p->speed = speed_map[G_PCLKRANGE(pci_mode)];
34728c2ecf20Sopenharmony_ci	p->width = (pci_mode & F_64BIT) ? 64 : 32;
34738c2ecf20Sopenharmony_ci	pci_mode = G_PCIXINITPAT(pci_mode);
34748c2ecf20Sopenharmony_ci	if (pci_mode == 0)
34758c2ecf20Sopenharmony_ci		p->variant = PCI_VARIANT_PCI;
34768c2ecf20Sopenharmony_ci	else if (pci_mode < 4)
34778c2ecf20Sopenharmony_ci		p->variant = PCI_VARIANT_PCIX_MODE1_PARITY;
34788c2ecf20Sopenharmony_ci	else if (pci_mode < 8)
34798c2ecf20Sopenharmony_ci		p->variant = PCI_VARIANT_PCIX_MODE1_ECC;
34808c2ecf20Sopenharmony_ci	else
34818c2ecf20Sopenharmony_ci		p->variant = PCI_VARIANT_PCIX_266_MODE2;
34828c2ecf20Sopenharmony_ci}
34838c2ecf20Sopenharmony_ci
34848c2ecf20Sopenharmony_ci/**
34858c2ecf20Sopenharmony_ci *	init_link_config - initialize a link's SW state
34868c2ecf20Sopenharmony_ci *	@lc: structure holding the link state
34878c2ecf20Sopenharmony_ci *	@caps: information about the current card
34888c2ecf20Sopenharmony_ci *
34898c2ecf20Sopenharmony_ci *	Initializes the SW state maintained for each link, including the link's
34908c2ecf20Sopenharmony_ci *	capabilities and default speed/duplex/flow-control/autonegotiation
34918c2ecf20Sopenharmony_ci *	settings.
34928c2ecf20Sopenharmony_ci */
34938c2ecf20Sopenharmony_cistatic void init_link_config(struct link_config *lc, unsigned int caps)
34948c2ecf20Sopenharmony_ci{
34958c2ecf20Sopenharmony_ci	lc->supported = caps;
34968c2ecf20Sopenharmony_ci	lc->requested_speed = lc->speed = SPEED_INVALID;
34978c2ecf20Sopenharmony_ci	lc->requested_duplex = lc->duplex = DUPLEX_INVALID;
34988c2ecf20Sopenharmony_ci	lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
34998c2ecf20Sopenharmony_ci	if (lc->supported & SUPPORTED_Autoneg) {
35008c2ecf20Sopenharmony_ci		lc->advertising = lc->supported;
35018c2ecf20Sopenharmony_ci		lc->autoneg = AUTONEG_ENABLE;
35028c2ecf20Sopenharmony_ci		lc->requested_fc |= PAUSE_AUTONEG;
35038c2ecf20Sopenharmony_ci	} else {
35048c2ecf20Sopenharmony_ci		lc->advertising = 0;
35058c2ecf20Sopenharmony_ci		lc->autoneg = AUTONEG_DISABLE;
35068c2ecf20Sopenharmony_ci	}
35078c2ecf20Sopenharmony_ci}
35088c2ecf20Sopenharmony_ci
35098c2ecf20Sopenharmony_ci/**
35108c2ecf20Sopenharmony_ci *	mc7_calc_size - calculate MC7 memory size
35118c2ecf20Sopenharmony_ci *	@cfg: the MC7 configuration
35128c2ecf20Sopenharmony_ci *
35138c2ecf20Sopenharmony_ci *	Calculates the size of an MC7 memory in bytes from the value of its
35148c2ecf20Sopenharmony_ci *	configuration register.
35158c2ecf20Sopenharmony_ci */
35168c2ecf20Sopenharmony_cistatic unsigned int mc7_calc_size(u32 cfg)
35178c2ecf20Sopenharmony_ci{
35188c2ecf20Sopenharmony_ci	unsigned int width = G_WIDTH(cfg);
35198c2ecf20Sopenharmony_ci	unsigned int banks = !!(cfg & F_BKS) + 1;
35208c2ecf20Sopenharmony_ci	unsigned int org = !!(cfg & F_ORG) + 1;
35218c2ecf20Sopenharmony_ci	unsigned int density = G_DEN(cfg);
35228c2ecf20Sopenharmony_ci	unsigned int MBs = ((256 << density) * banks) / (org << width);
35238c2ecf20Sopenharmony_ci
35248c2ecf20Sopenharmony_ci	return MBs << 20;
35258c2ecf20Sopenharmony_ci}
35268c2ecf20Sopenharmony_ci
35278c2ecf20Sopenharmony_cistatic void mc7_prep(struct adapter *adapter, struct mc7 *mc7,
35288c2ecf20Sopenharmony_ci		     unsigned int base_addr, const char *name)
35298c2ecf20Sopenharmony_ci{
35308c2ecf20Sopenharmony_ci	u32 cfg;
35318c2ecf20Sopenharmony_ci
35328c2ecf20Sopenharmony_ci	mc7->adapter = adapter;
35338c2ecf20Sopenharmony_ci	mc7->name = name;
35348c2ecf20Sopenharmony_ci	mc7->offset = base_addr - MC7_PMRX_BASE_ADDR;
35358c2ecf20Sopenharmony_ci	cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
35368c2ecf20Sopenharmony_ci	mc7->size = G_DEN(cfg) == M_DEN ? 0 : mc7_calc_size(cfg);
35378c2ecf20Sopenharmony_ci	mc7->width = G_WIDTH(cfg);
35388c2ecf20Sopenharmony_ci}
35398c2ecf20Sopenharmony_ci
35408c2ecf20Sopenharmony_cistatic void mac_prep(struct cmac *mac, struct adapter *adapter, int index)
35418c2ecf20Sopenharmony_ci{
35428c2ecf20Sopenharmony_ci	u16 devid;
35438c2ecf20Sopenharmony_ci
35448c2ecf20Sopenharmony_ci	mac->adapter = adapter;
35458c2ecf20Sopenharmony_ci	pci_read_config_word(adapter->pdev, 0x2, &devid);
35468c2ecf20Sopenharmony_ci
35478c2ecf20Sopenharmony_ci	if (devid == 0x37 && !adapter->params.vpd.xauicfg[1])
35488c2ecf20Sopenharmony_ci		index = 0;
35498c2ecf20Sopenharmony_ci	mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index;
35508c2ecf20Sopenharmony_ci	mac->nucast = 1;
35518c2ecf20Sopenharmony_ci
35528c2ecf20Sopenharmony_ci	if (adapter->params.rev == 0 && uses_xaui(adapter)) {
35538c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset,
35548c2ecf20Sopenharmony_ci			     is_10G(adapter) ? 0x2901c04 : 0x2301c04);
35558c2ecf20Sopenharmony_ci		t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset,
35568c2ecf20Sopenharmony_ci				 F_ENRGMII, 0);
35578c2ecf20Sopenharmony_ci	}
35588c2ecf20Sopenharmony_ci}
35598c2ecf20Sopenharmony_ci
35608c2ecf20Sopenharmony_cistatic void early_hw_init(struct adapter *adapter,
35618c2ecf20Sopenharmony_ci			  const struct adapter_info *ai)
35628c2ecf20Sopenharmony_ci{
35638c2ecf20Sopenharmony_ci	u32 val = V_PORTSPEED(is_10G(adapter) ? 3 : 2);
35648c2ecf20Sopenharmony_ci
35658c2ecf20Sopenharmony_ci	mi1_init(adapter, ai);
35668c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_I2C_CFG,	/* set for 80KHz */
35678c2ecf20Sopenharmony_ci		     V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1));
35688c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_T3DBG_GPIO_EN,
35698c2ecf20Sopenharmony_ci		     ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL);
35708c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_MC5_DB_SERVER_INDEX, 0);
35718c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_SG_OCO_BASE, V_BASE1(0xfff));
35728c2ecf20Sopenharmony_ci
35738c2ecf20Sopenharmony_ci	if (adapter->params.rev == 0 || !uses_xaui(adapter))
35748c2ecf20Sopenharmony_ci		val |= F_ENRGMII;
35758c2ecf20Sopenharmony_ci
35768c2ecf20Sopenharmony_ci	/* Enable MAC clocks so we can access the registers */
35778c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_XGM_PORT_CFG, val);
35788c2ecf20Sopenharmony_ci	t3_read_reg(adapter, A_XGM_PORT_CFG);
35798c2ecf20Sopenharmony_ci
35808c2ecf20Sopenharmony_ci	val |= F_CLKDIVRESET_;
35818c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_XGM_PORT_CFG, val);
35828c2ecf20Sopenharmony_ci	t3_read_reg(adapter, A_XGM_PORT_CFG);
35838c2ecf20Sopenharmony_ci	t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val);
35848c2ecf20Sopenharmony_ci	t3_read_reg(adapter, A_XGM_PORT_CFG);
35858c2ecf20Sopenharmony_ci}
35868c2ecf20Sopenharmony_ci
35878c2ecf20Sopenharmony_ci/*
35888c2ecf20Sopenharmony_ci * Reset the adapter.
35898c2ecf20Sopenharmony_ci * Older PCIe cards lose their config space during reset, PCI-X
35908c2ecf20Sopenharmony_ci * ones don't.
35918c2ecf20Sopenharmony_ci */
35928c2ecf20Sopenharmony_ciint t3_reset_adapter(struct adapter *adapter)
35938c2ecf20Sopenharmony_ci{
35948c2ecf20Sopenharmony_ci	int i, save_and_restore_pcie =
35958c2ecf20Sopenharmony_ci	    adapter->params.rev < T3_REV_B2 && is_pcie(adapter);
35968c2ecf20Sopenharmony_ci	uint16_t devid = 0;
35978c2ecf20Sopenharmony_ci
35988c2ecf20Sopenharmony_ci	if (save_and_restore_pcie)
35998c2ecf20Sopenharmony_ci		pci_save_state(adapter->pdev);
36008c2ecf20Sopenharmony_ci	t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE);
36018c2ecf20Sopenharmony_ci
36028c2ecf20Sopenharmony_ci	/*
36038c2ecf20Sopenharmony_ci	 * Delay. Give Some time to device to reset fully.
36048c2ecf20Sopenharmony_ci	 * XXX The delay time should be modified.
36058c2ecf20Sopenharmony_ci	 */
36068c2ecf20Sopenharmony_ci	for (i = 0; i < 10; i++) {
36078c2ecf20Sopenharmony_ci		msleep(50);
36088c2ecf20Sopenharmony_ci		pci_read_config_word(adapter->pdev, 0x00, &devid);
36098c2ecf20Sopenharmony_ci		if (devid == 0x1425)
36108c2ecf20Sopenharmony_ci			break;
36118c2ecf20Sopenharmony_ci	}
36128c2ecf20Sopenharmony_ci
36138c2ecf20Sopenharmony_ci	if (devid != 0x1425)
36148c2ecf20Sopenharmony_ci		return -1;
36158c2ecf20Sopenharmony_ci
36168c2ecf20Sopenharmony_ci	if (save_and_restore_pcie)
36178c2ecf20Sopenharmony_ci		pci_restore_state(adapter->pdev);
36188c2ecf20Sopenharmony_ci	return 0;
36198c2ecf20Sopenharmony_ci}
36208c2ecf20Sopenharmony_ci
36218c2ecf20Sopenharmony_cistatic int init_parity(struct adapter *adap)
36228c2ecf20Sopenharmony_ci{
36238c2ecf20Sopenharmony_ci	int i, err, addr;
36248c2ecf20Sopenharmony_ci
36258c2ecf20Sopenharmony_ci	if (t3_read_reg(adap, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
36268c2ecf20Sopenharmony_ci		return -EBUSY;
36278c2ecf20Sopenharmony_ci
36288c2ecf20Sopenharmony_ci	for (err = i = 0; !err && i < 16; i++)
36298c2ecf20Sopenharmony_ci		err = clear_sge_ctxt(adap, i, F_EGRESS);
36308c2ecf20Sopenharmony_ci	for (i = 0xfff0; !err && i <= 0xffff; i++)
36318c2ecf20Sopenharmony_ci		err = clear_sge_ctxt(adap, i, F_EGRESS);
36328c2ecf20Sopenharmony_ci	for (i = 0; !err && i < SGE_QSETS; i++)
36338c2ecf20Sopenharmony_ci		err = clear_sge_ctxt(adap, i, F_RESPONSEQ);
36348c2ecf20Sopenharmony_ci	if (err)
36358c2ecf20Sopenharmony_ci		return err;
36368c2ecf20Sopenharmony_ci
36378c2ecf20Sopenharmony_ci	t3_write_reg(adap, A_CIM_IBQ_DBG_DATA, 0);
36388c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
36398c2ecf20Sopenharmony_ci		for (addr = 0; addr <= M_IBQDBGADDR; addr++) {
36408c2ecf20Sopenharmony_ci			t3_write_reg(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGEN |
36418c2ecf20Sopenharmony_ci				     F_IBQDBGWR | V_IBQDBGQID(i) |
36428c2ecf20Sopenharmony_ci				     V_IBQDBGADDR(addr));
36438c2ecf20Sopenharmony_ci			err = t3_wait_op_done(adap, A_CIM_IBQ_DBG_CFG,
36448c2ecf20Sopenharmony_ci					      F_IBQDBGBUSY, 0, 2, 1);
36458c2ecf20Sopenharmony_ci			if (err)
36468c2ecf20Sopenharmony_ci				return err;
36478c2ecf20Sopenharmony_ci		}
36488c2ecf20Sopenharmony_ci	return 0;
36498c2ecf20Sopenharmony_ci}
36508c2ecf20Sopenharmony_ci
36518c2ecf20Sopenharmony_ci/*
36528c2ecf20Sopenharmony_ci * Initialize adapter SW state for the various HW modules, set initial values
36538c2ecf20Sopenharmony_ci * for some adapter tunables, take PHYs out of reset, and initialize the MDIO
36548c2ecf20Sopenharmony_ci * interface.
36558c2ecf20Sopenharmony_ci */
36568c2ecf20Sopenharmony_ciint t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
36578c2ecf20Sopenharmony_ci		    int reset)
36588c2ecf20Sopenharmony_ci{
36598c2ecf20Sopenharmony_ci	int ret;
36608c2ecf20Sopenharmony_ci	unsigned int i, j = -1;
36618c2ecf20Sopenharmony_ci
36628c2ecf20Sopenharmony_ci	get_pci_mode(adapter, &adapter->params.pci);
36638c2ecf20Sopenharmony_ci
36648c2ecf20Sopenharmony_ci	adapter->params.info = ai;
36658c2ecf20Sopenharmony_ci	adapter->params.nports = ai->nports0 + ai->nports1;
36668c2ecf20Sopenharmony_ci	adapter->params.chan_map = (!!ai->nports0) | (!!ai->nports1 << 1);
36678c2ecf20Sopenharmony_ci	adapter->params.rev = t3_read_reg(adapter, A_PL_REV);
36688c2ecf20Sopenharmony_ci	/*
36698c2ecf20Sopenharmony_ci	 * We used to only run the "adapter check task" once a second if
36708c2ecf20Sopenharmony_ci	 * we had PHYs which didn't support interrupts (we would check
36718c2ecf20Sopenharmony_ci	 * their link status once a second).  Now we check other conditions
36728c2ecf20Sopenharmony_ci	 * in that routine which could potentially impose a very high
36738c2ecf20Sopenharmony_ci	 * interrupt load on the system.  As such, we now always scan the
36748c2ecf20Sopenharmony_ci	 * adapter state once a second ...
36758c2ecf20Sopenharmony_ci	 */
36768c2ecf20Sopenharmony_ci	adapter->params.linkpoll_period = 10;
36778c2ecf20Sopenharmony_ci	adapter->params.stats_update_period = is_10G(adapter) ?
36788c2ecf20Sopenharmony_ci	    MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10);
36798c2ecf20Sopenharmony_ci	adapter->params.pci.vpd_cap_addr =
36808c2ecf20Sopenharmony_ci	    pci_find_capability(adapter->pdev, PCI_CAP_ID_VPD);
36818c2ecf20Sopenharmony_ci	if (!adapter->params.pci.vpd_cap_addr)
36828c2ecf20Sopenharmony_ci		return -ENODEV;
36838c2ecf20Sopenharmony_ci	ret = get_vpd_params(adapter, &adapter->params.vpd);
36848c2ecf20Sopenharmony_ci	if (ret < 0)
36858c2ecf20Sopenharmony_ci		return ret;
36868c2ecf20Sopenharmony_ci
36878c2ecf20Sopenharmony_ci	if (reset && t3_reset_adapter(adapter))
36888c2ecf20Sopenharmony_ci		return -1;
36898c2ecf20Sopenharmony_ci
36908c2ecf20Sopenharmony_ci	t3_sge_prep(adapter, &adapter->params.sge);
36918c2ecf20Sopenharmony_ci
36928c2ecf20Sopenharmony_ci	if (adapter->params.vpd.mclk) {
36938c2ecf20Sopenharmony_ci		struct tp_params *p = &adapter->params.tp;
36948c2ecf20Sopenharmony_ci
36958c2ecf20Sopenharmony_ci		mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX");
36968c2ecf20Sopenharmony_ci		mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX");
36978c2ecf20Sopenharmony_ci		mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM");
36988c2ecf20Sopenharmony_ci
36998c2ecf20Sopenharmony_ci		p->nchan = adapter->params.chan_map == 3 ? 2 : 1;
37008c2ecf20Sopenharmony_ci		p->pmrx_size = t3_mc7_size(&adapter->pmrx);
37018c2ecf20Sopenharmony_ci		p->pmtx_size = t3_mc7_size(&adapter->pmtx);
37028c2ecf20Sopenharmony_ci		p->cm_size = t3_mc7_size(&adapter->cm);
37038c2ecf20Sopenharmony_ci		p->chan_rx_size = p->pmrx_size / 2;	/* only 1 Rx channel */
37048c2ecf20Sopenharmony_ci		p->chan_tx_size = p->pmtx_size / p->nchan;
37058c2ecf20Sopenharmony_ci		p->rx_pg_size = 64 * 1024;
37068c2ecf20Sopenharmony_ci		p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024;
37078c2ecf20Sopenharmony_ci		p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size);
37088c2ecf20Sopenharmony_ci		p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size);
37098c2ecf20Sopenharmony_ci		p->ntimer_qs = p->cm_size >= (128 << 20) ||
37108c2ecf20Sopenharmony_ci		    adapter->params.rev > 0 ? 12 : 6;
37118c2ecf20Sopenharmony_ci	}
37128c2ecf20Sopenharmony_ci
37138c2ecf20Sopenharmony_ci	adapter->params.offload = t3_mc7_size(&adapter->pmrx) &&
37148c2ecf20Sopenharmony_ci				  t3_mc7_size(&adapter->pmtx) &&
37158c2ecf20Sopenharmony_ci				  t3_mc7_size(&adapter->cm);
37168c2ecf20Sopenharmony_ci
37178c2ecf20Sopenharmony_ci	if (is_offload(adapter)) {
37188c2ecf20Sopenharmony_ci		adapter->params.mc5.nservers = DEFAULT_NSERVERS;
37198c2ecf20Sopenharmony_ci		adapter->params.mc5.nfilters = adapter->params.rev > 0 ?
37208c2ecf20Sopenharmony_ci		    DEFAULT_NFILTERS : 0;
37218c2ecf20Sopenharmony_ci		adapter->params.mc5.nroutes = 0;
37228c2ecf20Sopenharmony_ci		t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT);
37238c2ecf20Sopenharmony_ci
37248c2ecf20Sopenharmony_ci		init_mtus(adapter->params.mtus);
37258c2ecf20Sopenharmony_ci		init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
37268c2ecf20Sopenharmony_ci	}
37278c2ecf20Sopenharmony_ci
37288c2ecf20Sopenharmony_ci	early_hw_init(adapter, ai);
37298c2ecf20Sopenharmony_ci	ret = init_parity(adapter);
37308c2ecf20Sopenharmony_ci	if (ret)
37318c2ecf20Sopenharmony_ci		return ret;
37328c2ecf20Sopenharmony_ci
37338c2ecf20Sopenharmony_ci	for_each_port(adapter, i) {
37348c2ecf20Sopenharmony_ci		u8 hw_addr[6];
37358c2ecf20Sopenharmony_ci		const struct port_type_info *pti;
37368c2ecf20Sopenharmony_ci		struct port_info *p = adap2pinfo(adapter, i);
37378c2ecf20Sopenharmony_ci
37388c2ecf20Sopenharmony_ci		while (!adapter->params.vpd.port_type[++j])
37398c2ecf20Sopenharmony_ci			;
37408c2ecf20Sopenharmony_ci
37418c2ecf20Sopenharmony_ci		pti = &port_types[adapter->params.vpd.port_type[j]];
37428c2ecf20Sopenharmony_ci		if (!pti->phy_prep) {
37438c2ecf20Sopenharmony_ci			CH_ALERT(adapter, "Invalid port type index %d\n",
37448c2ecf20Sopenharmony_ci				 adapter->params.vpd.port_type[j]);
37458c2ecf20Sopenharmony_ci			return -EINVAL;
37468c2ecf20Sopenharmony_ci		}
37478c2ecf20Sopenharmony_ci
37488c2ecf20Sopenharmony_ci		p->phy.mdio.dev = adapter->port[i];
37498c2ecf20Sopenharmony_ci		ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
37508c2ecf20Sopenharmony_ci				    ai->mdio_ops);
37518c2ecf20Sopenharmony_ci		if (ret)
37528c2ecf20Sopenharmony_ci			return ret;
37538c2ecf20Sopenharmony_ci		mac_prep(&p->mac, adapter, j);
37548c2ecf20Sopenharmony_ci
37558c2ecf20Sopenharmony_ci		/*
37568c2ecf20Sopenharmony_ci		 * The VPD EEPROM stores the base Ethernet address for the
37578c2ecf20Sopenharmony_ci		 * card.  A port's address is derived from the base by adding
37588c2ecf20Sopenharmony_ci		 * the port's index to the base's low octet.
37598c2ecf20Sopenharmony_ci		 */
37608c2ecf20Sopenharmony_ci		memcpy(hw_addr, adapter->params.vpd.eth_base, 5);
37618c2ecf20Sopenharmony_ci		hw_addr[5] = adapter->params.vpd.eth_base[5] + i;
37628c2ecf20Sopenharmony_ci
37638c2ecf20Sopenharmony_ci		memcpy(adapter->port[i]->dev_addr, hw_addr,
37648c2ecf20Sopenharmony_ci		       ETH_ALEN);
37658c2ecf20Sopenharmony_ci		init_link_config(&p->link_config, p->phy.caps);
37668c2ecf20Sopenharmony_ci		p->phy.ops->power_down(&p->phy, 1);
37678c2ecf20Sopenharmony_ci
37688c2ecf20Sopenharmony_ci		/*
37698c2ecf20Sopenharmony_ci		 * If the PHY doesn't support interrupts for link status
37708c2ecf20Sopenharmony_ci		 * changes, schedule a scan of the adapter links at least
37718c2ecf20Sopenharmony_ci		 * once a second.
37728c2ecf20Sopenharmony_ci		 */
37738c2ecf20Sopenharmony_ci		if (!(p->phy.caps & SUPPORTED_IRQ) &&
37748c2ecf20Sopenharmony_ci		    adapter->params.linkpoll_period > 10)
37758c2ecf20Sopenharmony_ci			adapter->params.linkpoll_period = 10;
37768c2ecf20Sopenharmony_ci	}
37778c2ecf20Sopenharmony_ci
37788c2ecf20Sopenharmony_ci	return 0;
37798c2ecf20Sopenharmony_ci}
37808c2ecf20Sopenharmony_ci
37818c2ecf20Sopenharmony_civoid t3_led_ready(struct adapter *adapter)
37828c2ecf20Sopenharmony_ci{
37838c2ecf20Sopenharmony_ci	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
37848c2ecf20Sopenharmony_ci			 F_GPIO0_OUT_VAL);
37858c2ecf20Sopenharmony_ci}
37868c2ecf20Sopenharmony_ci
37878c2ecf20Sopenharmony_ciint t3_replay_prep_adapter(struct adapter *adapter)
37888c2ecf20Sopenharmony_ci{
37898c2ecf20Sopenharmony_ci	const struct adapter_info *ai = adapter->params.info;
37908c2ecf20Sopenharmony_ci	unsigned int i, j = -1;
37918c2ecf20Sopenharmony_ci	int ret;
37928c2ecf20Sopenharmony_ci
37938c2ecf20Sopenharmony_ci	early_hw_init(adapter, ai);
37948c2ecf20Sopenharmony_ci	ret = init_parity(adapter);
37958c2ecf20Sopenharmony_ci	if (ret)
37968c2ecf20Sopenharmony_ci		return ret;
37978c2ecf20Sopenharmony_ci
37988c2ecf20Sopenharmony_ci	for_each_port(adapter, i) {
37998c2ecf20Sopenharmony_ci		const struct port_type_info *pti;
38008c2ecf20Sopenharmony_ci		struct port_info *p = adap2pinfo(adapter, i);
38018c2ecf20Sopenharmony_ci
38028c2ecf20Sopenharmony_ci		while (!adapter->params.vpd.port_type[++j])
38038c2ecf20Sopenharmony_ci			;
38048c2ecf20Sopenharmony_ci
38058c2ecf20Sopenharmony_ci		pti = &port_types[adapter->params.vpd.port_type[j]];
38068c2ecf20Sopenharmony_ci		ret = pti->phy_prep(&p->phy, adapter, p->phy.mdio.prtad, NULL);
38078c2ecf20Sopenharmony_ci		if (ret)
38088c2ecf20Sopenharmony_ci			return ret;
38098c2ecf20Sopenharmony_ci		p->phy.ops->power_down(&p->phy, 1);
38108c2ecf20Sopenharmony_ci	}
38118c2ecf20Sopenharmony_ci
38128c2ecf20Sopenharmony_ci	return 0;
38138c2ecf20Sopenharmony_ci}
38148c2ecf20Sopenharmony_ci
3815