1218792Snp/*-
2237436Snp * Copyright (c) 2012 Chelsio Communications, Inc.
3218792Snp * All rights reserved.
4218792Snp *
5218792Snp * Redistribution and use in source and binary forms, with or without
6218792Snp * modification, are permitted provided that the following conditions
7218792Snp * are met:
8218792Snp * 1. Redistributions of source code must retain the above copyright
9218792Snp *    notice, this list of conditions and the following disclaimer.
10218792Snp * 2. Redistributions in binary form must reproduce the above copyright
11218792Snp *    notice, this list of conditions and the following disclaimer in the
12218792Snp *    documentation and/or other materials provided with the distribution.
13218792Snp *
14218792Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15218792Snp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16218792Snp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17218792Snp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18218792Snp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19218792Snp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20218792Snp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21218792Snp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22218792Snp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23218792Snp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24218792Snp * SUCH DAMAGE.
25218792Snp */
26218792Snp
27218792Snp#include <sys/cdefs.h>
28218792Snp__FBSDID("$FreeBSD: releng/10.3/sys/dev/cxgbe/common/t4_hw.c 286897 2015-08-18 19:04:55Z np $");
29218792Snp
30237263Snp#include "opt_inet.h"
31237263Snp
32218792Snp#include "common.h"
33218792Snp#include "t4_regs.h"
34218792Snp#include "t4_regs_values.h"
35228561Snp#include "firmware/t4fw_interface.h"
36218792Snp
37220649Snp#undef msleep
38246385Snp#define msleep(x) do { \
39246385Snp	if (cold) \
40246385Snp		DELAY((x) * 1000); \
41246385Snp	else \
42246385Snp		pause("t4hw", (x) * hz / 1000); \
43246385Snp} while (0)
44218792Snp
45218792Snp/**
46218792Snp *	t4_wait_op_done_val - wait until an operation is completed
47218792Snp *	@adapter: the adapter performing the operation
48218792Snp *	@reg: the register to check for completion
49218792Snp *	@mask: a single-bit field within @reg that indicates completion
50218792Snp *	@polarity: the value of the field when the operation is completed
51218792Snp *	@attempts: number of check iterations
52218792Snp *	@delay: delay in usecs between iterations
53218792Snp *	@valp: where to store the value of the register at completion time
54218792Snp *
55218792Snp *	Wait until an operation is completed by checking a bit in a register
56218792Snp *	up to @attempts times.  If @valp is not NULL the value of the register
57218792Snp *	at the time it indicated completion is stored there.  Returns 0 if the
58218792Snp *	operation completes and	-EAGAIN	otherwise.
59218792Snp */
60218792Snpint t4_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
61218792Snp		        int polarity, int attempts, int delay, u32 *valp)
62218792Snp{
63218792Snp	while (1) {
64218792Snp		u32 val = t4_read_reg(adapter, reg);
65218792Snp
66218792Snp		if (!!(val & mask) == polarity) {
67218792Snp			if (valp)
68218792Snp				*valp = val;
69218792Snp			return 0;
70218792Snp		}
71218792Snp		if (--attempts == 0)
72218792Snp			return -EAGAIN;
73218792Snp		if (delay)
74218792Snp			udelay(delay);
75218792Snp	}
76218792Snp}
77218792Snp
78218792Snp/**
79218792Snp *	t4_set_reg_field - set a register field to a value
80218792Snp *	@adapter: the adapter to program
81218792Snp *	@addr: the register address
82218792Snp *	@mask: specifies the portion of the register to modify
83218792Snp *	@val: the new value for the register field
84218792Snp *
85218792Snp *	Sets a register field specified by the supplied mask to the
86218792Snp *	given value.
87218792Snp */
88218792Snpvoid t4_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask,
89218792Snp		      u32 val)
90218792Snp{
91218792Snp	u32 v = t4_read_reg(adapter, addr) & ~mask;
92218792Snp
93218792Snp	t4_write_reg(adapter, addr, v | val);
94218792Snp	(void) t4_read_reg(adapter, addr);      /* flush */
95218792Snp}
96218792Snp
97218792Snp/**
98218792Snp *	t4_read_indirect - read indirectly addressed registers
99218792Snp *	@adap: the adapter
100218792Snp *	@addr_reg: register holding the indirect address
101218792Snp *	@data_reg: register holding the value of the indirect register
102218792Snp *	@vals: where the read register values are stored
103218792Snp *	@nregs: how many indirect registers to read
104218792Snp *	@start_idx: index of first indirect register to read
105218792Snp *
106218792Snp *	Reads registers that are accessed indirectly through an address/data
107218792Snp *	register pair.
108218792Snp */
109218792Snpvoid t4_read_indirect(struct adapter *adap, unsigned int addr_reg,
110218792Snp		      unsigned int data_reg, u32 *vals, unsigned int nregs,
111218792Snp		      unsigned int start_idx)
112218792Snp{
113218792Snp	while (nregs--) {
114218792Snp		t4_write_reg(adap, addr_reg, start_idx);
115218792Snp		*vals++ = t4_read_reg(adap, data_reg);
116218792Snp		start_idx++;
117218792Snp	}
118218792Snp}
119218792Snp
120218792Snp/**
121218792Snp *	t4_write_indirect - write indirectly addressed registers
122218792Snp *	@adap: the adapter
123218792Snp *	@addr_reg: register holding the indirect addresses
124218792Snp *	@data_reg: register holding the value for the indirect registers
125218792Snp *	@vals: values to write
126218792Snp *	@nregs: how many indirect registers to write
127218792Snp *	@start_idx: address of first indirect register to write
128218792Snp *
129218792Snp *	Writes a sequential block of registers that are accessed indirectly
130218792Snp *	through an address/data register pair.
131218792Snp */
132218792Snpvoid t4_write_indirect(struct adapter *adap, unsigned int addr_reg,
133218792Snp		       unsigned int data_reg, const u32 *vals,
134218792Snp		       unsigned int nregs, unsigned int start_idx)
135218792Snp{
136218792Snp	while (nregs--) {
137218792Snp		t4_write_reg(adap, addr_reg, start_idx++);
138218792Snp		t4_write_reg(adap, data_reg, *vals++);
139218792Snp	}
140218792Snp}
141218792Snp
142218792Snp/*
143237436Snp * Read a 32-bit PCI Configuration Space register via the PCI-E backdoor
144237436Snp * mechanism.  This guarantees that we get the real value even if we're
145237436Snp * operating within a Virtual Machine and the Hypervisor is trapping our
146237436Snp * Configuration Space accesses.
147237436Snp */
148237436Snpu32 t4_hw_pci_read_cfg4(adapter_t *adap, int reg)
149237436Snp{
150237436Snp	t4_write_reg(adap, A_PCIE_CFG_SPACE_REQ,
151237436Snp		     F_ENABLE | F_LOCALCFG | V_FUNCTION(adap->pf) |
152237436Snp		     V_REGISTER(reg));
153237436Snp	return t4_read_reg(adap, A_PCIE_CFG_SPACE_DATA);
154237436Snp}
155237436Snp
156237436Snp/*
157247355Snp *	t4_report_fw_error - report firmware error
158247355Snp *	@adap: the adapter
159247355Snp *
160247355Snp *	The adapter firmware can indicate error conditions to the host.
161247355Snp *	This routine prints out the reason for the firmware error (as
162247355Snp *	reported by the firmware).
163247355Snp */
164247355Snpstatic void t4_report_fw_error(struct adapter *adap)
165247355Snp{
166247355Snp	static const char *reason[] = {
167247355Snp		"Crash",			/* PCIE_FW_EVAL_CRASH */
168247355Snp		"During Device Preparation",	/* PCIE_FW_EVAL_PREP */
169247355Snp		"During Device Configuration",	/* PCIE_FW_EVAL_CONF */
170247355Snp		"During Device Initialization",	/* PCIE_FW_EVAL_INIT */
171247355Snp		"Unexpected Event",		/* PCIE_FW_EVAL_UNEXPECTEDEVENT */
172247355Snp		"Insufficient Airflow",		/* PCIE_FW_EVAL_OVERHEAT */
173247355Snp		"Device Shutdown",		/* PCIE_FW_EVAL_DEVICESHUTDOWN */
174247355Snp		"Reserved",			/* reserved */
175247355Snp	};
176247355Snp	u32 pcie_fw;
177247355Snp
178247355Snp	pcie_fw = t4_read_reg(adap, A_PCIE_FW);
179250090Snp	if (pcie_fw & F_PCIE_FW_ERR)
180247355Snp		CH_ERR(adap, "Firmware reports adapter error: %s\n",
181247355Snp		       reason[G_PCIE_FW_EVAL(pcie_fw)]);
182247355Snp}
183247355Snp
184247355Snp/*
185218792Snp * Get the reply to a mailbox command and store it in @rpl in big-endian order.
186218792Snp */
187218792Snpstatic void get_mbox_rpl(struct adapter *adap, __be64 *rpl, int nflit,
188218792Snp			 u32 mbox_addr)
189218792Snp{
190218792Snp	for ( ; nflit; nflit--, mbox_addr += 8)
191218792Snp		*rpl++ = cpu_to_be64(t4_read_reg64(adap, mbox_addr));
192218792Snp}
193218792Snp
194218792Snp/*
195218792Snp * Handle a FW assertion reported in a mailbox.
196218792Snp */
197218792Snpstatic void fw_asrt(struct adapter *adap, u32 mbox_addr)
198218792Snp{
199218792Snp	struct fw_debug_cmd asrt;
200218792Snp
201218792Snp	get_mbox_rpl(adap, (__be64 *)&asrt, sizeof(asrt) / 8, mbox_addr);
202218792Snp	CH_ALERT(adap, "FW assertion at %.16s:%u, val0 %#x, val1 %#x\n",
203218792Snp		 asrt.u.assert.filename_0_7, ntohl(asrt.u.assert.line),
204218792Snp		 ntohl(asrt.u.assert.x), ntohl(asrt.u.assert.y));
205218792Snp}
206218792Snp
207218792Snp#define X_CIM_PF_NOACCESS 0xeeeeeeee
208218792Snp/**
209218792Snp *	t4_wr_mbox_meat - send a command to FW through the given mailbox
210218792Snp *	@adap: the adapter
211218792Snp *	@mbox: index of the mailbox to use
212218792Snp *	@cmd: the command to write
213218792Snp *	@size: command length in bytes
214218792Snp *	@rpl: where to optionally store the reply
215218792Snp *	@sleep_ok: if true we may sleep while awaiting command completion
216218792Snp *
217218792Snp *	Sends the given command to FW through the selected mailbox and waits
218218792Snp *	for the FW to execute the command.  If @rpl is not %NULL it is used to
219218792Snp *	store the FW's reply to the command.  The command and its optional
220218792Snp *	reply are of the same length.  Some FW commands like RESET and
221218792Snp *	INITIALIZE can take a considerable amount of time to execute.
222218792Snp *	@sleep_ok determines whether we may sleep while awaiting the response.
223218792Snp *	If sleeping is allowed we use progressive backoff otherwise we spin.
224218792Snp *
225218792Snp *	The return value is 0 on success or a negative errno on failure.  A
226218792Snp *	failure can happen either because we are not able to execute the
227218792Snp *	command or FW executes it but signals an error.  In the latter case
228218792Snp *	the return value is the error code indicated by FW (negated).
229218792Snp */
230218792Snpint t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
231218792Snp		    void *rpl, bool sleep_ok)
232218792Snp{
233218792Snp	/*
234218792Snp	 * We delay in small increments at first in an effort to maintain
235218792Snp	 * responsiveness for simple, fast executing commands but then back
236218792Snp	 * off to larger delays to a maximum retry delay.
237218792Snp	 */
238218792Snp	static const int delay[] = {
239228561Snp		1, 1, 3, 5, 10, 10, 20, 50, 100
240218792Snp	};
241218792Snp
242218792Snp	u32 v;
243218792Snp	u64 res;
244218792Snp	int i, ms, delay_idx;
245218792Snp	const __be64 *p = cmd;
246218792Snp	u32 data_reg = PF_REG(mbox, A_CIM_PF_MAILBOX_DATA);
247218792Snp	u32 ctl_reg = PF_REG(mbox, A_CIM_PF_MAILBOX_CTRL);
248218792Snp
249218792Snp	if ((size & 15) || size > MBOX_LEN)
250218792Snp		return -EINVAL;
251218792Snp
252218792Snp	v = G_MBOWNER(t4_read_reg(adap, ctl_reg));
253218792Snp	for (i = 0; v == X_MBOWNER_NONE && i < 3; i++)
254218792Snp		v = G_MBOWNER(t4_read_reg(adap, ctl_reg));
255218792Snp
256218792Snp	if (v != X_MBOWNER_PL)
257218792Snp		return v ? -EBUSY : -ETIMEDOUT;
258218792Snp
259218792Snp	for (i = 0; i < size; i += 8, p++)
260218792Snp		t4_write_reg64(adap, data_reg + i, be64_to_cpu(*p));
261218792Snp
262286271Snp	CH_DUMP_MBOX(adap, mbox, data_reg);
263286271Snp
264218792Snp	t4_write_reg(adap, ctl_reg, F_MBMSGVALID | V_MBOWNER(X_MBOWNER_FW));
265218792Snp	t4_read_reg(adap, ctl_reg);          /* flush write */
266218792Snp
267218792Snp	delay_idx = 0;
268218792Snp	ms = delay[0];
269218792Snp
270218792Snp	for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) {
271218792Snp		if (sleep_ok) {
272218792Snp			ms = delay[delay_idx];  /* last element may repeat */
273218792Snp			if (delay_idx < ARRAY_SIZE(delay) - 1)
274218792Snp				delay_idx++;
275218792Snp			msleep(ms);
276218792Snp		} else
277218792Snp			mdelay(ms);
278218792Snp
279218792Snp		v = t4_read_reg(adap, ctl_reg);
280218792Snp		if (v == X_CIM_PF_NOACCESS)
281218792Snp			continue;
282218792Snp		if (G_MBOWNER(v) == X_MBOWNER_PL) {
283218792Snp			if (!(v & F_MBMSGVALID)) {
284218792Snp				t4_write_reg(adap, ctl_reg,
285218792Snp					     V_MBOWNER(X_MBOWNER_NONE));
286218792Snp				continue;
287218792Snp			}
288218792Snp
289286271Snp			CH_DUMP_MBOX(adap, mbox, data_reg);
290286271Snp
291218792Snp			res = t4_read_reg64(adap, data_reg);
292218792Snp			if (G_FW_CMD_OP(res >> 32) == FW_DEBUG_CMD) {
293218792Snp				fw_asrt(adap, data_reg);
294218792Snp				res = V_FW_CMD_RETVAL(EIO);
295218792Snp			} else if (rpl)
296218792Snp				get_mbox_rpl(adap, rpl, size / 8, data_reg);
297218792Snp			t4_write_reg(adap, ctl_reg, V_MBOWNER(X_MBOWNER_NONE));
298218792Snp			return -G_FW_CMD_RETVAL((int)res);
299218792Snp		}
300218792Snp	}
301218792Snp
302247355Snp	/*
303247355Snp	 * We timed out waiting for a reply to our mailbox command.  Report
304247355Snp	 * the error and also check to see if the firmware reported any
305247355Snp	 * errors ...
306247355Snp	 */
307218792Snp	CH_ERR(adap, "command %#x in mailbox %d timed out\n",
308218792Snp	       *(const u8 *)cmd, mbox);
309247355Snp	if (t4_read_reg(adap, A_PCIE_FW) & F_PCIE_FW_ERR)
310247355Snp		t4_report_fw_error(adap);
311218792Snp	return -ETIMEDOUT;
312218792Snp}
313218792Snp
314218792Snp/**
315218792Snp *	t4_mc_read - read from MC through backdoor accesses
316218792Snp *	@adap: the adapter
317248925Snp *	@idx: which MC to access
318218792Snp *	@addr: address of first byte requested
319218792Snp *	@data: 64 bytes of data containing the requested address
320218792Snp *	@ecc: where to store the corresponding 64-bit ECC word
321218792Snp *
322218792Snp *	Read 64 bytes of data from MC starting at a 64-byte-aligned address
323218792Snp *	that covers the requested address @addr.  If @parity is not %NULL it
324218792Snp *	is assigned the 64-bit ECC word for the read data.
325218792Snp */
326248925Snpint t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
327218792Snp{
328218792Snp	int i;
329248925Snp	u32 mc_bist_cmd_reg, mc_bist_cmd_addr_reg, mc_bist_cmd_len_reg;
330248925Snp	u32 mc_bist_status_rdata_reg, mc_bist_data_pattern_reg;
331218792Snp
332248925Snp	if (is_t4(adap)) {
333248925Snp		mc_bist_cmd_reg = A_MC_BIST_CMD;
334248925Snp		mc_bist_cmd_addr_reg = A_MC_BIST_CMD_ADDR;
335248925Snp		mc_bist_cmd_len_reg = A_MC_BIST_CMD_LEN;
336248925Snp		mc_bist_status_rdata_reg = A_MC_BIST_STATUS_RDATA;
337248925Snp		mc_bist_data_pattern_reg = A_MC_BIST_DATA_PATTERN;
338248925Snp	} else {
339248925Snp		mc_bist_cmd_reg = MC_REG(A_MC_P_BIST_CMD, idx);
340248925Snp		mc_bist_cmd_addr_reg = MC_REG(A_MC_P_BIST_CMD_ADDR, idx);
341248925Snp		mc_bist_cmd_len_reg = MC_REG(A_MC_P_BIST_CMD_LEN, idx);
342248925Snp		mc_bist_status_rdata_reg = MC_REG(A_MC_P_BIST_STATUS_RDATA,
343248925Snp						  idx);
344248925Snp		mc_bist_data_pattern_reg = MC_REG(A_MC_P_BIST_DATA_PATTERN,
345248925Snp						  idx);
346248925Snp	}
347248925Snp
348248925Snp	if (t4_read_reg(adap, mc_bist_cmd_reg) & F_START_BIST)
349218792Snp		return -EBUSY;
350248925Snp	t4_write_reg(adap, mc_bist_cmd_addr_reg, addr & ~0x3fU);
351248925Snp	t4_write_reg(adap, mc_bist_cmd_len_reg, 64);
352248925Snp	t4_write_reg(adap, mc_bist_data_pattern_reg, 0xc);
353248925Snp	t4_write_reg(adap, mc_bist_cmd_reg, V_BIST_OPCODE(1) |
354248925Snp		     F_START_BIST | V_BIST_CMD_GAP(1));
355248925Snp	i = t4_wait_op_done(adap, mc_bist_cmd_reg, F_START_BIST, 0, 10, 1);
356218792Snp	if (i)
357218792Snp		return i;
358218792Snp
359248925Snp#define MC_DATA(i) MC_BIST_STATUS_REG(mc_bist_status_rdata_reg, i)
360218792Snp
361218792Snp	for (i = 15; i >= 0; i--)
362237436Snp		*data++ = ntohl(t4_read_reg(adap, MC_DATA(i)));
363218792Snp	if (ecc)
364218792Snp		*ecc = t4_read_reg64(adap, MC_DATA(16));
365218792Snp#undef MC_DATA
366218792Snp	return 0;
367218792Snp}
368218792Snp
369218792Snp/**
370218792Snp *	t4_edc_read - read from EDC through backdoor accesses
371218792Snp *	@adap: the adapter
372218792Snp *	@idx: which EDC to access
373218792Snp *	@addr: address of first byte requested
374218792Snp *	@data: 64 bytes of data containing the requested address
375218792Snp *	@ecc: where to store the corresponding 64-bit ECC word
376218792Snp *
377218792Snp *	Read 64 bytes of data from EDC starting at a 64-byte-aligned address
378218792Snp *	that covers the requested address @addr.  If @parity is not %NULL it
379218792Snp *	is assigned the 64-bit ECC word for the read data.
380218792Snp */
381218792Snpint t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
382218792Snp{
383218792Snp	int i;
384248925Snp	u32 edc_bist_cmd_reg, edc_bist_cmd_addr_reg, edc_bist_cmd_len_reg;
385248925Snp	u32 edc_bist_cmd_data_pattern, edc_bist_status_rdata_reg;
386218792Snp
387248925Snp	if (is_t4(adap)) {
388248925Snp		edc_bist_cmd_reg = EDC_REG(A_EDC_BIST_CMD, idx);
389248925Snp		edc_bist_cmd_addr_reg = EDC_REG(A_EDC_BIST_CMD_ADDR, idx);
390248925Snp		edc_bist_cmd_len_reg = EDC_REG(A_EDC_BIST_CMD_LEN, idx);
391248925Snp		edc_bist_cmd_data_pattern = EDC_REG(A_EDC_BIST_DATA_PATTERN,
392248925Snp						    idx);
393248925Snp		edc_bist_status_rdata_reg = EDC_REG(A_EDC_BIST_STATUS_RDATA,
394248925Snp						    idx);
395248925Snp	} else {
396248925Snp/*
397248925Snp * These macro are missing in t4_regs.h file.
398248925Snp * Added temporarily for testing.
399248925Snp */
400248925Snp#define EDC_STRIDE_T5 (EDC_T51_BASE_ADDR - EDC_T50_BASE_ADDR)
401248925Snp#define EDC_REG_T5(reg, idx) (reg + EDC_STRIDE_T5 * idx)
402248925Snp		edc_bist_cmd_reg = EDC_REG_T5(A_EDC_H_BIST_CMD, idx);
403248925Snp		edc_bist_cmd_addr_reg = EDC_REG_T5(A_EDC_H_BIST_CMD_ADDR, idx);
404248925Snp		edc_bist_cmd_len_reg = EDC_REG_T5(A_EDC_H_BIST_CMD_LEN, idx);
405248925Snp		edc_bist_cmd_data_pattern = EDC_REG_T5(A_EDC_H_BIST_DATA_PATTERN,
406248925Snp						    idx);
407248925Snp		edc_bist_status_rdata_reg = EDC_REG_T5(A_EDC_H_BIST_STATUS_RDATA,
408248925Snp						    idx);
409248925Snp#undef EDC_REG_T5
410248925Snp#undef EDC_STRIDE_T5
411248925Snp	}
412248925Snp
413248925Snp	if (t4_read_reg(adap, edc_bist_cmd_reg) & F_START_BIST)
414218792Snp		return -EBUSY;
415248925Snp	t4_write_reg(adap, edc_bist_cmd_addr_reg, addr & ~0x3fU);
416248925Snp	t4_write_reg(adap, edc_bist_cmd_len_reg, 64);
417248925Snp	t4_write_reg(adap, edc_bist_cmd_data_pattern, 0xc);
418248925Snp	t4_write_reg(adap, edc_bist_cmd_reg,
419218792Snp		     V_BIST_OPCODE(1) | V_BIST_CMD_GAP(1) | F_START_BIST);
420248925Snp	i = t4_wait_op_done(adap, edc_bist_cmd_reg, F_START_BIST, 0, 10, 1);
421218792Snp	if (i)
422218792Snp		return i;
423218792Snp
424248925Snp#define EDC_DATA(i) EDC_BIST_STATUS_REG(edc_bist_status_rdata_reg, i)
425218792Snp
426218792Snp	for (i = 15; i >= 0; i--)
427237436Snp		*data++ = ntohl(t4_read_reg(adap, EDC_DATA(i)));
428218792Snp	if (ecc)
429218792Snp		*ecc = t4_read_reg64(adap, EDC_DATA(16));
430218792Snp#undef EDC_DATA
431218792Snp	return 0;
432218792Snp}
433218792Snp
434218792Snp/**
435218792Snp *	t4_mem_read - read EDC 0, EDC 1 or MC into buffer
436218792Snp *	@adap: the adapter
437218792Snp *	@mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC
438218792Snp *	@addr: address within indicated memory type
439218792Snp *	@len: amount of memory to read
440218792Snp *	@buf: host memory buffer
441218792Snp *
442218792Snp *	Reads an [almost] arbitrary memory region in the firmware: the
443218792Snp *	firmware memory address, length and host buffer must be aligned on
444218792Snp *	32-bit boudaries.  The memory is returned as a raw byte sequence from
445218792Snp *	the firmware's memory.  If this memory contains data structures which
446218792Snp *	contain multi-byte integers, it's the callers responsibility to
447218792Snp *	perform appropriate byte order conversions.
448218792Snp */
449218792Snpint t4_mem_read(struct adapter *adap, int mtype, u32 addr, u32 len,
450218792Snp		__be32 *buf)
451218792Snp{
452218792Snp	u32 pos, start, end, offset;
453218792Snp	int ret;
454218792Snp
455218792Snp	/*
456218792Snp	 * Argument sanity checks ...
457218792Snp	 */
458218792Snp	if ((addr & 0x3) || (len & 0x3))
459218792Snp		return -EINVAL;
460218792Snp
461218792Snp	/*
462218792Snp	 * The underlaying EDC/MC read routines read 64 bytes at a time so we
463218792Snp	 * need to round down the start and round up the end.  We'll start
464218792Snp	 * copying out of the first line at (addr - start) a word at a time.
465218792Snp	 */
466218792Snp	start = addr & ~(64-1);
467218792Snp	end = (addr + len + 64-1) & ~(64-1);
468218792Snp	offset = (addr - start)/sizeof(__be32);
469218792Snp
470218792Snp	for (pos = start; pos < end; pos += 64, offset = 0) {
471218792Snp		__be32 data[16];
472218792Snp
473218792Snp		/*
474218792Snp		 * Read the chip's memory block and bail if there's an error.
475218792Snp		 */
476248925Snp		if ((mtype == MEM_MC) || (mtype == MEM_MC1))
477248925Snp			ret = t4_mc_read(adap, mtype - MEM_MC, pos, data, NULL);
478218792Snp		else
479218792Snp			ret = t4_edc_read(adap, mtype, pos, data, NULL);
480218792Snp		if (ret)
481218792Snp			return ret;
482218792Snp
483218792Snp		/*
484218792Snp		 * Copy the data into the caller's memory buffer.
485218792Snp		 */
486218792Snp		while (offset < 16 && len > 0) {
487218792Snp			*buf++ = data[offset++];
488218792Snp			len -= sizeof(__be32);
489218792Snp		}
490218792Snp	}
491218792Snp
492218792Snp	return 0;
493218792Snp}
494218792Snp
495218792Snp/*
496218792Snp * Partial EEPROM Vital Product Data structure.  Includes only the ID and
497218792Snp * VPD-R header.
498218792Snp */
499218792Snpstruct t4_vpd_hdr {
500218792Snp	u8  id_tag;
501218792Snp	u8  id_len[2];
502218792Snp	u8  id_data[ID_LEN];
503218792Snp	u8  vpdr_tag;
504218792Snp	u8  vpdr_len[2];
505218792Snp};
506218792Snp
507218792Snp/*
508218792Snp * EEPROM reads take a few tens of us while writes can take a bit over 5 ms.
509218792Snp */
510218792Snp#define EEPROM_MAX_RD_POLL 40
511218792Snp#define EEPROM_MAX_WR_POLL 6
512218792Snp#define EEPROM_STAT_ADDR   0x7bfc
513218792Snp#define VPD_BASE           0x400
514218792Snp#define VPD_BASE_OLD       0
515248925Snp#define VPD_LEN            1024
516218792Snp#define VPD_INFO_FLD_HDR_SIZE	3
517250090Snp#define CHELSIO_VPD_UNIQUE_ID 0x82
518218792Snp
519218792Snp/**
520218792Snp *	t4_seeprom_read - read a serial EEPROM location
521218792Snp *	@adapter: adapter to read
522218792Snp *	@addr: EEPROM virtual address
523218792Snp *	@data: where to store the read data
524218792Snp *
525218792Snp *	Read a 32-bit word from a location in serial EEPROM using the card's PCI
526218792Snp *	VPD capability.  Note that this function must be called with a virtual
527218792Snp *	address.
528218792Snp */
529218792Snpint t4_seeprom_read(struct adapter *adapter, u32 addr, u32 *data)
530218792Snp{
531218792Snp	u16 val;
532218792Snp	int attempts = EEPROM_MAX_RD_POLL;
533218792Snp	unsigned int base = adapter->params.pci.vpd_cap_addr;
534218792Snp
535218792Snp	if (addr >= EEPROMVSIZE || (addr & 3))
536218792Snp		return -EINVAL;
537218792Snp
538218792Snp	t4_os_pci_write_cfg2(adapter, base + PCI_VPD_ADDR, (u16)addr);
539218792Snp	do {
540218792Snp		udelay(10);
541218792Snp		t4_os_pci_read_cfg2(adapter, base + PCI_VPD_ADDR, &val);
542218792Snp	} while (!(val & PCI_VPD_ADDR_F) && --attempts);
543218792Snp
544218792Snp	if (!(val & PCI_VPD_ADDR_F)) {
545218792Snp		CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr);
546218792Snp		return -EIO;
547218792Snp	}
548218792Snp	t4_os_pci_read_cfg4(adapter, base + PCI_VPD_DATA, data);
549218792Snp	*data = le32_to_cpu(*data);
550218792Snp	return 0;
551218792Snp}
552218792Snp
553218792Snp/**
554218792Snp *	t4_seeprom_write - write a serial EEPROM location
555218792Snp *	@adapter: adapter to write
556218792Snp *	@addr: virtual EEPROM address
557218792Snp *	@data: value to write
558218792Snp *
559218792Snp *	Write a 32-bit word to a location in serial EEPROM using the card's PCI
560218792Snp *	VPD capability.  Note that this function must be called with a virtual
561218792Snp *	address.
562218792Snp */
563218792Snpint t4_seeprom_write(struct adapter *adapter, u32 addr, u32 data)
564218792Snp{
565218792Snp	u16 val;
566218792Snp	int attempts = EEPROM_MAX_WR_POLL;
567218792Snp	unsigned int base = adapter->params.pci.vpd_cap_addr;
568218792Snp
569218792Snp	if (addr >= EEPROMVSIZE || (addr & 3))
570218792Snp		return -EINVAL;
571218792Snp
572218792Snp	t4_os_pci_write_cfg4(adapter, base + PCI_VPD_DATA,
573218792Snp				 cpu_to_le32(data));
574218792Snp	t4_os_pci_write_cfg2(adapter, base + PCI_VPD_ADDR,
575218792Snp				 (u16)addr | PCI_VPD_ADDR_F);
576218792Snp	do {
577218792Snp		msleep(1);
578218792Snp		t4_os_pci_read_cfg2(adapter, base + PCI_VPD_ADDR, &val);
579218792Snp	} while ((val & PCI_VPD_ADDR_F) && --attempts);
580218792Snp
581218792Snp	if (val & PCI_VPD_ADDR_F) {
582218792Snp		CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr);
583218792Snp		return -EIO;
584218792Snp	}
585218792Snp	return 0;
586218792Snp}
587218792Snp
588218792Snp/**
589218792Snp *	t4_eeprom_ptov - translate a physical EEPROM address to virtual
590218792Snp *	@phys_addr: the physical EEPROM address
591218792Snp *	@fn: the PCI function number
592218792Snp *	@sz: size of function-specific area
593218792Snp *
594218792Snp *	Translate a physical EEPROM address to virtual.  The first 1K is
595218792Snp *	accessed through virtual addresses starting at 31K, the rest is
596218792Snp *	accessed through virtual addresses starting at 0.
597218792Snp *
598218792Snp *	The mapping is as follows:
599218792Snp *	[0..1K) -> [31K..32K)
600218792Snp *	[1K..1K+A) -> [ES-A..ES)
601218792Snp *	[1K+A..ES) -> [0..ES-A-1K)
602218792Snp *
603218792Snp *	where A = @fn * @sz, and ES = EEPROM size.
604218792Snp */
605218792Snpint t4_eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz)
606218792Snp{
607218792Snp	fn *= sz;
608218792Snp	if (phys_addr < 1024)
609218792Snp		return phys_addr + (31 << 10);
610218792Snp	if (phys_addr < 1024 + fn)
611218792Snp		return EEPROMSIZE - fn + phys_addr - 1024;
612218792Snp	if (phys_addr < EEPROMSIZE)
613218792Snp		return phys_addr - 1024 - fn;
614218792Snp	return -EINVAL;
615218792Snp}
616218792Snp
617218792Snp/**
618218792Snp *	t4_seeprom_wp - enable/disable EEPROM write protection
619218792Snp *	@adapter: the adapter
620218792Snp *	@enable: whether to enable or disable write protection
621218792Snp *
622218792Snp *	Enables or disables write protection on the serial EEPROM.
623218792Snp */
624218792Snpint t4_seeprom_wp(struct adapter *adapter, int enable)
625218792Snp{
626218792Snp	return t4_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
627218792Snp}
628218792Snp
629218792Snp/**
630218792Snp *	get_vpd_keyword_val - Locates an information field keyword in the VPD
631218792Snp *	@v: Pointer to buffered vpd data structure
632218792Snp *	@kw: The keyword to search for
633218792Snp *
634218792Snp *	Returns the value of the information field keyword or
635218792Snp *	-ENOENT otherwise.
636218792Snp */
637218792Snpstatic int get_vpd_keyword_val(const struct t4_vpd_hdr *v, const char *kw)
638218792Snp{
639218792Snp         int i;
640218792Snp	 unsigned int offset , len;
641218792Snp	 const u8 *buf = &v->id_tag;
642218792Snp	 const u8 *vpdr_len = &v->vpdr_tag;
643218792Snp	 offset = sizeof(struct t4_vpd_hdr);
644218792Snp	 len =  (u16)vpdr_len[1] + ((u16)vpdr_len[2] << 8);
645218792Snp
646218792Snp	 if (len + sizeof(struct t4_vpd_hdr) > VPD_LEN) {
647218792Snp		 return -ENOENT;
648218792Snp	 }
649218792Snp
650218792Snp         for (i = offset; i + VPD_INFO_FLD_HDR_SIZE <= offset + len;) {
651218792Snp		 if(memcmp(buf + i , kw , 2) == 0){
652218792Snp			 i += VPD_INFO_FLD_HDR_SIZE;
653218792Snp                         return i;
654218792Snp		  }
655218792Snp
656218792Snp                 i += VPD_INFO_FLD_HDR_SIZE + buf[i+2];
657218792Snp         }
658218792Snp
659218792Snp         return -ENOENT;
660218792Snp}
661218792Snp
662218792Snp
663218792Snp/**
664218792Snp *	get_vpd_params - read VPD parameters from VPD EEPROM
665218792Snp *	@adapter: adapter to read
666218792Snp *	@p: where to store the parameters
667218792Snp *
668218792Snp *	Reads card parameters stored in VPD EEPROM.
669218792Snp */
670218792Snpstatic int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
671218792Snp{
672218792Snp	int i, ret, addr;
673237436Snp	int ec, sn, pn, na;
674218792Snp	u8 vpd[VPD_LEN], csum;
675218792Snp	const struct t4_vpd_hdr *v;
676218792Snp
677218792Snp	/*
678218792Snp	 * Card information normally starts at VPD_BASE but early cards had
679218792Snp	 * it at 0.
680218792Snp	 */
681218792Snp	ret = t4_seeprom_read(adapter, VPD_BASE, (u32 *)(vpd));
682250090Snp	addr = *vpd == CHELSIO_VPD_UNIQUE_ID ? VPD_BASE : VPD_BASE_OLD;
683218792Snp
684218792Snp	for (i = 0; i < sizeof(vpd); i += 4) {
685218792Snp		ret = t4_seeprom_read(adapter, addr + i, (u32 *)(vpd + i));
686218792Snp		if (ret)
687218792Snp			return ret;
688218792Snp	}
689218792Snp 	v = (const struct t4_vpd_hdr *)vpd;
690218792Snp
691218792Snp#define FIND_VPD_KW(var,name) do { \
692218792Snp	var = get_vpd_keyword_val(v , name); \
693218792Snp	if (var < 0) { \
694218792Snp		CH_ERR(adapter, "missing VPD keyword " name "\n"); \
695218792Snp		return -EINVAL; \
696218792Snp	} \
697218792Snp} while (0)
698218792Snp
699218792Snp	FIND_VPD_KW(i, "RV");
700218792Snp	for (csum = 0; i >= 0; i--)
701218792Snp		csum += vpd[i];
702218792Snp
703218792Snp	if (csum) {
704218792Snp		CH_ERR(adapter, "corrupted VPD EEPROM, actual csum %u\n", csum);
705218792Snp		return -EINVAL;
706218792Snp	}
707218792Snp	FIND_VPD_KW(ec, "EC");
708218792Snp	FIND_VPD_KW(sn, "SN");
709237436Snp	FIND_VPD_KW(pn, "PN");
710237436Snp	FIND_VPD_KW(na, "NA");
711218792Snp#undef FIND_VPD_KW
712218792Snp
713218792Snp	memcpy(p->id, v->id_data, ID_LEN);
714218792Snp	strstrip(p->id);
715218792Snp	memcpy(p->ec, vpd + ec, EC_LEN);
716218792Snp	strstrip(p->ec);
717218792Snp	i = vpd[sn - VPD_INFO_FLD_HDR_SIZE + 2];
718218792Snp	memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN));
719218792Snp	strstrip(p->sn);
720250090Snp	i = vpd[pn - VPD_INFO_FLD_HDR_SIZE + 2];
721237436Snp	memcpy(p->pn, vpd + pn, min(i, PN_LEN));
722237436Snp	strstrip((char *)p->pn);
723250090Snp	i = vpd[na - VPD_INFO_FLD_HDR_SIZE + 2];
724237436Snp	memcpy(p->na, vpd + na, min(i, MACADDR_LEN));
725237436Snp	strstrip((char *)p->na);
726218792Snp
727218792Snp	return 0;
728218792Snp}
729218792Snp
730218792Snp/* serial flash and firmware constants and flash config file constants */
731218792Snpenum {
732218792Snp	SF_ATTEMPTS = 10,             /* max retries for SF operations */
733218792Snp
734218792Snp	/* flash command opcodes */
735218792Snp	SF_PROG_PAGE    = 2,          /* program page */
736218792Snp	SF_WR_DISABLE   = 4,          /* disable writes */
737218792Snp	SF_RD_STATUS    = 5,          /* read status register */
738218792Snp	SF_WR_ENABLE    = 6,          /* enable writes */
739218792Snp	SF_RD_DATA_FAST = 0xb,        /* read flash */
740218792Snp	SF_RD_ID        = 0x9f,       /* read ID */
741218792Snp	SF_ERASE_SECTOR = 0xd8,       /* erase sector */
742218792Snp};
743218792Snp
744218792Snp/**
745218792Snp *	sf1_read - read data from the serial flash
746218792Snp *	@adapter: the adapter
747218792Snp *	@byte_cnt: number of bytes to read
748218792Snp *	@cont: whether another operation will be chained
749218792Snp *	@lock: whether to lock SF for PL access only
750218792Snp *	@valp: where to store the read data
751218792Snp *
752218792Snp *	Reads up to 4 bytes of data from the serial flash.  The location of
753218792Snp *	the read needs to be specified prior to calling this by issuing the
754218792Snp *	appropriate commands to the serial flash.
755218792Snp */
756218792Snpstatic int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont,
757218792Snp		    int lock, u32 *valp)
758218792Snp{
759218792Snp	int ret;
760218792Snp
761218792Snp	if (!byte_cnt || byte_cnt > 4)
762218792Snp		return -EINVAL;
763218792Snp	if (t4_read_reg(adapter, A_SF_OP) & F_BUSY)
764218792Snp		return -EBUSY;
765218792Snp	t4_write_reg(adapter, A_SF_OP,
766218792Snp		     V_SF_LOCK(lock) | V_CONT(cont) | V_BYTECNT(byte_cnt - 1));
767218792Snp	ret = t4_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 5);
768218792Snp	if (!ret)
769218792Snp		*valp = t4_read_reg(adapter, A_SF_DATA);
770218792Snp	return ret;
771218792Snp}
772218792Snp
773218792Snp/**
774218792Snp *	sf1_write - write data to the serial flash
775218792Snp *	@adapter: the adapter
776218792Snp *	@byte_cnt: number of bytes to write
777218792Snp *	@cont: whether another operation will be chained
778218792Snp *	@lock: whether to lock SF for PL access only
779218792Snp *	@val: value to write
780218792Snp *
781218792Snp *	Writes up to 4 bytes of data to the serial flash.  The location of
782218792Snp *	the write needs to be specified prior to calling this by issuing the
783218792Snp *	appropriate commands to the serial flash.
784218792Snp */
785218792Snpstatic int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont,
786218792Snp		     int lock, u32 val)
787218792Snp{
788218792Snp	if (!byte_cnt || byte_cnt > 4)
789218792Snp		return -EINVAL;
790218792Snp	if (t4_read_reg(adapter, A_SF_OP) & F_BUSY)
791218792Snp		return -EBUSY;
792218792Snp	t4_write_reg(adapter, A_SF_DATA, val);
793218792Snp	t4_write_reg(adapter, A_SF_OP, V_SF_LOCK(lock) |
794218792Snp		     V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1));
795218792Snp	return t4_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 5);
796218792Snp}
797218792Snp
798218792Snp/**
799218792Snp *	flash_wait_op - wait for a flash operation to complete
800218792Snp *	@adapter: the adapter
801218792Snp *	@attempts: max number of polls of the status register
802218792Snp *	@delay: delay between polls in ms
803218792Snp *
804218792Snp *	Wait for a flash operation to complete by polling the status register.
805218792Snp */
806218792Snpstatic int flash_wait_op(struct adapter *adapter, int attempts, int delay)
807218792Snp{
808218792Snp	int ret;
809218792Snp	u32 status;
810218792Snp
811218792Snp	while (1) {
812218792Snp		if ((ret = sf1_write(adapter, 1, 1, 1, SF_RD_STATUS)) != 0 ||
813218792Snp		    (ret = sf1_read(adapter, 1, 0, 1, &status)) != 0)
814218792Snp			return ret;
815218792Snp		if (!(status & 1))
816218792Snp			return 0;
817218792Snp		if (--attempts == 0)
818218792Snp			return -EAGAIN;
819218792Snp		if (delay)
820218792Snp			msleep(delay);
821218792Snp	}
822218792Snp}
823218792Snp
824218792Snp/**
825218792Snp *	t4_read_flash - read words from serial flash
826218792Snp *	@adapter: the adapter
827218792Snp *	@addr: the start address for the read
828218792Snp *	@nwords: how many 32-bit words to read
829218792Snp *	@data: where to store the read data
830218792Snp *	@byte_oriented: whether to store data as bytes or as words
831218792Snp *
832218792Snp *	Read the specified number of 32-bit words from the serial flash.
833218792Snp *	If @byte_oriented is set the read data is stored as a byte array
834218792Snp *	(i.e., big-endian), otherwise as 32-bit words in the platform's
835218792Snp *	natural endianess.
836218792Snp */
837218792Snpint t4_read_flash(struct adapter *adapter, unsigned int addr,
838218792Snp		  unsigned int nwords, u32 *data, int byte_oriented)
839218792Snp{
840218792Snp	int ret;
841218792Snp
842218792Snp	if (addr + nwords * sizeof(u32) > adapter->params.sf_size || (addr & 3))
843218792Snp		return -EINVAL;
844218792Snp
845218792Snp	addr = swab32(addr) | SF_RD_DATA_FAST;
846218792Snp
847218792Snp	if ((ret = sf1_write(adapter, 4, 1, 0, addr)) != 0 ||
848218792Snp	    (ret = sf1_read(adapter, 1, 1, 0, data)) != 0)
849218792Snp		return ret;
850218792Snp
851218792Snp	for ( ; nwords; nwords--, data++) {
852218792Snp		ret = sf1_read(adapter, 4, nwords > 1, nwords == 1, data);
853218792Snp		if (nwords == 1)
854218792Snp			t4_write_reg(adapter, A_SF_OP, 0);    /* unlock SF */
855218792Snp		if (ret)
856218792Snp			return ret;
857218792Snp		if (byte_oriented)
858218792Snp			*data = htonl(*data);
859218792Snp	}
860218792Snp	return 0;
861218792Snp}
862218792Snp
863218792Snp/**
864218792Snp *	t4_write_flash - write up to a page of data to the serial flash
865218792Snp *	@adapter: the adapter
866218792Snp *	@addr: the start address to write
867218792Snp *	@n: length of data to write in bytes
868218792Snp *	@data: the data to write
869228561Snp *	@byte_oriented: whether to store data as bytes or as words
870218792Snp *
871218792Snp *	Writes up to a page of data (256 bytes) to the serial flash starting
872218792Snp *	at the given address.  All the data must be written to the same page.
873228561Snp *	If @byte_oriented is set the write data is stored as byte stream
874228561Snp *	(i.e. matches what on disk), otherwise in big-endian.
875218792Snp */
876218792Snpstatic int t4_write_flash(struct adapter *adapter, unsigned int addr,
877228561Snp			  unsigned int n, const u8 *data, int byte_oriented)
878218792Snp{
879218792Snp	int ret;
880218792Snp	u32 buf[SF_PAGE_SIZE / 4];
881218792Snp	unsigned int i, c, left, val, offset = addr & 0xff;
882218792Snp
883218792Snp	if (addr >= adapter->params.sf_size || offset + n > SF_PAGE_SIZE)
884218792Snp		return -EINVAL;
885218792Snp
886218792Snp	val = swab32(addr) | SF_PROG_PAGE;
887218792Snp
888218792Snp	if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 ||
889218792Snp	    (ret = sf1_write(adapter, 4, 1, 1, val)) != 0)
890218792Snp		goto unlock;
891218792Snp
892218792Snp	for (left = n; left; left -= c) {
893218792Snp		c = min(left, 4U);
894218792Snp		for (val = 0, i = 0; i < c; ++i)
895218792Snp			val = (val << 8) + *data++;
896218792Snp
897228561Snp		if (!byte_oriented)
898228561Snp			val = htonl(val);
899228561Snp
900218792Snp		ret = sf1_write(adapter, c, c != left, 1, val);
901218792Snp		if (ret)
902218792Snp			goto unlock;
903218792Snp	}
904218792Snp	ret = flash_wait_op(adapter, 8, 1);
905218792Snp	if (ret)
906218792Snp		goto unlock;
907218792Snp
908218792Snp	t4_write_reg(adapter, A_SF_OP, 0);    /* unlock SF */
909218792Snp
910218792Snp	/* Read the page to verify the write succeeded */
911228561Snp	ret = t4_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf,
912228561Snp			    byte_oriented);
913218792Snp	if (ret)
914218792Snp		return ret;
915218792Snp
916218792Snp	if (memcmp(data - n, (u8 *)buf + offset, n)) {
917218792Snp		CH_ERR(adapter, "failed to correctly write the flash page "
918218792Snp		       "at %#x\n", addr);
919218792Snp		return -EIO;
920218792Snp	}
921218792Snp	return 0;
922218792Snp
923218792Snpunlock:
924218792Snp	t4_write_reg(adapter, A_SF_OP, 0);    /* unlock SF */
925218792Snp	return ret;
926218792Snp}
927218792Snp
928218792Snp/**
929218792Snp *	t4_get_fw_version - read the firmware version
930218792Snp *	@adapter: the adapter
931218792Snp *	@vers: where to place the version
932218792Snp *
933218792Snp *	Reads the FW version from flash.
934218792Snp */
935218792Snpint t4_get_fw_version(struct adapter *adapter, u32 *vers)
936218792Snp{
937218792Snp	return t4_read_flash(adapter,
938228561Snp			     FLASH_FW_START + offsetof(struct fw_hdr, fw_ver), 1,
939218792Snp			     vers, 0);
940218792Snp}
941218792Snp
942218792Snp/**
943218792Snp *	t4_get_tp_version - read the TP microcode version
944218792Snp *	@adapter: the adapter
945218792Snp *	@vers: where to place the version
946218792Snp *
947218792Snp *	Reads the TP microcode version from flash.
948218792Snp */
949218792Snpint t4_get_tp_version(struct adapter *adapter, u32 *vers)
950218792Snp{
951228561Snp	return t4_read_flash(adapter, FLASH_FW_START + offsetof(struct fw_hdr,
952218792Snp							      tp_microcode_ver),
953218792Snp			     1, vers, 0);
954218792Snp}
955218792Snp
956218792Snp/**
957218792Snp *	t4_check_fw_version - check if the FW is compatible with this driver
958218792Snp *	@adapter: the adapter
959218792Snp *
960218792Snp *	Checks if an adapter's FW is compatible with the driver.  Returns 0
961218792Snp *	if there's exact match, a negative error if the version could not be
962218792Snp *	read or there's a major version mismatch, and a positive value if the
963218792Snp *	expected major version is found but there's a minor version mismatch.
964218792Snp */
965218792Snpint t4_check_fw_version(struct adapter *adapter)
966218792Snp{
967218792Snp	int ret, major, minor, micro;
968248925Snp	int exp_major, exp_minor, exp_micro;
969218792Snp
970218792Snp	ret = t4_get_fw_version(adapter, &adapter->params.fw_vers);
971218792Snp	if (!ret)
972218792Snp		ret = t4_get_tp_version(adapter, &adapter->params.tp_vers);
973218792Snp	if (ret)
974218792Snp		return ret;
975218792Snp
976218792Snp	major = G_FW_HDR_FW_VER_MAJOR(adapter->params.fw_vers);
977218792Snp	minor = G_FW_HDR_FW_VER_MINOR(adapter->params.fw_vers);
978218792Snp	micro = G_FW_HDR_FW_VER_MICRO(adapter->params.fw_vers);
979218792Snp
980248925Snp	switch (chip_id(adapter)) {
981248925Snp	case CHELSIO_T4:
982252661Snp		exp_major = T4FW_VERSION_MAJOR;
983252661Snp		exp_minor = T4FW_VERSION_MINOR;
984252661Snp		exp_micro = T4FW_VERSION_MICRO;
985248925Snp		break;
986248925Snp	case CHELSIO_T5:
987252661Snp		exp_major = T5FW_VERSION_MAJOR;
988252661Snp		exp_minor = T5FW_VERSION_MINOR;
989252661Snp		exp_micro = T5FW_VERSION_MICRO;
990248925Snp		break;
991248925Snp	default:
992248925Snp		CH_ERR(adapter, "Unsupported chip type, %x\n",
993248925Snp		    chip_id(adapter));
994248925Snp		return -EINVAL;
995248925Snp	}
996248925Snp
997248925Snp	if (major != exp_major) {            /* major mismatch - fail */
998218792Snp		CH_ERR(adapter, "card FW has major version %u, driver wants "
999248925Snp		       "%u\n", major, exp_major);
1000218792Snp		return -EINVAL;
1001218792Snp	}
1002218792Snp
1003248925Snp	if (minor == exp_minor && micro == exp_micro)
1004218792Snp		return 0;                                   /* perfect match */
1005218792Snp
1006218792Snp	/* Minor/micro version mismatch.  Report it but often it's OK. */
1007218792Snp	return 1;
1008218792Snp}
1009218792Snp
1010218792Snp/**
1011218792Snp *	t4_flash_erase_sectors - erase a range of flash sectors
1012218792Snp *	@adapter: the adapter
1013218792Snp *	@start: the first sector to erase
1014218792Snp *	@end: the last sector to erase
1015218792Snp *
1016218792Snp *	Erases the sectors in the given inclusive range.
1017218792Snp */
1018218792Snpstatic int t4_flash_erase_sectors(struct adapter *adapter, int start, int end)
1019218792Snp{
1020218792Snp	int ret = 0;
1021218792Snp
1022218792Snp	while (start <= end) {
1023218792Snp		if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 ||
1024218792Snp		    (ret = sf1_write(adapter, 4, 0, 1,
1025218792Snp				     SF_ERASE_SECTOR | (start << 8))) != 0 ||
1026218792Snp		    (ret = flash_wait_op(adapter, 14, 500)) != 0) {
1027218792Snp			CH_ERR(adapter, "erase of flash sector %d failed, "
1028218792Snp			       "error %d\n", start, ret);
1029218792Snp			break;
1030218792Snp		}
1031218792Snp		start++;
1032218792Snp	}
1033218792Snp	t4_write_reg(adapter, A_SF_OP, 0);    /* unlock SF */
1034218792Snp	return ret;
1035218792Snp}
1036218792Snp
1037218792Snp/**
1038228561Snp *	t4_flash_cfg_addr - return the address of the flash configuration file
1039228561Snp *	@adapter: the adapter
1040228561Snp *
1041228561Snp *	Return the address within the flash where the Firmware Configuration
1042250090Snp *	File is stored, or an error if the device FLASH is too small to contain
1043250090Snp *	a Firmware Configuration File.
1044228561Snp */
1045250090Snpint t4_flash_cfg_addr(struct adapter *adapter)
1046228561Snp{
1047250090Snp	/*
1048250090Snp	 * If the device FLASH isn't large enough to hold a Firmware
1049250090Snp	 * Configuration File, return an error.
1050250090Snp	 */
1051250090Snp	if (adapter->params.sf_size < FLASH_CFG_START + FLASH_CFG_MAX_SIZE)
1052250090Snp		return -ENOSPC;
1053250090Snp
1054250090Snp	return FLASH_CFG_START;
1055228561Snp}
1056228561Snp
1057228561Snp/**
1058218792Snp *	t4_load_cfg - download config file
1059218792Snp *	@adap: the adapter
1060218792Snp *	@cfg_data: the cfg text file to write
1061218792Snp *	@size: text file size
1062218792Snp *
1063218792Snp *	Write the supplied config text file to the card's serial flash.
1064218792Snp */
1065218792Snpint t4_load_cfg(struct adapter *adap, const u8 *cfg_data, unsigned int size)
1066218792Snp{
1067250090Snp	int ret, i, n, cfg_addr;
1068218792Snp	unsigned int addr;
1069218792Snp	unsigned int flash_cfg_start_sec;
1070218792Snp	unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
1071218792Snp
1072250090Snp	cfg_addr = t4_flash_cfg_addr(adap);
1073250090Snp	if (cfg_addr < 0)
1074250090Snp		return cfg_addr;
1075250090Snp
1076250090Snp	addr = cfg_addr;
1077228561Snp	flash_cfg_start_sec = addr / SF_SEC_SIZE;
1078218792Snp
1079218792Snp	if (size > FLASH_CFG_MAX_SIZE) {
1080218792Snp		CH_ERR(adap, "cfg file too large, max is %u bytes\n",
1081218792Snp		       FLASH_CFG_MAX_SIZE);
1082218792Snp		return -EFBIG;
1083218792Snp	}
1084218792Snp
1085218792Snp	i = DIV_ROUND_UP(FLASH_CFG_MAX_SIZE,	/* # of sectors spanned */
1086218792Snp			 sf_sec_size);
1087218792Snp	ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec,
1088218792Snp				     flash_cfg_start_sec + i - 1);
1089228561Snp	/*
1090228561Snp	 * If size == 0 then we're simply erasing the FLASH sectors associated
1091228561Snp	 * with the on-adapter Firmware Configuration File.
1092228561Snp	 */
1093228561Snp	if (ret || size == 0)
1094218792Snp		goto out;
1095218792Snp
1096237436Snp	/* this will write to the flash up to SF_PAGE_SIZE at a time */
1097218792Snp	for (i = 0; i< size; i+= SF_PAGE_SIZE) {
1098218792Snp		if ( (size - i) <  SF_PAGE_SIZE)
1099218792Snp			n = size - i;
1100218792Snp		else
1101218792Snp			n = SF_PAGE_SIZE;
1102228561Snp		ret = t4_write_flash(adap, addr, n, cfg_data, 1);
1103218792Snp		if (ret)
1104218792Snp			goto out;
1105218792Snp
1106218792Snp		addr += SF_PAGE_SIZE;
1107218792Snp		cfg_data += SF_PAGE_SIZE;
1108218792Snp	}
1109218792Snp
1110218792Snpout:
1111218792Snp	if (ret)
1112228561Snp		CH_ERR(adap, "config file %s failed %d\n",
1113228561Snp		       (size == 0 ? "clear" : "download"), ret);
1114218792Snp	return ret;
1115218792Snp}
1116218792Snp
1117218792Snp
1118218792Snp/**
1119218792Snp *	t4_load_fw - download firmware
1120218792Snp *	@adap: the adapter
1121218792Snp *	@fw_data: the firmware image to write
1122218792Snp *	@size: image size
1123218792Snp *
1124218792Snp *	Write the supplied firmware image to the card's serial flash.
1125218792Snp */
1126218792Snpint t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
1127218792Snp{
1128218792Snp	u32 csum;
1129218792Snp	int ret, addr;
1130218792Snp	unsigned int i;
1131218792Snp	u8 first_page[SF_PAGE_SIZE];
1132218792Snp	const u32 *p = (const u32 *)fw_data;
1133218792Snp	const struct fw_hdr *hdr = (const struct fw_hdr *)fw_data;
1134218792Snp	unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
1135252661Snp	unsigned int fw_start_sec;
1136252661Snp	unsigned int fw_start;
1137252661Snp	unsigned int fw_size;
1138218792Snp
1139252661Snp	if (ntohl(hdr->magic) == FW_HDR_MAGIC_BOOTSTRAP) {
1140252661Snp		fw_start_sec = FLASH_FWBOOTSTRAP_START_SEC;
1141252661Snp		fw_start = FLASH_FWBOOTSTRAP_START;
1142252661Snp		fw_size = FLASH_FWBOOTSTRAP_MAX_SIZE;
1143252661Snp	} else {
1144252661Snp		fw_start_sec = FLASH_FW_START_SEC;
1145252661Snp 		fw_start = FLASH_FW_START;
1146252661Snp		fw_size = FLASH_FW_MAX_SIZE;
1147252661Snp	}
1148218792Snp	if (!size) {
1149218792Snp		CH_ERR(adap, "FW image has no data\n");
1150218792Snp		return -EINVAL;
1151218792Snp	}
1152218792Snp	if (size & 511) {
1153218792Snp		CH_ERR(adap, "FW image size not multiple of 512 bytes\n");
1154218792Snp		return -EINVAL;
1155218792Snp	}
1156218792Snp	if (ntohs(hdr->len512) * 512 != size) {
1157218792Snp		CH_ERR(adap, "FW image size differs from size in FW header\n");
1158218792Snp		return -EINVAL;
1159218792Snp	}
1160252661Snp	if (size > fw_size) {
1161252661Snp		CH_ERR(adap, "FW image too large, max is %u bytes\n", fw_size);
1162218792Snp		return -EFBIG;
1163218792Snp	}
1164249629Snp	if ((is_t4(adap) && hdr->chip != FW_HDR_CHIP_T4) ||
1165249629Snp	    (is_t5(adap) && hdr->chip != FW_HDR_CHIP_T5)) {
1166249629Snp		CH_ERR(adap,
1167249629Snp		    "FW image (%d) is not suitable for this adapter (%d)\n",
1168249629Snp		    hdr->chip, chip_id(adap));
1169249629Snp		return -EINVAL;
1170249629Snp	}
1171218792Snp
1172218792Snp	for (csum = 0, i = 0; i < size / sizeof(csum); i++)
1173218792Snp		csum += ntohl(p[i]);
1174218792Snp
1175218792Snp	if (csum != 0xffffffff) {
1176218792Snp		CH_ERR(adap, "corrupted firmware image, checksum %#x\n",
1177218792Snp		       csum);
1178218792Snp		return -EINVAL;
1179218792Snp	}
1180218792Snp
1181218792Snp	i = DIV_ROUND_UP(size, sf_sec_size);        /* # of sectors spanned */
1182252661Snp	ret = t4_flash_erase_sectors(adap, fw_start_sec, fw_start_sec + i - 1);
1183218792Snp	if (ret)
1184218792Snp		goto out;
1185218792Snp
1186218792Snp	/*
1187218792Snp	 * We write the correct version at the end so the driver can see a bad
1188218792Snp	 * version if the FW write fails.  Start by writing a copy of the
1189218792Snp	 * first page with a bad version.
1190218792Snp	 */
1191218792Snp	memcpy(first_page, fw_data, SF_PAGE_SIZE);
1192218792Snp	((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff);
1193252661Snp	ret = t4_write_flash(adap, fw_start, SF_PAGE_SIZE, first_page, 1);
1194218792Snp	if (ret)
1195218792Snp		goto out;
1196218792Snp
1197252661Snp	addr = fw_start;
1198218792Snp	for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) {
1199218792Snp		addr += SF_PAGE_SIZE;
1200218792Snp		fw_data += SF_PAGE_SIZE;
1201228561Snp		ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, fw_data, 1);
1202218792Snp		if (ret)
1203218792Snp			goto out;
1204218792Snp	}
1205218792Snp
1206218792Snp	ret = t4_write_flash(adap,
1207252661Snp			     fw_start + offsetof(struct fw_hdr, fw_ver),
1208228561Snp			     sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver, 1);
1209218792Snpout:
1210218792Snp	if (ret)
1211218792Snp		CH_ERR(adap, "firmware download failed, error %d\n", ret);
1212218792Snp	return ret;
1213218792Snp}
1214218792Snp
1215237436Snp/* BIOS boot headers */
1216237436Snptypedef struct pci_expansion_rom_header {
1217237436Snp	u8	signature[2]; /* ROM Signature. Should be 0xaa55 */
1218237436Snp	u8	reserved[22]; /* Reserved per processor Architecture data */
1219237436Snp	u8	pcir_offset[2]; /* Offset to PCI Data Structure */
1220237436Snp} pci_exp_rom_header_t; /* PCI_EXPANSION_ROM_HEADER */
1221228561Snp
1222237436Snp/* Legacy PCI Expansion ROM Header */
1223237436Snptypedef struct legacy_pci_expansion_rom_header {
1224237436Snp	u8	signature[2]; /* ROM Signature. Should be 0xaa55 */
1225237436Snp	u8	size512; /* Current Image Size in units of 512 bytes */
1226237436Snp	u8	initentry_point[4];
1227237436Snp	u8	cksum; /* Checksum computed on the entire Image */
1228237436Snp	u8	reserved[16]; /* Reserved */
1229237436Snp	u8	pcir_offset[2]; /* Offset to PCI Data Struture */
1230237436Snp} legacy_pci_exp_rom_header_t; /* LEGACY_PCI_EXPANSION_ROM_HEADER */
1231237436Snp
1232237436Snp/* EFI PCI Expansion ROM Header */
1233237436Snptypedef struct efi_pci_expansion_rom_header {
1234237436Snp	u8	signature[2]; // ROM signature. The value 0xaa55
1235237436Snp	u8	initialization_size[2]; /* Units 512. Includes this header */
1236237436Snp	u8	efi_signature[4]; /* Signature from EFI image header. 0x0EF1 */
1237237436Snp	u8	efi_subsystem[2]; /* Subsystem value for EFI image header */
1238237436Snp	u8	efi_machine_type[2]; /* Machine type from EFI image header */
1239237436Snp	u8	compression_type[2]; /* Compression type. */
1240237436Snp		/*
1241237436Snp		 * Compression type definition
1242237436Snp		 * 0x0: uncompressed
1243237436Snp		 * 0x1: Compressed
1244237436Snp		 * 0x2-0xFFFF: Reserved
1245237436Snp		 */
1246237436Snp	u8	reserved[8]; /* Reserved */
1247237436Snp	u8	efi_image_header_offset[2]; /* Offset to EFI Image */
1248237436Snp	u8	pcir_offset[2]; /* Offset to PCI Data Structure */
1249237436Snp} efi_pci_exp_rom_header_t; /* EFI PCI Expansion ROM Header */
1250237436Snp
1251237436Snp/* PCI Data Structure Format */
1252237436Snptypedef struct pcir_data_structure { /* PCI Data Structure */
1253237436Snp	u8	signature[4]; /* Signature. The string "PCIR" */
1254237436Snp	u8	vendor_id[2]; /* Vendor Identification */
1255237436Snp	u8	device_id[2]; /* Device Identification */
1256237436Snp	u8	vital_product[2]; /* Pointer to Vital Product Data */
1257237436Snp	u8	length[2]; /* PCIR Data Structure Length */
1258237436Snp	u8	revision; /* PCIR Data Structure Revision */
1259237436Snp	u8	class_code[3]; /* Class Code */
1260237436Snp	u8	image_length[2]; /* Image Length. Multiple of 512B */
1261237436Snp	u8	code_revision[2]; /* Revision Level of Code/Data */
1262237436Snp	u8	code_type; /* Code Type. */
1263237436Snp		/*
1264237436Snp		 * PCI Expansion ROM Code Types
1265237436Snp		 * 0x00: Intel IA-32, PC-AT compatible. Legacy
1266237436Snp		 * 0x01: Open Firmware standard for PCI. FCODE
1267237436Snp		 * 0x02: Hewlett-Packard PA RISC. HP reserved
1268237436Snp		 * 0x03: EFI Image. EFI
1269237436Snp		 * 0x04-0xFF: Reserved.
1270237436Snp		 */
1271237436Snp	u8	indicator; /* Indicator. Identifies the last image in the ROM */
1272237436Snp	u8	reserved[2]; /* Reserved */
1273237436Snp} pcir_data_t; /* PCI__DATA_STRUCTURE */
1274237436Snp
1275237436Snp/* BOOT constants */
1276228561Snpenum {
1277228561Snp	BOOT_FLASH_BOOT_ADDR = 0x0,/* start address of boot image in flash */
1278228561Snp	BOOT_SIGNATURE = 0xaa55,   /* signature of BIOS boot ROM */
1279228561Snp	BOOT_SIZE_INC = 512,       /* image size measured in 512B chunks */
1280237436Snp	BOOT_MIN_SIZE = sizeof(pci_exp_rom_header_t), /* basic header */
1281237436Snp	BOOT_MAX_SIZE = 1024*BOOT_SIZE_INC, /* 1 byte * length increment  */
1282237436Snp	VENDOR_ID = 0x1425, /* Vendor ID */
1283237436Snp	PCIR_SIGNATURE = 0x52494350 /* PCIR signature */
1284228561Snp};
1285228561Snp
1286228561Snp/*
1287237436Snp *	modify_device_id - Modifies the device ID of the Boot BIOS image
1288237436Snp *	@adatper: the device ID to write.
1289237436Snp *	@boot_data: the boot image to modify.
1290237436Snp *
1291237436Snp *	Write the supplied device ID to the boot BIOS image.
1292237436Snp */
1293237436Snpstatic void modify_device_id(int device_id, u8 *boot_data)
1294237436Snp{
1295237436Snp	legacy_pci_exp_rom_header_t *header;
1296237436Snp	pcir_data_t *pcir_header;
1297237436Snp	u32 cur_header = 0;
1298237436Snp
1299237436Snp	/*
1300237436Snp	 * Loop through all chained images and change the device ID's
1301237436Snp	 */
1302237436Snp	while (1) {
1303237436Snp		header = (legacy_pci_exp_rom_header_t *) &boot_data[cur_header];
1304237436Snp		pcir_header = (pcir_data_t *) &boot_data[cur_header +
1305237436Snp		    le16_to_cpu(*(u16*)header->pcir_offset)];
1306237436Snp
1307237436Snp		/*
1308237436Snp		 * Only modify the Device ID if code type is Legacy or HP.
1309237436Snp		 * 0x00: Okay to modify
1310237436Snp		 * 0x01: FCODE. Do not be modify
1311237436Snp		 * 0x03: Okay to modify
1312237436Snp		 * 0x04-0xFF: Do not modify
1313237436Snp		 */
1314237436Snp		if (pcir_header->code_type == 0x00) {
1315237436Snp			u8 csum = 0;
1316237436Snp			int i;
1317237436Snp
1318237436Snp			/*
1319237436Snp			 * Modify Device ID to match current adatper
1320237436Snp			 */
1321237436Snp			*(u16*) pcir_header->device_id = device_id;
1322237436Snp
1323237436Snp			/*
1324237436Snp			 * Set checksum temporarily to 0.
1325237436Snp			 * We will recalculate it later.
1326237436Snp			 */
1327237436Snp			header->cksum = 0x0;
1328237436Snp
1329237436Snp			/*
1330237436Snp			 * Calculate and update checksum
1331237436Snp			 */
1332237436Snp			for (i = 0; i < (header->size512 * 512); i++)
1333237436Snp				csum += (u8)boot_data[cur_header + i];
1334237436Snp
1335237436Snp			/*
1336237436Snp			 * Invert summed value to create the checksum
1337237436Snp			 * Writing new checksum value directly to the boot data
1338237436Snp			 */
1339237436Snp			boot_data[cur_header + 7] = -csum;
1340237436Snp
1341237436Snp		} else if (pcir_header->code_type == 0x03) {
1342237436Snp
1343237436Snp			/*
1344237436Snp			 * Modify Device ID to match current adatper
1345237436Snp			 */
1346237436Snp			*(u16*) pcir_header->device_id = device_id;
1347237436Snp
1348237436Snp		}
1349237436Snp
1350237436Snp
1351237436Snp		/*
1352237436Snp		 * Check indicator element to identify if this is the last
1353237436Snp		 * image in the ROM.
1354237436Snp		 */
1355237436Snp		if (pcir_header->indicator & 0x80)
1356237436Snp			break;
1357237436Snp
1358237436Snp		/*
1359237436Snp		 * Move header pointer up to the next image in the ROM.
1360237436Snp		 */
1361237436Snp		cur_header += header->size512 * 512;
1362237436Snp	}
1363237436Snp}
1364237436Snp
1365237436Snp/*
1366228561Snp *	t4_load_boot - download boot flash
1367228561Snp *	@adapter: the adapter
1368228561Snp *	@boot_data: the boot image to write
1369237436Snp *	@boot_addr: offset in flash to write boot_data
1370228561Snp *	@size: image size
1371228561Snp *
1372228561Snp *	Write the supplied boot image to the card's serial flash.
1373228561Snp *	The boot image has the following sections: a 28-byte header and the
1374228561Snp *	boot image.
1375228561Snp */
1376237436Snpint t4_load_boot(struct adapter *adap, u8 *boot_data,
1377228561Snp		 unsigned int boot_addr, unsigned int size)
1378228561Snp{
1379237436Snp	pci_exp_rom_header_t *header;
1380237436Snp	int pcir_offset ;
1381237436Snp	pcir_data_t *pcir_header;
1382228561Snp	int ret, addr;
1383237436Snp	uint16_t device_id;
1384228561Snp	unsigned int i;
1385228561Snp	unsigned int boot_sector = boot_addr * 1024;
1386228561Snp	unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
1387228561Snp
1388228561Snp	/*
1389237436Snp	 * Make sure the boot image does not encroach on the firmware region
1390237436Snp	 */
1391237436Snp	if ((boot_sector + size) >> 16 > FLASH_FW_START_SEC) {
1392237436Snp		CH_ERR(adap, "boot image encroaching on firmware region\n");
1393237436Snp		return -EFBIG;
1394237436Snp	}
1395237436Snp
1396237436Snp	/*
1397237436Snp	 * Number of sectors spanned
1398237436Snp	 */
1399237436Snp	i = DIV_ROUND_UP(size ? size : FLASH_BOOTCFG_MAX_SIZE,
1400237436Snp			sf_sec_size);
1401237436Snp	ret = t4_flash_erase_sectors(adap, boot_sector >> 16,
1402237436Snp				     (boot_sector >> 16) + i - 1);
1403237436Snp
1404237436Snp	/*
1405237436Snp	 * If size == 0 then we're simply erasing the FLASH sectors associated
1406237436Snp	 * with the on-adapter option ROM file
1407237436Snp	 */
1408237436Snp	if (ret || (size == 0))
1409237436Snp		goto out;
1410237436Snp
1411237436Snp	/* Get boot header */
1412237436Snp	header = (pci_exp_rom_header_t *)boot_data;
1413237436Snp	pcir_offset = le16_to_cpu(*(u16 *)header->pcir_offset);
1414237436Snp	/* PCIR Data Structure */
1415237436Snp	pcir_header = (pcir_data_t *) &boot_data[pcir_offset];
1416237436Snp
1417237436Snp	/*
1418228561Snp	 * Perform some primitive sanity testing to avoid accidentally
1419228561Snp	 * writing garbage over the boot sectors.  We ought to check for
1420228561Snp	 * more but it's not worth it for now ...
1421228561Snp	 */
1422228561Snp	if (size < BOOT_MIN_SIZE || size > BOOT_MAX_SIZE) {
1423228561Snp		CH_ERR(adap, "boot image too small/large\n");
1424228561Snp		return -EFBIG;
1425228561Snp	}
1426228561Snp
1427228561Snp	/*
1428237436Snp	 * Check BOOT ROM header signature
1429228561Snp	 */
1430237436Snp	if (le16_to_cpu(*(u16*)header->signature) != BOOT_SIGNATURE ) {
1431237436Snp		CH_ERR(adap, "Boot image missing signature\n");
1432237436Snp		return -EINVAL;
1433228561Snp	}
1434228561Snp
1435237436Snp	/*
1436237436Snp	 * Check PCI header signature
1437237436Snp	 */
1438237436Snp	if (le32_to_cpu(*(u32*)pcir_header->signature) != PCIR_SIGNATURE) {
1439237436Snp		CH_ERR(adap, "PCI header missing signature\n");
1440237436Snp		return -EINVAL;
1441237436Snp	}
1442228561Snp
1443228561Snp	/*
1444237436Snp	 * Check Vendor ID matches Chelsio ID
1445237436Snp	 */
1446237436Snp	if (le16_to_cpu(*(u16*)pcir_header->vendor_id) != VENDOR_ID) {
1447237436Snp		CH_ERR(adap, "Vendor ID missing signature\n");
1448237436Snp		return -EINVAL;
1449237436Snp	}
1450237436Snp
1451237436Snp	/*
1452237436Snp	 * Retrieve adapter's device ID
1453237436Snp	 */
1454237436Snp	t4_os_pci_read_cfg2(adap, PCI_DEVICE_ID, &device_id);
1455237436Snp	/* Want to deal with PF 0 so I strip off PF 4 indicator */
1456237436Snp	device_id = (device_id & 0xff) | 0x4000;
1457237436Snp
1458237436Snp	/*
1459237436Snp	 * Check PCIE Device ID
1460237436Snp	 */
1461237436Snp	if (le16_to_cpu(*(u16*)pcir_header->device_id) != device_id) {
1462237436Snp		/*
1463237436Snp		 * Change the device ID in the Boot BIOS image to match
1464237436Snp		 * the Device ID of the current adapter.
1465237436Snp		 */
1466237436Snp		modify_device_id(device_id, boot_data);
1467237436Snp	}
1468237436Snp
1469237436Snp	/*
1470228561Snp	 * Skip over the first SF_PAGE_SIZE worth of data and write it after
1471228561Snp	 * we finish copying the rest of the boot image. This will ensure
1472228561Snp	 * that the BIOS boot header will only be written if the boot image
1473228561Snp	 * was written in full.
1474228561Snp	 */
1475228561Snp	addr = boot_sector;
1476228561Snp	for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) {
1477228561Snp		addr += SF_PAGE_SIZE;
1478228561Snp		boot_data += SF_PAGE_SIZE;
1479228561Snp		ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, boot_data, 0);
1480228561Snp		if (ret)
1481228561Snp			goto out;
1482228561Snp	}
1483228561Snp
1484228561Snp	ret = t4_write_flash(adap, boot_sector, SF_PAGE_SIZE, boot_data, 0);
1485228561Snp
1486228561Snpout:
1487228561Snp	if (ret)
1488228561Snp		CH_ERR(adap, "boot image download failed, error %d\n", ret);
1489228561Snp	return ret;
1490228561Snp}
1491228561Snp
1492218792Snp/**
1493218792Snp *	t4_read_cimq_cfg - read CIM queue configuration
1494218792Snp *	@adap: the adapter
1495218792Snp *	@base: holds the queue base addresses in bytes
1496218792Snp *	@size: holds the queue sizes in bytes
1497218792Snp *	@thres: holds the queue full thresholds in bytes
1498218792Snp *
1499218792Snp *	Returns the current configuration of the CIM queues, starting with
1500218792Snp *	the IBQs, then the OBQs.
1501218792Snp */
1502218792Snpvoid t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres)
1503218792Snp{
1504218792Snp	unsigned int i, v;
1505248925Snp	int cim_num_obq = is_t4(adap) ? CIM_NUM_OBQ : CIM_NUM_OBQ_T5;
1506218792Snp
1507218792Snp	for (i = 0; i < CIM_NUM_IBQ; i++) {
1508218792Snp		t4_write_reg(adap, A_CIM_QUEUE_CONFIG_REF, F_IBQSELECT |
1509218792Snp			     V_QUENUMSELECT(i));
1510218792Snp		v = t4_read_reg(adap, A_CIM_QUEUE_CONFIG_CTRL);
1511218792Snp		*base++ = G_CIMQBASE(v) * 256; /* value is in 256-byte units */
1512218792Snp		*size++ = G_CIMQSIZE(v) * 256; /* value is in 256-byte units */
1513218792Snp		*thres++ = G_QUEFULLTHRSH(v) * 8;   /* 8-byte unit */
1514218792Snp	}
1515248925Snp	for (i = 0; i < cim_num_obq; i++) {
1516218792Snp		t4_write_reg(adap, A_CIM_QUEUE_CONFIG_REF, F_OBQSELECT |
1517218792Snp			     V_QUENUMSELECT(i));
1518218792Snp		v = t4_read_reg(adap, A_CIM_QUEUE_CONFIG_CTRL);
1519218792Snp		*base++ = G_CIMQBASE(v) * 256; /* value is in 256-byte units */
1520218792Snp		*size++ = G_CIMQSIZE(v) * 256; /* value is in 256-byte units */
1521218792Snp	}
1522218792Snp}
1523218792Snp
1524218792Snp/**
1525218792Snp *	t4_read_cim_ibq - read the contents of a CIM inbound queue
1526218792Snp *	@adap: the adapter
1527218792Snp *	@qid: the queue index
1528218792Snp *	@data: where to store the queue contents
1529218792Snp *	@n: capacity of @data in 32-bit words
1530218792Snp *
1531218792Snp *	Reads the contents of the selected CIM queue starting at address 0 up
1532218792Snp *	to the capacity of @data.  @n must be a multiple of 4.  Returns < 0 on
1533218792Snp *	error and the number of 32-bit words actually read on success.
1534218792Snp */
1535218792Snpint t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data, size_t n)
1536218792Snp{
1537218792Snp	int i, err;
1538218792Snp	unsigned int addr;
1539218792Snp	const unsigned int nwords = CIM_IBQ_SIZE * 4;
1540218792Snp
1541218792Snp	if (qid > 5 || (n & 3))
1542218792Snp		return -EINVAL;
1543218792Snp
1544218792Snp	addr = qid * nwords;
1545218792Snp	if (n > nwords)
1546218792Snp		n = nwords;
1547218792Snp
1548218792Snp	for (i = 0; i < n; i++, addr++) {
1549218792Snp		t4_write_reg(adap, A_CIM_IBQ_DBG_CFG, V_IBQDBGADDR(addr) |
1550218792Snp			     F_IBQDBGEN);
1551248925Snp		/*
1552248925Snp		 * It might take 3-10ms before the IBQ debug read access is
1553248925Snp		 * allowed.  Wait for 1 Sec with a delay of 1 usec.
1554248925Snp		 */
1555218792Snp		err = t4_wait_op_done(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGBUSY, 0,
1556248925Snp				      1000000, 1);
1557218792Snp		if (err)
1558218792Snp			return err;
1559218792Snp		*data++ = t4_read_reg(adap, A_CIM_IBQ_DBG_DATA);
1560218792Snp	}
1561218792Snp	t4_write_reg(adap, A_CIM_IBQ_DBG_CFG, 0);
1562218792Snp	return i;
1563218792Snp}
1564218792Snp
1565218792Snp/**
1566218792Snp *	t4_read_cim_obq - read the contents of a CIM outbound queue
1567218792Snp *	@adap: the adapter
1568218792Snp *	@qid: the queue index
1569218792Snp *	@data: where to store the queue contents
1570218792Snp *	@n: capacity of @data in 32-bit words
1571218792Snp *
1572218792Snp *	Reads the contents of the selected CIM queue starting at address 0 up
1573218792Snp *	to the capacity of @data.  @n must be a multiple of 4.  Returns < 0 on
1574218792Snp *	error and the number of 32-bit words actually read on success.
1575218792Snp */
1576218792Snpint t4_read_cim_obq(struct adapter *adap, unsigned int qid, u32 *data, size_t n)
1577218792Snp{
1578218792Snp	int i, err;
1579218792Snp	unsigned int addr, v, nwords;
1580248925Snp	int cim_num_obq = is_t4(adap) ? CIM_NUM_OBQ : CIM_NUM_OBQ_T5;
1581218792Snp
1582248925Snp	if (qid >= cim_num_obq || (n & 3))
1583218792Snp		return -EINVAL;
1584218792Snp
1585218792Snp	t4_write_reg(adap, A_CIM_QUEUE_CONFIG_REF, F_OBQSELECT |
1586218792Snp		     V_QUENUMSELECT(qid));
1587218792Snp	v = t4_read_reg(adap, A_CIM_QUEUE_CONFIG_CTRL);
1588218792Snp
1589218792Snp	addr = G_CIMQBASE(v) * 64;    /* muliple of 256 -> muliple of 4 */
1590218792Snp	nwords = G_CIMQSIZE(v) * 64;  /* same */
1591218792Snp	if (n > nwords)
1592218792Snp		n = nwords;
1593218792Snp
1594218792Snp	for (i = 0; i < n; i++, addr++) {
1595218792Snp		t4_write_reg(adap, A_CIM_OBQ_DBG_CFG, V_OBQDBGADDR(addr) |
1596218792Snp			     F_OBQDBGEN);
1597218792Snp		err = t4_wait_op_done(adap, A_CIM_OBQ_DBG_CFG, F_OBQDBGBUSY, 0,
1598218792Snp				      2, 1);
1599218792Snp		if (err)
1600218792Snp			return err;
1601218792Snp		*data++ = t4_read_reg(adap, A_CIM_OBQ_DBG_DATA);
1602218792Snp	}
1603218792Snp	t4_write_reg(adap, A_CIM_OBQ_DBG_CFG, 0);
1604218792Snp	return i;
1605218792Snp}
1606218792Snp
1607218792Snpenum {
1608218792Snp	CIM_QCTL_BASE     = 0,
1609218792Snp	CIM_CTL_BASE      = 0x2000,
1610218792Snp	CIM_PBT_ADDR_BASE = 0x2800,
1611218792Snp	CIM_PBT_LRF_BASE  = 0x3000,
1612218792Snp	CIM_PBT_DATA_BASE = 0x3800
1613218792Snp};
1614218792Snp
1615218792Snp/**
1616218792Snp *	t4_cim_read - read a block from CIM internal address space
1617218792Snp *	@adap: the adapter
1618218792Snp *	@addr: the start address within the CIM address space
1619218792Snp *	@n: number of words to read
1620218792Snp *	@valp: where to store the result
1621218792Snp *
1622218792Snp *	Reads a block of 4-byte words from the CIM intenal address space.
1623218792Snp */
1624218792Snpint t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n,
1625218792Snp		unsigned int *valp)
1626218792Snp{
1627218792Snp	int ret = 0;
1628218792Snp
1629218792Snp	if (t4_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY)
1630218792Snp		return -EBUSY;
1631218792Snp
1632218792Snp	for ( ; !ret && n--; addr += 4) {
1633218792Snp		t4_write_reg(adap, A_CIM_HOST_ACC_CTRL, addr);
1634218792Snp		ret = t4_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY,
1635218792Snp				      0, 5, 2);
1636218792Snp		if (!ret)
1637218792Snp			*valp++ = t4_read_reg(adap, A_CIM_HOST_ACC_DATA);
1638218792Snp	}
1639218792Snp	return ret;
1640218792Snp}
1641218792Snp
1642218792Snp/**
1643218792Snp *	t4_cim_write - write a block into CIM internal address space
1644218792Snp *	@adap: the adapter
1645218792Snp *	@addr: the start address within the CIM address space
1646218792Snp *	@n: number of words to write
1647218792Snp *	@valp: set of values to write
1648218792Snp *
1649218792Snp *	Writes a block of 4-byte words into the CIM intenal address space.
1650218792Snp */
1651218792Snpint t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n,
1652218792Snp		 const unsigned int *valp)
1653218792Snp{
1654218792Snp	int ret = 0;
1655218792Snp
1656218792Snp	if (t4_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY)
1657218792Snp		return -EBUSY;
1658218792Snp
1659218792Snp	for ( ; !ret && n--; addr += 4) {
1660218792Snp		t4_write_reg(adap, A_CIM_HOST_ACC_DATA, *valp++);
1661218792Snp		t4_write_reg(adap, A_CIM_HOST_ACC_CTRL, addr | F_HOSTWRITE);
1662218792Snp		ret = t4_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY,
1663218792Snp				      0, 5, 2);
1664218792Snp	}
1665218792Snp	return ret;
1666218792Snp}
1667218792Snp
1668218792Snpstatic int t4_cim_write1(struct adapter *adap, unsigned int addr, unsigned int val)
1669218792Snp{
1670218792Snp	return t4_cim_write(adap, addr, 1, &val);
1671218792Snp}
1672218792Snp
1673218792Snp/**
1674218792Snp *	t4_cim_ctl_read - read a block from CIM control region
1675218792Snp *	@adap: the adapter
1676218792Snp *	@addr: the start address within the CIM control region
1677218792Snp *	@n: number of words to read
1678218792Snp *	@valp: where to store the result
1679218792Snp *
1680218792Snp *	Reads a block of 4-byte words from the CIM control region.
1681218792Snp */
1682218792Snpint t4_cim_ctl_read(struct adapter *adap, unsigned int addr, unsigned int n,
1683218792Snp		    unsigned int *valp)
1684218792Snp{
1685218792Snp	return t4_cim_read(adap, addr + CIM_CTL_BASE, n, valp);
1686218792Snp}
1687218792Snp
1688218792Snp/**
1689218792Snp *	t4_cim_read_la - read CIM LA capture buffer
1690218792Snp *	@adap: the adapter
1691218792Snp *	@la_buf: where to store the LA data
1692218792Snp *	@wrptr: the HW write pointer within the capture buffer
1693218792Snp *
1694218792Snp *	Reads the contents of the CIM LA buffer with the most recent entry at
1695218792Snp *	the end	of the returned data and with the entry at @wrptr first.
1696218792Snp *	We try to leave the LA in the running state we find it in.
1697218792Snp */
1698218792Snpint t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr)
1699218792Snp{
1700218792Snp	int i, ret;
1701218792Snp	unsigned int cfg, val, idx;
1702218792Snp
1703218792Snp	ret = t4_cim_read(adap, A_UP_UP_DBG_LA_CFG, 1, &cfg);
1704218792Snp	if (ret)
1705218792Snp		return ret;
1706218792Snp
1707218792Snp	if (cfg & F_UPDBGLAEN) {                /* LA is running, freeze it */
1708218792Snp		ret = t4_cim_write1(adap, A_UP_UP_DBG_LA_CFG, 0);
1709218792Snp		if (ret)
1710218792Snp			return ret;
1711218792Snp	}
1712218792Snp
1713218792Snp	ret = t4_cim_read(adap, A_UP_UP_DBG_LA_CFG, 1, &val);
1714218792Snp	if (ret)
1715218792Snp		goto restart;
1716218792Snp
1717218792Snp	idx = G_UPDBGLAWRPTR(val);
1718218792Snp	if (wrptr)
1719218792Snp		*wrptr = idx;
1720218792Snp
1721218792Snp	for (i = 0; i < adap->params.cim_la_size; i++) {
1722218792Snp		ret = t4_cim_write1(adap, A_UP_UP_DBG_LA_CFG,
1723218792Snp				    V_UPDBGLARDPTR(idx) | F_UPDBGLARDEN);
1724218792Snp		if (ret)
1725218792Snp			break;
1726218792Snp		ret = t4_cim_read(adap, A_UP_UP_DBG_LA_CFG, 1, &val);
1727218792Snp		if (ret)
1728218792Snp			break;
1729218792Snp		if (val & F_UPDBGLARDEN) {
1730218792Snp			ret = -ETIMEDOUT;
1731218792Snp			break;
1732218792Snp		}
1733218792Snp		ret = t4_cim_read(adap, A_UP_UP_DBG_LA_DATA, 1, &la_buf[i]);
1734218792Snp		if (ret)
1735218792Snp			break;
1736218792Snp		idx = (idx + 1) & M_UPDBGLARDPTR;
1737218792Snp	}
1738218792Snprestart:
1739218792Snp	if (cfg & F_UPDBGLAEN) {
1740218792Snp		int r = t4_cim_write1(adap, A_UP_UP_DBG_LA_CFG,
1741218792Snp				      cfg & ~F_UPDBGLARDEN);
1742218792Snp		if (!ret)
1743218792Snp			ret = r;
1744218792Snp	}
1745218792Snp	return ret;
1746218792Snp}
1747218792Snp
1748218792Snpvoid t4_cim_read_pif_la(struct adapter *adap, u32 *pif_req, u32 *pif_rsp,
1749218792Snp			unsigned int *pif_req_wrptr,
1750218792Snp			unsigned int *pif_rsp_wrptr)
1751218792Snp{
1752218792Snp	int i, j;
1753218792Snp	u32 cfg, val, req, rsp;
1754218792Snp
1755218792Snp	cfg = t4_read_reg(adap, A_CIM_DEBUGCFG);
1756218792Snp	if (cfg & F_LADBGEN)
1757218792Snp		t4_write_reg(adap, A_CIM_DEBUGCFG, cfg ^ F_LADBGEN);
1758218792Snp
1759218792Snp	val = t4_read_reg(adap, A_CIM_DEBUGSTS);
1760218792Snp	req = G_POLADBGWRPTR(val);
1761218792Snp	rsp = G_PILADBGWRPTR(val);
1762218792Snp	if (pif_req_wrptr)
1763218792Snp		*pif_req_wrptr = req;
1764218792Snp	if (pif_rsp_wrptr)
1765218792Snp		*pif_rsp_wrptr = rsp;
1766218792Snp
1767218792Snp	for (i = 0; i < CIM_PIFLA_SIZE; i++) {
1768218792Snp		for (j = 0; j < 6; j++) {
1769218792Snp			t4_write_reg(adap, A_CIM_DEBUGCFG, V_POLADBGRDPTR(req) |
1770218792Snp				     V_PILADBGRDPTR(rsp));
1771218792Snp			*pif_req++ = t4_read_reg(adap, A_CIM_PO_LA_DEBUGDATA);
1772218792Snp			*pif_rsp++ = t4_read_reg(adap, A_CIM_PI_LA_DEBUGDATA);
1773218792Snp			req++;
1774218792Snp			rsp++;
1775218792Snp		}
1776218792Snp		req = (req + 2) & M_POLADBGRDPTR;
1777218792Snp		rsp = (rsp + 2) & M_PILADBGRDPTR;
1778218792Snp	}
1779218792Snp	t4_write_reg(adap, A_CIM_DEBUGCFG, cfg);
1780218792Snp}
1781218792Snp
1782218792Snpvoid t4_cim_read_ma_la(struct adapter *adap, u32 *ma_req, u32 *ma_rsp)
1783218792Snp{
1784218792Snp	u32 cfg;
1785218792Snp	int i, j, idx;
1786218792Snp
1787218792Snp	cfg = t4_read_reg(adap, A_CIM_DEBUGCFG);
1788218792Snp	if (cfg & F_LADBGEN)
1789218792Snp		t4_write_reg(adap, A_CIM_DEBUGCFG, cfg ^ F_LADBGEN);
1790218792Snp
1791218792Snp	for (i = 0; i < CIM_MALA_SIZE; i++) {
1792218792Snp		for (j = 0; j < 5; j++) {
1793218792Snp			idx = 8 * i + j;
1794218792Snp			t4_write_reg(adap, A_CIM_DEBUGCFG, V_POLADBGRDPTR(idx) |
1795218792Snp				     V_PILADBGRDPTR(idx));
1796218792Snp			*ma_req++ = t4_read_reg(adap, A_CIM_PO_LA_MADEBUGDATA);
1797218792Snp			*ma_rsp++ = t4_read_reg(adap, A_CIM_PI_LA_MADEBUGDATA);
1798218792Snp		}
1799218792Snp	}
1800218792Snp	t4_write_reg(adap, A_CIM_DEBUGCFG, cfg);
1801218792Snp}
1802218792Snp
1803218792Snp/**
1804218792Snp *	t4_tp_read_la - read TP LA capture buffer
1805218792Snp *	@adap: the adapter
1806218792Snp *	@la_buf: where to store the LA data
1807218792Snp *	@wrptr: the HW write pointer within the capture buffer
1808218792Snp *
1809218792Snp *	Reads the contents of the TP LA buffer with the most recent entry at
1810218792Snp *	the end	of the returned data and with the entry at @wrptr first.
1811218792Snp *	We leave the LA in the running state we find it in.
1812218792Snp */
1813218792Snpvoid t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr)
1814218792Snp{
1815218792Snp	bool last_incomplete;
1816218792Snp	unsigned int i, cfg, val, idx;
1817218792Snp
1818218792Snp	cfg = t4_read_reg(adap, A_TP_DBG_LA_CONFIG) & 0xffff;
1819218792Snp	if (cfg & F_DBGLAENABLE)                    /* freeze LA */
1820218792Snp		t4_write_reg(adap, A_TP_DBG_LA_CONFIG,
1821218792Snp			     adap->params.tp.la_mask | (cfg ^ F_DBGLAENABLE));
1822218792Snp
1823218792Snp	val = t4_read_reg(adap, A_TP_DBG_LA_CONFIG);
1824218792Snp	idx = G_DBGLAWPTR(val);
1825218792Snp	last_incomplete = G_DBGLAMODE(val) >= 2 && (val & F_DBGLAWHLF) == 0;
1826218792Snp	if (last_incomplete)
1827218792Snp		idx = (idx + 1) & M_DBGLARPTR;
1828218792Snp	if (wrptr)
1829218792Snp		*wrptr = idx;
1830218792Snp
1831218792Snp	val &= 0xffff;
1832218792Snp	val &= ~V_DBGLARPTR(M_DBGLARPTR);
1833218792Snp	val |= adap->params.tp.la_mask;
1834218792Snp
1835218792Snp	for (i = 0; i < TPLA_SIZE; i++) {
1836218792Snp		t4_write_reg(adap, A_TP_DBG_LA_CONFIG, V_DBGLARPTR(idx) | val);
1837218792Snp		la_buf[i] = t4_read_reg64(adap, A_TP_DBG_LA_DATAL);
1838218792Snp		idx = (idx + 1) & M_DBGLARPTR;
1839218792Snp	}
1840218792Snp
1841218792Snp	/* Wipe out last entry if it isn't valid */
1842218792Snp	if (last_incomplete)
1843218792Snp		la_buf[TPLA_SIZE - 1] = ~0ULL;
1844218792Snp
1845218792Snp	if (cfg & F_DBGLAENABLE)                    /* restore running state */
1846218792Snp		t4_write_reg(adap, A_TP_DBG_LA_CONFIG,
1847218792Snp			     cfg | adap->params.tp.la_mask);
1848218792Snp}
1849218792Snp
1850218792Snpvoid t4_ulprx_read_la(struct adapter *adap, u32 *la_buf)
1851218792Snp{
1852218792Snp	unsigned int i, j;
1853218792Snp
1854218792Snp	for (i = 0; i < 8; i++) {
1855218792Snp		u32 *p = la_buf + i;
1856218792Snp
1857218792Snp		t4_write_reg(adap, A_ULP_RX_LA_CTL, i);
1858218792Snp		j = t4_read_reg(adap, A_ULP_RX_LA_WRPTR);
1859218792Snp		t4_write_reg(adap, A_ULP_RX_LA_RDPTR, j);
1860218792Snp		for (j = 0; j < ULPRX_LA_SIZE; j++, p += 8)
1861218792Snp			*p = t4_read_reg(adap, A_ULP_RX_LA_RDDATA);
1862218792Snp	}
1863218792Snp}
1864218792Snp
1865218792Snp#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
1866250090Snp		     FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \
1867250090Snp		     FW_PORT_CAP_SPEED_100G | FW_PORT_CAP_ANEG)
1868218792Snp
1869218792Snp/**
1870218792Snp *	t4_link_start - apply link configuration to MAC/PHY
1871218792Snp *	@phy: the PHY to setup
1872218792Snp *	@mac: the MAC to setup
1873218792Snp *	@lc: the requested link configuration
1874218792Snp *
1875218792Snp *	Set up a port's MAC and PHY according to a desired link configuration.
1876218792Snp *	- If the PHY can auto-negotiate first decide what to advertise, then
1877218792Snp *	  enable/disable auto-negotiation as desired, and reset.
1878218792Snp *	- If the PHY does not auto-negotiate just reset it.
1879218792Snp *	- If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
1880218792Snp *	  otherwise do it later based on the outcome of auto-negotiation.
1881218792Snp */
1882218792Snpint t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port,
1883218792Snp		  struct link_config *lc)
1884218792Snp{
1885218792Snp	struct fw_port_cmd c;
1886218792Snp	unsigned int fc = 0, mdi = V_FW_PORT_CAP_MDI(FW_PORT_CAP_MDI_AUTO);
1887218792Snp
1888218792Snp	lc->link_ok = 0;
1889218792Snp	if (lc->requested_fc & PAUSE_RX)
1890218792Snp		fc |= FW_PORT_CAP_FC_RX;
1891218792Snp	if (lc->requested_fc & PAUSE_TX)
1892218792Snp		fc |= FW_PORT_CAP_FC_TX;
1893218792Snp
1894218792Snp	memset(&c, 0, sizeof(c));
1895218792Snp	c.op_to_portid = htonl(V_FW_CMD_OP(FW_PORT_CMD) | F_FW_CMD_REQUEST |
1896218792Snp			       F_FW_CMD_EXEC | V_FW_PORT_CMD_PORTID(port));
1897218792Snp	c.action_to_len16 = htonl(V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) |
1898218792Snp				  FW_LEN16(c));
1899218792Snp
1900218792Snp	if (!(lc->supported & FW_PORT_CAP_ANEG)) {
1901218792Snp		c.u.l1cfg.rcap = htonl((lc->supported & ADVERT_MASK) | fc);
1902218792Snp		lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1903218792Snp	} else if (lc->autoneg == AUTONEG_DISABLE) {
1904218792Snp		c.u.l1cfg.rcap = htonl(lc->requested_speed | fc | mdi);
1905218792Snp		lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1906218792Snp	} else
1907218792Snp		c.u.l1cfg.rcap = htonl(lc->advertising | fc | mdi);
1908218792Snp
1909218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
1910218792Snp}
1911218792Snp
1912218792Snp/**
1913218792Snp *	t4_restart_aneg - restart autonegotiation
1914218792Snp *	@adap: the adapter
1915218792Snp *	@mbox: mbox to use for the FW command
1916218792Snp *	@port: the port id
1917218792Snp *
1918218792Snp *	Restarts autonegotiation for the selected port.
1919218792Snp */
1920218792Snpint t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port)
1921218792Snp{
1922218792Snp	struct fw_port_cmd c;
1923218792Snp
1924218792Snp	memset(&c, 0, sizeof(c));
1925218792Snp	c.op_to_portid = htonl(V_FW_CMD_OP(FW_PORT_CMD) | F_FW_CMD_REQUEST |
1926218792Snp			       F_FW_CMD_EXEC | V_FW_PORT_CMD_PORTID(port));
1927218792Snp	c.action_to_len16 = htonl(V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) |
1928218792Snp				  FW_LEN16(c));
1929218792Snp	c.u.l1cfg.rcap = htonl(FW_PORT_CAP_ANEG);
1930218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
1931218792Snp}
1932218792Snp
1933218792Snpstruct intr_info {
1934218792Snp	unsigned int mask;       /* bits to check in interrupt status */
1935218792Snp	const char *msg;         /* message to print or NULL */
1936218792Snp	short stat_idx;          /* stat counter to increment or -1 */
1937218792Snp	unsigned short fatal;    /* whether the condition reported is fatal */
1938218792Snp};
1939218792Snp
1940218792Snp/**
1941218792Snp *	t4_handle_intr_status - table driven interrupt handler
1942218792Snp *	@adapter: the adapter that generated the interrupt
1943218792Snp *	@reg: the interrupt status register to process
1944218792Snp *	@acts: table of interrupt actions
1945218792Snp *
1946218792Snp *	A table driven interrupt handler that applies a set of masks to an
1947218792Snp *	interrupt status word and performs the corresponding actions if the
1948218792Snp *	interrupts described by the mask have occured.  The actions include
1949218792Snp *	optionally emitting a warning or alert message.  The table is terminated
1950218792Snp *	by an entry specifying mask 0.  Returns the number of fatal interrupt
1951218792Snp *	conditions.
1952218792Snp */
1953218792Snpstatic int t4_handle_intr_status(struct adapter *adapter, unsigned int reg,
1954218792Snp				 const struct intr_info *acts)
1955218792Snp{
1956218792Snp	int fatal = 0;
1957218792Snp	unsigned int mask = 0;
1958218792Snp	unsigned int status = t4_read_reg(adapter, reg);
1959218792Snp
1960218792Snp	for ( ; acts->mask; ++acts) {
1961218792Snp		if (!(status & acts->mask))
1962218792Snp			continue;
1963218792Snp		if (acts->fatal) {
1964218792Snp			fatal++;
1965218792Snp			CH_ALERT(adapter, "%s (0x%x)\n",
1966218792Snp				 acts->msg, status & acts->mask);
1967218792Snp		} else if (acts->msg)
1968218792Snp			CH_WARN_RATELIMIT(adapter, "%s (0x%x)\n",
1969218792Snp					  acts->msg, status & acts->mask);
1970218792Snp		mask |= acts->mask;
1971218792Snp	}
1972218792Snp	status &= mask;
1973218792Snp	if (status)                           /* clear processed interrupts */
1974218792Snp		t4_write_reg(adapter, reg, status);
1975218792Snp	return fatal;
1976218792Snp}
1977218792Snp
1978218792Snp/*
1979218792Snp * Interrupt handler for the PCIE module.
1980218792Snp */
1981218792Snpstatic void pcie_intr_handler(struct adapter *adapter)
1982218792Snp{
1983218792Snp	static struct intr_info sysbus_intr_info[] = {
1984218792Snp		{ F_RNPP, "RXNP array parity error", -1, 1 },
1985218792Snp		{ F_RPCP, "RXPC array parity error", -1, 1 },
1986218792Snp		{ F_RCIP, "RXCIF array parity error", -1, 1 },
1987218792Snp		{ F_RCCP, "Rx completions control array parity error", -1, 1 },
1988218792Snp		{ F_RFTP, "RXFT array parity error", -1, 1 },
1989218792Snp		{ 0 }
1990218792Snp	};
1991218792Snp	static struct intr_info pcie_port_intr_info[] = {
1992218792Snp		{ F_TPCP, "TXPC array parity error", -1, 1 },
1993218792Snp		{ F_TNPP, "TXNP array parity error", -1, 1 },
1994218792Snp		{ F_TFTP, "TXFT array parity error", -1, 1 },
1995218792Snp		{ F_TCAP, "TXCA array parity error", -1, 1 },
1996218792Snp		{ F_TCIP, "TXCIF array parity error", -1, 1 },
1997218792Snp		{ F_RCAP, "RXCA array parity error", -1, 1 },
1998218792Snp		{ F_OTDD, "outbound request TLP discarded", -1, 1 },
1999218792Snp		{ F_RDPE, "Rx data parity error", -1, 1 },
2000218792Snp		{ F_TDUE, "Tx uncorrectable data error", -1, 1 },
2001218792Snp		{ 0 }
2002218792Snp	};
2003218792Snp	static struct intr_info pcie_intr_info[] = {
2004218792Snp		{ F_MSIADDRLPERR, "MSI AddrL parity error", -1, 1 },
2005218792Snp		{ F_MSIADDRHPERR, "MSI AddrH parity error", -1, 1 },
2006218792Snp		{ F_MSIDATAPERR, "MSI data parity error", -1, 1 },
2007218792Snp		{ F_MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
2008218792Snp		{ F_MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
2009218792Snp		{ F_MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
2010218792Snp		{ F_MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
2011218792Snp		{ F_PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 },
2012218792Snp		{ F_PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 },
2013218792Snp		{ F_TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
2014218792Snp		{ F_CCNTPERR, "PCI CMD channel count parity error", -1, 1 },
2015218792Snp		{ F_CREQPERR, "PCI CMD channel request parity error", -1, 1 },
2016218792Snp		{ F_CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
2017218792Snp		{ F_DCNTPERR, "PCI DMA channel count parity error", -1, 1 },
2018218792Snp		{ F_DREQPERR, "PCI DMA channel request parity error", -1, 1 },
2019218792Snp		{ F_DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
2020218792Snp		{ F_HCNTPERR, "PCI HMA channel count parity error", -1, 1 },
2021218792Snp		{ F_HREQPERR, "PCI HMA channel request parity error", -1, 1 },
2022218792Snp		{ F_HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
2023218792Snp		{ F_CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
2024218792Snp		{ F_FIDPERR, "PCI FID parity error", -1, 1 },
2025218792Snp		{ F_INTXCLRPERR, "PCI INTx clear parity error", -1, 1 },
2026218792Snp		{ F_MATAGPERR, "PCI MA tag parity error", -1, 1 },
2027218792Snp		{ F_PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
2028218792Snp		{ F_RXCPLPERR, "PCI Rx completion parity error", -1, 1 },
2029218792Snp		{ F_RXWRPERR, "PCI Rx write parity error", -1, 1 },
2030218792Snp		{ F_RPLPERR, "PCI replay buffer parity error", -1, 1 },
2031218792Snp		{ F_PCIESINT, "PCI core secondary fault", -1, 1 },
2032218792Snp		{ F_PCIEPINT, "PCI core primary fault", -1, 1 },
2033218792Snp		{ F_UNXSPLCPLERR, "PCI unexpected split completion error", -1,
2034218792Snp		  0 },
2035218792Snp		{ 0 }
2036218792Snp	};
2037218792Snp
2038248925Snp	static struct intr_info t5_pcie_intr_info[] = {
2039248925Snp		{ F_MSTGRPPERR, "Master Response Read Queue parity error",
2040248925Snp		  -1, 1 },
2041248925Snp		{ F_MSTTIMEOUTPERR, "Master Timeout FIFO parity error", -1, 1 },
2042248925Snp		{ F_MSIXSTIPERR, "MSI-X STI SRAM parity error", -1, 1 },
2043248925Snp		{ F_MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
2044248925Snp		{ F_MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
2045248925Snp		{ F_MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
2046248925Snp		{ F_MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
2047248925Snp		{ F_PIOCPLGRPPERR, "PCI PIO completion Group FIFO parity error",
2048248925Snp		  -1, 1 },
2049248925Snp		{ F_PIOREQGRPPERR, "PCI PIO request Group FIFO parity error",
2050248925Snp		  -1, 1 },
2051248925Snp		{ F_TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
2052248925Snp		{ F_MSTTAGQPERR, "PCI master tag queue parity error", -1, 1 },
2053248925Snp		{ F_CREQPERR, "PCI CMD channel request parity error", -1, 1 },
2054248925Snp		{ F_CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
2055248925Snp		{ F_DREQWRPERR, "PCI DMA channel write request parity error",
2056248925Snp		  -1, 1 },
2057248925Snp		{ F_DREQPERR, "PCI DMA channel request parity error", -1, 1 },
2058248925Snp		{ F_DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
2059248925Snp		{ F_HREQWRPERR, "PCI HMA channel count parity error", -1, 1 },
2060248925Snp		{ F_HREQPERR, "PCI HMA channel request parity error", -1, 1 },
2061248925Snp		{ F_HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
2062248925Snp		{ F_CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
2063248925Snp		{ F_FIDPERR, "PCI FID parity error", -1, 1 },
2064248925Snp		{ F_VFIDPERR, "PCI INTx clear parity error", -1, 1 },
2065248925Snp		{ F_MAGRPPERR, "PCI MA group FIFO parity error", -1, 1 },
2066248925Snp		{ F_PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
2067248925Snp		{ F_IPRXHDRGRPPERR, "PCI IP Rx header group parity error",
2068248925Snp		  -1, 1 },
2069248925Snp		{ F_IPRXDATAGRPPERR, "PCI IP Rx data group parity error",
2070248925Snp		  -1, 1 },
2071248925Snp		{ F_RPLPERR, "PCI IP replay buffer parity error", -1, 1 },
2072248925Snp		{ F_IPSOTPERR, "PCI IP SOT buffer parity error", -1, 1 },
2073248925Snp		{ F_TRGT1GRPPERR, "PCI TRGT1 group FIFOs parity error", -1, 1 },
2074248925Snp		{ F_READRSPERR, "Outbound read error", -1,
2075248925Snp		  0 },
2076248925Snp		{ 0 }
2077248925Snp	};
2078248925Snp
2079218792Snp	int fat;
2080218792Snp
2081270297Snp	if (is_t4(adapter))
2082270297Snp		fat = t4_handle_intr_status(adapter,
2083270297Snp					    A_PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
2084270297Snp					    sysbus_intr_info) +
2085270297Snp		      t4_handle_intr_status(adapter,
2086270297Snp					    A_PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
2087270297Snp					    pcie_port_intr_info) +
2088270297Snp		      t4_handle_intr_status(adapter, A_PCIE_INT_CAUSE,
2089270297Snp					    pcie_intr_info);
2090270297Snp	else
2091270297Snp		fat = t4_handle_intr_status(adapter, A_PCIE_INT_CAUSE,
2092270297Snp					    t5_pcie_intr_info);
2093218792Snp	if (fat)
2094218792Snp		t4_fatal_err(adapter);
2095218792Snp}
2096218792Snp
2097218792Snp/*
2098218792Snp * TP interrupt handler.
2099218792Snp */
2100218792Snpstatic void tp_intr_handler(struct adapter *adapter)
2101218792Snp{
2102218792Snp	static struct intr_info tp_intr_info[] = {
2103218792Snp		{ 0x3fffffff, "TP parity error", -1, 1 },
2104218792Snp		{ F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 },
2105218792Snp		{ 0 }
2106218792Snp	};
2107218792Snp
2108218792Snp	if (t4_handle_intr_status(adapter, A_TP_INT_CAUSE, tp_intr_info))
2109218792Snp		t4_fatal_err(adapter);
2110218792Snp}
2111218792Snp
2112218792Snp/*
2113218792Snp * SGE interrupt handler.
2114218792Snp */
2115218792Snpstatic void sge_intr_handler(struct adapter *adapter)
2116218792Snp{
2117218792Snp	u64 v;
2118218792Snp	u32 err;
2119218792Snp
2120218792Snp	static struct intr_info sge_intr_info[] = {
2121218792Snp		{ F_ERR_CPL_EXCEED_IQE_SIZE,
2122218792Snp		  "SGE received CPL exceeding IQE size", -1, 1 },
2123218792Snp		{ F_ERR_INVALID_CIDX_INC,
2124218792Snp		  "SGE GTS CIDX increment too large", -1, 0 },
2125218792Snp		{ F_ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 },
2126218792Snp		{ F_ERR_DROPPED_DB, "SGE doorbell dropped", -1, 0 },
2127218792Snp		{ F_ERR_DATA_CPL_ON_HIGH_QID1 | F_ERR_DATA_CPL_ON_HIGH_QID0,
2128218792Snp		  "SGE IQID > 1023 received CPL for FL", -1, 0 },
2129218792Snp		{ F_ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1,
2130218792Snp		  0 },
2131218792Snp		{ F_ERR_BAD_DB_PIDX2, "SGE DBP 2 pidx increment too large", -1,
2132218792Snp		  0 },
2133218792Snp		{ F_ERR_BAD_DB_PIDX1, "SGE DBP 1 pidx increment too large", -1,
2134218792Snp		  0 },
2135218792Snp		{ F_ERR_BAD_DB_PIDX0, "SGE DBP 0 pidx increment too large", -1,
2136218792Snp		  0 },
2137218792Snp		{ F_ERR_ING_CTXT_PRIO,
2138218792Snp		  "SGE too many priority ingress contexts", -1, 0 },
2139218792Snp		{ F_ERR_EGR_CTXT_PRIO,
2140218792Snp		  "SGE too many priority egress contexts", -1, 0 },
2141218792Snp		{ F_INGRESS_SIZE_ERR, "SGE illegal ingress QID", -1, 0 },
2142218792Snp		{ F_EGRESS_SIZE_ERR, "SGE illegal egress QID", -1, 0 },
2143218792Snp		{ 0 }
2144218792Snp	};
2145218792Snp
2146218792Snp	v = (u64)t4_read_reg(adapter, A_SGE_INT_CAUSE1) |
2147218792Snp	    ((u64)t4_read_reg(adapter, A_SGE_INT_CAUSE2) << 32);
2148218792Snp	if (v) {
2149218792Snp		CH_ALERT(adapter, "SGE parity error (%#llx)\n",
2150218792Snp			 (unsigned long long)v);
2151218792Snp		t4_write_reg(adapter, A_SGE_INT_CAUSE1, v);
2152218792Snp		t4_write_reg(adapter, A_SGE_INT_CAUSE2, v >> 32);
2153218792Snp	}
2154218792Snp
2155218792Snp	v |= t4_handle_intr_status(adapter, A_SGE_INT_CAUSE3, sge_intr_info);
2156218792Snp
2157218792Snp	err = t4_read_reg(adapter, A_SGE_ERROR_STATS);
2158218792Snp	if (err & F_ERROR_QID_VALID) {
2159218792Snp		CH_ERR(adapter, "SGE error for queue %u\n", G_ERROR_QID(err));
2160228561Snp		if (err & F_UNCAPTURED_ERROR)
2161228561Snp			CH_ERR(adapter, "SGE UNCAPTURED_ERROR set (clearing)\n");
2162228561Snp		t4_write_reg(adapter, A_SGE_ERROR_STATS, F_ERROR_QID_VALID |
2163228561Snp			     F_UNCAPTURED_ERROR);
2164218792Snp	}
2165218792Snp
2166218792Snp	if (v != 0)
2167218792Snp		t4_fatal_err(adapter);
2168218792Snp}
2169218792Snp
2170218792Snp#define CIM_OBQ_INTR (F_OBQULP0PARERR | F_OBQULP1PARERR | F_OBQULP2PARERR |\
2171218792Snp		      F_OBQULP3PARERR | F_OBQSGEPARERR | F_OBQNCSIPARERR)
2172218792Snp#define CIM_IBQ_INTR (F_IBQTP0PARERR | F_IBQTP1PARERR | F_IBQULPPARERR |\
2173218792Snp		      F_IBQSGEHIPARERR | F_IBQSGELOPARERR | F_IBQNCSIPARERR)
2174218792Snp
2175218792Snp/*
2176218792Snp * CIM interrupt handler.
2177218792Snp */
2178218792Snpstatic void cim_intr_handler(struct adapter *adapter)
2179218792Snp{
2180218792Snp	static struct intr_info cim_intr_info[] = {
2181218792Snp		{ F_PREFDROPINT, "CIM control register prefetch drop", -1, 1 },
2182218792Snp		{ CIM_OBQ_INTR, "CIM OBQ parity error", -1, 1 },
2183218792Snp		{ CIM_IBQ_INTR, "CIM IBQ parity error", -1, 1 },
2184218792Snp		{ F_MBUPPARERR, "CIM mailbox uP parity error", -1, 1 },
2185218792Snp		{ F_MBHOSTPARERR, "CIM mailbox host parity error", -1, 1 },
2186218792Snp		{ F_TIEQINPARERRINT, "CIM TIEQ outgoing parity error", -1, 1 },
2187218792Snp		{ F_TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 },
2188218792Snp		{ 0 }
2189218792Snp	};
2190218792Snp	static struct intr_info cim_upintr_info[] = {
2191218792Snp		{ F_RSVDSPACEINT, "CIM reserved space access", -1, 1 },
2192218792Snp		{ F_ILLTRANSINT, "CIM illegal transaction", -1, 1 },
2193218792Snp		{ F_ILLWRINT, "CIM illegal write", -1, 1 },
2194218792Snp		{ F_ILLRDINT, "CIM illegal read", -1, 1 },
2195218792Snp		{ F_ILLRDBEINT, "CIM illegal read BE", -1, 1 },
2196218792Snp		{ F_ILLWRBEINT, "CIM illegal write BE", -1, 1 },
2197218792Snp		{ F_SGLRDBOOTINT, "CIM single read from boot space", -1, 1 },
2198218792Snp		{ F_SGLWRBOOTINT, "CIM single write to boot space", -1, 1 },
2199218792Snp		{ F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1 },
2200218792Snp		{ F_SGLRDFLASHINT, "CIM single read from flash space", -1, 1 },
2201218792Snp		{ F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1 },
2202218792Snp		{ F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1 },
2203218792Snp		{ F_SGLRDEEPROMINT, "CIM single EEPROM read", -1, 1 },
2204218792Snp		{ F_SGLWREEPROMINT, "CIM single EEPROM write", -1, 1 },
2205218792Snp		{ F_BLKRDEEPROMINT, "CIM block EEPROM read", -1, 1 },
2206218792Snp		{ F_BLKWREEPROMINT, "CIM block EEPROM write", -1, 1 },
2207218792Snp		{ F_SGLRDCTLINT , "CIM single read from CTL space", -1, 1 },
2208218792Snp		{ F_SGLWRCTLINT , "CIM single write to CTL space", -1, 1 },
2209218792Snp		{ F_BLKRDCTLINT , "CIM block read from CTL space", -1, 1 },
2210218792Snp		{ F_BLKWRCTLINT , "CIM block write to CTL space", -1, 1 },
2211218792Snp		{ F_SGLRDPLINT , "CIM single read from PL space", -1, 1 },
2212218792Snp		{ F_SGLWRPLINT , "CIM single write to PL space", -1, 1 },
2213218792Snp		{ F_BLKRDPLINT , "CIM block read from PL space", -1, 1 },
2214218792Snp		{ F_BLKWRPLINT , "CIM block write to PL space", -1, 1 },
2215218792Snp		{ F_REQOVRLOOKUPINT , "CIM request FIFO overwrite", -1, 1 },
2216218792Snp		{ F_RSPOVRLOOKUPINT , "CIM response FIFO overwrite", -1, 1 },
2217218792Snp		{ F_TIMEOUTINT , "CIM PIF timeout", -1, 1 },
2218218792Snp		{ F_TIMEOUTMAINT , "CIM PIF MA timeout", -1, 1 },
2219218792Snp		{ 0 }
2220218792Snp	};
2221218792Snp	int fat;
2222218792Snp
2223247355Snp	if (t4_read_reg(adapter, A_PCIE_FW) & F_PCIE_FW_ERR)
2224247355Snp		t4_report_fw_error(adapter);
2225247355Snp
2226218792Snp	fat = t4_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE,
2227218792Snp				    cim_intr_info) +
2228218792Snp	      t4_handle_intr_status(adapter, A_CIM_HOST_UPACC_INT_CAUSE,
2229218792Snp				    cim_upintr_info);
2230218792Snp	if (fat)
2231218792Snp		t4_fatal_err(adapter);
2232218792Snp}
2233218792Snp
2234218792Snp/*
2235218792Snp * ULP RX interrupt handler.
2236218792Snp */
2237218792Snpstatic void ulprx_intr_handler(struct adapter *adapter)
2238218792Snp{
2239218792Snp	static struct intr_info ulprx_intr_info[] = {
2240218792Snp		{ F_CAUSE_CTX_1, "ULPRX channel 1 context error", -1, 1 },
2241218792Snp		{ F_CAUSE_CTX_0, "ULPRX channel 0 context error", -1, 1 },
2242218792Snp		{ 0x7fffff, "ULPRX parity error", -1, 1 },
2243218792Snp		{ 0 }
2244218792Snp	};
2245218792Snp
2246218792Snp	if (t4_handle_intr_status(adapter, A_ULP_RX_INT_CAUSE, ulprx_intr_info))
2247218792Snp		t4_fatal_err(adapter);
2248218792Snp}
2249218792Snp
2250218792Snp/*
2251218792Snp * ULP TX interrupt handler.
2252218792Snp */
2253218792Snpstatic void ulptx_intr_handler(struct adapter *adapter)
2254218792Snp{
2255218792Snp	static struct intr_info ulptx_intr_info[] = {
2256218792Snp		{ F_PBL_BOUND_ERR_CH3, "ULPTX channel 3 PBL out of bounds", -1,
2257218792Snp		  0 },
2258218792Snp		{ F_PBL_BOUND_ERR_CH2, "ULPTX channel 2 PBL out of bounds", -1,
2259218792Snp		  0 },
2260218792Snp		{ F_PBL_BOUND_ERR_CH1, "ULPTX channel 1 PBL out of bounds", -1,
2261218792Snp		  0 },
2262218792Snp		{ F_PBL_BOUND_ERR_CH0, "ULPTX channel 0 PBL out of bounds", -1,
2263218792Snp		  0 },
2264218792Snp		{ 0xfffffff, "ULPTX parity error", -1, 1 },
2265218792Snp		{ 0 }
2266218792Snp	};
2267218792Snp
2268218792Snp	if (t4_handle_intr_status(adapter, A_ULP_TX_INT_CAUSE, ulptx_intr_info))
2269218792Snp		t4_fatal_err(adapter);
2270218792Snp}
2271218792Snp
2272218792Snp/*
2273218792Snp * PM TX interrupt handler.
2274218792Snp */
2275218792Snpstatic void pmtx_intr_handler(struct adapter *adapter)
2276218792Snp{
2277218792Snp	static struct intr_info pmtx_intr_info[] = {
2278218792Snp		{ F_PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large", -1, 1 },
2279218792Snp		{ F_PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large", -1, 1 },
2280218792Snp		{ F_PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large", -1, 1 },
2281218792Snp		{ F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 },
2282218792Snp		{ 0xffffff0, "PMTX framing error", -1, 1 },
2283218792Snp		{ F_OESPI_PAR_ERROR, "PMTX oespi parity error", -1, 1 },
2284218792Snp		{ F_DB_OPTIONS_PAR_ERROR, "PMTX db_options parity error", -1,
2285218792Snp		  1 },
2286218792Snp		{ F_ICSPI_PAR_ERROR, "PMTX icspi parity error", -1, 1 },
2287218792Snp		{ F_C_PCMD_PAR_ERROR, "PMTX c_pcmd parity error", -1, 1},
2288218792Snp		{ 0 }
2289218792Snp	};
2290218792Snp
2291218792Snp	if (t4_handle_intr_status(adapter, A_PM_TX_INT_CAUSE, pmtx_intr_info))
2292218792Snp		t4_fatal_err(adapter);
2293218792Snp}
2294218792Snp
2295218792Snp/*
2296218792Snp * PM RX interrupt handler.
2297218792Snp */
2298218792Snpstatic void pmrx_intr_handler(struct adapter *adapter)
2299218792Snp{
2300218792Snp	static struct intr_info pmrx_intr_info[] = {
2301218792Snp		{ F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 },
2302218792Snp		{ 0x3ffff0, "PMRX framing error", -1, 1 },
2303218792Snp		{ F_OCSPI_PAR_ERROR, "PMRX ocspi parity error", -1, 1 },
2304218792Snp		{ F_DB_OPTIONS_PAR_ERROR, "PMRX db_options parity error", -1,
2305218792Snp		  1 },
2306218792Snp		{ F_IESPI_PAR_ERROR, "PMRX iespi parity error", -1, 1 },
2307218792Snp		{ F_E_PCMD_PAR_ERROR, "PMRX e_pcmd parity error", -1, 1},
2308218792Snp		{ 0 }
2309218792Snp	};
2310218792Snp
2311218792Snp	if (t4_handle_intr_status(adapter, A_PM_RX_INT_CAUSE, pmrx_intr_info))
2312218792Snp		t4_fatal_err(adapter);
2313218792Snp}
2314218792Snp
2315218792Snp/*
2316218792Snp * CPL switch interrupt handler.
2317218792Snp */
2318218792Snpstatic void cplsw_intr_handler(struct adapter *adapter)
2319218792Snp{
2320218792Snp	static struct intr_info cplsw_intr_info[] = {
2321218792Snp		{ F_CIM_OP_MAP_PERR, "CPLSW CIM op_map parity error", -1, 1 },
2322218792Snp		{ F_CIM_OVFL_ERROR, "CPLSW CIM overflow", -1, 1 },
2323218792Snp		{ F_TP_FRAMING_ERROR, "CPLSW TP framing error", -1, 1 },
2324218792Snp		{ F_SGE_FRAMING_ERROR, "CPLSW SGE framing error", -1, 1 },
2325218792Snp		{ F_CIM_FRAMING_ERROR, "CPLSW CIM framing error", -1, 1 },
2326218792Snp		{ F_ZERO_SWITCH_ERROR, "CPLSW no-switch error", -1, 1 },
2327218792Snp		{ 0 }
2328218792Snp	};
2329218792Snp
2330218792Snp	if (t4_handle_intr_status(adapter, A_CPL_INTR_CAUSE, cplsw_intr_info))
2331218792Snp		t4_fatal_err(adapter);
2332218792Snp}
2333218792Snp
2334218792Snp/*
2335218792Snp * LE interrupt handler.
2336218792Snp */
2337218792Snpstatic void le_intr_handler(struct adapter *adap)
2338218792Snp{
2339218792Snp	static struct intr_info le_intr_info[] = {
2340218792Snp		{ F_LIPMISS, "LE LIP miss", -1, 0 },
2341218792Snp		{ F_LIP0, "LE 0 LIP error", -1, 0 },
2342218792Snp		{ F_PARITYERR, "LE parity error", -1, 1 },
2343218792Snp		{ F_UNKNOWNCMD, "LE unknown command", -1, 1 },
2344218792Snp		{ F_REQQPARERR, "LE request queue parity error", -1, 1 },
2345218792Snp		{ 0 }
2346218792Snp	};
2347218792Snp
2348218792Snp	if (t4_handle_intr_status(adap, A_LE_DB_INT_CAUSE, le_intr_info))
2349218792Snp		t4_fatal_err(adap);
2350218792Snp}
2351218792Snp
2352218792Snp/*
2353218792Snp * MPS interrupt handler.
2354218792Snp */
2355218792Snpstatic void mps_intr_handler(struct adapter *adapter)
2356218792Snp{
2357218792Snp	static struct intr_info mps_rx_intr_info[] = {
2358218792Snp		{ 0xffffff, "MPS Rx parity error", -1, 1 },
2359218792Snp		{ 0 }
2360218792Snp	};
2361218792Snp	static struct intr_info mps_tx_intr_info[] = {
2362218792Snp		{ V_TPFIFO(M_TPFIFO), "MPS Tx TP FIFO parity error", -1, 1 },
2363218792Snp		{ F_NCSIFIFO, "MPS Tx NC-SI FIFO parity error", -1, 1 },
2364218792Snp		{ V_TXDATAFIFO(M_TXDATAFIFO), "MPS Tx data FIFO parity error",
2365218792Snp		  -1, 1 },
2366218792Snp		{ V_TXDESCFIFO(M_TXDESCFIFO), "MPS Tx desc FIFO parity error",
2367218792Snp		  -1, 1 },
2368218792Snp		{ F_BUBBLE, "MPS Tx underflow", -1, 1 },
2369218792Snp		{ F_SECNTERR, "MPS Tx SOP/EOP error", -1, 1 },
2370218792Snp		{ F_FRMERR, "MPS Tx framing error", -1, 1 },
2371218792Snp		{ 0 }
2372218792Snp	};
2373218792Snp	static struct intr_info mps_trc_intr_info[] = {
2374218792Snp		{ V_FILTMEM(M_FILTMEM), "MPS TRC filter parity error", -1, 1 },
2375218792Snp		{ V_PKTFIFO(M_PKTFIFO), "MPS TRC packet FIFO parity error", -1,
2376218792Snp		  1 },
2377218792Snp		{ F_MISCPERR, "MPS TRC misc parity error", -1, 1 },
2378218792Snp		{ 0 }
2379218792Snp	};
2380218792Snp	static struct intr_info mps_stat_sram_intr_info[] = {
2381218792Snp		{ 0x1fffff, "MPS statistics SRAM parity error", -1, 1 },
2382218792Snp		{ 0 }
2383218792Snp	};
2384218792Snp	static struct intr_info mps_stat_tx_intr_info[] = {
2385218792Snp		{ 0xfffff, "MPS statistics Tx FIFO parity error", -1, 1 },
2386218792Snp		{ 0 }
2387218792Snp	};
2388218792Snp	static struct intr_info mps_stat_rx_intr_info[] = {
2389218792Snp		{ 0xffffff, "MPS statistics Rx FIFO parity error", -1, 1 },
2390218792Snp		{ 0 }
2391218792Snp	};
2392218792Snp	static struct intr_info mps_cls_intr_info[] = {
2393218792Snp		{ F_MATCHSRAM, "MPS match SRAM parity error", -1, 1 },
2394218792Snp		{ F_MATCHTCAM, "MPS match TCAM parity error", -1, 1 },
2395218792Snp		{ F_HASHSRAM, "MPS hash SRAM parity error", -1, 1 },
2396218792Snp		{ 0 }
2397218792Snp	};
2398218792Snp
2399218792Snp	int fat;
2400218792Snp
2401218792Snp	fat = t4_handle_intr_status(adapter, A_MPS_RX_PERR_INT_CAUSE,
2402218792Snp				    mps_rx_intr_info) +
2403218792Snp	      t4_handle_intr_status(adapter, A_MPS_TX_INT_CAUSE,
2404218792Snp				    mps_tx_intr_info) +
2405218792Snp	      t4_handle_intr_status(adapter, A_MPS_TRC_INT_CAUSE,
2406218792Snp				    mps_trc_intr_info) +
2407218792Snp	      t4_handle_intr_status(adapter, A_MPS_STAT_PERR_INT_CAUSE_SRAM,
2408218792Snp				    mps_stat_sram_intr_info) +
2409218792Snp	      t4_handle_intr_status(adapter, A_MPS_STAT_PERR_INT_CAUSE_TX_FIFO,
2410218792Snp				    mps_stat_tx_intr_info) +
2411218792Snp	      t4_handle_intr_status(adapter, A_MPS_STAT_PERR_INT_CAUSE_RX_FIFO,
2412218792Snp				    mps_stat_rx_intr_info) +
2413218792Snp	      t4_handle_intr_status(adapter, A_MPS_CLS_INT_CAUSE,
2414218792Snp				    mps_cls_intr_info);
2415218792Snp
2416218792Snp	t4_write_reg(adapter, A_MPS_INT_CAUSE, 0);
2417218792Snp	t4_read_reg(adapter, A_MPS_INT_CAUSE);                    /* flush */
2418218792Snp	if (fat)
2419218792Snp		t4_fatal_err(adapter);
2420218792Snp}
2421218792Snp
2422218792Snp#define MEM_INT_MASK (F_PERR_INT_CAUSE | F_ECC_CE_INT_CAUSE | F_ECC_UE_INT_CAUSE)
2423218792Snp
2424218792Snp/*
2425218792Snp * EDC/MC interrupt handler.
2426218792Snp */
2427218792Snpstatic void mem_intr_handler(struct adapter *adapter, int idx)
2428218792Snp{
2429218792Snp	static const char name[3][5] = { "EDC0", "EDC1", "MC" };
2430218792Snp
2431218792Snp	unsigned int addr, cnt_addr, v;
2432218792Snp
2433218792Snp	if (idx <= MEM_EDC1) {
2434218792Snp		addr = EDC_REG(A_EDC_INT_CAUSE, idx);
2435218792Snp		cnt_addr = EDC_REG(A_EDC_ECC_STATUS, idx);
2436218792Snp	} else {
2437250090Snp		if (is_t4(adapter)) {
2438250090Snp			addr = A_MC_INT_CAUSE;
2439250090Snp			cnt_addr = A_MC_ECC_STATUS;
2440250090Snp		} else {
2441250090Snp			addr = A_MC_P_INT_CAUSE;
2442250090Snp			cnt_addr = A_MC_P_ECC_STATUS;
2443250090Snp		}
2444218792Snp	}
2445218792Snp
2446218792Snp	v = t4_read_reg(adapter, addr) & MEM_INT_MASK;
2447218792Snp	if (v & F_PERR_INT_CAUSE)
2448218792Snp		CH_ALERT(adapter, "%s FIFO parity error\n", name[idx]);
2449218792Snp	if (v & F_ECC_CE_INT_CAUSE) {
2450218792Snp		u32 cnt = G_ECC_CECNT(t4_read_reg(adapter, cnt_addr));
2451218792Snp
2452218792Snp		t4_write_reg(adapter, cnt_addr, V_ECC_CECNT(M_ECC_CECNT));
2453218792Snp		CH_WARN_RATELIMIT(adapter,
2454218792Snp				  "%u %s correctable ECC data error%s\n",
2455218792Snp				  cnt, name[idx], cnt > 1 ? "s" : "");
2456218792Snp	}
2457218792Snp	if (v & F_ECC_UE_INT_CAUSE)
2458218792Snp		CH_ALERT(adapter, "%s uncorrectable ECC data error\n",
2459218792Snp			 name[idx]);
2460218792Snp
2461218792Snp	t4_write_reg(adapter, addr, v);
2462218792Snp	if (v & (F_PERR_INT_CAUSE | F_ECC_UE_INT_CAUSE))
2463218792Snp		t4_fatal_err(adapter);
2464218792Snp}
2465218792Snp
2466218792Snp/*
2467218792Snp * MA interrupt handler.
2468218792Snp */
2469218792Snpstatic void ma_intr_handler(struct adapter *adapter)
2470218792Snp{
2471218792Snp	u32 v, status = t4_read_reg(adapter, A_MA_INT_CAUSE);
2472218792Snp
2473270297Snp	if (status & F_MEM_PERR_INT_CAUSE) {
2474218792Snp		CH_ALERT(adapter, "MA parity error, parity status %#x\n",
2475270297Snp			 t4_read_reg(adapter, A_MA_PARITY_ERROR_STATUS1));
2476270297Snp		if (is_t5(adapter))
2477270297Snp			CH_ALERT(adapter,
2478270297Snp				 "MA parity error, parity status %#x\n",
2479270297Snp				 t4_read_reg(adapter,
2480270297Snp				 	     A_MA_PARITY_ERROR_STATUS2));
2481270297Snp	}
2482218792Snp	if (status & F_MEM_WRAP_INT_CAUSE) {
2483218792Snp		v = t4_read_reg(adapter, A_MA_INT_WRAP_STATUS);
2484218792Snp		CH_ALERT(adapter, "MA address wrap-around error by client %u to"
2485218792Snp			 " address %#x\n", G_MEM_WRAP_CLIENT_NUM(v),
2486218792Snp			 G_MEM_WRAP_ADDRESS(v) << 4);
2487218792Snp	}
2488218792Snp	t4_write_reg(adapter, A_MA_INT_CAUSE, status);
2489218792Snp	t4_fatal_err(adapter);
2490218792Snp}
2491218792Snp
2492218792Snp/*
2493218792Snp * SMB interrupt handler.
2494218792Snp */
2495218792Snpstatic void smb_intr_handler(struct adapter *adap)
2496218792Snp{
2497218792Snp	static struct intr_info smb_intr_info[] = {
2498218792Snp		{ F_MSTTXFIFOPARINT, "SMB master Tx FIFO parity error", -1, 1 },
2499218792Snp		{ F_MSTRXFIFOPARINT, "SMB master Rx FIFO parity error", -1, 1 },
2500218792Snp		{ F_SLVFIFOPARINT, "SMB slave FIFO parity error", -1, 1 },
2501218792Snp		{ 0 }
2502218792Snp	};
2503218792Snp
2504218792Snp	if (t4_handle_intr_status(adap, A_SMB_INT_CAUSE, smb_intr_info))
2505218792Snp		t4_fatal_err(adap);
2506218792Snp}
2507218792Snp
2508218792Snp/*
2509218792Snp * NC-SI interrupt handler.
2510218792Snp */
2511218792Snpstatic void ncsi_intr_handler(struct adapter *adap)
2512218792Snp{
2513218792Snp	static struct intr_info ncsi_intr_info[] = {
2514218792Snp		{ F_CIM_DM_PRTY_ERR, "NC-SI CIM parity error", -1, 1 },
2515218792Snp		{ F_MPS_DM_PRTY_ERR, "NC-SI MPS parity error", -1, 1 },
2516218792Snp		{ F_TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error", -1, 1 },
2517218792Snp		{ F_RXFIFO_PRTY_ERR, "NC-SI Rx FIFO parity error", -1, 1 },
2518218792Snp		{ 0 }
2519218792Snp	};
2520218792Snp
2521218792Snp	if (t4_handle_intr_status(adap, A_NCSI_INT_CAUSE, ncsi_intr_info))
2522218792Snp		t4_fatal_err(adap);
2523218792Snp}
2524218792Snp
2525218792Snp/*
2526218792Snp * XGMAC interrupt handler.
2527218792Snp */
2528218792Snpstatic void xgmac_intr_handler(struct adapter *adap, int port)
2529218792Snp{
2530248925Snp	u32 v, int_cause_reg;
2531218792Snp
2532248925Snp	if (is_t4(adap))
2533248925Snp		int_cause_reg = PORT_REG(port, A_XGMAC_PORT_INT_CAUSE);
2534248925Snp	else
2535248925Snp		int_cause_reg = T5_PORT_REG(port, A_MAC_PORT_INT_CAUSE);
2536248925Snp
2537248925Snp	v = t4_read_reg(adap, int_cause_reg);
2538248925Snp	v &= (F_TXFIFO_PRTY_ERR | F_RXFIFO_PRTY_ERR);
2539218792Snp	if (!v)
2540218792Snp		return;
2541218792Snp
2542218792Snp	if (v & F_TXFIFO_PRTY_ERR)
2543218792Snp		CH_ALERT(adap, "XGMAC %d Tx FIFO parity error\n", port);
2544218792Snp	if (v & F_RXFIFO_PRTY_ERR)
2545218792Snp		CH_ALERT(adap, "XGMAC %d Rx FIFO parity error\n", port);
2546248925Snp	t4_write_reg(adap, int_cause_reg, v);
2547218792Snp	t4_fatal_err(adap);
2548218792Snp}
2549218792Snp
2550218792Snp/*
2551218792Snp * PL interrupt handler.
2552218792Snp */
2553218792Snpstatic void pl_intr_handler(struct adapter *adap)
2554218792Snp{
2555218792Snp	static struct intr_info pl_intr_info[] = {
2556250090Snp		{ F_FATALPERR, "Fatal parity error", -1, 1 },
2557218792Snp		{ F_PERRVFID, "PL VFID_MAP parity error", -1, 1 },
2558218792Snp		{ 0 }
2559218792Snp	};
2560218792Snp
2561250090Snp	static struct intr_info t5_pl_intr_info[] = {
2562250090Snp		{ F_PL_BUSPERR, "PL bus parity error", -1, 1 },
2563250090Snp		{ F_FATALPERR, "Fatal parity error", -1, 1 },
2564250090Snp		{ 0 }
2565250090Snp	};
2566250090Snp
2567250090Snp	if (t4_handle_intr_status(adap, A_PL_PL_INT_CAUSE,
2568250090Snp	    is_t4(adap) ?  pl_intr_info : t5_pl_intr_info))
2569218792Snp		t4_fatal_err(adap);
2570218792Snp}
2571218792Snp
2572218792Snp#define PF_INTR_MASK (F_PFSW | F_PFCIM)
2573218792Snp#define GLBL_INTR_MASK (F_CIM | F_MPS | F_PL | F_PCIE | F_MC | F_EDC0 | \
2574218792Snp		F_EDC1 | F_LE | F_TP | F_MA | F_PM_TX | F_PM_RX | F_ULP_RX | \
2575218792Snp		F_CPL_SWITCH | F_SGE | F_ULP_TX)
2576218792Snp
2577218792Snp/**
2578218792Snp *	t4_slow_intr_handler - control path interrupt handler
2579218792Snp *	@adapter: the adapter
2580218792Snp *
2581218792Snp *	T4 interrupt handler for non-data global interrupt events, e.g., errors.
2582218792Snp *	The designation 'slow' is because it involves register reads, while
2583218792Snp *	data interrupts typically don't involve any MMIOs.
2584218792Snp */
2585218792Snpint t4_slow_intr_handler(struct adapter *adapter)
2586218792Snp{
2587218792Snp	u32 cause = t4_read_reg(adapter, A_PL_INT_CAUSE);
2588218792Snp
2589218792Snp	if (!(cause & GLBL_INTR_MASK))
2590218792Snp		return 0;
2591218792Snp	if (cause & F_CIM)
2592218792Snp		cim_intr_handler(adapter);
2593218792Snp	if (cause & F_MPS)
2594218792Snp		mps_intr_handler(adapter);
2595218792Snp	if (cause & F_NCSI)
2596218792Snp		ncsi_intr_handler(adapter);
2597218792Snp	if (cause & F_PL)
2598218792Snp		pl_intr_handler(adapter);
2599218792Snp	if (cause & F_SMB)
2600218792Snp		smb_intr_handler(adapter);
2601218792Snp	if (cause & F_XGMAC0)
2602218792Snp		xgmac_intr_handler(adapter, 0);
2603218792Snp	if (cause & F_XGMAC1)
2604218792Snp		xgmac_intr_handler(adapter, 1);
2605218792Snp	if (cause & F_XGMAC_KR0)
2606218792Snp		xgmac_intr_handler(adapter, 2);
2607218792Snp	if (cause & F_XGMAC_KR1)
2608218792Snp		xgmac_intr_handler(adapter, 3);
2609218792Snp	if (cause & F_PCIE)
2610218792Snp		pcie_intr_handler(adapter);
2611218792Snp	if (cause & F_MC)
2612218792Snp		mem_intr_handler(adapter, MEM_MC);
2613218792Snp	if (cause & F_EDC0)
2614218792Snp		mem_intr_handler(adapter, MEM_EDC0);
2615218792Snp	if (cause & F_EDC1)
2616218792Snp		mem_intr_handler(adapter, MEM_EDC1);
2617218792Snp	if (cause & F_LE)
2618218792Snp		le_intr_handler(adapter);
2619218792Snp	if (cause & F_TP)
2620218792Snp		tp_intr_handler(adapter);
2621218792Snp	if (cause & F_MA)
2622218792Snp		ma_intr_handler(adapter);
2623218792Snp	if (cause & F_PM_TX)
2624218792Snp		pmtx_intr_handler(adapter);
2625218792Snp	if (cause & F_PM_RX)
2626218792Snp		pmrx_intr_handler(adapter);
2627218792Snp	if (cause & F_ULP_RX)
2628218792Snp		ulprx_intr_handler(adapter);
2629218792Snp	if (cause & F_CPL_SWITCH)
2630218792Snp		cplsw_intr_handler(adapter);
2631218792Snp	if (cause & F_SGE)
2632218792Snp		sge_intr_handler(adapter);
2633218792Snp	if (cause & F_ULP_TX)
2634218792Snp		ulptx_intr_handler(adapter);
2635218792Snp
2636218792Snp	/* Clear the interrupts just processed for which we are the master. */
2637218792Snp	t4_write_reg(adapter, A_PL_INT_CAUSE, cause & GLBL_INTR_MASK);
2638218792Snp	(void) t4_read_reg(adapter, A_PL_INT_CAUSE); /* flush */
2639218792Snp	return 1;
2640218792Snp}
2641218792Snp
2642218792Snp/**
2643218792Snp *	t4_intr_enable - enable interrupts
2644218792Snp *	@adapter: the adapter whose interrupts should be enabled
2645218792Snp *
2646218792Snp *	Enable PF-specific interrupts for the calling function and the top-level
2647218792Snp *	interrupt concentrator for global interrupts.  Interrupts are already
2648218792Snp *	enabled at each module,	here we just enable the roots of the interrupt
2649218792Snp *	hierarchies.
2650218792Snp *
2651218792Snp *	Note: this function should be called only when the driver manages
2652218792Snp *	non PF-specific interrupts from the various HW modules.  Only one PCI
2653218792Snp *	function at a time should be doing this.
2654218792Snp */
2655218792Snpvoid t4_intr_enable(struct adapter *adapter)
2656218792Snp{
2657218792Snp	u32 pf = G_SOURCEPF(t4_read_reg(adapter, A_PL_WHOAMI));
2658218792Snp
2659218792Snp	t4_write_reg(adapter, A_SGE_INT_ENABLE3, F_ERR_CPL_EXCEED_IQE_SIZE |
2660218792Snp		     F_ERR_INVALID_CIDX_INC | F_ERR_CPL_OPCODE_0 |
2661218792Snp		     F_ERR_DROPPED_DB | F_ERR_DATA_CPL_ON_HIGH_QID1 |
2662218792Snp		     F_ERR_DATA_CPL_ON_HIGH_QID0 | F_ERR_BAD_DB_PIDX3 |
2663218792Snp		     F_ERR_BAD_DB_PIDX2 | F_ERR_BAD_DB_PIDX1 |
2664218792Snp		     F_ERR_BAD_DB_PIDX0 | F_ERR_ING_CTXT_PRIO |
2665218792Snp		     F_ERR_EGR_CTXT_PRIO | F_INGRESS_SIZE_ERR |
2666218792Snp		     F_EGRESS_SIZE_ERR);
2667218792Snp	t4_write_reg(adapter, MYPF_REG(A_PL_PF_INT_ENABLE), PF_INTR_MASK);
2668218792Snp	t4_set_reg_field(adapter, A_PL_INT_MAP0, 0, 1 << pf);
2669218792Snp}
2670218792Snp
2671218792Snp/**
2672218792Snp *	t4_intr_disable - disable interrupts
2673218792Snp *	@adapter: the adapter whose interrupts should be disabled
2674218792Snp *
2675218792Snp *	Disable interrupts.  We only disable the top-level interrupt
2676218792Snp *	concentrators.  The caller must be a PCI function managing global
2677218792Snp *	interrupts.
2678218792Snp */
2679218792Snpvoid t4_intr_disable(struct adapter *adapter)
2680218792Snp{
2681218792Snp	u32 pf = G_SOURCEPF(t4_read_reg(adapter, A_PL_WHOAMI));
2682218792Snp
2683218792Snp	t4_write_reg(adapter, MYPF_REG(A_PL_PF_INT_ENABLE), 0);
2684218792Snp	t4_set_reg_field(adapter, A_PL_INT_MAP0, 1 << pf, 0);
2685218792Snp}
2686218792Snp
2687218792Snp/**
2688218792Snp *	t4_intr_clear - clear all interrupts
2689218792Snp *	@adapter: the adapter whose interrupts should be cleared
2690218792Snp *
2691218792Snp *	Clears all interrupts.  The caller must be a PCI function managing
2692218792Snp *	global interrupts.
2693218792Snp */
2694218792Snpvoid t4_intr_clear(struct adapter *adapter)
2695218792Snp{
2696218792Snp	static const unsigned int cause_reg[] = {
2697218792Snp		A_SGE_INT_CAUSE1, A_SGE_INT_CAUSE2, A_SGE_INT_CAUSE3,
2698218792Snp		A_PCIE_NONFAT_ERR, A_PCIE_INT_CAUSE,
2699270297Snp		A_MA_INT_WRAP_STATUS, A_MA_PARITY_ERROR_STATUS1, A_MA_INT_CAUSE,
2700218792Snp		A_EDC_INT_CAUSE, EDC_REG(A_EDC_INT_CAUSE, 1),
2701218792Snp		A_CIM_HOST_INT_CAUSE, A_CIM_HOST_UPACC_INT_CAUSE,
2702218792Snp		MYPF_REG(A_CIM_PF_HOST_INT_CAUSE),
2703218792Snp		A_TP_INT_CAUSE,
2704218792Snp		A_ULP_RX_INT_CAUSE, A_ULP_TX_INT_CAUSE,
2705218792Snp		A_PM_RX_INT_CAUSE, A_PM_TX_INT_CAUSE,
2706218792Snp		A_MPS_RX_PERR_INT_CAUSE,
2707218792Snp		A_CPL_INTR_CAUSE,
2708218792Snp		MYPF_REG(A_PL_PF_INT_CAUSE),
2709218792Snp		A_PL_PL_INT_CAUSE,
2710218792Snp		A_LE_DB_INT_CAUSE,
2711218792Snp	};
2712218792Snp
2713218792Snp	unsigned int i;
2714218792Snp
2715218792Snp	for (i = 0; i < ARRAY_SIZE(cause_reg); ++i)
2716218792Snp		t4_write_reg(adapter, cause_reg[i], 0xffffffff);
2717218792Snp
2718250090Snp	t4_write_reg(adapter, is_t4(adapter) ? A_MC_INT_CAUSE :
2719250090Snp				A_MC_P_INT_CAUSE, 0xffffffff);
2720250090Snp
2721270297Snp	if (is_t4(adapter)) {
2722270297Snp		t4_write_reg(adapter, A_PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
2723270297Snp				0xffffffff);
2724270297Snp		t4_write_reg(adapter, A_PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
2725270297Snp				0xffffffff);
2726270297Snp	} else
2727270297Snp		t4_write_reg(adapter, A_MA_PARITY_ERROR_STATUS2, 0xffffffff);
2728270297Snp
2729218792Snp	t4_write_reg(adapter, A_PL_INT_CAUSE, GLBL_INTR_MASK);
2730218792Snp	(void) t4_read_reg(adapter, A_PL_INT_CAUSE);          /* flush */
2731218792Snp}
2732218792Snp
2733218792Snp/**
2734218792Snp *	hash_mac_addr - return the hash value of a MAC address
2735218792Snp *	@addr: the 48-bit Ethernet MAC address
2736218792Snp *
2737218792Snp *	Hashes a MAC address according to the hash function used by HW inexact
2738218792Snp *	(hash) address matching.
2739218792Snp */
2740218792Snpstatic int hash_mac_addr(const u8 *addr)
2741218792Snp{
2742218792Snp	u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2];
2743218792Snp	u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5];
2744218792Snp	a ^= b;
2745218792Snp	a ^= (a >> 12);
2746218792Snp	a ^= (a >> 6);
2747218792Snp	return a & 0x3f;
2748218792Snp}
2749218792Snp
2750218792Snp/**
2751218792Snp *	t4_config_rss_range - configure a portion of the RSS mapping table
2752218792Snp *	@adapter: the adapter
2753218792Snp *	@mbox: mbox to use for the FW command
2754218792Snp *	@viid: virtual interface whose RSS subtable is to be written
2755218792Snp *	@start: start entry in the table to write
2756218792Snp *	@n: how many table entries to write
2757218792Snp *	@rspq: values for the "response queue" (Ingress Queue) lookup table
2758218792Snp *	@nrspq: number of values in @rspq
2759218792Snp *
2760218792Snp *	Programs the selected part of the VI's RSS mapping table with the
2761218792Snp *	provided values.  If @nrspq < @n the supplied values are used repeatedly
2762218792Snp *	until the full table range is populated.
2763218792Snp *
2764218792Snp *	The caller must ensure the values in @rspq are in the range allowed for
2765218792Snp *	@viid.
2766218792Snp */
2767218792Snpint t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid,
2768218792Snp			int start, int n, const u16 *rspq, unsigned int nrspq)
2769218792Snp{
2770218792Snp	int ret;
2771218792Snp	const u16 *rsp = rspq;
2772218792Snp	const u16 *rsp_end = rspq + nrspq;
2773218792Snp	struct fw_rss_ind_tbl_cmd cmd;
2774218792Snp
2775218792Snp	memset(&cmd, 0, sizeof(cmd));
2776218792Snp	cmd.op_to_viid = htonl(V_FW_CMD_OP(FW_RSS_IND_TBL_CMD) |
2777218792Snp			       F_FW_CMD_REQUEST | F_FW_CMD_WRITE |
2778218792Snp			       V_FW_RSS_IND_TBL_CMD_VIID(viid));
2779218792Snp	cmd.retval_len16 = htonl(FW_LEN16(cmd));
2780218792Snp
2781218792Snp
2782218792Snp	/*
2783218792Snp	 * Each firmware RSS command can accommodate up to 32 RSS Ingress
2784218792Snp	 * Queue Identifiers.  These Ingress Queue IDs are packed three to
2785218792Snp	 * a 32-bit word as 10-bit values with the upper remaining 2 bits
2786218792Snp	 * reserved.
2787218792Snp	 */
2788218792Snp	while (n > 0) {
2789218792Snp		int nq = min(n, 32);
2790228561Snp		int nq_packed = 0;
2791218792Snp		__be32 *qp = &cmd.iq0_to_iq2;
2792218792Snp
2793218792Snp		/*
2794218792Snp		 * Set up the firmware RSS command header to send the next
2795218792Snp		 * "nq" Ingress Queue IDs to the firmware.
2796218792Snp		 */
2797218792Snp		cmd.niqid = htons(nq);
2798218792Snp		cmd.startidx = htons(start);
2799218792Snp
2800218792Snp		/*
2801218792Snp		 * "nq" more done for the start of the next loop.
2802218792Snp		 */
2803218792Snp		start += nq;
2804218792Snp		n -= nq;
2805218792Snp
2806218792Snp		/*
2807218792Snp		 * While there are still Ingress Queue IDs to stuff into the
2808218792Snp		 * current firmware RSS command, retrieve them from the
2809218792Snp		 * Ingress Queue ID array and insert them into the command.
2810218792Snp		 */
2811218792Snp		while (nq > 0) {
2812218792Snp			/*
2813218792Snp			 * Grab up to the next 3 Ingress Queue IDs (wrapping
2814218792Snp			 * around the Ingress Queue ID array if necessary) and
2815218792Snp			 * insert them into the firmware RSS command at the
2816218792Snp			 * current 3-tuple position within the commad.
2817218792Snp			 */
2818228561Snp			u16 qbuf[3];
2819228561Snp			u16 *qbp = qbuf;
2820228561Snp			int nqbuf = min(3, nq);
2821218792Snp
2822228561Snp			nq -= nqbuf;
2823228561Snp			qbuf[0] = qbuf[1] = qbuf[2] = 0;
2824228561Snp			while (nqbuf && nq_packed < 32) {
2825228561Snp				nqbuf--;
2826228561Snp				nq_packed++;
2827228561Snp				*qbp++ = *rsp++;
2828228561Snp				if (rsp >= rsp_end)
2829228561Snp					rsp = rspq;
2830228561Snp			}
2831228561Snp			*qp++ = cpu_to_be32(V_FW_RSS_IND_TBL_CMD_IQ0(qbuf[0]) |
2832228561Snp					    V_FW_RSS_IND_TBL_CMD_IQ1(qbuf[1]) |
2833228561Snp					    V_FW_RSS_IND_TBL_CMD_IQ2(qbuf[2]));
2834218792Snp		}
2835218792Snp
2836218792Snp		/*
2837218792Snp		 * Send this portion of the RRS table update to the firmware;
2838218792Snp		 * bail out on any errors.
2839218792Snp		 */
2840218792Snp		ret = t4_wr_mbox(adapter, mbox, &cmd, sizeof(cmd), NULL);
2841218792Snp		if (ret)
2842218792Snp			return ret;
2843218792Snp	}
2844218792Snp
2845218792Snp	return 0;
2846218792Snp}
2847218792Snp
2848218792Snp/**
2849218792Snp *	t4_config_glbl_rss - configure the global RSS mode
2850218792Snp *	@adapter: the adapter
2851218792Snp *	@mbox: mbox to use for the FW command
2852218792Snp *	@mode: global RSS mode
2853218792Snp *	@flags: mode-specific flags
2854218792Snp *
2855218792Snp *	Sets the global RSS mode.
2856218792Snp */
2857218792Snpint t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode,
2858218792Snp		       unsigned int flags)
2859218792Snp{
2860218792Snp	struct fw_rss_glb_config_cmd c;
2861218792Snp
2862218792Snp	memset(&c, 0, sizeof(c));
2863218792Snp	c.op_to_write = htonl(V_FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) |
2864218792Snp			      F_FW_CMD_REQUEST | F_FW_CMD_WRITE);
2865218792Snp	c.retval_len16 = htonl(FW_LEN16(c));
2866218792Snp	if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL) {
2867218792Snp		c.u.manual.mode_pkd = htonl(V_FW_RSS_GLB_CONFIG_CMD_MODE(mode));
2868218792Snp	} else if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL) {
2869218792Snp		c.u.basicvirtual.mode_pkd =
2870218792Snp			htonl(V_FW_RSS_GLB_CONFIG_CMD_MODE(mode));
2871218792Snp		c.u.basicvirtual.synmapen_to_hashtoeplitz = htonl(flags);
2872218792Snp	} else
2873218792Snp		return -EINVAL;
2874218792Snp	return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL);
2875218792Snp}
2876218792Snp
2877218792Snp/**
2878218792Snp *	t4_config_vi_rss - configure per VI RSS settings
2879218792Snp *	@adapter: the adapter
2880218792Snp *	@mbox: mbox to use for the FW command
2881218792Snp *	@viid: the VI id
2882218792Snp *	@flags: RSS flags
2883218792Snp *	@defq: id of the default RSS queue for the VI.
2884218792Snp *
2885218792Snp *	Configures VI-specific RSS properties.
2886218792Snp */
2887218792Snpint t4_config_vi_rss(struct adapter *adapter, int mbox, unsigned int viid,
2888218792Snp		     unsigned int flags, unsigned int defq)
2889218792Snp{
2890218792Snp	struct fw_rss_vi_config_cmd c;
2891218792Snp
2892218792Snp	memset(&c, 0, sizeof(c));
2893218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) |
2894218792Snp			     F_FW_CMD_REQUEST | F_FW_CMD_WRITE |
2895218792Snp			     V_FW_RSS_VI_CONFIG_CMD_VIID(viid));
2896218792Snp	c.retval_len16 = htonl(FW_LEN16(c));
2897218792Snp	c.u.basicvirtual.defaultq_to_udpen = htonl(flags |
2898218792Snp					V_FW_RSS_VI_CONFIG_CMD_DEFAULTQ(defq));
2899218792Snp	return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL);
2900218792Snp}
2901218792Snp
2902218792Snp/* Read an RSS table row */
2903218792Snpstatic int rd_rss_row(struct adapter *adap, int row, u32 *val)
2904218792Snp{
2905218792Snp	t4_write_reg(adap, A_TP_RSS_LKP_TABLE, 0xfff00000 | row);
2906218792Snp	return t4_wait_op_done_val(adap, A_TP_RSS_LKP_TABLE, F_LKPTBLROWVLD, 1,
2907218792Snp				   5, 0, val);
2908218792Snp}
2909218792Snp
2910218792Snp/**
2911218792Snp *	t4_read_rss - read the contents of the RSS mapping table
2912218792Snp *	@adapter: the adapter
2913218792Snp *	@map: holds the contents of the RSS mapping table
2914218792Snp *
2915218792Snp *	Reads the contents of the RSS hash->queue mapping table.
2916218792Snp */
2917218792Snpint t4_read_rss(struct adapter *adapter, u16 *map)
2918218792Snp{
2919218792Snp	u32 val;
2920218792Snp	int i, ret;
2921218792Snp
2922218792Snp	for (i = 0; i < RSS_NENTRIES / 2; ++i) {
2923218792Snp		ret = rd_rss_row(adapter, i, &val);
2924218792Snp		if (ret)
2925218792Snp			return ret;
2926218792Snp		*map++ = G_LKPTBLQUEUE0(val);
2927218792Snp		*map++ = G_LKPTBLQUEUE1(val);
2928218792Snp	}
2929218792Snp	return 0;
2930218792Snp}
2931218792Snp
2932218792Snp/**
2933218792Snp *	t4_read_rss_key - read the global RSS key
2934218792Snp *	@adap: the adapter
2935218792Snp *	@key: 10-entry array holding the 320-bit RSS key
2936218792Snp *
2937218792Snp *	Reads the global 320-bit RSS key.
2938218792Snp */
2939218792Snpvoid t4_read_rss_key(struct adapter *adap, u32 *key)
2940218792Snp{
2941218792Snp	t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, key, 10,
2942218792Snp			 A_TP_RSS_SECRET_KEY0);
2943218792Snp}
2944218792Snp
2945218792Snp/**
2946218792Snp *	t4_write_rss_key - program one of the RSS keys
2947218792Snp *	@adap: the adapter
2948218792Snp *	@key: 10-entry array holding the 320-bit RSS key
2949218792Snp *	@idx: which RSS key to write
2950218792Snp *
2951218792Snp *	Writes one of the RSS keys with the given 320-bit value.  If @idx is
2952218792Snp *	0..15 the corresponding entry in the RSS key table is written,
2953218792Snp *	otherwise the global RSS key is written.
2954218792Snp */
2955218792Snpvoid t4_write_rss_key(struct adapter *adap, const u32 *key, int idx)
2956218792Snp{
2957218792Snp	t4_write_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, key, 10,
2958218792Snp			  A_TP_RSS_SECRET_KEY0);
2959218792Snp	if (idx >= 0 && idx < 16)
2960218792Snp		t4_write_reg(adap, A_TP_RSS_CONFIG_VRT,
2961218792Snp			     V_KEYWRADDR(idx) | F_KEYWREN);
2962218792Snp}
2963218792Snp
2964218792Snp/**
2965218792Snp *	t4_read_rss_pf_config - read PF RSS Configuration Table
2966218792Snp *	@adapter: the adapter
2967218792Snp *	@index: the entry in the PF RSS table to read
2968218792Snp *	@valp: where to store the returned value
2969218792Snp *
2970218792Snp *	Reads the PF RSS Configuration Table at the specified index and returns
2971218792Snp *	the value found there.
2972218792Snp */
2973218792Snpvoid t4_read_rss_pf_config(struct adapter *adapter, unsigned int index, u32 *valp)
2974218792Snp{
2975218792Snp	t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
2976218792Snp			 valp, 1, A_TP_RSS_PF0_CONFIG + index);
2977218792Snp}
2978218792Snp
2979218792Snp/**
2980218792Snp *	t4_write_rss_pf_config - write PF RSS Configuration Table
2981218792Snp *	@adapter: the adapter
2982218792Snp *	@index: the entry in the VF RSS table to read
2983218792Snp *	@val: the value to store
2984218792Snp *
2985218792Snp *	Writes the PF RSS Configuration Table at the specified index with the
2986218792Snp *	specified value.
2987218792Snp */
2988218792Snpvoid t4_write_rss_pf_config(struct adapter *adapter, unsigned int index, u32 val)
2989218792Snp{
2990218792Snp	t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
2991218792Snp			  &val, 1, A_TP_RSS_PF0_CONFIG + index);
2992218792Snp}
2993218792Snp
2994218792Snp/**
2995218792Snp *	t4_read_rss_vf_config - read VF RSS Configuration Table
2996218792Snp *	@adapter: the adapter
2997218792Snp *	@index: the entry in the VF RSS table to read
2998218792Snp *	@vfl: where to store the returned VFL
2999218792Snp *	@vfh: where to store the returned VFH
3000218792Snp *
3001218792Snp *	Reads the VF RSS Configuration Table at the specified index and returns
3002218792Snp *	the (VFL, VFH) values found there.
3003218792Snp */
3004218792Snpvoid t4_read_rss_vf_config(struct adapter *adapter, unsigned int index,
3005218792Snp			   u32 *vfl, u32 *vfh)
3006218792Snp{
3007218792Snp	u32 vrt;
3008218792Snp
3009218792Snp	/*
3010218792Snp	 * Request that the index'th VF Table values be read into VFL/VFH.
3011218792Snp	 */
3012218792Snp	vrt = t4_read_reg(adapter, A_TP_RSS_CONFIG_VRT);
3013218792Snp	vrt &= ~(F_VFRDRG | V_VFWRADDR(M_VFWRADDR) | F_VFWREN | F_KEYWREN);
3014218792Snp	vrt |= V_VFWRADDR(index) | F_VFRDEN;
3015218792Snp	t4_write_reg(adapter, A_TP_RSS_CONFIG_VRT, vrt);
3016218792Snp
3017218792Snp	/*
3018218792Snp	 * Grab the VFL/VFH values ...
3019218792Snp	 */
3020218792Snp	t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3021218792Snp			 vfl, 1, A_TP_RSS_VFL_CONFIG);
3022218792Snp	t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3023218792Snp			 vfh, 1, A_TP_RSS_VFH_CONFIG);
3024218792Snp}
3025218792Snp
3026218792Snp/**
3027218792Snp *	t4_write_rss_vf_config - write VF RSS Configuration Table
3028218792Snp *
3029218792Snp *	@adapter: the adapter
3030218792Snp *	@index: the entry in the VF RSS table to write
3031218792Snp *	@vfl: the VFL to store
3032218792Snp *	@vfh: the VFH to store
3033218792Snp *
3034218792Snp *	Writes the VF RSS Configuration Table at the specified index with the
3035218792Snp *	specified (VFL, VFH) values.
3036218792Snp */
3037218792Snpvoid t4_write_rss_vf_config(struct adapter *adapter, unsigned int index,
3038218792Snp			    u32 vfl, u32 vfh)
3039218792Snp{
3040218792Snp	u32 vrt;
3041218792Snp
3042218792Snp	/*
3043218792Snp	 * Load up VFL/VFH with the values to be written ...
3044218792Snp	 */
3045218792Snp	t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3046218792Snp			  &vfl, 1, A_TP_RSS_VFL_CONFIG);
3047218792Snp	t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3048218792Snp			  &vfh, 1, A_TP_RSS_VFH_CONFIG);
3049218792Snp
3050218792Snp	/*
3051218792Snp	 * Write the VFL/VFH into the VF Table at index'th location.
3052218792Snp	 */
3053218792Snp	vrt = t4_read_reg(adapter, A_TP_RSS_CONFIG_VRT);
3054218792Snp	vrt &= ~(F_VFRDRG | F_VFRDEN | V_VFWRADDR(M_VFWRADDR) | F_KEYWREN);
3055218792Snp	vrt |= V_VFWRADDR(index) | F_VFWREN;
3056218792Snp	t4_write_reg(adapter, A_TP_RSS_CONFIG_VRT, vrt);
3057218792Snp}
3058218792Snp
3059218792Snp/**
3060218792Snp *	t4_read_rss_pf_map - read PF RSS Map
3061218792Snp *	@adapter: the adapter
3062218792Snp *
3063218792Snp *	Reads the PF RSS Map register and returns its value.
3064218792Snp */
3065218792Snpu32 t4_read_rss_pf_map(struct adapter *adapter)
3066218792Snp{
3067218792Snp	u32 pfmap;
3068218792Snp
3069218792Snp	t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3070218792Snp			 &pfmap, 1, A_TP_RSS_PF_MAP);
3071218792Snp	return pfmap;
3072218792Snp}
3073218792Snp
3074218792Snp/**
3075218792Snp *	t4_write_rss_pf_map - write PF RSS Map
3076218792Snp *	@adapter: the adapter
3077218792Snp *	@pfmap: PF RSS Map value
3078218792Snp *
3079218792Snp *	Writes the specified value to the PF RSS Map register.
3080218792Snp */
3081218792Snpvoid t4_write_rss_pf_map(struct adapter *adapter, u32 pfmap)
3082218792Snp{
3083218792Snp	t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3084218792Snp			  &pfmap, 1, A_TP_RSS_PF_MAP);
3085218792Snp}
3086218792Snp
3087218792Snp/**
3088218792Snp *	t4_read_rss_pf_mask - read PF RSS Mask
3089218792Snp *	@adapter: the adapter
3090218792Snp *
3091218792Snp *	Reads the PF RSS Mask register and returns its value.
3092218792Snp */
3093218792Snpu32 t4_read_rss_pf_mask(struct adapter *adapter)
3094218792Snp{
3095218792Snp	u32 pfmask;
3096218792Snp
3097218792Snp	t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3098218792Snp			 &pfmask, 1, A_TP_RSS_PF_MSK);
3099218792Snp	return pfmask;
3100218792Snp}
3101218792Snp
3102218792Snp/**
3103218792Snp *	t4_write_rss_pf_mask - write PF RSS Mask
3104218792Snp *	@adapter: the adapter
3105218792Snp *	@pfmask: PF RSS Mask value
3106218792Snp *
3107218792Snp *	Writes the specified value to the PF RSS Mask register.
3108218792Snp */
3109218792Snpvoid t4_write_rss_pf_mask(struct adapter *adapter, u32 pfmask)
3110218792Snp{
3111218792Snp	t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3112218792Snp			  &pfmask, 1, A_TP_RSS_PF_MSK);
3113218792Snp}
3114218792Snp
3115281259Snpstatic void refresh_vlan_pri_map(struct adapter *adap)
3116281259Snp{
3117281259Snp
3118281259Snp        t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3119281259Snp                         &adap->params.tp.vlan_pri_map, 1,
3120281259Snp                         A_TP_VLAN_PRI_MAP);
3121281259Snp
3122281259Snp	/*
3123281259Snp	 * Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field
3124281259Snp	 * shift positions of several elements of the Compressed Filter Tuple
3125281259Snp	 * for this adapter which we need frequently ...
3126281259Snp	 */
3127281259Snp	adap->params.tp.vlan_shift = t4_filter_field_shift(adap, F_VLAN);
3128281259Snp	adap->params.tp.vnic_shift = t4_filter_field_shift(adap, F_VNIC_ID);
3129281259Snp	adap->params.tp.port_shift = t4_filter_field_shift(adap, F_PORT);
3130281259Snp	adap->params.tp.protocol_shift = t4_filter_field_shift(adap, F_PROTOCOL);
3131281259Snp
3132281259Snp	/*
3133281259Snp	 * If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID
3134281259Snp	 * represents the presense of an Outer VLAN instead of a VNIC ID.
3135281259Snp	 */
3136281259Snp	if ((adap->params.tp.ingress_config & F_VNIC) == 0)
3137281259Snp		adap->params.tp.vnic_shift = -1;
3138281259Snp}
3139281259Snp
3140218792Snp/**
3141218792Snp *	t4_set_filter_mode - configure the optional components of filter tuples
3142218792Snp *	@adap: the adapter
3143218792Snp *	@mode_map: a bitmap selcting which optional filter components to enable
3144218792Snp *
3145218792Snp *	Sets the filter mode by selecting the optional components to enable
3146218792Snp *	in filter tuples.  Returns 0 on success and a negative error if the
3147218792Snp *	requested mode needs more bits than are available for optional
3148218792Snp *	components.
3149218792Snp */
3150218792Snpint t4_set_filter_mode(struct adapter *adap, unsigned int mode_map)
3151218792Snp{
3152218792Snp	static u8 width[] = { 1, 3, 17, 17, 8, 8, 16, 9, 3, 1 };
3153218792Snp
3154218792Snp	int i, nbits = 0;
3155218792Snp
3156218792Snp	for (i = S_FCOE; i <= S_FRAGMENTATION; i++)
3157218792Snp		if (mode_map & (1 << i))
3158218792Snp			nbits += width[i];
3159218792Snp	if (nbits > FILTER_OPT_LEN)
3160218792Snp		return -EINVAL;
3161218792Snp	t4_write_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, &mode_map, 1,
3162218792Snp			  A_TP_VLAN_PRI_MAP);
3163281259Snp	refresh_vlan_pri_map(adap);
3164281259Snp
3165218792Snp	return 0;
3166218792Snp}
3167218792Snp
3168218792Snp/**
3169218792Snp *	t4_tp_get_tcp_stats - read TP's TCP MIB counters
3170218792Snp *	@adap: the adapter
3171218792Snp *	@v4: holds the TCP/IP counter values
3172218792Snp *	@v6: holds the TCP/IPv6 counter values
3173218792Snp *
3174218792Snp *	Returns the values of TP's TCP/IP and TCP/IPv6 MIB counters.
3175218792Snp *	Either @v4 or @v6 may be %NULL to skip the corresponding stats.
3176218792Snp */
3177218792Snpvoid t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
3178218792Snp			 struct tp_tcp_stats *v6)
3179218792Snp{
3180218792Snp	u32 val[A_TP_MIB_TCP_RXT_SEG_LO - A_TP_MIB_TCP_OUT_RST + 1];
3181218792Snp
3182218792Snp#define STAT_IDX(x) ((A_TP_MIB_TCP_##x) - A_TP_MIB_TCP_OUT_RST)
3183218792Snp#define STAT(x)     val[STAT_IDX(x)]
3184218792Snp#define STAT64(x)   (((u64)STAT(x##_HI) << 32) | STAT(x##_LO))
3185218792Snp
3186218792Snp	if (v4) {
3187218792Snp		t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val,
3188218792Snp				 ARRAY_SIZE(val), A_TP_MIB_TCP_OUT_RST);
3189218792Snp		v4->tcpOutRsts = STAT(OUT_RST);
3190218792Snp		v4->tcpInSegs  = STAT64(IN_SEG);
3191218792Snp		v4->tcpOutSegs = STAT64(OUT_SEG);
3192218792Snp		v4->tcpRetransSegs = STAT64(RXT_SEG);
3193218792Snp	}
3194218792Snp	if (v6) {
3195218792Snp		t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val,
3196218792Snp				 ARRAY_SIZE(val), A_TP_MIB_TCP_V6OUT_RST);
3197218792Snp		v6->tcpOutRsts = STAT(OUT_RST);
3198218792Snp		v6->tcpInSegs  = STAT64(IN_SEG);
3199218792Snp		v6->tcpOutSegs = STAT64(OUT_SEG);
3200218792Snp		v6->tcpRetransSegs = STAT64(RXT_SEG);
3201218792Snp	}
3202218792Snp#undef STAT64
3203218792Snp#undef STAT
3204218792Snp#undef STAT_IDX
3205218792Snp}
3206218792Snp
3207218792Snp/**
3208218792Snp *	t4_tp_get_err_stats - read TP's error MIB counters
3209218792Snp *	@adap: the adapter
3210218792Snp *	@st: holds the counter values
3211218792Snp *
3212218792Snp *	Returns the values of TP's error counters.
3213218792Snp */
3214218792Snpvoid t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st)
3215218792Snp{
3216218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->macInErrs,
3217218792Snp			 12, A_TP_MIB_MAC_IN_ERR_0);
3218218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->tnlCongDrops,
3219218792Snp			 8, A_TP_MIB_TNL_CNG_DROP_0);
3220218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->tnlTxDrops,
3221218792Snp			 4, A_TP_MIB_TNL_DROP_0);
3222218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->ofldVlanDrops,
3223218792Snp			 4, A_TP_MIB_OFD_VLN_DROP_0);
3224218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->tcp6InErrs,
3225218792Snp			 4, A_TP_MIB_TCP_V6IN_ERR_0);
3226218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->ofldNoNeigh,
3227218792Snp			 2, A_TP_MIB_OFD_ARP_DROP);
3228218792Snp}
3229218792Snp
3230218792Snp/**
3231218792Snp *	t4_tp_get_proxy_stats - read TP's proxy MIB counters
3232218792Snp *	@adap: the adapter
3233218792Snp *	@st: holds the counter values
3234218792Snp *
3235218792Snp *	Returns the values of TP's proxy counters.
3236218792Snp */
3237218792Snpvoid t4_tp_get_proxy_stats(struct adapter *adap, struct tp_proxy_stats *st)
3238218792Snp{
3239218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->proxy,
3240218792Snp			 4, A_TP_MIB_TNL_LPBK_0);
3241218792Snp}
3242218792Snp
3243218792Snp/**
3244218792Snp *	t4_tp_get_cpl_stats - read TP's CPL MIB counters
3245218792Snp *	@adap: the adapter
3246218792Snp *	@st: holds the counter values
3247218792Snp *
3248218792Snp *	Returns the values of TP's CPL counters.
3249218792Snp */
3250218792Snpvoid t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st)
3251218792Snp{
3252218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->req,
3253218792Snp			 8, A_TP_MIB_CPL_IN_REQ_0);
3254218792Snp}
3255218792Snp
3256218792Snp/**
3257218792Snp *	t4_tp_get_rdma_stats - read TP's RDMA MIB counters
3258218792Snp *	@adap: the adapter
3259218792Snp *	@st: holds the counter values
3260218792Snp *
3261218792Snp *	Returns the values of TP's RDMA counters.
3262218792Snp */
3263218792Snpvoid t4_tp_get_rdma_stats(struct adapter *adap, struct tp_rdma_stats *st)
3264218792Snp{
3265218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->rqe_dfr_mod,
3266218792Snp			 2, A_TP_MIB_RQE_DFR_MOD);
3267218792Snp}
3268218792Snp
3269218792Snp/**
3270218792Snp *	t4_get_fcoe_stats - read TP's FCoE MIB counters for a port
3271218792Snp *	@adap: the adapter
3272218792Snp *	@idx: the port index
3273218792Snp *	@st: holds the counter values
3274218792Snp *
3275218792Snp *	Returns the values of TP's FCoE counters for the selected port.
3276218792Snp */
3277218792Snpvoid t4_get_fcoe_stats(struct adapter *adap, unsigned int idx,
3278218792Snp		       struct tp_fcoe_stats *st)
3279218792Snp{
3280218792Snp	u32 val[2];
3281218792Snp
3282218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->framesDDP,
3283218792Snp			 1, A_TP_MIB_FCOE_DDP_0 + idx);
3284218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->framesDrop,
3285218792Snp			 1, A_TP_MIB_FCOE_DROP_0 + idx);
3286218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val,
3287218792Snp			 2, A_TP_MIB_FCOE_BYTE_0_HI + 2 * idx);
3288218792Snp	st->octetsDDP = ((u64)val[0] << 32) | val[1];
3289218792Snp}
3290218792Snp
3291218792Snp/**
3292218792Snp *	t4_get_usm_stats - read TP's non-TCP DDP MIB counters
3293218792Snp *	@adap: the adapter
3294218792Snp *	@st: holds the counter values
3295218792Snp *
3296218792Snp *	Returns the values of TP's counters for non-TCP directly-placed packets.
3297218792Snp */
3298218792Snpvoid t4_get_usm_stats(struct adapter *adap, struct tp_usm_stats *st)
3299218792Snp{
3300218792Snp	u32 val[4];
3301218792Snp
3302218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val, 4,
3303218792Snp			 A_TP_MIB_USM_PKTS);
3304218792Snp	st->frames = val[0];
3305218792Snp	st->drops = val[1];
3306218792Snp	st->octets = ((u64)val[2] << 32) | val[3];
3307218792Snp}
3308218792Snp
3309218792Snp/**
3310218792Snp *	t4_read_mtu_tbl - returns the values in the HW path MTU table
3311218792Snp *	@adap: the adapter
3312218792Snp *	@mtus: where to store the MTU values
3313218792Snp *	@mtu_log: where to store the MTU base-2 log (may be %NULL)
3314218792Snp *
3315218792Snp *	Reads the HW path MTU table.
3316218792Snp */
3317218792Snpvoid t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log)
3318218792Snp{
3319218792Snp	u32 v;
3320218792Snp	int i;
3321218792Snp
3322218792Snp	for (i = 0; i < NMTUS; ++i) {
3323218792Snp		t4_write_reg(adap, A_TP_MTU_TABLE,
3324218792Snp			     V_MTUINDEX(0xff) | V_MTUVALUE(i));
3325218792Snp		v = t4_read_reg(adap, A_TP_MTU_TABLE);
3326218792Snp		mtus[i] = G_MTUVALUE(v);
3327218792Snp		if (mtu_log)
3328218792Snp			mtu_log[i] = G_MTUWIDTH(v);
3329218792Snp	}
3330218792Snp}
3331218792Snp
3332218792Snp/**
3333218792Snp *	t4_read_cong_tbl - reads the congestion control table
3334218792Snp *	@adap: the adapter
3335218792Snp *	@incr: where to store the alpha values
3336218792Snp *
3337218792Snp *	Reads the additive increments programmed into the HW congestion
3338218792Snp *	control table.
3339218792Snp */
3340218792Snpvoid t4_read_cong_tbl(struct adapter *adap, u16 incr[NMTUS][NCCTRL_WIN])
3341218792Snp{
3342218792Snp	unsigned int mtu, w;
3343218792Snp
3344218792Snp	for (mtu = 0; mtu < NMTUS; ++mtu)
3345218792Snp		for (w = 0; w < NCCTRL_WIN; ++w) {
3346218792Snp			t4_write_reg(adap, A_TP_CCTRL_TABLE,
3347218792Snp				     V_ROWINDEX(0xffff) | (mtu << 5) | w);
3348218792Snp			incr[mtu][w] = (u16)t4_read_reg(adap,
3349218792Snp						A_TP_CCTRL_TABLE) & 0x1fff;
3350218792Snp		}
3351218792Snp}
3352218792Snp
3353218792Snp/**
3354218792Snp *	t4_read_pace_tbl - read the pace table
3355218792Snp *	@adap: the adapter
3356218792Snp *	@pace_vals: holds the returned values
3357218792Snp *
3358218792Snp *	Returns the values of TP's pace table in microseconds.
3359218792Snp */
3360218792Snpvoid t4_read_pace_tbl(struct adapter *adap, unsigned int pace_vals[NTX_SCHED])
3361218792Snp{
3362218792Snp	unsigned int i, v;
3363218792Snp
3364218792Snp	for (i = 0; i < NTX_SCHED; i++) {
3365218792Snp		t4_write_reg(adap, A_TP_PACE_TABLE, 0xffff0000 + i);
3366218792Snp		v = t4_read_reg(adap, A_TP_PACE_TABLE);
3367218792Snp		pace_vals[i] = dack_ticks_to_usec(adap, v);
3368218792Snp	}
3369218792Snp}
3370218792Snp
3371218792Snp/**
3372218792Snp *	t4_tp_wr_bits_indirect - set/clear bits in an indirect TP register
3373218792Snp *	@adap: the adapter
3374218792Snp *	@addr: the indirect TP register address
3375218792Snp *	@mask: specifies the field within the register to modify
3376218792Snp *	@val: new value for the field
3377218792Snp *
3378218792Snp *	Sets a field of an indirect TP register to the given value.
3379218792Snp */
3380218792Snpvoid t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr,
3381218792Snp			    unsigned int mask, unsigned int val)
3382218792Snp{
3383218792Snp	t4_write_reg(adap, A_TP_PIO_ADDR, addr);
3384218792Snp	val |= t4_read_reg(adap, A_TP_PIO_DATA) & ~mask;
3385218792Snp	t4_write_reg(adap, A_TP_PIO_DATA, val);
3386218792Snp}
3387218792Snp
3388218792Snp/**
3389218792Snp *	init_cong_ctrl - initialize congestion control parameters
3390218792Snp *	@a: the alpha values for congestion control
3391218792Snp *	@b: the beta values for congestion control
3392218792Snp *
3393218792Snp *	Initialize the congestion control parameters.
3394218792Snp */
3395218792Snpstatic void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b)
3396218792Snp{
3397218792Snp	a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
3398218792Snp	a[9] = 2;
3399218792Snp	a[10] = 3;
3400218792Snp	a[11] = 4;
3401218792Snp	a[12] = 5;
3402218792Snp	a[13] = 6;
3403218792Snp	a[14] = 7;
3404218792Snp	a[15] = 8;
3405218792Snp	a[16] = 9;
3406218792Snp	a[17] = 10;
3407218792Snp	a[18] = 14;
3408218792Snp	a[19] = 17;
3409218792Snp	a[20] = 21;
3410218792Snp	a[21] = 25;
3411218792Snp	a[22] = 30;
3412218792Snp	a[23] = 35;
3413218792Snp	a[24] = 45;
3414218792Snp	a[25] = 60;
3415218792Snp	a[26] = 80;
3416218792Snp	a[27] = 100;
3417218792Snp	a[28] = 200;
3418218792Snp	a[29] = 300;
3419218792Snp	a[30] = 400;
3420218792Snp	a[31] = 500;
3421218792Snp
3422218792Snp	b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0;
3423218792Snp	b[9] = b[10] = 1;
3424218792Snp	b[11] = b[12] = 2;
3425218792Snp	b[13] = b[14] = b[15] = b[16] = 3;
3426218792Snp	b[17] = b[18] = b[19] = b[20] = b[21] = 4;
3427218792Snp	b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5;
3428218792Snp	b[28] = b[29] = 6;
3429218792Snp	b[30] = b[31] = 7;
3430218792Snp}
3431218792Snp
3432218792Snp/* The minimum additive increment value for the congestion control table */
3433218792Snp#define CC_MIN_INCR 2U
3434218792Snp
3435218792Snp/**
3436218792Snp *	t4_load_mtus - write the MTU and congestion control HW tables
3437218792Snp *	@adap: the adapter
3438218792Snp *	@mtus: the values for the MTU table
3439218792Snp *	@alpha: the values for the congestion control alpha parameter
3440218792Snp *	@beta: the values for the congestion control beta parameter
3441218792Snp *
3442218792Snp *	Write the HW MTU table with the supplied MTUs and the high-speed
3443218792Snp *	congestion control table with the supplied alpha, beta, and MTUs.
3444218792Snp *	We write the two tables together because the additive increments
3445218792Snp *	depend on the MTUs.
3446218792Snp */
3447218792Snpvoid t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
3448218792Snp		  const unsigned short *alpha, const unsigned short *beta)
3449218792Snp{
3450218792Snp	static const unsigned int avg_pkts[NCCTRL_WIN] = {
3451218792Snp		2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640,
3452218792Snp		896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480,
3453218792Snp		28672, 40960, 57344, 81920, 114688, 163840, 229376
3454218792Snp	};
3455218792Snp
3456218792Snp	unsigned int i, w;
3457218792Snp
3458218792Snp	for (i = 0; i < NMTUS; ++i) {
3459218792Snp		unsigned int mtu = mtus[i];
3460218792Snp		unsigned int log2 = fls(mtu);
3461218792Snp
3462218792Snp		if (!(mtu & ((1 << log2) >> 2)))     /* round */
3463218792Snp			log2--;
3464218792Snp		t4_write_reg(adap, A_TP_MTU_TABLE, V_MTUINDEX(i) |
3465218792Snp			     V_MTUWIDTH(log2) | V_MTUVALUE(mtu));
3466218792Snp
3467218792Snp		for (w = 0; w < NCCTRL_WIN; ++w) {
3468218792Snp			unsigned int inc;
3469218792Snp
3470218792Snp			inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w],
3471218792Snp				  CC_MIN_INCR);
3472218792Snp
3473218792Snp			t4_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) |
3474218792Snp				     (w << 16) | (beta[w] << 13) | inc);
3475218792Snp		}
3476218792Snp	}
3477218792Snp}
3478218792Snp
3479218792Snp/**
3480218792Snp *	t4_set_pace_tbl - set the pace table
3481218792Snp *	@adap: the adapter
3482218792Snp *	@pace_vals: the pace values in microseconds
3483218792Snp *	@start: index of the first entry in the HW pace table to set
3484218792Snp *	@n: how many entries to set
3485218792Snp *
3486218792Snp *	Sets (a subset of the) HW pace table.
3487218792Snp */
3488218792Snpint t4_set_pace_tbl(struct adapter *adap, const unsigned int *pace_vals,
3489218792Snp		     unsigned int start, unsigned int n)
3490218792Snp{
3491218792Snp	unsigned int vals[NTX_SCHED], i;
3492218792Snp	unsigned int tick_ns = dack_ticks_to_usec(adap, 1000);
3493218792Snp
3494218792Snp	if (n > NTX_SCHED)
3495218792Snp	    return -ERANGE;
3496218792Snp
3497218792Snp	/* convert values from us to dack ticks, rounding to closest value */
3498218792Snp	for (i = 0; i < n; i++, pace_vals++) {
3499218792Snp		vals[i] = (1000 * *pace_vals + tick_ns / 2) / tick_ns;
3500218792Snp		if (vals[i] > 0x7ff)
3501218792Snp			return -ERANGE;
3502218792Snp		if (*pace_vals && vals[i] == 0)
3503218792Snp			return -ERANGE;
3504218792Snp	}
3505218792Snp	for (i = 0; i < n; i++, start++)
3506218792Snp		t4_write_reg(adap, A_TP_PACE_TABLE, (start << 16) | vals[i]);
3507218792Snp	return 0;
3508218792Snp}
3509218792Snp
3510218792Snp/**
3511218792Snp *	t4_set_sched_bps - set the bit rate for a HW traffic scheduler
3512218792Snp *	@adap: the adapter
3513218792Snp *	@kbps: target rate in Kbps
3514218792Snp *	@sched: the scheduler index
3515218792Snp *
3516218792Snp *	Configure a Tx HW scheduler for the target rate.
3517218792Snp */
3518218792Snpint t4_set_sched_bps(struct adapter *adap, int sched, unsigned int kbps)
3519218792Snp{
3520218792Snp	unsigned int v, tps, cpt, bpt, delta, mindelta = ~0;
3521218792Snp	unsigned int clk = adap->params.vpd.cclk * 1000;
3522218792Snp	unsigned int selected_cpt = 0, selected_bpt = 0;
3523218792Snp
3524218792Snp	if (kbps > 0) {
3525218792Snp		kbps *= 125;     /* -> bytes */
3526218792Snp		for (cpt = 1; cpt <= 255; cpt++) {
3527218792Snp			tps = clk / cpt;
3528218792Snp			bpt = (kbps + tps / 2) / tps;
3529218792Snp			if (bpt > 0 && bpt <= 255) {
3530218792Snp				v = bpt * tps;
3531218792Snp				delta = v >= kbps ? v - kbps : kbps - v;
3532218792Snp				if (delta < mindelta) {
3533218792Snp					mindelta = delta;
3534218792Snp					selected_cpt = cpt;
3535218792Snp					selected_bpt = bpt;
3536218792Snp				}
3537218792Snp			} else if (selected_cpt)
3538218792Snp				break;
3539218792Snp		}
3540218792Snp		if (!selected_cpt)
3541218792Snp			return -EINVAL;
3542218792Snp	}
3543218792Snp	t4_write_reg(adap, A_TP_TM_PIO_ADDR,
3544218792Snp		     A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2);
3545218792Snp	v = t4_read_reg(adap, A_TP_TM_PIO_DATA);
3546218792Snp	if (sched & 1)
3547218792Snp		v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24);
3548218792Snp	else
3549218792Snp		v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8);
3550218792Snp	t4_write_reg(adap, A_TP_TM_PIO_DATA, v);
3551218792Snp	return 0;
3552218792Snp}
3553218792Snp
3554218792Snp/**
3555218792Snp *	t4_set_sched_ipg - set the IPG for a Tx HW packet rate scheduler
3556218792Snp *	@adap: the adapter
3557218792Snp *	@sched: the scheduler index
3558218792Snp *	@ipg: the interpacket delay in tenths of nanoseconds
3559218792Snp *
3560218792Snp *	Set the interpacket delay for a HW packet rate scheduler.
3561218792Snp */
3562218792Snpint t4_set_sched_ipg(struct adapter *adap, int sched, unsigned int ipg)
3563218792Snp{
3564218792Snp	unsigned int v, addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2;
3565218792Snp
3566218792Snp	/* convert ipg to nearest number of core clocks */
3567218792Snp	ipg *= core_ticks_per_usec(adap);
3568218792Snp	ipg = (ipg + 5000) / 10000;
3569218792Snp	if (ipg > M_TXTIMERSEPQ0)
3570218792Snp		return -EINVAL;
3571218792Snp
3572218792Snp	t4_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3573218792Snp	v = t4_read_reg(adap, A_TP_TM_PIO_DATA);
3574218792Snp	if (sched & 1)
3575218792Snp		v = (v & V_TXTIMERSEPQ0(M_TXTIMERSEPQ0)) | V_TXTIMERSEPQ1(ipg);
3576218792Snp	else
3577218792Snp		v = (v & V_TXTIMERSEPQ1(M_TXTIMERSEPQ1)) | V_TXTIMERSEPQ0(ipg);
3578218792Snp	t4_write_reg(adap, A_TP_TM_PIO_DATA, v);
3579218792Snp	t4_read_reg(adap, A_TP_TM_PIO_DATA);
3580218792Snp	return 0;
3581218792Snp}
3582218792Snp
3583218792Snp/**
3584218792Snp *	t4_get_tx_sched - get the configuration of a Tx HW traffic scheduler
3585218792Snp *	@adap: the adapter
3586218792Snp *	@sched: the scheduler index
3587218792Snp *	@kbps: the byte rate in Kbps
3588218792Snp *	@ipg: the interpacket delay in tenths of nanoseconds
3589218792Snp *
3590218792Snp *	Return the current configuration of a HW Tx scheduler.
3591218792Snp */
3592218792Snpvoid t4_get_tx_sched(struct adapter *adap, unsigned int sched, unsigned int *kbps,
3593218792Snp		     unsigned int *ipg)
3594218792Snp{
3595218792Snp	unsigned int v, addr, bpt, cpt;
3596218792Snp
3597218792Snp	if (kbps) {
3598218792Snp		addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
3599218792Snp		t4_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3600218792Snp		v = t4_read_reg(adap, A_TP_TM_PIO_DATA);
3601218792Snp		if (sched & 1)
3602218792Snp			v >>= 16;
3603218792Snp		bpt = (v >> 8) & 0xff;
3604218792Snp		cpt = v & 0xff;
3605218792Snp		if (!cpt)
3606218792Snp			*kbps = 0;        /* scheduler disabled */
3607218792Snp		else {
3608218792Snp			v = (adap->params.vpd.cclk * 1000) / cpt; /* ticks/s */
3609218792Snp			*kbps = (v * bpt) / 125;
3610218792Snp		}
3611218792Snp	}
3612218792Snp	if (ipg) {
3613218792Snp		addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2;
3614218792Snp		t4_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3615218792Snp		v = t4_read_reg(adap, A_TP_TM_PIO_DATA);
3616218792Snp		if (sched & 1)
3617218792Snp			v >>= 16;
3618218792Snp		v &= 0xffff;
3619218792Snp		*ipg = (10000 * v) / core_ticks_per_usec(adap);
3620218792Snp	}
3621218792Snp}
3622218792Snp
3623218792Snp/*
3624218792Snp * Calculates a rate in bytes/s given the number of 256-byte units per 4K core
3625218792Snp * clocks.  The formula is
3626218792Snp *
3627218792Snp * bytes/s = bytes256 * 256 * ClkFreq / 4096
3628218792Snp *
3629218792Snp * which is equivalent to
3630218792Snp *
3631218792Snp * bytes/s = 62.5 * bytes256 * ClkFreq_ms
3632218792Snp */
3633218792Snpstatic u64 chan_rate(struct adapter *adap, unsigned int bytes256)
3634218792Snp{
3635218792Snp	u64 v = bytes256 * adap->params.vpd.cclk;
3636218792Snp
3637218792Snp	return v * 62 + v / 2;
3638218792Snp}
3639218792Snp
3640218792Snp/**
3641218792Snp *	t4_get_chan_txrate - get the current per channel Tx rates
3642218792Snp *	@adap: the adapter
3643218792Snp *	@nic_rate: rates for NIC traffic
3644218792Snp *	@ofld_rate: rates for offloaded traffic
3645218792Snp *
3646218792Snp *	Return the current Tx rates in bytes/s for NIC and offloaded traffic
3647218792Snp *	for each channel.
3648218792Snp */
3649218792Snpvoid t4_get_chan_txrate(struct adapter *adap, u64 *nic_rate, u64 *ofld_rate)
3650218792Snp{
3651218792Snp	u32 v;
3652218792Snp
3653218792Snp	v = t4_read_reg(adap, A_TP_TX_TRATE);
3654218792Snp	nic_rate[0] = chan_rate(adap, G_TNLRATE0(v));
3655218792Snp	nic_rate[1] = chan_rate(adap, G_TNLRATE1(v));
3656218792Snp	nic_rate[2] = chan_rate(adap, G_TNLRATE2(v));
3657218792Snp	nic_rate[3] = chan_rate(adap, G_TNLRATE3(v));
3658218792Snp
3659218792Snp	v = t4_read_reg(adap, A_TP_TX_ORATE);
3660218792Snp	ofld_rate[0] = chan_rate(adap, G_OFDRATE0(v));
3661218792Snp	ofld_rate[1] = chan_rate(adap, G_OFDRATE1(v));
3662218792Snp	ofld_rate[2] = chan_rate(adap, G_OFDRATE2(v));
3663218792Snp	ofld_rate[3] = chan_rate(adap, G_OFDRATE3(v));
3664218792Snp}
3665218792Snp
3666218792Snp/**
3667218792Snp *	t4_set_trace_filter - configure one of the tracing filters
3668218792Snp *	@adap: the adapter
3669218792Snp *	@tp: the desired trace filter parameters
3670218792Snp *	@idx: which filter to configure
3671218792Snp *	@enable: whether to enable or disable the filter
3672218792Snp *
3673253691Snp *	Configures one of the tracing filters available in HW.  If @tp is %NULL
3674253691Snp *	it indicates that the filter is already written in the register and it
3675253691Snp *	just needs to be enabled or disabled.
3676218792Snp */
3677253691Snpint t4_set_trace_filter(struct adapter *adap, const struct trace_params *tp,
3678253691Snp    int idx, int enable)
3679218792Snp{
3680218792Snp	int i, ofst = idx * 4;
3681218792Snp	u32 data_reg, mask_reg, cfg;
3682218792Snp	u32 multitrc = F_TRCMULTIFILTER;
3683253691Snp	u32 en = is_t4(adap) ? F_TFEN : F_T5_TFEN;
3684218792Snp
3685253691Snp	if (idx < 0 || idx >= NTRACE)
3686253691Snp		return -EINVAL;
3687253691Snp
3688253691Snp	if (tp == NULL || !enable) {
3689253691Snp		t4_set_reg_field(adap, A_MPS_TRC_FILTER_MATCH_CTL_A + ofst, en,
3690253691Snp		    enable ? en : 0);
3691237436Snp		return 0;
3692218792Snp	}
3693218792Snp
3694237436Snp	/*
3695237436Snp	 * TODO - After T4 data book is updated, specify the exact
3696237436Snp	 * section below.
3697237436Snp	 *
3698237436Snp	 * See T4 data book - MPS section for a complete description
3699237436Snp	 * of the below if..else handling of A_MPS_TRC_CFG register
3700237436Snp	 * value.
3701237436Snp	 */
3702237436Snp	cfg = t4_read_reg(adap, A_MPS_TRC_CFG);
3703237436Snp	if (cfg & F_TRCMULTIFILTER) {
3704237436Snp		/*
3705237436Snp		 * If multiple tracers are enabled, then maximum
3706237436Snp		 * capture size is 2.5KB (FIFO size of a single channel)
3707237436Snp		 * minus 2 flits for CPL_TRACE_PKT header.
3708237436Snp		 */
3709237436Snp		if (tp->snap_len > ((10 * 1024 / 4) - (2 * 8)))
3710237436Snp			return -EINVAL;
3711253691Snp	} else {
3712237436Snp		/*
3713237436Snp		 * If multiple tracers are disabled, to avoid deadlocks
3714237436Snp		 * maximum packet capture size of 9600 bytes is recommended.
3715237436Snp		 * Also in this mode, only trace0 can be enabled and running.
3716237436Snp		 */
3717218792Snp		multitrc = 0;
3718237436Snp		if (tp->snap_len > 9600 || idx)
3719218792Snp			return -EINVAL;
3720218792Snp	}
3721218792Snp
3722253691Snp	if (tp->port > (is_t4(adap) ? 11 : 19) || tp->invert > 1 ||
3723253691Snp	    tp->skip_len > M_TFLENGTH || tp->skip_ofst > M_TFOFFSET ||
3724253691Snp	    tp->min_len > M_TFMINPKTSIZE)
3725237436Snp		return -EINVAL;
3726237436Snp
3727218792Snp	/* stop the tracer we'll be changing */
3728253691Snp	t4_set_reg_field(adap, A_MPS_TRC_FILTER_MATCH_CTL_A + ofst, en, 0);
3729218792Snp
3730218792Snp	idx *= (A_MPS_TRC_FILTER1_MATCH - A_MPS_TRC_FILTER0_MATCH);
3731218792Snp	data_reg = A_MPS_TRC_FILTER0_MATCH + idx;
3732218792Snp	mask_reg = A_MPS_TRC_FILTER0_DONT_CARE + idx;
3733218792Snp
3734218792Snp	for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) {
3735218792Snp		t4_write_reg(adap, data_reg, tp->data[i]);
3736218792Snp		t4_write_reg(adap, mask_reg, ~tp->mask[i]);
3737218792Snp	}
3738218792Snp	t4_write_reg(adap, A_MPS_TRC_FILTER_MATCH_CTL_B + ofst,
3739218792Snp		     V_TFCAPTUREMAX(tp->snap_len) |
3740218792Snp		     V_TFMINPKTSIZE(tp->min_len));
3741218792Snp	t4_write_reg(adap, A_MPS_TRC_FILTER_MATCH_CTL_A + ofst,
3742253691Snp		     V_TFOFFSET(tp->skip_ofst) | V_TFLENGTH(tp->skip_len) | en |
3743253691Snp		     (is_t4(adap) ?
3744253691Snp		     V_TFPORT(tp->port) | V_TFINVERTMATCH(tp->invert) :
3745253691Snp		     V_T5_TFPORT(tp->port) | V_T5_TFINVERTMATCH(tp->invert)));
3746218792Snp
3747218792Snp	return 0;
3748218792Snp}
3749218792Snp
3750218792Snp/**
3751218792Snp *	t4_get_trace_filter - query one of the tracing filters
3752218792Snp *	@adap: the adapter
3753218792Snp *	@tp: the current trace filter parameters
3754218792Snp *	@idx: which trace filter to query
3755218792Snp *	@enabled: non-zero if the filter is enabled
3756218792Snp *
3757218792Snp *	Returns the current settings of one of the HW tracing filters.
3758218792Snp */
3759218792Snpvoid t4_get_trace_filter(struct adapter *adap, struct trace_params *tp, int idx,
3760218792Snp			 int *enabled)
3761218792Snp{
3762218792Snp	u32 ctla, ctlb;
3763218792Snp	int i, ofst = idx * 4;
3764218792Snp	u32 data_reg, mask_reg;
3765218792Snp
3766218792Snp	ctla = t4_read_reg(adap, A_MPS_TRC_FILTER_MATCH_CTL_A + ofst);
3767218792Snp	ctlb = t4_read_reg(adap, A_MPS_TRC_FILTER_MATCH_CTL_B + ofst);
3768218792Snp
3769248925Snp	if (is_t4(adap)) {
3770248925Snp		*enabled = !!(ctla & F_TFEN);
3771248925Snp		tp->port =  G_TFPORT(ctla);
3772253691Snp		tp->invert = !!(ctla & F_TFINVERTMATCH);
3773248925Snp	} else {
3774248925Snp		*enabled = !!(ctla & F_T5_TFEN);
3775248925Snp		tp->port = G_T5_TFPORT(ctla);
3776253691Snp		tp->invert = !!(ctla & F_T5_TFINVERTMATCH);
3777248925Snp	}
3778218792Snp	tp->snap_len = G_TFCAPTUREMAX(ctlb);
3779218792Snp	tp->min_len = G_TFMINPKTSIZE(ctlb);
3780218792Snp	tp->skip_ofst = G_TFOFFSET(ctla);
3781218792Snp	tp->skip_len = G_TFLENGTH(ctla);
3782218792Snp
3783218792Snp	ofst = (A_MPS_TRC_FILTER1_MATCH - A_MPS_TRC_FILTER0_MATCH) * idx;
3784218792Snp	data_reg = A_MPS_TRC_FILTER0_MATCH + ofst;
3785218792Snp	mask_reg = A_MPS_TRC_FILTER0_DONT_CARE + ofst;
3786218792Snp
3787218792Snp	for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) {
3788218792Snp		tp->mask[i] = ~t4_read_reg(adap, mask_reg);
3789218792Snp		tp->data[i] = t4_read_reg(adap, data_reg) & tp->mask[i];
3790218792Snp	}
3791218792Snp}
3792218792Snp
3793218792Snp/**
3794218792Snp *	t4_pmtx_get_stats - returns the HW stats from PMTX
3795218792Snp *	@adap: the adapter
3796218792Snp *	@cnt: where to store the count statistics
3797218792Snp *	@cycles: where to store the cycle statistics
3798218792Snp *
3799218792Snp *	Returns performance statistics from PMTX.
3800218792Snp */
3801218792Snpvoid t4_pmtx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[])
3802218792Snp{
3803218792Snp	int i;
3804248925Snp	u32 data[2];
3805218792Snp
3806218792Snp	for (i = 0; i < PM_NSTATS; i++) {
3807218792Snp		t4_write_reg(adap, A_PM_TX_STAT_CONFIG, i + 1);
3808218792Snp		cnt[i] = t4_read_reg(adap, A_PM_TX_STAT_COUNT);
3809248925Snp		if (is_t4(adap))
3810248925Snp			cycles[i] = t4_read_reg64(adap, A_PM_TX_STAT_LSB);
3811248925Snp		else {
3812248925Snp			t4_read_indirect(adap, A_PM_TX_DBG_CTRL,
3813248925Snp					 A_PM_TX_DBG_DATA, data, 2,
3814248925Snp					 A_PM_TX_DBG_STAT_MSB);
3815248925Snp			cycles[i] = (((u64)data[0] << 32) | data[1]);
3816248925Snp		}
3817218792Snp	}
3818218792Snp}
3819218792Snp
3820218792Snp/**
3821218792Snp *	t4_pmrx_get_stats - returns the HW stats from PMRX
3822218792Snp *	@adap: the adapter
3823218792Snp *	@cnt: where to store the count statistics
3824218792Snp *	@cycles: where to store the cycle statistics
3825218792Snp *
3826218792Snp *	Returns performance statistics from PMRX.
3827218792Snp */
3828218792Snpvoid t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[])
3829218792Snp{
3830218792Snp	int i;
3831248925Snp	u32 data[2];
3832218792Snp
3833218792Snp	for (i = 0; i < PM_NSTATS; i++) {
3834218792Snp		t4_write_reg(adap, A_PM_RX_STAT_CONFIG, i + 1);
3835218792Snp		cnt[i] = t4_read_reg(adap, A_PM_RX_STAT_COUNT);
3836248925Snp		if (is_t4(adap))
3837248925Snp			cycles[i] = t4_read_reg64(adap, A_PM_RX_STAT_LSB);
3838248925Snp		else {
3839248925Snp			t4_read_indirect(adap, A_PM_RX_DBG_CTRL,
3840248925Snp					 A_PM_RX_DBG_DATA, data, 2,
3841248925Snp					 A_PM_RX_DBG_STAT_MSB);
3842248925Snp			cycles[i] = (((u64)data[0] << 32) | data[1]);
3843248925Snp		}
3844218792Snp	}
3845218792Snp}
3846218792Snp
3847218792Snp/**
3848218792Snp *	get_mps_bg_map - return the buffer groups associated with a port
3849218792Snp *	@adap: the adapter
3850218792Snp *	@idx: the port index
3851218792Snp *
3852218792Snp *	Returns a bitmap indicating which MPS buffer groups are associated
3853218792Snp *	with the given port.  Bit i is set if buffer group i is used by the
3854218792Snp *	port.
3855218792Snp */
3856218792Snpstatic unsigned int get_mps_bg_map(struct adapter *adap, int idx)
3857218792Snp{
3858218792Snp	u32 n = G_NUMPORTS(t4_read_reg(adap, A_MPS_CMN_CTL));
3859218792Snp
3860218792Snp	if (n == 0)
3861218792Snp		return idx == 0 ? 0xf : 0;
3862218792Snp	if (n == 1)
3863218792Snp		return idx < 2 ? (3 << (2 * idx)) : 0;
3864218792Snp	return 1 << idx;
3865218792Snp}
3866218792Snp
3867218792Snp/**
3868237436Snp *      t4_get_port_stats_offset - collect port stats relative to a previous
3869237436Snp *                                 snapshot
3870237436Snp *      @adap: The adapter
3871237436Snp *      @idx: The port
3872237436Snp *      @stats: Current stats to fill
3873237436Snp *      @offset: Previous stats snapshot
3874237436Snp */
3875237436Snpvoid t4_get_port_stats_offset(struct adapter *adap, int idx,
3876237436Snp		struct port_stats *stats,
3877237436Snp		struct port_stats *offset)
3878237436Snp{
3879237436Snp	u64 *s, *o;
3880237436Snp	int i;
3881237436Snp
3882237436Snp	t4_get_port_stats(adap, idx, stats);
3883237436Snp	for (i = 0, s = (u64 *)stats, o = (u64 *)offset ;
3884237436Snp			i < (sizeof(struct port_stats)/sizeof(u64)) ;
3885237436Snp			i++, s++, o++)
3886237436Snp		*s -= *o;
3887237436Snp}
3888237436Snp
3889237436Snp/**
3890218792Snp *	t4_get_port_stats - collect port statistics
3891218792Snp *	@adap: the adapter
3892218792Snp *	@idx: the port index
3893218792Snp *	@p: the stats structure to fill
3894218792Snp *
3895218792Snp *	Collect statistics related to the given port from HW.
3896218792Snp */
3897218792Snpvoid t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
3898218792Snp{
3899218792Snp	u32 bgmap = get_mps_bg_map(adap, idx);
3900218792Snp
3901218792Snp#define GET_STAT(name) \
3902248925Snp	t4_read_reg64(adap, \
3903248925Snp	(is_t4(adap) ? PORT_REG(idx, A_MPS_PORT_STAT_##name##_L) : \
3904248925Snp	T5_PORT_REG(idx, A_MPS_PORT_STAT_##name##_L)))
3905218792Snp#define GET_STAT_COM(name) t4_read_reg64(adap, A_MPS_STAT_##name##_L)
3906218792Snp
3907228561Snp	p->tx_pause            = GET_STAT(TX_PORT_PAUSE);
3908218792Snp	p->tx_octets           = GET_STAT(TX_PORT_BYTES);
3909218792Snp	p->tx_frames           = GET_STAT(TX_PORT_FRAMES);
3910218792Snp	p->tx_bcast_frames     = GET_STAT(TX_PORT_BCAST);
3911218792Snp	p->tx_mcast_frames     = GET_STAT(TX_PORT_MCAST);
3912218792Snp	p->tx_ucast_frames     = GET_STAT(TX_PORT_UCAST);
3913218792Snp	p->tx_error_frames     = GET_STAT(TX_PORT_ERROR);
3914218792Snp	p->tx_frames_64        = GET_STAT(TX_PORT_64B);
3915218792Snp	p->tx_frames_65_127    = GET_STAT(TX_PORT_65B_127B);
3916218792Snp	p->tx_frames_128_255   = GET_STAT(TX_PORT_128B_255B);
3917218792Snp	p->tx_frames_256_511   = GET_STAT(TX_PORT_256B_511B);
3918218792Snp	p->tx_frames_512_1023  = GET_STAT(TX_PORT_512B_1023B);
3919218792Snp	p->tx_frames_1024_1518 = GET_STAT(TX_PORT_1024B_1518B);
3920218792Snp	p->tx_frames_1519_max  = GET_STAT(TX_PORT_1519B_MAX);
3921218792Snp	p->tx_drop             = GET_STAT(TX_PORT_DROP);
3922218792Snp	p->tx_ppp0             = GET_STAT(TX_PORT_PPP0);
3923218792Snp	p->tx_ppp1             = GET_STAT(TX_PORT_PPP1);
3924218792Snp	p->tx_ppp2             = GET_STAT(TX_PORT_PPP2);
3925218792Snp	p->tx_ppp3             = GET_STAT(TX_PORT_PPP3);
3926218792Snp	p->tx_ppp4             = GET_STAT(TX_PORT_PPP4);
3927218792Snp	p->tx_ppp5             = GET_STAT(TX_PORT_PPP5);
3928218792Snp	p->tx_ppp6             = GET_STAT(TX_PORT_PPP6);
3929218792Snp	p->tx_ppp7             = GET_STAT(TX_PORT_PPP7);
3930218792Snp
3931228561Snp	p->rx_pause            = GET_STAT(RX_PORT_PAUSE);
3932218792Snp	p->rx_octets           = GET_STAT(RX_PORT_BYTES);
3933218792Snp	p->rx_frames           = GET_STAT(RX_PORT_FRAMES);
3934218792Snp	p->rx_bcast_frames     = GET_STAT(RX_PORT_BCAST);
3935218792Snp	p->rx_mcast_frames     = GET_STAT(RX_PORT_MCAST);
3936218792Snp	p->rx_ucast_frames     = GET_STAT(RX_PORT_UCAST);
3937218792Snp	p->rx_too_long         = GET_STAT(RX_PORT_MTU_ERROR);
3938218792Snp	p->rx_jabber           = GET_STAT(RX_PORT_MTU_CRC_ERROR);
3939218792Snp	p->rx_fcs_err          = GET_STAT(RX_PORT_CRC_ERROR);
3940218792Snp	p->rx_len_err          = GET_STAT(RX_PORT_LEN_ERROR);
3941218792Snp	p->rx_symbol_err       = GET_STAT(RX_PORT_SYM_ERROR);
3942218792Snp	p->rx_runt             = GET_STAT(RX_PORT_LESS_64B);
3943218792Snp	p->rx_frames_64        = GET_STAT(RX_PORT_64B);
3944218792Snp	p->rx_frames_65_127    = GET_STAT(RX_PORT_65B_127B);
3945218792Snp	p->rx_frames_128_255   = GET_STAT(RX_PORT_128B_255B);
3946218792Snp	p->rx_frames_256_511   = GET_STAT(RX_PORT_256B_511B);
3947218792Snp	p->rx_frames_512_1023  = GET_STAT(RX_PORT_512B_1023B);
3948218792Snp	p->rx_frames_1024_1518 = GET_STAT(RX_PORT_1024B_1518B);
3949218792Snp	p->rx_frames_1519_max  = GET_STAT(RX_PORT_1519B_MAX);
3950218792Snp	p->rx_ppp0             = GET_STAT(RX_PORT_PPP0);
3951218792Snp	p->rx_ppp1             = GET_STAT(RX_PORT_PPP1);
3952218792Snp	p->rx_ppp2             = GET_STAT(RX_PORT_PPP2);
3953218792Snp	p->rx_ppp3             = GET_STAT(RX_PORT_PPP3);
3954218792Snp	p->rx_ppp4             = GET_STAT(RX_PORT_PPP4);
3955218792Snp	p->rx_ppp5             = GET_STAT(RX_PORT_PPP5);
3956218792Snp	p->rx_ppp6             = GET_STAT(RX_PORT_PPP6);
3957218792Snp	p->rx_ppp7             = GET_STAT(RX_PORT_PPP7);
3958218792Snp
3959218792Snp	p->rx_ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_DROP_FRAME) : 0;
3960218792Snp	p->rx_ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_DROP_FRAME) : 0;
3961218792Snp	p->rx_ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_DROP_FRAME) : 0;
3962218792Snp	p->rx_ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_DROP_FRAME) : 0;
3963218792Snp	p->rx_trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_TRUNC_FRAME) : 0;
3964218792Snp	p->rx_trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_TRUNC_FRAME) : 0;
3965218792Snp	p->rx_trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_TRUNC_FRAME) : 0;
3966218792Snp	p->rx_trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_TRUNC_FRAME) : 0;
3967218792Snp
3968218792Snp#undef GET_STAT
3969218792Snp#undef GET_STAT_COM
3970218792Snp}
3971218792Snp
3972218792Snp/**
3973218792Snp *	t4_clr_port_stats - clear port statistics
3974218792Snp *	@adap: the adapter
3975218792Snp *	@idx: the port index
3976218792Snp *
3977218792Snp *	Clear HW statistics for the given port.
3978218792Snp */
3979218792Snpvoid t4_clr_port_stats(struct adapter *adap, int idx)
3980218792Snp{
3981218792Snp	unsigned int i;
3982218792Snp	u32 bgmap = get_mps_bg_map(adap, idx);
3983248925Snp	u32 port_base_addr;
3984218792Snp
3985248925Snp	if (is_t4(adap))
3986248925Snp		port_base_addr = PORT_BASE(idx);
3987248925Snp	else
3988248925Snp		port_base_addr = T5_PORT_BASE(idx);
3989248925Snp
3990218792Snp	for (i = A_MPS_PORT_STAT_TX_PORT_BYTES_L;
3991248925Snp			i <= A_MPS_PORT_STAT_TX_PORT_PPP7_H; i += 8)
3992248925Snp		t4_write_reg(adap, port_base_addr + i, 0);
3993218792Snp	for (i = A_MPS_PORT_STAT_RX_PORT_BYTES_L;
3994248925Snp			i <= A_MPS_PORT_STAT_RX_PORT_LESS_64B_H; i += 8)
3995248925Snp		t4_write_reg(adap, port_base_addr + i, 0);
3996218792Snp	for (i = 0; i < 4; i++)
3997218792Snp		if (bgmap & (1 << i)) {
3998218792Snp			t4_write_reg(adap,
3999218792Snp				A_MPS_STAT_RX_BG_0_MAC_DROP_FRAME_L + i * 8, 0);
4000218792Snp			t4_write_reg(adap,
4001218792Snp				A_MPS_STAT_RX_BG_0_MAC_TRUNC_FRAME_L + i * 8, 0);
4002218792Snp		}
4003218792Snp}
4004218792Snp
4005218792Snp/**
4006218792Snp *	t4_get_lb_stats - collect loopback port statistics
4007218792Snp *	@adap: the adapter
4008218792Snp *	@idx: the loopback port index
4009218792Snp *	@p: the stats structure to fill
4010218792Snp *
4011218792Snp *	Return HW statistics for the given loopback port.
4012218792Snp */
4013218792Snpvoid t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p)
4014218792Snp{
4015218792Snp	u32 bgmap = get_mps_bg_map(adap, idx);
4016218792Snp
4017218792Snp#define GET_STAT(name) \
4018248925Snp	t4_read_reg64(adap, \
4019248925Snp	(is_t4(adap) ? \
4020248925Snp	PORT_REG(idx, A_MPS_PORT_STAT_LB_PORT_##name##_L) : \
4021248925Snp	T5_PORT_REG(idx, A_MPS_PORT_STAT_LB_PORT_##name##_L)))
4022218792Snp#define GET_STAT_COM(name) t4_read_reg64(adap, A_MPS_STAT_##name##_L)
4023218792Snp
4024218792Snp	p->octets           = GET_STAT(BYTES);
4025218792Snp	p->frames           = GET_STAT(FRAMES);
4026218792Snp	p->bcast_frames     = GET_STAT(BCAST);
4027218792Snp	p->mcast_frames     = GET_STAT(MCAST);
4028218792Snp	p->ucast_frames     = GET_STAT(UCAST);
4029218792Snp	p->error_frames     = GET_STAT(ERROR);
4030218792Snp
4031218792Snp	p->frames_64        = GET_STAT(64B);
4032218792Snp	p->frames_65_127    = GET_STAT(65B_127B);
4033218792Snp	p->frames_128_255   = GET_STAT(128B_255B);
4034218792Snp	p->frames_256_511   = GET_STAT(256B_511B);
4035218792Snp	p->frames_512_1023  = GET_STAT(512B_1023B);
4036218792Snp	p->frames_1024_1518 = GET_STAT(1024B_1518B);
4037218792Snp	p->frames_1519_max  = GET_STAT(1519B_MAX);
4038248925Snp	p->drop             = GET_STAT(DROP_FRAMES);
4039218792Snp
4040218792Snp	p->ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_DROP_FRAME) : 0;
4041218792Snp	p->ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_DROP_FRAME) : 0;
4042218792Snp	p->ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_DROP_FRAME) : 0;
4043218792Snp	p->ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_DROP_FRAME) : 0;
4044218792Snp	p->trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_TRUNC_FRAME) : 0;
4045218792Snp	p->trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_TRUNC_FRAME) : 0;
4046218792Snp	p->trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_TRUNC_FRAME) : 0;
4047218792Snp	p->trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_TRUNC_FRAME) : 0;
4048218792Snp
4049218792Snp#undef GET_STAT
4050218792Snp#undef GET_STAT_COM
4051218792Snp}
4052218792Snp
4053218792Snp/**
4054218792Snp *	t4_wol_magic_enable - enable/disable magic packet WoL
4055218792Snp *	@adap: the adapter
4056218792Snp *	@port: the physical port index
4057218792Snp *	@addr: MAC address expected in magic packets, %NULL to disable
4058218792Snp *
4059218792Snp *	Enables/disables magic packet wake-on-LAN for the selected port.
4060218792Snp */
4061218792Snpvoid t4_wol_magic_enable(struct adapter *adap, unsigned int port,
4062218792Snp			 const u8 *addr)
4063218792Snp{
4064248925Snp	u32 mag_id_reg_l, mag_id_reg_h, port_cfg_reg;
4065248925Snp
4066248925Snp	if (is_t4(adap)) {
4067248925Snp		mag_id_reg_l = PORT_REG(port, A_XGMAC_PORT_MAGIC_MACID_LO);
4068248925Snp		mag_id_reg_h = PORT_REG(port, A_XGMAC_PORT_MAGIC_MACID_HI);
4069248925Snp		port_cfg_reg = PORT_REG(port, A_XGMAC_PORT_CFG2);
4070248925Snp	} else {
4071248925Snp		mag_id_reg_l = T5_PORT_REG(port, A_MAC_PORT_MAGIC_MACID_LO);
4072248925Snp		mag_id_reg_h = T5_PORT_REG(port, A_MAC_PORT_MAGIC_MACID_HI);
4073248925Snp		port_cfg_reg = T5_PORT_REG(port, A_MAC_PORT_CFG2);
4074248925Snp	}
4075248925Snp
4076218792Snp	if (addr) {
4077248925Snp		t4_write_reg(adap, mag_id_reg_l,
4078218792Snp			     (addr[2] << 24) | (addr[3] << 16) |
4079218792Snp			     (addr[4] << 8) | addr[5]);
4080248925Snp		t4_write_reg(adap, mag_id_reg_h,
4081218792Snp			     (addr[0] << 8) | addr[1]);
4082218792Snp	}
4083248925Snp	t4_set_reg_field(adap, port_cfg_reg, F_MAGICEN,
4084218792Snp			 V_MAGICEN(addr != NULL));
4085218792Snp}
4086218792Snp
4087218792Snp/**
4088218792Snp *	t4_wol_pat_enable - enable/disable pattern-based WoL
4089218792Snp *	@adap: the adapter
4090218792Snp *	@port: the physical port index
4091218792Snp *	@map: bitmap of which HW pattern filters to set
4092218792Snp *	@mask0: byte mask for bytes 0-63 of a packet
4093218792Snp *	@mask1: byte mask for bytes 64-127 of a packet
4094218792Snp *	@crc: Ethernet CRC for selected bytes
4095218792Snp *	@enable: enable/disable switch
4096218792Snp *
4097218792Snp *	Sets the pattern filters indicated in @map to mask out the bytes
4098218792Snp *	specified in @mask0/@mask1 in received packets and compare the CRC of
4099218792Snp *	the resulting packet against @crc.  If @enable is %true pattern-based
4100218792Snp *	WoL is enabled, otherwise disabled.
4101218792Snp */
4102218792Snpint t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
4103218792Snp		      u64 mask0, u64 mask1, unsigned int crc, bool enable)
4104218792Snp{
4105218792Snp	int i;
4106248925Snp	u32 port_cfg_reg;
4107218792Snp
4108248925Snp	if (is_t4(adap))
4109248925Snp		port_cfg_reg = PORT_REG(port, A_XGMAC_PORT_CFG2);
4110248925Snp	else
4111248925Snp		port_cfg_reg = T5_PORT_REG(port, A_MAC_PORT_CFG2);
4112248925Snp
4113218792Snp	if (!enable) {
4114248925Snp		t4_set_reg_field(adap, port_cfg_reg, F_PATEN, 0);
4115218792Snp		return 0;
4116218792Snp	}
4117218792Snp	if (map > 0xff)
4118218792Snp		return -EINVAL;
4119218792Snp
4120248925Snp#define EPIO_REG(name) \
4121248925Snp	(is_t4(adap) ? PORT_REG(port, A_XGMAC_PORT_EPIO_##name) : \
4122248925Snp	T5_PORT_REG(port, A_MAC_PORT_EPIO_##name))
4123218792Snp
4124218792Snp	t4_write_reg(adap, EPIO_REG(DATA1), mask0 >> 32);
4125218792Snp	t4_write_reg(adap, EPIO_REG(DATA2), mask1);
4126218792Snp	t4_write_reg(adap, EPIO_REG(DATA3), mask1 >> 32);
4127218792Snp
4128218792Snp	for (i = 0; i < NWOL_PAT; i++, map >>= 1) {
4129218792Snp		if (!(map & 1))
4130218792Snp			continue;
4131218792Snp
4132218792Snp		/* write byte masks */
4133218792Snp		t4_write_reg(adap, EPIO_REG(DATA0), mask0);
4134218792Snp		t4_write_reg(adap, EPIO_REG(OP), V_ADDRESS(i) | F_EPIOWR);
4135218792Snp		t4_read_reg(adap, EPIO_REG(OP));                /* flush */
4136218792Snp		if (t4_read_reg(adap, EPIO_REG(OP)) & F_BUSY)
4137218792Snp			return -ETIMEDOUT;
4138218792Snp
4139218792Snp		/* write CRC */
4140218792Snp		t4_write_reg(adap, EPIO_REG(DATA0), crc);
4141218792Snp		t4_write_reg(adap, EPIO_REG(OP), V_ADDRESS(i + 32) | F_EPIOWR);
4142218792Snp		t4_read_reg(adap, EPIO_REG(OP));                /* flush */
4143218792Snp		if (t4_read_reg(adap, EPIO_REG(OP)) & F_BUSY)
4144218792Snp			return -ETIMEDOUT;
4145218792Snp	}
4146218792Snp#undef EPIO_REG
4147218792Snp
4148248925Snp	t4_set_reg_field(adap, port_cfg_reg, 0, F_PATEN);
4149218792Snp	return 0;
4150218792Snp}
4151218792Snp
4152218792Snp/**
4153218792Snp *	t4_mk_filtdelwr - create a delete filter WR
4154218792Snp *	@ftid: the filter ID
4155218792Snp *	@wr: the filter work request to populate
4156218792Snp *	@qid: ingress queue to receive the delete notification
4157218792Snp *
4158218792Snp *	Creates a filter work request to delete the supplied filter.  If @qid is
4159218792Snp *	negative the delete notification is suppressed.
4160218792Snp */
4161218792Snpvoid t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid)
4162218792Snp{
4163218792Snp	memset(wr, 0, sizeof(*wr));
4164218792Snp	wr->op_pkd = htonl(V_FW_WR_OP(FW_FILTER_WR));
4165218792Snp	wr->len16_pkd = htonl(V_FW_WR_LEN16(sizeof(*wr) / 16));
4166218792Snp	wr->tid_to_iq = htonl(V_FW_FILTER_WR_TID(ftid) |
4167218792Snp			      V_FW_FILTER_WR_NOREPLY(qid < 0));
4168218792Snp	wr->del_filter_to_l2tix = htonl(F_FW_FILTER_WR_DEL_FILTER);
4169218792Snp	if (qid >= 0)
4170218792Snp		wr->rx_chan_rx_rpl_iq = htons(V_FW_FILTER_WR_RX_RPL_IQ(qid));
4171218792Snp}
4172218792Snp
4173218792Snp#define INIT_CMD(var, cmd, rd_wr) do { \
4174218792Snp	(var).op_to_write = htonl(V_FW_CMD_OP(FW_##cmd##_CMD) | \
4175218792Snp				  F_FW_CMD_REQUEST | F_FW_CMD_##rd_wr); \
4176218792Snp	(var).retval_len16 = htonl(FW_LEN16(var)); \
4177218792Snp} while (0)
4178218792Snp
4179237436Snpint t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox, u32 addr, u32 val)
4180237436Snp{
4181237436Snp	struct fw_ldst_cmd c;
4182237436Snp
4183237436Snp	memset(&c, 0, sizeof(c));
4184237436Snp	c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
4185237436Snp		F_FW_CMD_WRITE | V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FIRMWARE));
4186237436Snp	c.cycles_to_len16 = htonl(FW_LEN16(c));
4187237436Snp	c.u.addrval.addr = htonl(addr);
4188237436Snp	c.u.addrval.val = htonl(val);
4189237436Snp
4190237436Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4191237436Snp}
4192237436Snp
4193218792Snp/**
4194218792Snp *	t4_mdio_rd - read a PHY register through MDIO
4195218792Snp *	@adap: the adapter
4196218792Snp *	@mbox: mailbox to use for the FW command
4197218792Snp *	@phy_addr: the PHY address
4198218792Snp *	@mmd: the PHY MMD to access (0 for clause 22 PHYs)
4199218792Snp *	@reg: the register to read
4200218792Snp *	@valp: where to store the value
4201218792Snp *
4202218792Snp *	Issues a FW command through the given mailbox to read a PHY register.
4203218792Snp */
4204218792Snpint t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
4205218792Snp	       unsigned int mmd, unsigned int reg, unsigned int *valp)
4206218792Snp{
4207218792Snp	int ret;
4208218792Snp	struct fw_ldst_cmd c;
4209218792Snp
4210218792Snp	memset(&c, 0, sizeof(c));
4211218792Snp	c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
4212218792Snp		F_FW_CMD_READ | V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO));
4213218792Snp	c.cycles_to_len16 = htonl(FW_LEN16(c));
4214218792Snp	c.u.mdio.paddr_mmd = htons(V_FW_LDST_CMD_PADDR(phy_addr) |
4215218792Snp				   V_FW_LDST_CMD_MMD(mmd));
4216218792Snp	c.u.mdio.raddr = htons(reg);
4217218792Snp
4218218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4219218792Snp	if (ret == 0)
4220218792Snp		*valp = ntohs(c.u.mdio.rval);
4221218792Snp	return ret;
4222218792Snp}
4223218792Snp
4224218792Snp/**
4225218792Snp *	t4_mdio_wr - write a PHY register through MDIO
4226218792Snp *	@adap: the adapter
4227218792Snp *	@mbox: mailbox to use for the FW command
4228218792Snp *	@phy_addr: the PHY address
4229218792Snp *	@mmd: the PHY MMD to access (0 for clause 22 PHYs)
4230218792Snp *	@reg: the register to write
4231218792Snp *	@valp: value to write
4232218792Snp *
4233218792Snp *	Issues a FW command through the given mailbox to write a PHY register.
4234218792Snp */
4235218792Snpint t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
4236218792Snp	       unsigned int mmd, unsigned int reg, unsigned int val)
4237218792Snp{
4238218792Snp	struct fw_ldst_cmd c;
4239218792Snp
4240218792Snp	memset(&c, 0, sizeof(c));
4241218792Snp	c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
4242218792Snp		F_FW_CMD_WRITE | V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO));
4243218792Snp	c.cycles_to_len16 = htonl(FW_LEN16(c));
4244218792Snp	c.u.mdio.paddr_mmd = htons(V_FW_LDST_CMD_PADDR(phy_addr) |
4245218792Snp				   V_FW_LDST_CMD_MMD(mmd));
4246218792Snp	c.u.mdio.raddr = htons(reg);
4247218792Snp	c.u.mdio.rval = htons(val);
4248218792Snp
4249218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4250218792Snp}
4251218792Snp
4252218792Snp/**
4253269082Snp *	t4_i2c_rd - read I2C data from adapter
4254269082Snp *	@adap: the adapter
4255269082Snp *	@port: Port number if per-port device; <0 if not
4256269082Snp *	@devid: per-port device ID or absolute device ID
4257269082Snp *	@offset: byte offset into device I2C space
4258269082Snp *	@len: byte length of I2C space data
4259269082Snp *	@buf: buffer in which to return I2C data
4260269082Snp *
4261269082Snp *	Reads the I2C data from the indicated device and location.
4262269082Snp */
4263269082Snpint t4_i2c_rd(struct adapter *adap, unsigned int mbox,
4264269082Snp	      int port, unsigned int devid,
4265269082Snp	      unsigned int offset, unsigned int len,
4266269082Snp	      u8 *buf)
4267269082Snp{
4268269082Snp	struct fw_ldst_cmd ldst;
4269269082Snp	int ret;
4270269082Snp
4271269082Snp	if (port >= 4 ||
4272269082Snp	    devid >= 256 ||
4273269082Snp	    offset >= 256 ||
4274269082Snp	    len > sizeof ldst.u.i2c.data)
4275269082Snp		return -EINVAL;
4276269082Snp
4277269082Snp	memset(&ldst, 0, sizeof ldst);
4278269082Snp	ldst.op_to_addrspace =
4279269082Snp		cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) |
4280269082Snp			    F_FW_CMD_REQUEST |
4281269082Snp			    F_FW_CMD_READ |
4282269082Snp			    V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_I2C));
4283269082Snp	ldst.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst));
4284269082Snp	ldst.u.i2c.pid = (port < 0 ? 0xff : port);
4285269082Snp	ldst.u.i2c.did = devid;
4286269082Snp	ldst.u.i2c.boffset = offset;
4287269082Snp	ldst.u.i2c.blen = len;
4288269082Snp	ret = t4_wr_mbox(adap, mbox, &ldst, sizeof ldst, &ldst);
4289269082Snp	if (!ret)
4290269082Snp		memcpy(buf, ldst.u.i2c.data, len);
4291269082Snp	return ret;
4292269082Snp}
4293269082Snp
4294269082Snp/**
4295269082Snp *	t4_i2c_wr - write I2C data to adapter
4296269082Snp *	@adap: the adapter
4297269082Snp *	@port: Port number if per-port device; <0 if not
4298269082Snp *	@devid: per-port device ID or absolute device ID
4299269082Snp *	@offset: byte offset into device I2C space
4300269082Snp *	@len: byte length of I2C space data
4301269082Snp *	@buf: buffer containing new I2C data
4302269082Snp *
4303269082Snp *	Write the I2C data to the indicated device and location.
4304269082Snp */
4305269082Snpint t4_i2c_wr(struct adapter *adap, unsigned int mbox,
4306269082Snp	      int port, unsigned int devid,
4307269082Snp	      unsigned int offset, unsigned int len,
4308269082Snp	      u8 *buf)
4309269082Snp{
4310269082Snp	struct fw_ldst_cmd ldst;
4311269082Snp
4312269082Snp	if (port >= 4 ||
4313269082Snp	    devid >= 256 ||
4314269082Snp	    offset >= 256 ||
4315269082Snp	    len > sizeof ldst.u.i2c.data)
4316269082Snp		return -EINVAL;
4317269082Snp
4318269082Snp	memset(&ldst, 0, sizeof ldst);
4319269082Snp	ldst.op_to_addrspace =
4320269082Snp		cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) |
4321269082Snp			    F_FW_CMD_REQUEST |
4322269082Snp			    F_FW_CMD_WRITE |
4323269082Snp			    V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_I2C));
4324269082Snp	ldst.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst));
4325269082Snp	ldst.u.i2c.pid = (port < 0 ? 0xff : port);
4326269082Snp	ldst.u.i2c.did = devid;
4327269082Snp	ldst.u.i2c.boffset = offset;
4328269082Snp	ldst.u.i2c.blen = len;
4329269082Snp	memcpy(ldst.u.i2c.data, buf, len);
4330269082Snp	return t4_wr_mbox(adap, mbox, &ldst, sizeof ldst, &ldst);
4331269082Snp}
4332269082Snp
4333269082Snp/**
4334237436Snp *	t4_sge_ctxt_flush - flush the SGE context cache
4335237436Snp *	@adap: the adapter
4336237436Snp *	@mbox: mailbox to use for the FW command
4337237436Snp *
4338237436Snp *	Issues a FW command through the given mailbox to flush the
4339237436Snp *	SGE context cache.
4340237436Snp */
4341237436Snpint t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox)
4342237436Snp{
4343237436Snp	int ret;
4344237436Snp	struct fw_ldst_cmd c;
4345237436Snp
4346237436Snp	memset(&c, 0, sizeof(c));
4347237436Snp	c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
4348237436Snp			F_FW_CMD_READ |
4349237436Snp			V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_SGE_EGRC));
4350237436Snp	c.cycles_to_len16 = htonl(FW_LEN16(c));
4351237436Snp	c.u.idctxt.msg_ctxtflush = htonl(F_FW_LDST_CMD_CTXTFLUSH);
4352237436Snp
4353237436Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4354237436Snp	return ret;
4355237436Snp}
4356237436Snp
4357237436Snp/**
4358218792Snp *	t4_sge_ctxt_rd - read an SGE context through FW
4359218792Snp *	@adap: the adapter
4360218792Snp *	@mbox: mailbox to use for the FW command
4361218792Snp *	@cid: the context id
4362218792Snp *	@ctype: the context type
4363218792Snp *	@data: where to store the context data
4364218792Snp *
4365218792Snp *	Issues a FW command through the given mailbox to read an SGE context.
4366218792Snp */
4367218792Snpint t4_sge_ctxt_rd(struct adapter *adap, unsigned int mbox, unsigned int cid,
4368218792Snp		   enum ctxt_type ctype, u32 *data)
4369218792Snp{
4370218792Snp	int ret;
4371218792Snp	struct fw_ldst_cmd c;
4372218792Snp
4373218792Snp	if (ctype == CTXT_EGRESS)
4374218792Snp		ret = FW_LDST_ADDRSPC_SGE_EGRC;
4375218792Snp	else if (ctype == CTXT_INGRESS)
4376218792Snp		ret = FW_LDST_ADDRSPC_SGE_INGC;
4377218792Snp	else if (ctype == CTXT_FLM)
4378218792Snp		ret = FW_LDST_ADDRSPC_SGE_FLMC;
4379218792Snp	else
4380218792Snp		ret = FW_LDST_ADDRSPC_SGE_CONMC;
4381218792Snp
4382218792Snp	memset(&c, 0, sizeof(c));
4383218792Snp	c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
4384218792Snp				  F_FW_CMD_READ | V_FW_LDST_CMD_ADDRSPACE(ret));
4385218792Snp	c.cycles_to_len16 = htonl(FW_LEN16(c));
4386218792Snp	c.u.idctxt.physid = htonl(cid);
4387218792Snp
4388218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4389218792Snp	if (ret == 0) {
4390218792Snp		data[0] = ntohl(c.u.idctxt.ctxt_data0);
4391218792Snp		data[1] = ntohl(c.u.idctxt.ctxt_data1);
4392218792Snp		data[2] = ntohl(c.u.idctxt.ctxt_data2);
4393218792Snp		data[3] = ntohl(c.u.idctxt.ctxt_data3);
4394218792Snp		data[4] = ntohl(c.u.idctxt.ctxt_data4);
4395218792Snp		data[5] = ntohl(c.u.idctxt.ctxt_data5);
4396218792Snp	}
4397218792Snp	return ret;
4398218792Snp}
4399218792Snp
4400218792Snp/**
4401218792Snp *	t4_sge_ctxt_rd_bd - read an SGE context bypassing FW
4402218792Snp *	@adap: the adapter
4403218792Snp *	@cid: the context id
4404218792Snp *	@ctype: the context type
4405218792Snp *	@data: where to store the context data
4406218792Snp *
4407218792Snp *	Reads an SGE context directly, bypassing FW.  This is only for
4408218792Snp *	debugging when FW is unavailable.
4409218792Snp */
4410218792Snpint t4_sge_ctxt_rd_bd(struct adapter *adap, unsigned int cid, enum ctxt_type ctype,
4411218792Snp		      u32 *data)
4412218792Snp{
4413218792Snp	int i, ret;
4414218792Snp
4415218792Snp	t4_write_reg(adap, A_SGE_CTXT_CMD, V_CTXTQID(cid) | V_CTXTTYPE(ctype));
4416218792Snp	ret = t4_wait_op_done(adap, A_SGE_CTXT_CMD, F_BUSY, 0, 3, 1);
4417218792Snp	if (!ret)
4418218792Snp		for (i = A_SGE_CTXT_DATA0; i <= A_SGE_CTXT_DATA5; i += 4)
4419218792Snp			*data++ = t4_read_reg(adap, i);
4420218792Snp	return ret;
4421218792Snp}
4422218792Snp
4423218792Snp/**
4424218792Snp *	t4_fw_hello - establish communication with FW
4425218792Snp *	@adap: the adapter
4426218792Snp *	@mbox: mailbox to use for the FW command
4427218792Snp *	@evt_mbox: mailbox to receive async FW events
4428218792Snp *	@master: specifies the caller's willingness to be the device master
4429237436Snp *	@state: returns the current device state (if non-NULL)
4430218792Snp *
4431237436Snp *	Issues a command to establish communication with FW.  Returns either
4432237436Snp *	an error (negative integer) or the mailbox of the Master PF.
4433218792Snp */
4434218792Snpint t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox,
4435218792Snp		enum dev_master master, enum dev_state *state)
4436218792Snp{
4437218792Snp	int ret;
4438218792Snp	struct fw_hello_cmd c;
4439228561Snp	u32 v;
4440228561Snp	unsigned int master_mbox;
4441228561Snp	int retries = FW_CMD_HELLO_RETRIES;
4442218792Snp
4443228561Snpretry:
4444218792Snp	memset(&c, 0, sizeof(c));
4445218792Snp	INIT_CMD(c, HELLO, WRITE);
4446228561Snp	c.err_to_clearinit = htonl(
4447218792Snp		V_FW_HELLO_CMD_MASTERDIS(master == MASTER_CANT) |
4448218792Snp		V_FW_HELLO_CMD_MASTERFORCE(master == MASTER_MUST) |
4449218792Snp		V_FW_HELLO_CMD_MBMASTER(master == MASTER_MUST ? mbox :
4450218792Snp			M_FW_HELLO_CMD_MBMASTER) |
4451228561Snp		V_FW_HELLO_CMD_MBASYNCNOT(evt_mbox) |
4452228561Snp		V_FW_HELLO_CMD_STAGE(FW_HELLO_CMD_STAGE_OS) |
4453228561Snp		F_FW_HELLO_CMD_CLEARINIT);
4454218792Snp
4455228561Snp	/*
4456228561Snp	 * Issue the HELLO command to the firmware.  If it's not successful
4457228561Snp	 * but indicates that we got a "busy" or "timeout" condition, retry
4458247355Snp	 * the HELLO until we exhaust our retry limit.  If we do exceed our
4459247355Snp	 * retry limit, check to see if the firmware left us any error
4460247355Snp	 * information and report that if so ...
4461228561Snp	 */
4462218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4463228561Snp	if (ret != FW_SUCCESS) {
4464228561Snp		if ((ret == -EBUSY || ret == -ETIMEDOUT) && retries-- > 0)
4465228561Snp			goto retry;
4466247355Snp		if (t4_read_reg(adap, A_PCIE_FW) & F_PCIE_FW_ERR)
4467247355Snp			t4_report_fw_error(adap);
4468228561Snp		return ret;
4469228561Snp	}
4470228561Snp
4471228561Snp	v = ntohl(c.err_to_clearinit);
4472228561Snp	master_mbox = G_FW_HELLO_CMD_MBMASTER(v);
4473228561Snp	if (state) {
4474228561Snp		if (v & F_FW_HELLO_CMD_ERR)
4475228561Snp			*state = DEV_STATE_ERR;
4476228561Snp		else if (v & F_FW_HELLO_CMD_INIT)
4477218792Snp			*state = DEV_STATE_INIT;
4478218792Snp		else
4479218792Snp			*state = DEV_STATE_UNINIT;
4480218792Snp	}
4481228561Snp
4482228561Snp	/*
4483228561Snp	 * If we're not the Master PF then we need to wait around for the
4484228561Snp	 * Master PF Driver to finish setting up the adapter.
4485228561Snp	 *
4486228561Snp	 * Note that we also do this wait if we're a non-Master-capable PF and
4487228561Snp	 * there is no current Master PF; a Master PF may show up momentarily
4488228561Snp	 * and we wouldn't want to fail pointlessly.  (This can happen when an
4489228561Snp	 * OS loads lots of different drivers rapidly at the same time).  In
4490228561Snp	 * this case, the Master PF returned by the firmware will be
4491228561Snp	 * M_PCIE_FW_MASTER so the test below will work ...
4492228561Snp	 */
4493228561Snp	if ((v & (F_FW_HELLO_CMD_ERR|F_FW_HELLO_CMD_INIT)) == 0 &&
4494228561Snp	    master_mbox != mbox) {
4495228561Snp		int waiting = FW_CMD_HELLO_TIMEOUT;
4496228561Snp
4497228561Snp		/*
4498228561Snp		 * Wait for the firmware to either indicate an error or
4499228561Snp		 * initialized state.  If we see either of these we bail out
4500228561Snp		 * and report the issue to the caller.  If we exhaust the
4501228561Snp		 * "hello timeout" and we haven't exhausted our retries, try
4502228561Snp		 * again.  Otherwise bail with a timeout error.
4503228561Snp		 */
4504228561Snp		for (;;) {
4505228561Snp			u32 pcie_fw;
4506228561Snp
4507228561Snp			msleep(50);
4508228561Snp			waiting -= 50;
4509228561Snp
4510228561Snp			/*
4511228561Snp			 * If neither Error nor Initialialized are indicated
4512228561Snp			 * by the firmware keep waiting till we exhaust our
4513228561Snp			 * timeout ... and then retry if we haven't exhausted
4514228561Snp			 * our retries ...
4515228561Snp			 */
4516228561Snp			pcie_fw = t4_read_reg(adap, A_PCIE_FW);
4517228561Snp			if (!(pcie_fw & (F_PCIE_FW_ERR|F_PCIE_FW_INIT))) {
4518228561Snp				if (waiting <= 0) {
4519228561Snp					if (retries-- > 0)
4520228561Snp						goto retry;
4521228561Snp
4522228561Snp					return -ETIMEDOUT;
4523228561Snp				}
4524228561Snp				continue;
4525228561Snp			}
4526228561Snp
4527228561Snp			/*
4528228561Snp			 * We either have an Error or Initialized condition
4529228561Snp			 * report errors preferentially.
4530228561Snp			 */
4531228561Snp			if (state) {
4532228561Snp				if (pcie_fw & F_PCIE_FW_ERR)
4533228561Snp					*state = DEV_STATE_ERR;
4534228561Snp				else if (pcie_fw & F_PCIE_FW_INIT)
4535228561Snp					*state = DEV_STATE_INIT;
4536228561Snp			}
4537228561Snp
4538228561Snp			/*
4539228561Snp			 * If we arrived before a Master PF was selected and
4540228561Snp			 * there's not a valid Master PF, grab its identity
4541228561Snp			 * for our caller.
4542228561Snp			 */
4543228561Snp			if (master_mbox == M_PCIE_FW_MASTER &&
4544228561Snp			    (pcie_fw & F_PCIE_FW_MASTER_VLD))
4545228561Snp				master_mbox = G_PCIE_FW_MASTER(pcie_fw);
4546228561Snp			break;
4547228561Snp		}
4548228561Snp	}
4549228561Snp
4550228561Snp	return master_mbox;
4551218792Snp}
4552218792Snp
4553218792Snp/**
4554218792Snp *	t4_fw_bye - end communication with FW
4555218792Snp *	@adap: the adapter
4556218792Snp *	@mbox: mailbox to use for the FW command
4557218792Snp *
4558218792Snp *	Issues a command to terminate communication with FW.
4559218792Snp */
4560218792Snpint t4_fw_bye(struct adapter *adap, unsigned int mbox)
4561218792Snp{
4562218792Snp	struct fw_bye_cmd c;
4563218792Snp
4564218792Snp	memset(&c, 0, sizeof(c));
4565218792Snp	INIT_CMD(c, BYE, WRITE);
4566218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4567218792Snp}
4568218792Snp
4569218792Snp/**
4570228561Snp *	t4_fw_reset - issue a reset to FW
4571218792Snp *	@adap: the adapter
4572218792Snp *	@mbox: mailbox to use for the FW command
4573228561Snp *	@reset: specifies the type of reset to perform
4574218792Snp *
4575228561Snp *	Issues a reset command of the specified type to FW.
4576218792Snp */
4577228561Snpint t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset)
4578218792Snp{
4579228561Snp	struct fw_reset_cmd c;
4580218792Snp
4581218792Snp	memset(&c, 0, sizeof(c));
4582228561Snp	INIT_CMD(c, RESET, WRITE);
4583228561Snp	c.val = htonl(reset);
4584218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4585218792Snp}
4586218792Snp
4587218792Snp/**
4588237436Snp *	t4_fw_halt - issue a reset/halt to FW and put uP into RESET
4589237436Snp *	@adap: the adapter
4590237436Snp *	@mbox: mailbox to use for the FW RESET command (if desired)
4591237436Snp *	@force: force uP into RESET even if FW RESET command fails
4592237436Snp *
4593237436Snp *	Issues a RESET command to firmware (if desired) with a HALT indication
4594237436Snp *	and then puts the microprocessor into RESET state.  The RESET command
4595237436Snp *	will only be issued if a legitimate mailbox is provided (mbox <=
4596237436Snp *	M_PCIE_FW_MASTER).
4597237436Snp *
4598237436Snp *	This is generally used in order for the host to safely manipulate the
4599237436Snp *	adapter without fear of conflicting with whatever the firmware might
4600237436Snp *	be doing.  The only way out of this state is to RESTART the firmware
4601237436Snp *	...
4602237436Snp */
4603237436Snpint t4_fw_halt(struct adapter *adap, unsigned int mbox, int force)
4604237436Snp{
4605237436Snp	int ret = 0;
4606237436Snp
4607237436Snp	/*
4608237436Snp	 * If a legitimate mailbox is provided, issue a RESET command
4609237436Snp	 * with a HALT indication.
4610237436Snp	 */
4611237436Snp	if (mbox <= M_PCIE_FW_MASTER) {
4612237436Snp		struct fw_reset_cmd c;
4613237436Snp
4614237436Snp		memset(&c, 0, sizeof(c));
4615237436Snp		INIT_CMD(c, RESET, WRITE);
4616237436Snp		c.val = htonl(F_PIORST | F_PIORSTMODE);
4617237436Snp		c.halt_pkd = htonl(F_FW_RESET_CMD_HALT);
4618237436Snp		ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4619237436Snp	}
4620237436Snp
4621237436Snp	/*
4622237436Snp	 * Normally we won't complete the operation if the firmware RESET
4623237436Snp	 * command fails but if our caller insists we'll go ahead and put the
4624237436Snp	 * uP into RESET.  This can be useful if the firmware is hung or even
4625237436Snp	 * missing ...  We'll have to take the risk of putting the uP into
4626237436Snp	 * RESET without the cooperation of firmware in that case.
4627237436Snp	 *
4628237436Snp	 * We also force the firmware's HALT flag to be on in case we bypassed
4629237436Snp	 * the firmware RESET command above or we're dealing with old firmware
4630237436Snp	 * which doesn't have the HALT capability.  This will serve as a flag
4631237436Snp	 * for the incoming firmware to know that it's coming out of a HALT
4632237436Snp	 * rather than a RESET ... if it's new enough to understand that ...
4633237436Snp	 */
4634237436Snp	if (ret == 0 || force) {
4635237436Snp		t4_set_reg_field(adap, A_CIM_BOOT_CFG, F_UPCRST, F_UPCRST);
4636237436Snp		t4_set_reg_field(adap, A_PCIE_FW, F_PCIE_FW_HALT, F_PCIE_FW_HALT);
4637237436Snp	}
4638237436Snp
4639237436Snp	/*
4640237436Snp	 * And we always return the result of the firmware RESET command
4641237436Snp	 * even when we force the uP into RESET ...
4642237436Snp	 */
4643237436Snp	return ret;
4644237436Snp}
4645237436Snp
4646237436Snp/**
4647237436Snp *	t4_fw_restart - restart the firmware by taking the uP out of RESET
4648237436Snp *	@adap: the adapter
4649237436Snp *	@reset: if we want to do a RESET to restart things
4650237436Snp *
4651237436Snp *	Restart firmware previously halted by t4_fw_halt().  On successful
4652237436Snp *	return the previous PF Master remains as the new PF Master and there
4653237436Snp *	is no need to issue a new HELLO command, etc.
4654237436Snp *
4655237436Snp *	We do this in two ways:
4656237436Snp *
4657237436Snp *	 1. If we're dealing with newer firmware we'll simply want to take
4658237436Snp *	    the chip's microprocessor out of RESET.  This will cause the
4659237436Snp *	    firmware to start up from its start vector.  And then we'll loop
4660237436Snp *	    until the firmware indicates it's started again (PCIE_FW.HALT
4661237436Snp *	    reset to 0) or we timeout.
4662237436Snp *
4663237436Snp *	 2. If we're dealing with older firmware then we'll need to RESET
4664237436Snp *	    the chip since older firmware won't recognize the PCIE_FW.HALT
4665237436Snp *	    flag and automatically RESET itself on startup.
4666237436Snp */
4667237436Snpint t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset)
4668237436Snp{
4669237436Snp	if (reset) {
4670237436Snp		/*
4671237436Snp		 * Since we're directing the RESET instead of the firmware
4672237436Snp		 * doing it automatically, we need to clear the PCIE_FW.HALT
4673237436Snp		 * bit.
4674237436Snp		 */
4675237436Snp		t4_set_reg_field(adap, A_PCIE_FW, F_PCIE_FW_HALT, 0);
4676237436Snp
4677237436Snp		/*
4678237436Snp		 * If we've been given a valid mailbox, first try to get the
4679237436Snp		 * firmware to do the RESET.  If that works, great and we can
4680237436Snp		 * return success.  Otherwise, if we haven't been given a
4681237436Snp		 * valid mailbox or the RESET command failed, fall back to
4682237436Snp		 * hitting the chip with a hammer.
4683237436Snp		 */
4684237436Snp		if (mbox <= M_PCIE_FW_MASTER) {
4685237436Snp			t4_set_reg_field(adap, A_CIM_BOOT_CFG, F_UPCRST, 0);
4686237436Snp			msleep(100);
4687237436Snp			if (t4_fw_reset(adap, mbox,
4688237436Snp					F_PIORST | F_PIORSTMODE) == 0)
4689237436Snp				return 0;
4690237436Snp		}
4691237436Snp
4692237436Snp		t4_write_reg(adap, A_PL_RST, F_PIORST | F_PIORSTMODE);
4693237436Snp		msleep(2000);
4694237436Snp	} else {
4695237436Snp		int ms;
4696237436Snp
4697237436Snp		t4_set_reg_field(adap, A_CIM_BOOT_CFG, F_UPCRST, 0);
4698237436Snp		for (ms = 0; ms < FW_CMD_MAX_TIMEOUT; ) {
4699237436Snp			if (!(t4_read_reg(adap, A_PCIE_FW) & F_PCIE_FW_HALT))
4700237436Snp				return FW_SUCCESS;
4701237436Snp			msleep(100);
4702237436Snp			ms += 100;
4703237436Snp		}
4704237436Snp		return -ETIMEDOUT;
4705237436Snp	}
4706237436Snp	return 0;
4707237436Snp}
4708237436Snp
4709237436Snp/**
4710237436Snp *	t4_fw_upgrade - perform all of the steps necessary to upgrade FW
4711237436Snp *	@adap: the adapter
4712237436Snp *	@mbox: mailbox to use for the FW RESET command (if desired)
4713237436Snp *	@fw_data: the firmware image to write
4714237436Snp *	@size: image size
4715237436Snp *	@force: force upgrade even if firmware doesn't cooperate
4716237436Snp *
4717237436Snp *	Perform all of the steps necessary for upgrading an adapter's
4718237436Snp *	firmware image.  Normally this requires the cooperation of the
4719237436Snp *	existing firmware in order to halt all existing activities
4720237436Snp *	but if an invalid mailbox token is passed in we skip that step
4721237436Snp *	(though we'll still put the adapter microprocessor into RESET in
4722237436Snp *	that case).
4723237436Snp *
4724237436Snp *	On successful return the new firmware will have been loaded and
4725237436Snp *	the adapter will have been fully RESET losing all previous setup
4726237436Snp *	state.  On unsuccessful return the adapter may be completely hosed ...
4727237436Snp *	positive errno indicates that the adapter is ~probably~ intact, a
4728237436Snp *	negative errno indicates that things are looking bad ...
4729237436Snp */
4730237436Snpint t4_fw_upgrade(struct adapter *adap, unsigned int mbox,
4731237436Snp		  const u8 *fw_data, unsigned int size, int force)
4732237436Snp{
4733237436Snp	const struct fw_hdr *fw_hdr = (const struct fw_hdr *)fw_data;
4734252661Snp	unsigned int bootstrap = ntohl(fw_hdr->magic) == FW_HDR_MAGIC_BOOTSTRAP;
4735237436Snp	int reset, ret;
4736237436Snp
4737252661Snp	if (!bootstrap) {
4738252661Snp		ret = t4_fw_halt(adap, mbox, force);
4739252661Snp		if (ret < 0 && !force)
4740252661Snp			return ret;
4741252661Snp	}
4742237436Snp
4743237436Snp	ret = t4_load_fw(adap, fw_data, size);
4744252661Snp	if (ret < 0 || bootstrap)
4745237436Snp		return ret;
4746237436Snp
4747237436Snp	/*
4748237436Snp	 * Older versions of the firmware don't understand the new
4749237436Snp	 * PCIE_FW.HALT flag and so won't know to perform a RESET when they
4750237436Snp	 * restart.  So for newly loaded older firmware we'll have to do the
4751237436Snp	 * RESET for it so it starts up on a clean slate.  We can tell if
4752237436Snp	 * the newly loaded firmware will handle this right by checking
4753237436Snp	 * its header flags to see if it advertises the capability.
4754237436Snp	 */
4755237436Snp	reset = ((ntohl(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0);
4756237436Snp	return t4_fw_restart(adap, mbox, reset);
4757237436Snp}
4758237436Snp
4759237436Snp/**
4760228561Snp *	t4_fw_initialize - ask FW to initialize the device
4761218792Snp *	@adap: the adapter
4762218792Snp *	@mbox: mailbox to use for the FW command
4763218792Snp *
4764228561Snp *	Issues a command to FW to partially initialize the device.  This
4765228561Snp *	performs initialization that generally doesn't depend on user input.
4766218792Snp */
4767228561Snpint t4_fw_initialize(struct adapter *adap, unsigned int mbox)
4768218792Snp{
4769228561Snp	struct fw_initialize_cmd c;
4770218792Snp
4771218792Snp	memset(&c, 0, sizeof(c));
4772228561Snp	INIT_CMD(c, INITIALIZE, WRITE);
4773218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4774218792Snp}
4775218792Snp
4776218792Snp/**
4777218792Snp *	t4_query_params - query FW or device parameters
4778218792Snp *	@adap: the adapter
4779218792Snp *	@mbox: mailbox to use for the FW command
4780218792Snp *	@pf: the PF
4781218792Snp *	@vf: the VF
4782218792Snp *	@nparams: the number of parameters
4783218792Snp *	@params: the parameter names
4784218792Snp *	@val: the parameter values
4785218792Snp *
4786218792Snp *	Reads the value of FW or device parameters.  Up to 7 parameters can be
4787218792Snp *	queried at once.
4788218792Snp */
4789218792Snpint t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
4790218792Snp		    unsigned int vf, unsigned int nparams, const u32 *params,
4791218792Snp		    u32 *val)
4792218792Snp{
4793218792Snp	int i, ret;
4794218792Snp	struct fw_params_cmd c;
4795218792Snp	__be32 *p = &c.param[0].mnem;
4796218792Snp
4797218792Snp	if (nparams > 7)
4798218792Snp		return -EINVAL;
4799218792Snp
4800218792Snp	memset(&c, 0, sizeof(c));
4801218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_PARAMS_CMD) | F_FW_CMD_REQUEST |
4802218792Snp			    F_FW_CMD_READ | V_FW_PARAMS_CMD_PFN(pf) |
4803218792Snp			    V_FW_PARAMS_CMD_VFN(vf));
4804218792Snp	c.retval_len16 = htonl(FW_LEN16(c));
4805218792Snp
4806250090Snp	for (i = 0; i < nparams; i++, p += 2, params++)
4807250090Snp		*p = htonl(*params);
4808218792Snp
4809218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4810218792Snp	if (ret == 0)
4811218792Snp		for (i = 0, p = &c.param[0].val; i < nparams; i++, p += 2)
4812218792Snp			*val++ = ntohl(*p);
4813218792Snp	return ret;
4814218792Snp}
4815218792Snp
4816218792Snp/**
4817218792Snp *	t4_set_params - sets FW or device parameters
4818218792Snp *	@adap: the adapter
4819218792Snp *	@mbox: mailbox to use for the FW command
4820218792Snp *	@pf: the PF
4821218792Snp *	@vf: the VF
4822218792Snp *	@nparams: the number of parameters
4823218792Snp *	@params: the parameter names
4824218792Snp *	@val: the parameter values
4825218792Snp *
4826218792Snp *	Sets the value of FW or device parameters.  Up to 7 parameters can be
4827218792Snp *	specified at once.
4828218792Snp */
4829218792Snpint t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
4830218792Snp		  unsigned int vf, unsigned int nparams, const u32 *params,
4831218792Snp		  const u32 *val)
4832218792Snp{
4833218792Snp	struct fw_params_cmd c;
4834218792Snp	__be32 *p = &c.param[0].mnem;
4835218792Snp
4836218792Snp	if (nparams > 7)
4837218792Snp		return -EINVAL;
4838218792Snp
4839218792Snp	memset(&c, 0, sizeof(c));
4840218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_PARAMS_CMD) | F_FW_CMD_REQUEST |
4841218792Snp			    F_FW_CMD_WRITE | V_FW_PARAMS_CMD_PFN(pf) |
4842218792Snp			    V_FW_PARAMS_CMD_VFN(vf));
4843218792Snp	c.retval_len16 = htonl(FW_LEN16(c));
4844218792Snp
4845218792Snp	while (nparams--) {
4846250090Snp		*p++ = htonl(*params);
4847250090Snp		params++;
4848250090Snp		*p++ = htonl(*val);
4849250090Snp		val++;
4850218792Snp	}
4851218792Snp
4852218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4853218792Snp}
4854218792Snp
4855218792Snp/**
4856218792Snp *	t4_cfg_pfvf - configure PF/VF resource limits
4857218792Snp *	@adap: the adapter
4858218792Snp *	@mbox: mailbox to use for the FW command
4859218792Snp *	@pf: the PF being configured
4860218792Snp *	@vf: the VF being configured
4861218792Snp *	@txq: the max number of egress queues
4862218792Snp *	@txq_eth_ctrl: the max number of egress Ethernet or control queues
4863218792Snp *	@rxqi: the max number of interrupt-capable ingress queues
4864218792Snp *	@rxq: the max number of interruptless ingress queues
4865218792Snp *	@tc: the PCI traffic class
4866218792Snp *	@vi: the max number of virtual interfaces
4867218792Snp *	@cmask: the channel access rights mask for the PF/VF
4868218792Snp *	@pmask: the port access rights mask for the PF/VF
4869218792Snp *	@nexact: the maximum number of exact MPS filters
4870218792Snp *	@rcaps: read capabilities
4871218792Snp *	@wxcaps: write/execute capabilities
4872218792Snp *
4873218792Snp *	Configures resource limits and capabilities for a physical or virtual
4874218792Snp *	function.
4875218792Snp */
4876218792Snpint t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf,
4877218792Snp		unsigned int vf, unsigned int txq, unsigned int txq_eth_ctrl,
4878218792Snp		unsigned int rxqi, unsigned int rxq, unsigned int tc,
4879218792Snp		unsigned int vi, unsigned int cmask, unsigned int pmask,
4880218792Snp		unsigned int nexact, unsigned int rcaps, unsigned int wxcaps)
4881218792Snp{
4882218792Snp	struct fw_pfvf_cmd c;
4883218792Snp
4884218792Snp	memset(&c, 0, sizeof(c));
4885218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_PFVF_CMD) | F_FW_CMD_REQUEST |
4886218792Snp			    F_FW_CMD_WRITE | V_FW_PFVF_CMD_PFN(pf) |
4887218792Snp			    V_FW_PFVF_CMD_VFN(vf));
4888218792Snp	c.retval_len16 = htonl(FW_LEN16(c));
4889218792Snp	c.niqflint_niq = htonl(V_FW_PFVF_CMD_NIQFLINT(rxqi) |
4890218792Snp			       V_FW_PFVF_CMD_NIQ(rxq));
4891218792Snp	c.type_to_neq = htonl(V_FW_PFVF_CMD_CMASK(cmask) |
4892218792Snp			      V_FW_PFVF_CMD_PMASK(pmask) |
4893218792Snp			      V_FW_PFVF_CMD_NEQ(txq));
4894218792Snp	c.tc_to_nexactf = htonl(V_FW_PFVF_CMD_TC(tc) | V_FW_PFVF_CMD_NVI(vi) |
4895218792Snp				V_FW_PFVF_CMD_NEXACTF(nexact));
4896218792Snp	c.r_caps_to_nethctrl = htonl(V_FW_PFVF_CMD_R_CAPS(rcaps) |
4897218792Snp				     V_FW_PFVF_CMD_WX_CAPS(wxcaps) |
4898218792Snp				     V_FW_PFVF_CMD_NETHCTRL(txq_eth_ctrl));
4899218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4900218792Snp}
4901218792Snp
4902218792Snp/**
4903237436Snp *	t4_alloc_vi_func - allocate a virtual interface
4904218792Snp *	@adap: the adapter
4905218792Snp *	@mbox: mailbox to use for the FW command
4906218792Snp *	@port: physical port associated with the VI
4907218792Snp *	@pf: the PF owning the VI
4908218792Snp *	@vf: the VF owning the VI
4909218792Snp *	@nmac: number of MAC addresses needed (1 to 5)
4910218792Snp *	@mac: the MAC addresses of the VI
4911218792Snp *	@rss_size: size of RSS table slice associated with this VI
4912237436Snp *	@portfunc: which Port Application Function MAC Address is desired
4913237436Snp *	@idstype: Intrusion Detection Type
4914218792Snp *
4915218792Snp *	Allocates a virtual interface for the given physical port.  If @mac is
4916218792Snp *	not %NULL it contains the MAC addresses of the VI as assigned by FW.
4917218792Snp *	@mac should be large enough to hold @nmac Ethernet addresses, they are
4918218792Snp *	stored consecutively so the space needed is @nmac * 6 bytes.
4919218792Snp *	Returns a negative error number or the non-negative VI id.
4920218792Snp */
4921237436Snpint t4_alloc_vi_func(struct adapter *adap, unsigned int mbox,
4922237436Snp		     unsigned int port, unsigned int pf, unsigned int vf,
4923270297Snp		     unsigned int nmac, u8 *mac, u16 *rss_size,
4924237436Snp		     unsigned int portfunc, unsigned int idstype)
4925218792Snp{
4926218792Snp	int ret;
4927218792Snp	struct fw_vi_cmd c;
4928218792Snp
4929218792Snp	memset(&c, 0, sizeof(c));
4930218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_VI_CMD) | F_FW_CMD_REQUEST |
4931218792Snp			    F_FW_CMD_WRITE | F_FW_CMD_EXEC |
4932218792Snp			    V_FW_VI_CMD_PFN(pf) | V_FW_VI_CMD_VFN(vf));
4933218792Snp	c.alloc_to_len16 = htonl(F_FW_VI_CMD_ALLOC | FW_LEN16(c));
4934237436Snp	c.type_to_viid = htons(V_FW_VI_CMD_TYPE(idstype) |
4935237436Snp			       V_FW_VI_CMD_FUNC(portfunc));
4936218792Snp	c.portid_pkd = V_FW_VI_CMD_PORTID(port);
4937218792Snp	c.nmac = nmac - 1;
4938218792Snp
4939218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4940218792Snp	if (ret)
4941218792Snp		return ret;
4942218792Snp
4943218792Snp	if (mac) {
4944218792Snp		memcpy(mac, c.mac, sizeof(c.mac));
4945218792Snp		switch (nmac) {
4946218792Snp		case 5:
4947218792Snp			memcpy(mac + 24, c.nmac3, sizeof(c.nmac3));
4948218792Snp		case 4:
4949218792Snp			memcpy(mac + 18, c.nmac2, sizeof(c.nmac2));
4950218792Snp		case 3:
4951218792Snp			memcpy(mac + 12, c.nmac1, sizeof(c.nmac1));
4952218792Snp		case 2:
4953218792Snp			memcpy(mac + 6,  c.nmac0, sizeof(c.nmac0));
4954218792Snp		}
4955218792Snp	}
4956218792Snp	if (rss_size)
4957247289Snp		*rss_size = G_FW_VI_CMD_RSSSIZE(ntohs(c.norss_rsssize));
4958237436Snp	return G_FW_VI_CMD_VIID(htons(c.type_to_viid));
4959218792Snp}
4960218792Snp
4961218792Snp/**
4962237436Snp *	t4_alloc_vi - allocate an [Ethernet Function] virtual interface
4963237436Snp *	@adap: the adapter
4964237436Snp *	@mbox: mailbox to use for the FW command
4965237436Snp *	@port: physical port associated with the VI
4966237436Snp *	@pf: the PF owning the VI
4967237436Snp *	@vf: the VF owning the VI
4968237436Snp *	@nmac: number of MAC addresses needed (1 to 5)
4969237436Snp *	@mac: the MAC addresses of the VI
4970237436Snp *	@rss_size: size of RSS table slice associated with this VI
4971237436Snp *
4972237436Snp *	backwards compatible and convieniance routine to allocate a Virtual
4973237436Snp *	Interface with a Ethernet Port Application Function and Intrustion
4974237436Snp *	Detection System disabled.
4975237436Snp */
4976237436Snpint t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port,
4977237436Snp		unsigned int pf, unsigned int vf, unsigned int nmac, u8 *mac,
4978270297Snp		u16 *rss_size)
4979237436Snp{
4980237436Snp	return t4_alloc_vi_func(adap, mbox, port, pf, vf, nmac, mac, rss_size,
4981237436Snp				FW_VI_FUNC_ETH, 0);
4982237436Snp}
4983237436Snp
4984237436Snp/**
4985218792Snp *	t4_free_vi - free a virtual interface
4986218792Snp *	@adap: the adapter
4987218792Snp *	@mbox: mailbox to use for the FW command
4988218792Snp *	@pf: the PF owning the VI
4989218792Snp *	@vf: the VF owning the VI
4990218792Snp *	@viid: virtual interface identifiler
4991218792Snp *
4992218792Snp *	Free a previously allocated virtual interface.
4993218792Snp */
4994218792Snpint t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf,
4995218792Snp	       unsigned int vf, unsigned int viid)
4996218792Snp{
4997218792Snp	struct fw_vi_cmd c;
4998218792Snp
4999218792Snp	memset(&c, 0, sizeof(c));
5000218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_VI_CMD) |
5001218792Snp			    F_FW_CMD_REQUEST |
5002218792Snp			    F_FW_CMD_EXEC |
5003218792Snp			    V_FW_VI_CMD_PFN(pf) |
5004218792Snp			    V_FW_VI_CMD_VFN(vf));
5005218792Snp	c.alloc_to_len16 = htonl(F_FW_VI_CMD_FREE | FW_LEN16(c));
5006218792Snp	c.type_to_viid = htons(V_FW_VI_CMD_VIID(viid));
5007218792Snp
5008218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
5009218792Snp}
5010218792Snp
5011218792Snp/**
5012218792Snp *	t4_set_rxmode - set Rx properties of a virtual interface
5013218792Snp *	@adap: the adapter
5014218792Snp *	@mbox: mailbox to use for the FW command
5015218792Snp *	@viid: the VI id
5016218792Snp *	@mtu: the new MTU or -1
5017218792Snp *	@promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change
5018218792Snp *	@all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change
5019218792Snp *	@bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change
5020218792Snp *	@vlanex: 1 to enable HVLAN extraction, 0 to disable it, -1 no change
5021218792Snp *	@sleep_ok: if true we may sleep while awaiting command completion
5022218792Snp *
5023218792Snp *	Sets Rx properties of a virtual interface.
5024218792Snp */
5025218792Snpint t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
5026218792Snp		  int mtu, int promisc, int all_multi, int bcast, int vlanex,
5027218792Snp		  bool sleep_ok)
5028218792Snp{
5029218792Snp	struct fw_vi_rxmode_cmd c;
5030218792Snp
5031218792Snp	/* convert to FW values */
5032218792Snp	if (mtu < 0)
5033218792Snp		mtu = M_FW_VI_RXMODE_CMD_MTU;
5034218792Snp	if (promisc < 0)
5035218792Snp		promisc = M_FW_VI_RXMODE_CMD_PROMISCEN;
5036218792Snp	if (all_multi < 0)
5037218792Snp		all_multi = M_FW_VI_RXMODE_CMD_ALLMULTIEN;
5038218792Snp	if (bcast < 0)
5039218792Snp		bcast = M_FW_VI_RXMODE_CMD_BROADCASTEN;
5040218792Snp	if (vlanex < 0)
5041218792Snp		vlanex = M_FW_VI_RXMODE_CMD_VLANEXEN;
5042218792Snp
5043218792Snp	memset(&c, 0, sizeof(c));
5044218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_RXMODE_CMD) | F_FW_CMD_REQUEST |
5045218792Snp			     F_FW_CMD_WRITE | V_FW_VI_RXMODE_CMD_VIID(viid));
5046218792Snp	c.retval_len16 = htonl(FW_LEN16(c));
5047218792Snp	c.mtu_to_vlanexen = htonl(V_FW_VI_RXMODE_CMD_MTU(mtu) |
5048218792Snp				  V_FW_VI_RXMODE_CMD_PROMISCEN(promisc) |
5049218792Snp				  V_FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) |
5050218792Snp				  V_FW_VI_RXMODE_CMD_BROADCASTEN(bcast) |
5051218792Snp				  V_FW_VI_RXMODE_CMD_VLANEXEN(vlanex));
5052218792Snp	return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok);
5053218792Snp}
5054218792Snp
5055218792Snp/**
5056218792Snp *	t4_alloc_mac_filt - allocates exact-match filters for MAC addresses
5057218792Snp *	@adap: the adapter
5058218792Snp *	@mbox: mailbox to use for the FW command
5059218792Snp *	@viid: the VI id
5060218792Snp *	@free: if true any existing filters for this VI id are first removed
5061218792Snp *	@naddr: the number of MAC addresses to allocate filters for (up to 7)
5062218792Snp *	@addr: the MAC address(es)
5063218792Snp *	@idx: where to store the index of each allocated filter
5064218792Snp *	@hash: pointer to hash address filter bitmap
5065218792Snp *	@sleep_ok: call is allowed to sleep
5066218792Snp *
5067218792Snp *	Allocates an exact-match filter for each of the supplied addresses and
5068218792Snp *	sets it to the corresponding address.  If @idx is not %NULL it should
5069218792Snp *	have at least @naddr entries, each of which will be set to the index of
5070218792Snp *	the filter allocated for the corresponding MAC address.  If a filter
5071218792Snp *	could not be allocated for an address its index is set to 0xffff.
5072218792Snp *	If @hash is not %NULL addresses that fail to allocate an exact filter
5073218792Snp *	are hashed and update the hash filter bitmap pointed at by @hash.
5074218792Snp *
5075218792Snp *	Returns a negative error number or the number of filters allocated.
5076218792Snp */
5077218792Snpint t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
5078218792Snp		      unsigned int viid, bool free, unsigned int naddr,
5079218792Snp		      const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok)
5080218792Snp{
5081218792Snp	int offset, ret = 0;
5082218792Snp	struct fw_vi_mac_cmd c;
5083218792Snp	unsigned int nfilters = 0;
5084248925Snp	unsigned int max_naddr = is_t4(adap) ?
5085248925Snp				       NUM_MPS_CLS_SRAM_L_INSTANCES :
5086248925Snp				       NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
5087218792Snp	unsigned int rem = naddr;
5088218792Snp
5089248925Snp	if (naddr > max_naddr)
5090218792Snp		return -EINVAL;
5091218792Snp
5092218792Snp	for (offset = 0; offset < naddr ; /**/) {
5093218792Snp		unsigned int fw_naddr = (rem < ARRAY_SIZE(c.u.exact)
5094218792Snp					 ? rem
5095218792Snp					 : ARRAY_SIZE(c.u.exact));
5096218792Snp		size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
5097218792Snp						     u.exact[fw_naddr]), 16);
5098218792Snp		struct fw_vi_mac_exact *p;
5099218792Snp		int i;
5100218792Snp
5101218792Snp		memset(&c, 0, sizeof(c));
5102218792Snp		c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) |
5103218792Snp				     F_FW_CMD_REQUEST |
5104218792Snp				     F_FW_CMD_WRITE |
5105218792Snp				     V_FW_CMD_EXEC(free) |
5106218792Snp				     V_FW_VI_MAC_CMD_VIID(viid));
5107218792Snp		c.freemacs_to_len16 = htonl(V_FW_VI_MAC_CMD_FREEMACS(free) |
5108218792Snp					    V_FW_CMD_LEN16(len16));
5109218792Snp
5110218792Snp		for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
5111218792Snp			p->valid_to_idx = htons(
5112218792Snp				F_FW_VI_MAC_CMD_VALID |
5113218792Snp				V_FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC));
5114218792Snp			memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr));
5115218792Snp		}
5116218792Snp
5117218792Snp		/*
5118218792Snp		 * It's okay if we run out of space in our MAC address arena.
5119218792Snp		 * Some of the addresses we submit may get stored so we need
5120218792Snp		 * to run through the reply to see what the results were ...
5121218792Snp		 */
5122218792Snp		ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok);
5123218792Snp		if (ret && ret != -FW_ENOMEM)
5124218792Snp			break;
5125218792Snp
5126218792Snp		for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
5127218792Snp			u16 index = G_FW_VI_MAC_CMD_IDX(ntohs(p->valid_to_idx));
5128218792Snp
5129218792Snp			if (idx)
5130248925Snp				idx[offset+i] = (index >=  max_naddr
5131218792Snp						 ? 0xffff
5132218792Snp						 : index);
5133248925Snp			if (index < max_naddr)
5134218792Snp				nfilters++;
5135218792Snp			else if (hash)
5136218792Snp				*hash |= (1ULL << hash_mac_addr(addr[offset+i]));
5137218792Snp		}
5138218792Snp
5139218792Snp		free = false;
5140218792Snp		offset += fw_naddr;
5141218792Snp		rem -= fw_naddr;
5142218792Snp	}
5143218792Snp
5144218792Snp	if (ret == 0 || ret == -FW_ENOMEM)
5145218792Snp		ret = nfilters;
5146218792Snp	return ret;
5147218792Snp}
5148218792Snp
5149218792Snp/**
5150218792Snp *	t4_change_mac - modifies the exact-match filter for a MAC address
5151218792Snp *	@adap: the adapter
5152218792Snp *	@mbox: mailbox to use for the FW command
5153218792Snp *	@viid: the VI id
5154218792Snp *	@idx: index of existing filter for old value of MAC address, or -1
5155218792Snp *	@addr: the new MAC address value
5156218792Snp *	@persist: whether a new MAC allocation should be persistent
5157218792Snp *	@add_smt: if true also add the address to the HW SMT
5158218792Snp *
5159218792Snp *	Modifies an exact-match filter and sets it to the new MAC address if
5160218792Snp *	@idx >= 0, or adds the MAC address to a new filter if @idx < 0.  In the
5161218792Snp *	latter case the address is added persistently if @persist is %true.
5162218792Snp *
5163218792Snp *	Note that in general it is not possible to modify the value of a given
5164218792Snp *	filter so the generic way to modify an address filter is to free the one
5165218792Snp *	being used by the old address value and allocate a new filter for the
5166218792Snp *	new address value.
5167218792Snp *
5168218792Snp *	Returns a negative error number or the index of the filter with the new
5169218792Snp *	MAC value.  Note that this index may differ from @idx.
5170218792Snp */
5171218792Snpint t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid,
5172218792Snp		  int idx, const u8 *addr, bool persist, bool add_smt)
5173218792Snp{
5174218792Snp	int ret, mode;
5175218792Snp	struct fw_vi_mac_cmd c;
5176218792Snp	struct fw_vi_mac_exact *p = c.u.exact;
5177248925Snp	unsigned int max_mac_addr = is_t4(adap) ?
5178248925Snp				    NUM_MPS_CLS_SRAM_L_INSTANCES :
5179248925Snp				    NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
5180218792Snp
5181218792Snp	if (idx < 0)                             /* new allocation */
5182218792Snp		idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC;
5183218792Snp	mode = add_smt ? FW_VI_MAC_SMT_AND_MPSTCAM : FW_VI_MAC_MPS_TCAM_ENTRY;
5184218792Snp
5185218792Snp	memset(&c, 0, sizeof(c));
5186218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) | F_FW_CMD_REQUEST |
5187218792Snp			     F_FW_CMD_WRITE | V_FW_VI_MAC_CMD_VIID(viid));
5188218792Snp	c.freemacs_to_len16 = htonl(V_FW_CMD_LEN16(1));
5189218792Snp	p->valid_to_idx = htons(F_FW_VI_MAC_CMD_VALID |
5190218792Snp				V_FW_VI_MAC_CMD_SMAC_RESULT(mode) |
5191218792Snp				V_FW_VI_MAC_CMD_IDX(idx));
5192218792Snp	memcpy(p->macaddr, addr, sizeof(p->macaddr));
5193218792Snp
5194248925Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
5195218792Snp	if (ret == 0) {
5196218792Snp		ret = G_FW_VI_MAC_CMD_IDX(ntohs(p->valid_to_idx));
5197248925Snp		if (ret >= max_mac_addr)
5198218792Snp			ret = -ENOMEM;
5199218792Snp	}
5200218792Snp	return ret;
5201218792Snp}
5202218792Snp
5203218792Snp/**
5204218792Snp *	t4_set_addr_hash - program the MAC inexact-match hash filter
5205218792Snp *	@adap: the adapter
5206218792Snp *	@mbox: mailbox to use for the FW command
5207218792Snp *	@viid: the VI id
5208218792Snp *	@ucast: whether the hash filter should also match unicast addresses
5209218792Snp *	@vec: the value to be written to the hash filter
5210218792Snp *	@sleep_ok: call is allowed to sleep
5211218792Snp *
5212218792Snp *	Sets the 64-bit inexact-match hash filter for a virtual interface.
5213218792Snp */
5214218792Snpint t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid,
5215218792Snp		     bool ucast, u64 vec, bool sleep_ok)
5216218792Snp{
5217218792Snp	struct fw_vi_mac_cmd c;
5218218792Snp
5219218792Snp	memset(&c, 0, sizeof(c));
5220218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) | F_FW_CMD_REQUEST |
5221218792Snp			     F_FW_CMD_WRITE | V_FW_VI_ENABLE_CMD_VIID(viid));
5222218792Snp	c.freemacs_to_len16 = htonl(F_FW_VI_MAC_CMD_HASHVECEN |
5223218792Snp				    V_FW_VI_MAC_CMD_HASHUNIEN(ucast) |
5224218792Snp				    V_FW_CMD_LEN16(1));
5225218792Snp	c.u.hash.hashvec = cpu_to_be64(vec);
5226218792Snp	return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok);
5227218792Snp}
5228218792Snp
5229218792Snp/**
5230218792Snp *	t4_enable_vi - enable/disable a virtual interface
5231218792Snp *	@adap: the adapter
5232218792Snp *	@mbox: mailbox to use for the FW command
5233218792Snp *	@viid: the VI id
5234218792Snp *	@rx_en: 1=enable Rx, 0=disable Rx
5235218792Snp *	@tx_en: 1=enable Tx, 0=disable Tx
5236218792Snp *
5237218792Snp *	Enables/disables a virtual interface.
5238218792Snp */
5239218792Snpint t4_enable_vi(struct adapter *adap, unsigned int mbox, unsigned int viid,
5240218792Snp		 bool rx_en, bool tx_en)
5241218792Snp{
5242218792Snp	struct fw_vi_enable_cmd c;
5243218792Snp
5244218792Snp	memset(&c, 0, sizeof(c));
5245218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_ENABLE_CMD) | F_FW_CMD_REQUEST |
5246218792Snp			     F_FW_CMD_EXEC | V_FW_VI_ENABLE_CMD_VIID(viid));
5247218792Snp	c.ien_to_len16 = htonl(V_FW_VI_ENABLE_CMD_IEN(rx_en) |
5248218792Snp			       V_FW_VI_ENABLE_CMD_EEN(tx_en) | FW_LEN16(c));
5249218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5250218792Snp}
5251218792Snp
5252218792Snp/**
5253218792Snp *	t4_identify_port - identify a VI's port by blinking its LED
5254218792Snp *	@adap: the adapter
5255218792Snp *	@mbox: mailbox to use for the FW command
5256218792Snp *	@viid: the VI id
5257218792Snp *	@nblinks: how many times to blink LED at 2.5 Hz
5258218792Snp *
5259218792Snp *	Identifies a VI's port by blinking its LED.
5260218792Snp */
5261218792Snpint t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid,
5262218792Snp		     unsigned int nblinks)
5263218792Snp{
5264218792Snp	struct fw_vi_enable_cmd c;
5265218792Snp
5266218792Snp	memset(&c, 0, sizeof(c));
5267218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_ENABLE_CMD) | F_FW_CMD_REQUEST |
5268218792Snp			     F_FW_CMD_EXEC | V_FW_VI_ENABLE_CMD_VIID(viid));
5269218792Snp	c.ien_to_len16 = htonl(F_FW_VI_ENABLE_CMD_LED | FW_LEN16(c));
5270218792Snp	c.blinkdur = htons(nblinks);
5271218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5272218792Snp}
5273218792Snp
5274218792Snp/**
5275218792Snp *	t4_iq_start_stop - enable/disable an ingress queue and its FLs
5276218792Snp *	@adap: the adapter
5277218792Snp *	@mbox: mailbox to use for the FW command
5278218792Snp *	@start: %true to enable the queues, %false to disable them
5279218792Snp *	@pf: the PF owning the queues
5280218792Snp *	@vf: the VF owning the queues
5281218792Snp *	@iqid: ingress queue id
5282218792Snp *	@fl0id: FL0 queue id or 0xffff if no attached FL0
5283218792Snp *	@fl1id: FL1 queue id or 0xffff if no attached FL1
5284218792Snp *
5285218792Snp *	Starts or stops an ingress queue and its associated FLs, if any.
5286218792Snp */
5287218792Snpint t4_iq_start_stop(struct adapter *adap, unsigned int mbox, bool start,
5288218792Snp		     unsigned int pf, unsigned int vf, unsigned int iqid,
5289218792Snp		     unsigned int fl0id, unsigned int fl1id)
5290218792Snp{
5291218792Snp	struct fw_iq_cmd c;
5292218792Snp
5293218792Snp	memset(&c, 0, sizeof(c));
5294218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_IQ_CMD) | F_FW_CMD_REQUEST |
5295218792Snp			    F_FW_CMD_EXEC | V_FW_IQ_CMD_PFN(pf) |
5296218792Snp			    V_FW_IQ_CMD_VFN(vf));
5297218792Snp	c.alloc_to_len16 = htonl(V_FW_IQ_CMD_IQSTART(start) |
5298218792Snp				 V_FW_IQ_CMD_IQSTOP(!start) | FW_LEN16(c));
5299218792Snp	c.iqid = htons(iqid);
5300218792Snp	c.fl0id = htons(fl0id);
5301218792Snp	c.fl1id = htons(fl1id);
5302218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5303218792Snp}
5304218792Snp
5305218792Snp/**
5306218792Snp *	t4_iq_free - free an ingress queue and its FLs
5307218792Snp *	@adap: the adapter
5308218792Snp *	@mbox: mailbox to use for the FW command
5309218792Snp *	@pf: the PF owning the queues
5310218792Snp *	@vf: the VF owning the queues
5311218792Snp *	@iqtype: the ingress queue type (FW_IQ_TYPE_FL_INT_CAP, etc.)
5312218792Snp *	@iqid: ingress queue id
5313218792Snp *	@fl0id: FL0 queue id or 0xffff if no attached FL0
5314218792Snp *	@fl1id: FL1 queue id or 0xffff if no attached FL1
5315218792Snp *
5316218792Snp *	Frees an ingress queue and its associated FLs, if any.
5317218792Snp */
5318218792Snpint t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
5319218792Snp	       unsigned int vf, unsigned int iqtype, unsigned int iqid,
5320218792Snp	       unsigned int fl0id, unsigned int fl1id)
5321218792Snp{
5322218792Snp	struct fw_iq_cmd c;
5323218792Snp
5324218792Snp	memset(&c, 0, sizeof(c));
5325218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_IQ_CMD) | F_FW_CMD_REQUEST |
5326218792Snp			    F_FW_CMD_EXEC | V_FW_IQ_CMD_PFN(pf) |
5327218792Snp			    V_FW_IQ_CMD_VFN(vf));
5328218792Snp	c.alloc_to_len16 = htonl(F_FW_IQ_CMD_FREE | FW_LEN16(c));
5329218792Snp	c.type_to_iqandstindex = htonl(V_FW_IQ_CMD_TYPE(iqtype));
5330218792Snp	c.iqid = htons(iqid);
5331218792Snp	c.fl0id = htons(fl0id);
5332218792Snp	c.fl1id = htons(fl1id);
5333218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5334218792Snp}
5335218792Snp
5336218792Snp/**
5337218792Snp *	t4_eth_eq_free - free an Ethernet egress queue
5338218792Snp *	@adap: the adapter
5339218792Snp *	@mbox: mailbox to use for the FW command
5340218792Snp *	@pf: the PF owning the queue
5341218792Snp *	@vf: the VF owning the queue
5342218792Snp *	@eqid: egress queue id
5343218792Snp *
5344218792Snp *	Frees an Ethernet egress queue.
5345218792Snp */
5346218792Snpint t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
5347218792Snp		   unsigned int vf, unsigned int eqid)
5348218792Snp{
5349218792Snp	struct fw_eq_eth_cmd c;
5350218792Snp
5351218792Snp	memset(&c, 0, sizeof(c));
5352218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_EQ_ETH_CMD) | F_FW_CMD_REQUEST |
5353218792Snp			    F_FW_CMD_EXEC | V_FW_EQ_ETH_CMD_PFN(pf) |
5354218792Snp			    V_FW_EQ_ETH_CMD_VFN(vf));
5355218792Snp	c.alloc_to_len16 = htonl(F_FW_EQ_ETH_CMD_FREE | FW_LEN16(c));
5356218792Snp	c.eqid_pkd = htonl(V_FW_EQ_ETH_CMD_EQID(eqid));
5357218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5358218792Snp}
5359218792Snp
5360218792Snp/**
5361218792Snp *	t4_ctrl_eq_free - free a control egress queue
5362218792Snp *	@adap: the adapter
5363218792Snp *	@mbox: mailbox to use for the FW command
5364218792Snp *	@pf: the PF owning the queue
5365218792Snp *	@vf: the VF owning the queue
5366218792Snp *	@eqid: egress queue id
5367218792Snp *
5368218792Snp *	Frees a control egress queue.
5369218792Snp */
5370218792Snpint t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
5371218792Snp		    unsigned int vf, unsigned int eqid)
5372218792Snp{
5373218792Snp	struct fw_eq_ctrl_cmd c;
5374218792Snp
5375218792Snp	memset(&c, 0, sizeof(c));
5376218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_EQ_CTRL_CMD) | F_FW_CMD_REQUEST |
5377218792Snp			    F_FW_CMD_EXEC | V_FW_EQ_CTRL_CMD_PFN(pf) |
5378218792Snp			    V_FW_EQ_CTRL_CMD_VFN(vf));
5379218792Snp	c.alloc_to_len16 = htonl(F_FW_EQ_CTRL_CMD_FREE | FW_LEN16(c));
5380218792Snp	c.cmpliqid_eqid = htonl(V_FW_EQ_CTRL_CMD_EQID(eqid));
5381218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5382218792Snp}
5383218792Snp
5384218792Snp/**
5385218792Snp *	t4_ofld_eq_free - free an offload egress queue
5386218792Snp *	@adap: the adapter
5387218792Snp *	@mbox: mailbox to use for the FW command
5388218792Snp *	@pf: the PF owning the queue
5389218792Snp *	@vf: the VF owning the queue
5390218792Snp *	@eqid: egress queue id
5391218792Snp *
5392218792Snp *	Frees a control egress queue.
5393218792Snp */
5394218792Snpint t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
5395218792Snp		    unsigned int vf, unsigned int eqid)
5396218792Snp{
5397218792Snp	struct fw_eq_ofld_cmd c;
5398218792Snp
5399218792Snp	memset(&c, 0, sizeof(c));
5400218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_EQ_OFLD_CMD) | F_FW_CMD_REQUEST |
5401218792Snp			    F_FW_CMD_EXEC | V_FW_EQ_OFLD_CMD_PFN(pf) |
5402218792Snp			    V_FW_EQ_OFLD_CMD_VFN(vf));
5403218792Snp	c.alloc_to_len16 = htonl(F_FW_EQ_OFLD_CMD_FREE | FW_LEN16(c));
5404218792Snp	c.eqid_pkd = htonl(V_FW_EQ_OFLD_CMD_EQID(eqid));
5405218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5406218792Snp}
5407218792Snp
5408218792Snp/**
5409218792Snp *	t4_handle_fw_rpl - process a FW reply message
5410218792Snp *	@adap: the adapter
5411218792Snp *	@rpl: start of the FW message
5412218792Snp *
5413218792Snp *	Processes a FW message, such as link state change messages.
5414218792Snp */
5415218792Snpint t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl)
5416218792Snp{
5417218792Snp	u8 opcode = *(const u8 *)rpl;
5418237436Snp	const struct fw_port_cmd *p = (const void *)rpl;
5419237436Snp	unsigned int action = G_FW_PORT_CMD_ACTION(ntohl(p->action_to_len16));
5420218792Snp
5421237436Snp	if (opcode == FW_PORT_CMD && action == FW_PORT_ACTION_GET_PORT_INFO) {
5422237436Snp		/* link/module state change message */
5423218792Snp		int speed = 0, fc = 0, i;
5424218792Snp		int chan = G_FW_PORT_CMD_PORTID(ntohl(p->op_to_portid));
5425218792Snp		struct port_info *pi = NULL;
5426218792Snp		struct link_config *lc;
5427218792Snp		u32 stat = ntohl(p->u.info.lstatus_to_modtype);
5428218792Snp		int link_ok = (stat & F_FW_PORT_CMD_LSTATUS) != 0;
5429218792Snp		u32 mod = G_FW_PORT_CMD_MODTYPE(stat);
5430218792Snp
5431218792Snp		if (stat & F_FW_PORT_CMD_RXPAUSE)
5432218792Snp			fc |= PAUSE_RX;
5433218792Snp		if (stat & F_FW_PORT_CMD_TXPAUSE)
5434218792Snp			fc |= PAUSE_TX;
5435218792Snp		if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M))
5436218792Snp			speed = SPEED_100;
5437218792Snp		else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G))
5438218792Snp			speed = SPEED_1000;
5439218792Snp		else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G))
5440218792Snp			speed = SPEED_10000;
5441250090Snp		else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G))
5442250090Snp			speed = SPEED_40000;
5443218792Snp
5444218792Snp		for_each_port(adap, i) {
5445218792Snp			pi = adap2pinfo(adap, i);
5446218792Snp			if (pi->tx_chan == chan)
5447218792Snp				break;
5448218792Snp		}
5449218792Snp		lc = &pi->link_cfg;
5450218792Snp
5451281207Snp		if (mod != pi->mod_type) {
5452281207Snp			pi->mod_type = mod;
5453281207Snp			t4_os_portmod_changed(adap, i);
5454281207Snp		}
5455218792Snp		if (link_ok != lc->link_ok || speed != lc->speed ||
5456218792Snp		    fc != lc->fc) {                    /* something changed */
5457252747Snp			int reason;
5458252747Snp
5459252747Snp			if (!link_ok && lc->link_ok)
5460252747Snp				reason = G_FW_PORT_CMD_LINKDNRC(stat);
5461252747Snp			else
5462252747Snp				reason = -1;
5463252747Snp
5464218792Snp			lc->link_ok = link_ok;
5465218792Snp			lc->speed = speed;
5466218792Snp			lc->fc = fc;
5467250090Snp			lc->supported = ntohs(p->u.info.pcap);
5468252747Snp			t4_os_link_changed(adap, i, link_ok, reason);
5469218792Snp		}
5470237436Snp	} else {
5471237436Snp		CH_WARN_RATELIMIT(adap,
5472237436Snp		    "Unknown firmware reply 0x%x (0x%x)\n", opcode, action);
5473237436Snp		return -EINVAL;
5474218792Snp	}
5475218792Snp	return 0;
5476218792Snp}
5477218792Snp
5478218792Snp/**
5479218792Snp *	get_pci_mode - determine a card's PCI mode
5480218792Snp *	@adapter: the adapter
5481218792Snp *	@p: where to store the PCI settings
5482218792Snp *
5483218792Snp *	Determines a card's PCI mode and associated parameters, such as speed
5484218792Snp *	and width.
5485218792Snp */
5486218792Snpstatic void __devinit get_pci_mode(struct adapter *adapter,
5487218792Snp				   struct pci_params *p)
5488218792Snp{
5489218792Snp	u16 val;
5490218792Snp	u32 pcie_cap;
5491218792Snp
5492218792Snp	pcie_cap = t4_os_find_pci_capability(adapter, PCI_CAP_ID_EXP);
5493218792Snp	if (pcie_cap) {
5494218792Snp		t4_os_pci_read_cfg2(adapter, pcie_cap + PCI_EXP_LNKSTA, &val);
5495218792Snp		p->speed = val & PCI_EXP_LNKSTA_CLS;
5496218792Snp		p->width = (val & PCI_EXP_LNKSTA_NLW) >> 4;
5497218792Snp	}
5498218792Snp}
5499218792Snp
5500218792Snp/**
5501218792Snp *	init_link_config - initialize a link's SW state
5502218792Snp *	@lc: structure holding the link state
5503218792Snp *	@caps: link capabilities
5504218792Snp *
5505218792Snp *	Initializes the SW state maintained for each link, including the link's
5506218792Snp *	capabilities and default speed/flow-control/autonegotiation settings.
5507218792Snp */
5508218792Snpstatic void __devinit init_link_config(struct link_config *lc,
5509218792Snp				       unsigned int caps)
5510218792Snp{
5511218792Snp	lc->supported = caps;
5512218792Snp	lc->requested_speed = 0;
5513218792Snp	lc->speed = 0;
5514218792Snp	lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
5515218792Snp	if (lc->supported & FW_PORT_CAP_ANEG) {
5516218792Snp		lc->advertising = lc->supported & ADVERT_MASK;
5517218792Snp		lc->autoneg = AUTONEG_ENABLE;
5518218792Snp		lc->requested_fc |= PAUSE_AUTONEG;
5519218792Snp	} else {
5520218792Snp		lc->advertising = 0;
5521218792Snp		lc->autoneg = AUTONEG_DISABLE;
5522218792Snp	}
5523218792Snp}
5524218792Snp
5525218792Snpstatic int __devinit get_flash_params(struct adapter *adapter)
5526218792Snp{
5527218792Snp	int ret;
5528218792Snp	u32 info = 0;
5529218792Snp
5530218792Snp	ret = sf1_write(adapter, 1, 1, 0, SF_RD_ID);
5531218792Snp	if (!ret)
5532218792Snp		ret = sf1_read(adapter, 3, 0, 1, &info);
5533218792Snp	t4_write_reg(adapter, A_SF_OP, 0);               /* unlock SF */
5534218792Snp	if (ret < 0)
5535218792Snp		return ret;
5536218792Snp
5537218792Snp	if ((info & 0xff) != 0x20)             /* not a Numonix flash */
5538218792Snp		return -EINVAL;
5539218792Snp	info >>= 16;                           /* log2 of size */
5540218792Snp	if (info >= 0x14 && info < 0x18)
5541218792Snp		adapter->params.sf_nsec = 1 << (info - 16);
5542218792Snp	else if (info == 0x18)
5543218792Snp		adapter->params.sf_nsec = 64;
5544218792Snp	else
5545218792Snp		return -EINVAL;
5546218792Snp	adapter->params.sf_size = 1 << info;
5547218792Snp	return 0;
5548218792Snp}
5549218792Snp
5550228561Snpstatic void __devinit set_pcie_completion_timeout(struct adapter *adapter,
5551228561Snp						  u8 range)
5552228561Snp{
5553228561Snp	u16 val;
5554228561Snp	u32 pcie_cap;
5555228561Snp
5556228561Snp	pcie_cap = t4_os_find_pci_capability(adapter, PCI_CAP_ID_EXP);
5557228561Snp	if (pcie_cap) {
5558228561Snp		t4_os_pci_read_cfg2(adapter, pcie_cap + PCI_EXP_DEVCTL2, &val);
5559228561Snp		val &= 0xfff0;
5560228561Snp		val |= range ;
5561228561Snp		t4_os_pci_write_cfg2(adapter, pcie_cap + PCI_EXP_DEVCTL2, val);
5562228561Snp	}
5563228561Snp}
5564228561Snp
5565218792Snp/**
5566218792Snp *	t4_prep_adapter - prepare SW and HW for operation
5567218792Snp *	@adapter: the adapter
5568218792Snp *	@reset: if true perform a HW reset
5569218792Snp *
5570218792Snp *	Initialize adapter SW state for the various HW modules, set initial
5571218792Snp *	values for some adapter tunables, take PHYs out of reset, and
5572218792Snp *	initialize the MDIO interface.
5573218792Snp */
5574218792Snpint __devinit t4_prep_adapter(struct adapter *adapter)
5575218792Snp{
5576218792Snp	int ret;
5577248925Snp	uint16_t device_id;
5578248925Snp	uint32_t pl_rev;
5579218792Snp
5580218792Snp	get_pci_mode(adapter, &adapter->params.pci);
5581218792Snp
5582248925Snp	pl_rev = t4_read_reg(adapter, A_PL_REV);
5583248925Snp	adapter->params.chipid = G_CHIPID(pl_rev);
5584248925Snp	adapter->params.rev = G_REV(pl_rev);
5585248925Snp	if (adapter->params.chipid == 0) {
5586248925Snp		/* T4 did not have chipid in PL_REV (T5 onwards do) */
5587248925Snp		adapter->params.chipid = CHELSIO_T4;
5588248925Snp
5589248925Snp		/* T4A1 chip is not supported */
5590248925Snp		if (adapter->params.rev == 1) {
5591248925Snp			CH_ALERT(adapter, "T4 rev 1 chip is not supported.\n");
5592248925Snp			return -EINVAL;
5593248925Snp		}
5594237436Snp	}
5595218792Snp	adapter->params.pci.vpd_cap_addr =
5596248925Snp	    t4_os_find_pci_capability(adapter, PCI_CAP_ID_VPD);
5597218792Snp
5598218792Snp	ret = get_flash_params(adapter);
5599218792Snp	if (ret < 0)
5600218792Snp		return ret;
5601218792Snp
5602218792Snp	ret = get_vpd_params(adapter, &adapter->params.vpd);
5603218792Snp	if (ret < 0)
5604218792Snp		return ret;
5605218792Snp
5606248925Snp	/* Cards with real ASICs have the chipid in the PCIe device id */
5607248925Snp	t4_os_pci_read_cfg2(adapter, PCI_DEVICE_ID, &device_id);
5608248925Snp	if (device_id >> 12 == adapter->params.chipid)
5609248925Snp		adapter->params.cim_la_size = CIMLA_SIZE;
5610248925Snp	else {
5611237436Snp		/* FPGA */
5612248925Snp		adapter->params.fpga = 1;
5613218792Snp		adapter->params.cim_la_size = 2 * CIMLA_SIZE;
5614218792Snp	}
5615218792Snp
5616218792Snp	init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
5617218792Snp
5618218792Snp	/*
5619218792Snp	 * Default port and clock for debugging in case we can't reach FW.
5620218792Snp	 */
5621218792Snp	adapter->params.nports = 1;
5622218792Snp	adapter->params.portvec = 1;
5623218792Snp	adapter->params.vpd.cclk = 50000;
5624218792Snp
5625228561Snp	/* Set pci completion timeout value to 4 seconds. */
5626228561Snp	set_pcie_completion_timeout(adapter, 0xd);
5627218792Snp	return 0;
5628218792Snp}
5629218792Snp
5630252705Snp/**
5631252705Snp *	t4_init_tp_params - initialize adap->params.tp
5632252705Snp *	@adap: the adapter
5633252705Snp *
5634252705Snp *	Initialize various fields of the adapter's TP Parameters structure.
5635252705Snp */
5636252705Snpint __devinit t4_init_tp_params(struct adapter *adap)
5637252705Snp{
5638252705Snp	int chan;
5639252705Snp	u32 v;
5640252705Snp
5641252705Snp	v = t4_read_reg(adap, A_TP_TIMER_RESOLUTION);
5642252705Snp	adap->params.tp.tre = G_TIMERRESOLUTION(v);
5643252705Snp	adap->params.tp.dack_re = G_DELAYEDACKRESOLUTION(v);
5644252705Snp
5645252705Snp	/* MODQ_REQ_MAP defaults to setting queues 0-3 to chan 0-3 */
5646252705Snp	for (chan = 0; chan < NCHAN; chan++)
5647252705Snp		adap->params.tp.tx_modq[chan] = chan;
5648252705Snp
5649252705Snp	t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA,
5650252705Snp			 &adap->params.tp.ingress_config, 1,
5651252705Snp			 A_TP_INGRESS_CONFIG);
5652281259Snp	refresh_vlan_pri_map(adap);
5653252705Snp
5654252705Snp	return 0;
5655252705Snp}
5656252705Snp
5657252705Snp/**
5658252705Snp *	t4_filter_field_shift - calculate filter field shift
5659252705Snp *	@adap: the adapter
5660252705Snp *	@filter_sel: the desired field (from TP_VLAN_PRI_MAP bits)
5661252705Snp *
5662252705Snp *	Return the shift position of a filter field within the Compressed
5663252705Snp *	Filter Tuple.  The filter field is specified via its selection bit
5664252705Snp *	within TP_VLAN_PRI_MAL (filter mode).  E.g. F_VLAN.
5665252705Snp */
5666252705Snpint t4_filter_field_shift(const struct adapter *adap, int filter_sel)
5667252705Snp{
5668252705Snp	unsigned int filter_mode = adap->params.tp.vlan_pri_map;
5669252705Snp	unsigned int sel;
5670252705Snp	int field_shift;
5671252705Snp
5672252705Snp	if ((filter_mode & filter_sel) == 0)
5673252705Snp		return -1;
5674252705Snp
5675252705Snp	for (sel = 1, field_shift = 0; sel < filter_sel; sel <<= 1) {
5676252705Snp	    switch (filter_mode & sel) {
5677252705Snp		case F_FCOE:          field_shift += W_FT_FCOE;          break;
5678252705Snp		case F_PORT:          field_shift += W_FT_PORT;          break;
5679252705Snp		case F_VNIC_ID:       field_shift += W_FT_VNIC_ID;       break;
5680252705Snp		case F_VLAN:          field_shift += W_FT_VLAN;          break;
5681252705Snp		case F_TOS:           field_shift += W_FT_TOS;           break;
5682252705Snp		case F_PROTOCOL:      field_shift += W_FT_PROTOCOL;      break;
5683252705Snp		case F_ETHERTYPE:     field_shift += W_FT_ETHERTYPE;     break;
5684252705Snp		case F_MACMATCH:      field_shift += W_FT_MACMATCH;      break;
5685252705Snp		case F_MPSHITTYPE:    field_shift += W_FT_MPSHITTYPE;    break;
5686252705Snp		case F_FRAGMENTATION: field_shift += W_FT_FRAGMENTATION; break;
5687252705Snp	    }
5688252705Snp	}
5689252705Snp	return field_shift;
5690252705Snp}
5691252705Snp
5692218792Snpint __devinit t4_port_init(struct port_info *p, int mbox, int pf, int vf)
5693218792Snp{
5694218792Snp	u8 addr[6];
5695218792Snp	int ret, i, j;
5696218792Snp	struct fw_port_cmd c;
5697270297Snp	u16 rss_size;
5698218792Snp	adapter_t *adap = p->adapter;
5699286897Snp	u32 param, val;
5700218792Snp
5701218792Snp	memset(&c, 0, sizeof(c));
5702218792Snp
5703218792Snp	for (i = 0, j = -1; i <= p->port_id; i++) {
5704218792Snp		do {
5705218792Snp			j++;
5706218792Snp		} while ((adap->params.portvec & (1 << j)) == 0);
5707218792Snp	}
5708218792Snp
5709218792Snp	c.op_to_portid = htonl(V_FW_CMD_OP(FW_PORT_CMD) |
5710218792Snp			       F_FW_CMD_REQUEST | F_FW_CMD_READ |
5711218792Snp			       V_FW_PORT_CMD_PORTID(j));
5712218792Snp	c.action_to_len16 = htonl(
5713218792Snp		V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) |
5714218792Snp		FW_LEN16(c));
5715218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
5716218792Snp	if (ret)
5717218792Snp		return ret;
5718218792Snp
5719218792Snp	ret = t4_alloc_vi(adap, mbox, j, pf, vf, 1, addr, &rss_size);
5720218792Snp	if (ret < 0)
5721218792Snp		return ret;
5722218792Snp
5723218792Snp	p->viid = ret;
5724218792Snp	p->tx_chan = j;
5725265410Snp	p->rx_chan_map = get_mps_bg_map(adap, j);
5726218792Snp	p->lport = j;
5727218792Snp	p->rss_size = rss_size;
5728218792Snp	t4_os_set_hw_addr(adap, p->port_id, addr);
5729218792Snp
5730218792Snp	ret = ntohl(c.u.info.lstatus_to_modtype);
5731218792Snp	p->mdio_addr = (ret & F_FW_PORT_CMD_MDIOCAP) ?
5732218792Snp		G_FW_PORT_CMD_MDIOADDR(ret) : -1;
5733218792Snp	p->port_type = G_FW_PORT_CMD_PTYPE(ret);
5734218792Snp	p->mod_type = G_FW_PORT_CMD_MODTYPE(ret);
5735218792Snp
5736218792Snp	init_link_config(&p->link_cfg, ntohs(c.u.info.pcap));
5737218792Snp
5738286897Snp	param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
5739286897Snp	    V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_RSSINFO) |
5740286897Snp	    V_FW_PARAMS_PARAM_YZ(p->viid);
5741286897Snp	ret = t4_query_params(adap, mbox, pf, vf, 1, &param, &val);
5742286897Snp	if (ret)
5743286897Snp		p->rss_base = 0xffff;
5744286897Snp	else {
5745286897Snp		/* MPASS((val >> 16) == rss_size); */
5746286897Snp		p->rss_base = val & 0xffff;
5747286897Snp	}
5748286897Snp
5749218792Snp	return 0;
5750218792Snp}
5751259142Snp
5752270297Snpint t4_sched_config(struct adapter *adapter, int type, int minmaxen,
5753270297Snp    		    int sleep_ok)
5754259142Snp{
5755259142Snp	struct fw_sched_cmd cmd;
5756259142Snp
5757259142Snp	memset(&cmd, 0, sizeof(cmd));
5758259142Snp	cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_SCHED_CMD) |
5759259142Snp				      F_FW_CMD_REQUEST |
5760259142Snp				      F_FW_CMD_WRITE);
5761259142Snp	cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
5762259142Snp
5763259142Snp	cmd.u.config.sc = FW_SCHED_SC_CONFIG;
5764259142Snp	cmd.u.config.type = type;
5765259142Snp	cmd.u.config.minmaxen = minmaxen;
5766259142Snp
5767259142Snp	return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd),
5768270297Snp			       NULL, sleep_ok);
5769259142Snp}
5770259142Snp
5771259142Snpint t4_sched_params(struct adapter *adapter, int type, int level, int mode,
5772259142Snp		    int rateunit, int ratemode, int channel, int cl,
5773270297Snp		    int minrate, int maxrate, int weight, int pktsize,
5774270297Snp		    int sleep_ok)
5775259142Snp{
5776259142Snp	struct fw_sched_cmd cmd;
5777259142Snp
5778259142Snp	memset(&cmd, 0, sizeof(cmd));
5779259142Snp	cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_SCHED_CMD) |
5780259142Snp				      F_FW_CMD_REQUEST |
5781259142Snp				      F_FW_CMD_WRITE);
5782259142Snp	cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
5783259142Snp
5784259142Snp	cmd.u.params.sc = FW_SCHED_SC_PARAMS;
5785259142Snp	cmd.u.params.type = type;
5786259142Snp	cmd.u.params.level = level;
5787259142Snp	cmd.u.params.mode = mode;
5788259142Snp	cmd.u.params.ch = channel;
5789259142Snp	cmd.u.params.cl = cl;
5790259142Snp	cmd.u.params.unit = rateunit;
5791259142Snp	cmd.u.params.rate = ratemode;
5792259142Snp	cmd.u.params.min = cpu_to_be32(minrate);
5793259142Snp	cmd.u.params.max = cpu_to_be32(maxrate);
5794259142Snp	cmd.u.params.weight = cpu_to_be16(weight);
5795259142Snp	cmd.u.params.pktsize = cpu_to_be16(pktsize);
5796259142Snp
5797259142Snp	return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd),
5798270297Snp			       NULL, sleep_ok);
5799259142Snp}
5800