t4_hw.c revision 281207
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: stable/10/sys/dev/cxgbe/common/t4_hw.c 281207 2015-04-07 15:32:43Z 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
262218792Snp	t4_write_reg(adap, ctl_reg, F_MBMSGVALID | V_MBOWNER(X_MBOWNER_FW));
263218792Snp	t4_read_reg(adap, ctl_reg);          /* flush write */
264218792Snp
265218792Snp	delay_idx = 0;
266218792Snp	ms = delay[0];
267218792Snp
268218792Snp	for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) {
269218792Snp		if (sleep_ok) {
270218792Snp			ms = delay[delay_idx];  /* last element may repeat */
271218792Snp			if (delay_idx < ARRAY_SIZE(delay) - 1)
272218792Snp				delay_idx++;
273218792Snp			msleep(ms);
274218792Snp		} else
275218792Snp			mdelay(ms);
276218792Snp
277218792Snp		v = t4_read_reg(adap, ctl_reg);
278218792Snp		if (v == X_CIM_PF_NOACCESS)
279218792Snp			continue;
280218792Snp		if (G_MBOWNER(v) == X_MBOWNER_PL) {
281218792Snp			if (!(v & F_MBMSGVALID)) {
282218792Snp				t4_write_reg(adap, ctl_reg,
283218792Snp					     V_MBOWNER(X_MBOWNER_NONE));
284218792Snp				continue;
285218792Snp			}
286218792Snp
287218792Snp			res = t4_read_reg64(adap, data_reg);
288218792Snp			if (G_FW_CMD_OP(res >> 32) == FW_DEBUG_CMD) {
289218792Snp				fw_asrt(adap, data_reg);
290218792Snp				res = V_FW_CMD_RETVAL(EIO);
291218792Snp			} else if (rpl)
292218792Snp				get_mbox_rpl(adap, rpl, size / 8, data_reg);
293218792Snp			t4_write_reg(adap, ctl_reg, V_MBOWNER(X_MBOWNER_NONE));
294218792Snp			return -G_FW_CMD_RETVAL((int)res);
295218792Snp		}
296218792Snp	}
297218792Snp
298247355Snp	/*
299247355Snp	 * We timed out waiting for a reply to our mailbox command.  Report
300247355Snp	 * the error and also check to see if the firmware reported any
301247355Snp	 * errors ...
302247355Snp	 */
303218792Snp	CH_ERR(adap, "command %#x in mailbox %d timed out\n",
304218792Snp	       *(const u8 *)cmd, mbox);
305247355Snp	if (t4_read_reg(adap, A_PCIE_FW) & F_PCIE_FW_ERR)
306247355Snp		t4_report_fw_error(adap);
307218792Snp	return -ETIMEDOUT;
308218792Snp}
309218792Snp
310218792Snp/**
311218792Snp *	t4_mc_read - read from MC through backdoor accesses
312218792Snp *	@adap: the adapter
313248925Snp *	@idx: which MC to access
314218792Snp *	@addr: address of first byte requested
315218792Snp *	@data: 64 bytes of data containing the requested address
316218792Snp *	@ecc: where to store the corresponding 64-bit ECC word
317218792Snp *
318218792Snp *	Read 64 bytes of data from MC starting at a 64-byte-aligned address
319218792Snp *	that covers the requested address @addr.  If @parity is not %NULL it
320218792Snp *	is assigned the 64-bit ECC word for the read data.
321218792Snp */
322248925Snpint t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
323218792Snp{
324218792Snp	int i;
325248925Snp	u32 mc_bist_cmd_reg, mc_bist_cmd_addr_reg, mc_bist_cmd_len_reg;
326248925Snp	u32 mc_bist_status_rdata_reg, mc_bist_data_pattern_reg;
327218792Snp
328248925Snp	if (is_t4(adap)) {
329248925Snp		mc_bist_cmd_reg = A_MC_BIST_CMD;
330248925Snp		mc_bist_cmd_addr_reg = A_MC_BIST_CMD_ADDR;
331248925Snp		mc_bist_cmd_len_reg = A_MC_BIST_CMD_LEN;
332248925Snp		mc_bist_status_rdata_reg = A_MC_BIST_STATUS_RDATA;
333248925Snp		mc_bist_data_pattern_reg = A_MC_BIST_DATA_PATTERN;
334248925Snp	} else {
335248925Snp		mc_bist_cmd_reg = MC_REG(A_MC_P_BIST_CMD, idx);
336248925Snp		mc_bist_cmd_addr_reg = MC_REG(A_MC_P_BIST_CMD_ADDR, idx);
337248925Snp		mc_bist_cmd_len_reg = MC_REG(A_MC_P_BIST_CMD_LEN, idx);
338248925Snp		mc_bist_status_rdata_reg = MC_REG(A_MC_P_BIST_STATUS_RDATA,
339248925Snp						  idx);
340248925Snp		mc_bist_data_pattern_reg = MC_REG(A_MC_P_BIST_DATA_PATTERN,
341248925Snp						  idx);
342248925Snp	}
343248925Snp
344248925Snp	if (t4_read_reg(adap, mc_bist_cmd_reg) & F_START_BIST)
345218792Snp		return -EBUSY;
346248925Snp	t4_write_reg(adap, mc_bist_cmd_addr_reg, addr & ~0x3fU);
347248925Snp	t4_write_reg(adap, mc_bist_cmd_len_reg, 64);
348248925Snp	t4_write_reg(adap, mc_bist_data_pattern_reg, 0xc);
349248925Snp	t4_write_reg(adap, mc_bist_cmd_reg, V_BIST_OPCODE(1) |
350248925Snp		     F_START_BIST | V_BIST_CMD_GAP(1));
351248925Snp	i = t4_wait_op_done(adap, mc_bist_cmd_reg, F_START_BIST, 0, 10, 1);
352218792Snp	if (i)
353218792Snp		return i;
354218792Snp
355248925Snp#define MC_DATA(i) MC_BIST_STATUS_REG(mc_bist_status_rdata_reg, i)
356218792Snp
357218792Snp	for (i = 15; i >= 0; i--)
358237436Snp		*data++ = ntohl(t4_read_reg(adap, MC_DATA(i)));
359218792Snp	if (ecc)
360218792Snp		*ecc = t4_read_reg64(adap, MC_DATA(16));
361218792Snp#undef MC_DATA
362218792Snp	return 0;
363218792Snp}
364218792Snp
365218792Snp/**
366218792Snp *	t4_edc_read - read from EDC through backdoor accesses
367218792Snp *	@adap: the adapter
368218792Snp *	@idx: which EDC to access
369218792Snp *	@addr: address of first byte requested
370218792Snp *	@data: 64 bytes of data containing the requested address
371218792Snp *	@ecc: where to store the corresponding 64-bit ECC word
372218792Snp *
373218792Snp *	Read 64 bytes of data from EDC starting at a 64-byte-aligned address
374218792Snp *	that covers the requested address @addr.  If @parity is not %NULL it
375218792Snp *	is assigned the 64-bit ECC word for the read data.
376218792Snp */
377218792Snpint t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
378218792Snp{
379218792Snp	int i;
380248925Snp	u32 edc_bist_cmd_reg, edc_bist_cmd_addr_reg, edc_bist_cmd_len_reg;
381248925Snp	u32 edc_bist_cmd_data_pattern, edc_bist_status_rdata_reg;
382218792Snp
383248925Snp	if (is_t4(adap)) {
384248925Snp		edc_bist_cmd_reg = EDC_REG(A_EDC_BIST_CMD, idx);
385248925Snp		edc_bist_cmd_addr_reg = EDC_REG(A_EDC_BIST_CMD_ADDR, idx);
386248925Snp		edc_bist_cmd_len_reg = EDC_REG(A_EDC_BIST_CMD_LEN, idx);
387248925Snp		edc_bist_cmd_data_pattern = EDC_REG(A_EDC_BIST_DATA_PATTERN,
388248925Snp						    idx);
389248925Snp		edc_bist_status_rdata_reg = EDC_REG(A_EDC_BIST_STATUS_RDATA,
390248925Snp						    idx);
391248925Snp	} else {
392248925Snp/*
393248925Snp * These macro are missing in t4_regs.h file.
394248925Snp * Added temporarily for testing.
395248925Snp */
396248925Snp#define EDC_STRIDE_T5 (EDC_T51_BASE_ADDR - EDC_T50_BASE_ADDR)
397248925Snp#define EDC_REG_T5(reg, idx) (reg + EDC_STRIDE_T5 * idx)
398248925Snp		edc_bist_cmd_reg = EDC_REG_T5(A_EDC_H_BIST_CMD, idx);
399248925Snp		edc_bist_cmd_addr_reg = EDC_REG_T5(A_EDC_H_BIST_CMD_ADDR, idx);
400248925Snp		edc_bist_cmd_len_reg = EDC_REG_T5(A_EDC_H_BIST_CMD_LEN, idx);
401248925Snp		edc_bist_cmd_data_pattern = EDC_REG_T5(A_EDC_H_BIST_DATA_PATTERN,
402248925Snp						    idx);
403248925Snp		edc_bist_status_rdata_reg = EDC_REG_T5(A_EDC_H_BIST_STATUS_RDATA,
404248925Snp						    idx);
405248925Snp#undef EDC_REG_T5
406248925Snp#undef EDC_STRIDE_T5
407248925Snp	}
408248925Snp
409248925Snp	if (t4_read_reg(adap, edc_bist_cmd_reg) & F_START_BIST)
410218792Snp		return -EBUSY;
411248925Snp	t4_write_reg(adap, edc_bist_cmd_addr_reg, addr & ~0x3fU);
412248925Snp	t4_write_reg(adap, edc_bist_cmd_len_reg, 64);
413248925Snp	t4_write_reg(adap, edc_bist_cmd_data_pattern, 0xc);
414248925Snp	t4_write_reg(adap, edc_bist_cmd_reg,
415218792Snp		     V_BIST_OPCODE(1) | V_BIST_CMD_GAP(1) | F_START_BIST);
416248925Snp	i = t4_wait_op_done(adap, edc_bist_cmd_reg, F_START_BIST, 0, 10, 1);
417218792Snp	if (i)
418218792Snp		return i;
419218792Snp
420248925Snp#define EDC_DATA(i) EDC_BIST_STATUS_REG(edc_bist_status_rdata_reg, i)
421218792Snp
422218792Snp	for (i = 15; i >= 0; i--)
423237436Snp		*data++ = ntohl(t4_read_reg(adap, EDC_DATA(i)));
424218792Snp	if (ecc)
425218792Snp		*ecc = t4_read_reg64(adap, EDC_DATA(16));
426218792Snp#undef EDC_DATA
427218792Snp	return 0;
428218792Snp}
429218792Snp
430218792Snp/**
431218792Snp *	t4_mem_read - read EDC 0, EDC 1 or MC into buffer
432218792Snp *	@adap: the adapter
433218792Snp *	@mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC
434218792Snp *	@addr: address within indicated memory type
435218792Snp *	@len: amount of memory to read
436218792Snp *	@buf: host memory buffer
437218792Snp *
438218792Snp *	Reads an [almost] arbitrary memory region in the firmware: the
439218792Snp *	firmware memory address, length and host buffer must be aligned on
440218792Snp *	32-bit boudaries.  The memory is returned as a raw byte sequence from
441218792Snp *	the firmware's memory.  If this memory contains data structures which
442218792Snp *	contain multi-byte integers, it's the callers responsibility to
443218792Snp *	perform appropriate byte order conversions.
444218792Snp */
445218792Snpint t4_mem_read(struct adapter *adap, int mtype, u32 addr, u32 len,
446218792Snp		__be32 *buf)
447218792Snp{
448218792Snp	u32 pos, start, end, offset;
449218792Snp	int ret;
450218792Snp
451218792Snp	/*
452218792Snp	 * Argument sanity checks ...
453218792Snp	 */
454218792Snp	if ((addr & 0x3) || (len & 0x3))
455218792Snp		return -EINVAL;
456218792Snp
457218792Snp	/*
458218792Snp	 * The underlaying EDC/MC read routines read 64 bytes at a time so we
459218792Snp	 * need to round down the start and round up the end.  We'll start
460218792Snp	 * copying out of the first line at (addr - start) a word at a time.
461218792Snp	 */
462218792Snp	start = addr & ~(64-1);
463218792Snp	end = (addr + len + 64-1) & ~(64-1);
464218792Snp	offset = (addr - start)/sizeof(__be32);
465218792Snp
466218792Snp	for (pos = start; pos < end; pos += 64, offset = 0) {
467218792Snp		__be32 data[16];
468218792Snp
469218792Snp		/*
470218792Snp		 * Read the chip's memory block and bail if there's an error.
471218792Snp		 */
472248925Snp		if ((mtype == MEM_MC) || (mtype == MEM_MC1))
473248925Snp			ret = t4_mc_read(adap, mtype - MEM_MC, pos, data, NULL);
474218792Snp		else
475218792Snp			ret = t4_edc_read(adap, mtype, pos, data, NULL);
476218792Snp		if (ret)
477218792Snp			return ret;
478218792Snp
479218792Snp		/*
480218792Snp		 * Copy the data into the caller's memory buffer.
481218792Snp		 */
482218792Snp		while (offset < 16 && len > 0) {
483218792Snp			*buf++ = data[offset++];
484218792Snp			len -= sizeof(__be32);
485218792Snp		}
486218792Snp	}
487218792Snp
488218792Snp	return 0;
489218792Snp}
490218792Snp
491218792Snp/*
492218792Snp * Partial EEPROM Vital Product Data structure.  Includes only the ID and
493218792Snp * VPD-R header.
494218792Snp */
495218792Snpstruct t4_vpd_hdr {
496218792Snp	u8  id_tag;
497218792Snp	u8  id_len[2];
498218792Snp	u8  id_data[ID_LEN];
499218792Snp	u8  vpdr_tag;
500218792Snp	u8  vpdr_len[2];
501218792Snp};
502218792Snp
503218792Snp/*
504218792Snp * EEPROM reads take a few tens of us while writes can take a bit over 5 ms.
505218792Snp */
506218792Snp#define EEPROM_MAX_RD_POLL 40
507218792Snp#define EEPROM_MAX_WR_POLL 6
508218792Snp#define EEPROM_STAT_ADDR   0x7bfc
509218792Snp#define VPD_BASE           0x400
510218792Snp#define VPD_BASE_OLD       0
511248925Snp#define VPD_LEN            1024
512218792Snp#define VPD_INFO_FLD_HDR_SIZE	3
513250090Snp#define CHELSIO_VPD_UNIQUE_ID 0x82
514218792Snp
515218792Snp/**
516218792Snp *	t4_seeprom_read - read a serial EEPROM location
517218792Snp *	@adapter: adapter to read
518218792Snp *	@addr: EEPROM virtual address
519218792Snp *	@data: where to store the read data
520218792Snp *
521218792Snp *	Read a 32-bit word from a location in serial EEPROM using the card's PCI
522218792Snp *	VPD capability.  Note that this function must be called with a virtual
523218792Snp *	address.
524218792Snp */
525218792Snpint t4_seeprom_read(struct adapter *adapter, u32 addr, u32 *data)
526218792Snp{
527218792Snp	u16 val;
528218792Snp	int attempts = EEPROM_MAX_RD_POLL;
529218792Snp	unsigned int base = adapter->params.pci.vpd_cap_addr;
530218792Snp
531218792Snp	if (addr >= EEPROMVSIZE || (addr & 3))
532218792Snp		return -EINVAL;
533218792Snp
534218792Snp	t4_os_pci_write_cfg2(adapter, base + PCI_VPD_ADDR, (u16)addr);
535218792Snp	do {
536218792Snp		udelay(10);
537218792Snp		t4_os_pci_read_cfg2(adapter, base + PCI_VPD_ADDR, &val);
538218792Snp	} while (!(val & PCI_VPD_ADDR_F) && --attempts);
539218792Snp
540218792Snp	if (!(val & PCI_VPD_ADDR_F)) {
541218792Snp		CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr);
542218792Snp		return -EIO;
543218792Snp	}
544218792Snp	t4_os_pci_read_cfg4(adapter, base + PCI_VPD_DATA, data);
545218792Snp	*data = le32_to_cpu(*data);
546218792Snp	return 0;
547218792Snp}
548218792Snp
549218792Snp/**
550218792Snp *	t4_seeprom_write - write a serial EEPROM location
551218792Snp *	@adapter: adapter to write
552218792Snp *	@addr: virtual EEPROM address
553218792Snp *	@data: value to write
554218792Snp *
555218792Snp *	Write a 32-bit word to a location in serial EEPROM using the card's PCI
556218792Snp *	VPD capability.  Note that this function must be called with a virtual
557218792Snp *	address.
558218792Snp */
559218792Snpint t4_seeprom_write(struct adapter *adapter, u32 addr, u32 data)
560218792Snp{
561218792Snp	u16 val;
562218792Snp	int attempts = EEPROM_MAX_WR_POLL;
563218792Snp	unsigned int base = adapter->params.pci.vpd_cap_addr;
564218792Snp
565218792Snp	if (addr >= EEPROMVSIZE || (addr & 3))
566218792Snp		return -EINVAL;
567218792Snp
568218792Snp	t4_os_pci_write_cfg4(adapter, base + PCI_VPD_DATA,
569218792Snp				 cpu_to_le32(data));
570218792Snp	t4_os_pci_write_cfg2(adapter, base + PCI_VPD_ADDR,
571218792Snp				 (u16)addr | PCI_VPD_ADDR_F);
572218792Snp	do {
573218792Snp		msleep(1);
574218792Snp		t4_os_pci_read_cfg2(adapter, base + PCI_VPD_ADDR, &val);
575218792Snp	} while ((val & PCI_VPD_ADDR_F) && --attempts);
576218792Snp
577218792Snp	if (val & PCI_VPD_ADDR_F) {
578218792Snp		CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr);
579218792Snp		return -EIO;
580218792Snp	}
581218792Snp	return 0;
582218792Snp}
583218792Snp
584218792Snp/**
585218792Snp *	t4_eeprom_ptov - translate a physical EEPROM address to virtual
586218792Snp *	@phys_addr: the physical EEPROM address
587218792Snp *	@fn: the PCI function number
588218792Snp *	@sz: size of function-specific area
589218792Snp *
590218792Snp *	Translate a physical EEPROM address to virtual.  The first 1K is
591218792Snp *	accessed through virtual addresses starting at 31K, the rest is
592218792Snp *	accessed through virtual addresses starting at 0.
593218792Snp *
594218792Snp *	The mapping is as follows:
595218792Snp *	[0..1K) -> [31K..32K)
596218792Snp *	[1K..1K+A) -> [ES-A..ES)
597218792Snp *	[1K+A..ES) -> [0..ES-A-1K)
598218792Snp *
599218792Snp *	where A = @fn * @sz, and ES = EEPROM size.
600218792Snp */
601218792Snpint t4_eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz)
602218792Snp{
603218792Snp	fn *= sz;
604218792Snp	if (phys_addr < 1024)
605218792Snp		return phys_addr + (31 << 10);
606218792Snp	if (phys_addr < 1024 + fn)
607218792Snp		return EEPROMSIZE - fn + phys_addr - 1024;
608218792Snp	if (phys_addr < EEPROMSIZE)
609218792Snp		return phys_addr - 1024 - fn;
610218792Snp	return -EINVAL;
611218792Snp}
612218792Snp
613218792Snp/**
614218792Snp *	t4_seeprom_wp - enable/disable EEPROM write protection
615218792Snp *	@adapter: the adapter
616218792Snp *	@enable: whether to enable or disable write protection
617218792Snp *
618218792Snp *	Enables or disables write protection on the serial EEPROM.
619218792Snp */
620218792Snpint t4_seeprom_wp(struct adapter *adapter, int enable)
621218792Snp{
622218792Snp	return t4_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
623218792Snp}
624218792Snp
625218792Snp/**
626218792Snp *	get_vpd_keyword_val - Locates an information field keyword in the VPD
627218792Snp *	@v: Pointer to buffered vpd data structure
628218792Snp *	@kw: The keyword to search for
629218792Snp *
630218792Snp *	Returns the value of the information field keyword or
631218792Snp *	-ENOENT otherwise.
632218792Snp */
633218792Snpstatic int get_vpd_keyword_val(const struct t4_vpd_hdr *v, const char *kw)
634218792Snp{
635218792Snp         int i;
636218792Snp	 unsigned int offset , len;
637218792Snp	 const u8 *buf = &v->id_tag;
638218792Snp	 const u8 *vpdr_len = &v->vpdr_tag;
639218792Snp	 offset = sizeof(struct t4_vpd_hdr);
640218792Snp	 len =  (u16)vpdr_len[1] + ((u16)vpdr_len[2] << 8);
641218792Snp
642218792Snp	 if (len + sizeof(struct t4_vpd_hdr) > VPD_LEN) {
643218792Snp		 return -ENOENT;
644218792Snp	 }
645218792Snp
646218792Snp         for (i = offset; i + VPD_INFO_FLD_HDR_SIZE <= offset + len;) {
647218792Snp		 if(memcmp(buf + i , kw , 2) == 0){
648218792Snp			 i += VPD_INFO_FLD_HDR_SIZE;
649218792Snp                         return i;
650218792Snp		  }
651218792Snp
652218792Snp                 i += VPD_INFO_FLD_HDR_SIZE + buf[i+2];
653218792Snp         }
654218792Snp
655218792Snp         return -ENOENT;
656218792Snp}
657218792Snp
658218792Snp
659218792Snp/**
660218792Snp *	get_vpd_params - read VPD parameters from VPD EEPROM
661218792Snp *	@adapter: adapter to read
662218792Snp *	@p: where to store the parameters
663218792Snp *
664218792Snp *	Reads card parameters stored in VPD EEPROM.
665218792Snp */
666218792Snpstatic int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
667218792Snp{
668218792Snp	int i, ret, addr;
669237436Snp	int ec, sn, pn, na;
670218792Snp	u8 vpd[VPD_LEN], csum;
671218792Snp	const struct t4_vpd_hdr *v;
672218792Snp
673218792Snp	/*
674218792Snp	 * Card information normally starts at VPD_BASE but early cards had
675218792Snp	 * it at 0.
676218792Snp	 */
677218792Snp	ret = t4_seeprom_read(adapter, VPD_BASE, (u32 *)(vpd));
678250090Snp	addr = *vpd == CHELSIO_VPD_UNIQUE_ID ? VPD_BASE : VPD_BASE_OLD;
679218792Snp
680218792Snp	for (i = 0; i < sizeof(vpd); i += 4) {
681218792Snp		ret = t4_seeprom_read(adapter, addr + i, (u32 *)(vpd + i));
682218792Snp		if (ret)
683218792Snp			return ret;
684218792Snp	}
685218792Snp 	v = (const struct t4_vpd_hdr *)vpd;
686218792Snp
687218792Snp#define FIND_VPD_KW(var,name) do { \
688218792Snp	var = get_vpd_keyword_val(v , name); \
689218792Snp	if (var < 0) { \
690218792Snp		CH_ERR(adapter, "missing VPD keyword " name "\n"); \
691218792Snp		return -EINVAL; \
692218792Snp	} \
693218792Snp} while (0)
694218792Snp
695218792Snp	FIND_VPD_KW(i, "RV");
696218792Snp	for (csum = 0; i >= 0; i--)
697218792Snp		csum += vpd[i];
698218792Snp
699218792Snp	if (csum) {
700218792Snp		CH_ERR(adapter, "corrupted VPD EEPROM, actual csum %u\n", csum);
701218792Snp		return -EINVAL;
702218792Snp	}
703218792Snp	FIND_VPD_KW(ec, "EC");
704218792Snp	FIND_VPD_KW(sn, "SN");
705237436Snp	FIND_VPD_KW(pn, "PN");
706237436Snp	FIND_VPD_KW(na, "NA");
707218792Snp#undef FIND_VPD_KW
708218792Snp
709218792Snp	memcpy(p->id, v->id_data, ID_LEN);
710218792Snp	strstrip(p->id);
711218792Snp	memcpy(p->ec, vpd + ec, EC_LEN);
712218792Snp	strstrip(p->ec);
713218792Snp	i = vpd[sn - VPD_INFO_FLD_HDR_SIZE + 2];
714218792Snp	memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN));
715218792Snp	strstrip(p->sn);
716250090Snp	i = vpd[pn - VPD_INFO_FLD_HDR_SIZE + 2];
717237436Snp	memcpy(p->pn, vpd + pn, min(i, PN_LEN));
718237436Snp	strstrip((char *)p->pn);
719250090Snp	i = vpd[na - VPD_INFO_FLD_HDR_SIZE + 2];
720237436Snp	memcpy(p->na, vpd + na, min(i, MACADDR_LEN));
721237436Snp	strstrip((char *)p->na);
722218792Snp
723218792Snp	return 0;
724218792Snp}
725218792Snp
726218792Snp/* serial flash and firmware constants and flash config file constants */
727218792Snpenum {
728218792Snp	SF_ATTEMPTS = 10,             /* max retries for SF operations */
729218792Snp
730218792Snp	/* flash command opcodes */
731218792Snp	SF_PROG_PAGE    = 2,          /* program page */
732218792Snp	SF_WR_DISABLE   = 4,          /* disable writes */
733218792Snp	SF_RD_STATUS    = 5,          /* read status register */
734218792Snp	SF_WR_ENABLE    = 6,          /* enable writes */
735218792Snp	SF_RD_DATA_FAST = 0xb,        /* read flash */
736218792Snp	SF_RD_ID        = 0x9f,       /* read ID */
737218792Snp	SF_ERASE_SECTOR = 0xd8,       /* erase sector */
738218792Snp};
739218792Snp
740218792Snp/**
741218792Snp *	sf1_read - read data from the serial flash
742218792Snp *	@adapter: the adapter
743218792Snp *	@byte_cnt: number of bytes to read
744218792Snp *	@cont: whether another operation will be chained
745218792Snp *	@lock: whether to lock SF for PL access only
746218792Snp *	@valp: where to store the read data
747218792Snp *
748218792Snp *	Reads up to 4 bytes of data from the serial flash.  The location of
749218792Snp *	the read needs to be specified prior to calling this by issuing the
750218792Snp *	appropriate commands to the serial flash.
751218792Snp */
752218792Snpstatic int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont,
753218792Snp		    int lock, u32 *valp)
754218792Snp{
755218792Snp	int ret;
756218792Snp
757218792Snp	if (!byte_cnt || byte_cnt > 4)
758218792Snp		return -EINVAL;
759218792Snp	if (t4_read_reg(adapter, A_SF_OP) & F_BUSY)
760218792Snp		return -EBUSY;
761218792Snp	t4_write_reg(adapter, A_SF_OP,
762218792Snp		     V_SF_LOCK(lock) | V_CONT(cont) | V_BYTECNT(byte_cnt - 1));
763218792Snp	ret = t4_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 5);
764218792Snp	if (!ret)
765218792Snp		*valp = t4_read_reg(adapter, A_SF_DATA);
766218792Snp	return ret;
767218792Snp}
768218792Snp
769218792Snp/**
770218792Snp *	sf1_write - write data to the serial flash
771218792Snp *	@adapter: the adapter
772218792Snp *	@byte_cnt: number of bytes to write
773218792Snp *	@cont: whether another operation will be chained
774218792Snp *	@lock: whether to lock SF for PL access only
775218792Snp *	@val: value to write
776218792Snp *
777218792Snp *	Writes up to 4 bytes of data to the serial flash.  The location of
778218792Snp *	the write needs to be specified prior to calling this by issuing the
779218792Snp *	appropriate commands to the serial flash.
780218792Snp */
781218792Snpstatic int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont,
782218792Snp		     int lock, u32 val)
783218792Snp{
784218792Snp	if (!byte_cnt || byte_cnt > 4)
785218792Snp		return -EINVAL;
786218792Snp	if (t4_read_reg(adapter, A_SF_OP) & F_BUSY)
787218792Snp		return -EBUSY;
788218792Snp	t4_write_reg(adapter, A_SF_DATA, val);
789218792Snp	t4_write_reg(adapter, A_SF_OP, V_SF_LOCK(lock) |
790218792Snp		     V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1));
791218792Snp	return t4_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 5);
792218792Snp}
793218792Snp
794218792Snp/**
795218792Snp *	flash_wait_op - wait for a flash operation to complete
796218792Snp *	@adapter: the adapter
797218792Snp *	@attempts: max number of polls of the status register
798218792Snp *	@delay: delay between polls in ms
799218792Snp *
800218792Snp *	Wait for a flash operation to complete by polling the status register.
801218792Snp */
802218792Snpstatic int flash_wait_op(struct adapter *adapter, int attempts, int delay)
803218792Snp{
804218792Snp	int ret;
805218792Snp	u32 status;
806218792Snp
807218792Snp	while (1) {
808218792Snp		if ((ret = sf1_write(adapter, 1, 1, 1, SF_RD_STATUS)) != 0 ||
809218792Snp		    (ret = sf1_read(adapter, 1, 0, 1, &status)) != 0)
810218792Snp			return ret;
811218792Snp		if (!(status & 1))
812218792Snp			return 0;
813218792Snp		if (--attempts == 0)
814218792Snp			return -EAGAIN;
815218792Snp		if (delay)
816218792Snp			msleep(delay);
817218792Snp	}
818218792Snp}
819218792Snp
820218792Snp/**
821218792Snp *	t4_read_flash - read words from serial flash
822218792Snp *	@adapter: the adapter
823218792Snp *	@addr: the start address for the read
824218792Snp *	@nwords: how many 32-bit words to read
825218792Snp *	@data: where to store the read data
826218792Snp *	@byte_oriented: whether to store data as bytes or as words
827218792Snp *
828218792Snp *	Read the specified number of 32-bit words from the serial flash.
829218792Snp *	If @byte_oriented is set the read data is stored as a byte array
830218792Snp *	(i.e., big-endian), otherwise as 32-bit words in the platform's
831218792Snp *	natural endianess.
832218792Snp */
833218792Snpint t4_read_flash(struct adapter *adapter, unsigned int addr,
834218792Snp		  unsigned int nwords, u32 *data, int byte_oriented)
835218792Snp{
836218792Snp	int ret;
837218792Snp
838218792Snp	if (addr + nwords * sizeof(u32) > adapter->params.sf_size || (addr & 3))
839218792Snp		return -EINVAL;
840218792Snp
841218792Snp	addr = swab32(addr) | SF_RD_DATA_FAST;
842218792Snp
843218792Snp	if ((ret = sf1_write(adapter, 4, 1, 0, addr)) != 0 ||
844218792Snp	    (ret = sf1_read(adapter, 1, 1, 0, data)) != 0)
845218792Snp		return ret;
846218792Snp
847218792Snp	for ( ; nwords; nwords--, data++) {
848218792Snp		ret = sf1_read(adapter, 4, nwords > 1, nwords == 1, data);
849218792Snp		if (nwords == 1)
850218792Snp			t4_write_reg(adapter, A_SF_OP, 0);    /* unlock SF */
851218792Snp		if (ret)
852218792Snp			return ret;
853218792Snp		if (byte_oriented)
854218792Snp			*data = htonl(*data);
855218792Snp	}
856218792Snp	return 0;
857218792Snp}
858218792Snp
859218792Snp/**
860218792Snp *	t4_write_flash - write up to a page of data to the serial flash
861218792Snp *	@adapter: the adapter
862218792Snp *	@addr: the start address to write
863218792Snp *	@n: length of data to write in bytes
864218792Snp *	@data: the data to write
865228561Snp *	@byte_oriented: whether to store data as bytes or as words
866218792Snp *
867218792Snp *	Writes up to a page of data (256 bytes) to the serial flash starting
868218792Snp *	at the given address.  All the data must be written to the same page.
869228561Snp *	If @byte_oriented is set the write data is stored as byte stream
870228561Snp *	(i.e. matches what on disk), otherwise in big-endian.
871218792Snp */
872218792Snpstatic int t4_write_flash(struct adapter *adapter, unsigned int addr,
873228561Snp			  unsigned int n, const u8 *data, int byte_oriented)
874218792Snp{
875218792Snp	int ret;
876218792Snp	u32 buf[SF_PAGE_SIZE / 4];
877218792Snp	unsigned int i, c, left, val, offset = addr & 0xff;
878218792Snp
879218792Snp	if (addr >= adapter->params.sf_size || offset + n > SF_PAGE_SIZE)
880218792Snp		return -EINVAL;
881218792Snp
882218792Snp	val = swab32(addr) | SF_PROG_PAGE;
883218792Snp
884218792Snp	if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 ||
885218792Snp	    (ret = sf1_write(adapter, 4, 1, 1, val)) != 0)
886218792Snp		goto unlock;
887218792Snp
888218792Snp	for (left = n; left; left -= c) {
889218792Snp		c = min(left, 4U);
890218792Snp		for (val = 0, i = 0; i < c; ++i)
891218792Snp			val = (val << 8) + *data++;
892218792Snp
893228561Snp		if (!byte_oriented)
894228561Snp			val = htonl(val);
895228561Snp
896218792Snp		ret = sf1_write(adapter, c, c != left, 1, val);
897218792Snp		if (ret)
898218792Snp			goto unlock;
899218792Snp	}
900218792Snp	ret = flash_wait_op(adapter, 8, 1);
901218792Snp	if (ret)
902218792Snp		goto unlock;
903218792Snp
904218792Snp	t4_write_reg(adapter, A_SF_OP, 0);    /* unlock SF */
905218792Snp
906218792Snp	/* Read the page to verify the write succeeded */
907228561Snp	ret = t4_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf,
908228561Snp			    byte_oriented);
909218792Snp	if (ret)
910218792Snp		return ret;
911218792Snp
912218792Snp	if (memcmp(data - n, (u8 *)buf + offset, n)) {
913218792Snp		CH_ERR(adapter, "failed to correctly write the flash page "
914218792Snp		       "at %#x\n", addr);
915218792Snp		return -EIO;
916218792Snp	}
917218792Snp	return 0;
918218792Snp
919218792Snpunlock:
920218792Snp	t4_write_reg(adapter, A_SF_OP, 0);    /* unlock SF */
921218792Snp	return ret;
922218792Snp}
923218792Snp
924218792Snp/**
925218792Snp *	t4_get_fw_version - read the firmware version
926218792Snp *	@adapter: the adapter
927218792Snp *	@vers: where to place the version
928218792Snp *
929218792Snp *	Reads the FW version from flash.
930218792Snp */
931218792Snpint t4_get_fw_version(struct adapter *adapter, u32 *vers)
932218792Snp{
933218792Snp	return t4_read_flash(adapter,
934228561Snp			     FLASH_FW_START + offsetof(struct fw_hdr, fw_ver), 1,
935218792Snp			     vers, 0);
936218792Snp}
937218792Snp
938218792Snp/**
939218792Snp *	t4_get_tp_version - read the TP microcode version
940218792Snp *	@adapter: the adapter
941218792Snp *	@vers: where to place the version
942218792Snp *
943218792Snp *	Reads the TP microcode version from flash.
944218792Snp */
945218792Snpint t4_get_tp_version(struct adapter *adapter, u32 *vers)
946218792Snp{
947228561Snp	return t4_read_flash(adapter, FLASH_FW_START + offsetof(struct fw_hdr,
948218792Snp							      tp_microcode_ver),
949218792Snp			     1, vers, 0);
950218792Snp}
951218792Snp
952218792Snp/**
953218792Snp *	t4_check_fw_version - check if the FW is compatible with this driver
954218792Snp *	@adapter: the adapter
955218792Snp *
956218792Snp *	Checks if an adapter's FW is compatible with the driver.  Returns 0
957218792Snp *	if there's exact match, a negative error if the version could not be
958218792Snp *	read or there's a major version mismatch, and a positive value if the
959218792Snp *	expected major version is found but there's a minor version mismatch.
960218792Snp */
961218792Snpint t4_check_fw_version(struct adapter *adapter)
962218792Snp{
963218792Snp	int ret, major, minor, micro;
964248925Snp	int exp_major, exp_minor, exp_micro;
965218792Snp
966218792Snp	ret = t4_get_fw_version(adapter, &adapter->params.fw_vers);
967218792Snp	if (!ret)
968218792Snp		ret = t4_get_tp_version(adapter, &adapter->params.tp_vers);
969218792Snp	if (ret)
970218792Snp		return ret;
971218792Snp
972218792Snp	major = G_FW_HDR_FW_VER_MAJOR(adapter->params.fw_vers);
973218792Snp	minor = G_FW_HDR_FW_VER_MINOR(adapter->params.fw_vers);
974218792Snp	micro = G_FW_HDR_FW_VER_MICRO(adapter->params.fw_vers);
975218792Snp
976248925Snp	switch (chip_id(adapter)) {
977248925Snp	case CHELSIO_T4:
978252661Snp		exp_major = T4FW_VERSION_MAJOR;
979252661Snp		exp_minor = T4FW_VERSION_MINOR;
980252661Snp		exp_micro = T4FW_VERSION_MICRO;
981248925Snp		break;
982248925Snp	case CHELSIO_T5:
983252661Snp		exp_major = T5FW_VERSION_MAJOR;
984252661Snp		exp_minor = T5FW_VERSION_MINOR;
985252661Snp		exp_micro = T5FW_VERSION_MICRO;
986248925Snp		break;
987248925Snp	default:
988248925Snp		CH_ERR(adapter, "Unsupported chip type, %x\n",
989248925Snp		    chip_id(adapter));
990248925Snp		return -EINVAL;
991248925Snp	}
992248925Snp
993248925Snp	if (major != exp_major) {            /* major mismatch - fail */
994218792Snp		CH_ERR(adapter, "card FW has major version %u, driver wants "
995248925Snp		       "%u\n", major, exp_major);
996218792Snp		return -EINVAL;
997218792Snp	}
998218792Snp
999248925Snp	if (minor == exp_minor && micro == exp_micro)
1000218792Snp		return 0;                                   /* perfect match */
1001218792Snp
1002218792Snp	/* Minor/micro version mismatch.  Report it but often it's OK. */
1003218792Snp	return 1;
1004218792Snp}
1005218792Snp
1006218792Snp/**
1007218792Snp *	t4_flash_erase_sectors - erase a range of flash sectors
1008218792Snp *	@adapter: the adapter
1009218792Snp *	@start: the first sector to erase
1010218792Snp *	@end: the last sector to erase
1011218792Snp *
1012218792Snp *	Erases the sectors in the given inclusive range.
1013218792Snp */
1014218792Snpstatic int t4_flash_erase_sectors(struct adapter *adapter, int start, int end)
1015218792Snp{
1016218792Snp	int ret = 0;
1017218792Snp
1018218792Snp	while (start <= end) {
1019218792Snp		if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 ||
1020218792Snp		    (ret = sf1_write(adapter, 4, 0, 1,
1021218792Snp				     SF_ERASE_SECTOR | (start << 8))) != 0 ||
1022218792Snp		    (ret = flash_wait_op(adapter, 14, 500)) != 0) {
1023218792Snp			CH_ERR(adapter, "erase of flash sector %d failed, "
1024218792Snp			       "error %d\n", start, ret);
1025218792Snp			break;
1026218792Snp		}
1027218792Snp		start++;
1028218792Snp	}
1029218792Snp	t4_write_reg(adapter, A_SF_OP, 0);    /* unlock SF */
1030218792Snp	return ret;
1031218792Snp}
1032218792Snp
1033218792Snp/**
1034228561Snp *	t4_flash_cfg_addr - return the address of the flash configuration file
1035228561Snp *	@adapter: the adapter
1036228561Snp *
1037228561Snp *	Return the address within the flash where the Firmware Configuration
1038250090Snp *	File is stored, or an error if the device FLASH is too small to contain
1039250090Snp *	a Firmware Configuration File.
1040228561Snp */
1041250090Snpint t4_flash_cfg_addr(struct adapter *adapter)
1042228561Snp{
1043250090Snp	/*
1044250090Snp	 * If the device FLASH isn't large enough to hold a Firmware
1045250090Snp	 * Configuration File, return an error.
1046250090Snp	 */
1047250090Snp	if (adapter->params.sf_size < FLASH_CFG_START + FLASH_CFG_MAX_SIZE)
1048250090Snp		return -ENOSPC;
1049250090Snp
1050250090Snp	return FLASH_CFG_START;
1051228561Snp}
1052228561Snp
1053228561Snp/**
1054218792Snp *	t4_load_cfg - download config file
1055218792Snp *	@adap: the adapter
1056218792Snp *	@cfg_data: the cfg text file to write
1057218792Snp *	@size: text file size
1058218792Snp *
1059218792Snp *	Write the supplied config text file to the card's serial flash.
1060218792Snp */
1061218792Snpint t4_load_cfg(struct adapter *adap, const u8 *cfg_data, unsigned int size)
1062218792Snp{
1063250090Snp	int ret, i, n, cfg_addr;
1064218792Snp	unsigned int addr;
1065218792Snp	unsigned int flash_cfg_start_sec;
1066218792Snp	unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
1067218792Snp
1068250090Snp	cfg_addr = t4_flash_cfg_addr(adap);
1069250090Snp	if (cfg_addr < 0)
1070250090Snp		return cfg_addr;
1071250090Snp
1072250090Snp	addr = cfg_addr;
1073228561Snp	flash_cfg_start_sec = addr / SF_SEC_SIZE;
1074218792Snp
1075218792Snp	if (size > FLASH_CFG_MAX_SIZE) {
1076218792Snp		CH_ERR(adap, "cfg file too large, max is %u bytes\n",
1077218792Snp		       FLASH_CFG_MAX_SIZE);
1078218792Snp		return -EFBIG;
1079218792Snp	}
1080218792Snp
1081218792Snp	i = DIV_ROUND_UP(FLASH_CFG_MAX_SIZE,	/* # of sectors spanned */
1082218792Snp			 sf_sec_size);
1083218792Snp	ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec,
1084218792Snp				     flash_cfg_start_sec + i - 1);
1085228561Snp	/*
1086228561Snp	 * If size == 0 then we're simply erasing the FLASH sectors associated
1087228561Snp	 * with the on-adapter Firmware Configuration File.
1088228561Snp	 */
1089228561Snp	if (ret || size == 0)
1090218792Snp		goto out;
1091218792Snp
1092237436Snp	/* this will write to the flash up to SF_PAGE_SIZE at a time */
1093218792Snp	for (i = 0; i< size; i+= SF_PAGE_SIZE) {
1094218792Snp		if ( (size - i) <  SF_PAGE_SIZE)
1095218792Snp			n = size - i;
1096218792Snp		else
1097218792Snp			n = SF_PAGE_SIZE;
1098228561Snp		ret = t4_write_flash(adap, addr, n, cfg_data, 1);
1099218792Snp		if (ret)
1100218792Snp			goto out;
1101218792Snp
1102218792Snp		addr += SF_PAGE_SIZE;
1103218792Snp		cfg_data += SF_PAGE_SIZE;
1104218792Snp	}
1105218792Snp
1106218792Snpout:
1107218792Snp	if (ret)
1108228561Snp		CH_ERR(adap, "config file %s failed %d\n",
1109228561Snp		       (size == 0 ? "clear" : "download"), ret);
1110218792Snp	return ret;
1111218792Snp}
1112218792Snp
1113218792Snp
1114218792Snp/**
1115218792Snp *	t4_load_fw - download firmware
1116218792Snp *	@adap: the adapter
1117218792Snp *	@fw_data: the firmware image to write
1118218792Snp *	@size: image size
1119218792Snp *
1120218792Snp *	Write the supplied firmware image to the card's serial flash.
1121218792Snp */
1122218792Snpint t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
1123218792Snp{
1124218792Snp	u32 csum;
1125218792Snp	int ret, addr;
1126218792Snp	unsigned int i;
1127218792Snp	u8 first_page[SF_PAGE_SIZE];
1128218792Snp	const u32 *p = (const u32 *)fw_data;
1129218792Snp	const struct fw_hdr *hdr = (const struct fw_hdr *)fw_data;
1130218792Snp	unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
1131252661Snp	unsigned int fw_start_sec;
1132252661Snp	unsigned int fw_start;
1133252661Snp	unsigned int fw_size;
1134218792Snp
1135252661Snp	if (ntohl(hdr->magic) == FW_HDR_MAGIC_BOOTSTRAP) {
1136252661Snp		fw_start_sec = FLASH_FWBOOTSTRAP_START_SEC;
1137252661Snp		fw_start = FLASH_FWBOOTSTRAP_START;
1138252661Snp		fw_size = FLASH_FWBOOTSTRAP_MAX_SIZE;
1139252661Snp	} else {
1140252661Snp		fw_start_sec = FLASH_FW_START_SEC;
1141252661Snp 		fw_start = FLASH_FW_START;
1142252661Snp		fw_size = FLASH_FW_MAX_SIZE;
1143252661Snp	}
1144218792Snp	if (!size) {
1145218792Snp		CH_ERR(adap, "FW image has no data\n");
1146218792Snp		return -EINVAL;
1147218792Snp	}
1148218792Snp	if (size & 511) {
1149218792Snp		CH_ERR(adap, "FW image size not multiple of 512 bytes\n");
1150218792Snp		return -EINVAL;
1151218792Snp	}
1152218792Snp	if (ntohs(hdr->len512) * 512 != size) {
1153218792Snp		CH_ERR(adap, "FW image size differs from size in FW header\n");
1154218792Snp		return -EINVAL;
1155218792Snp	}
1156252661Snp	if (size > fw_size) {
1157252661Snp		CH_ERR(adap, "FW image too large, max is %u bytes\n", fw_size);
1158218792Snp		return -EFBIG;
1159218792Snp	}
1160249629Snp	if ((is_t4(adap) && hdr->chip != FW_HDR_CHIP_T4) ||
1161249629Snp	    (is_t5(adap) && hdr->chip != FW_HDR_CHIP_T5)) {
1162249629Snp		CH_ERR(adap,
1163249629Snp		    "FW image (%d) is not suitable for this adapter (%d)\n",
1164249629Snp		    hdr->chip, chip_id(adap));
1165249629Snp		return -EINVAL;
1166249629Snp	}
1167218792Snp
1168218792Snp	for (csum = 0, i = 0; i < size / sizeof(csum); i++)
1169218792Snp		csum += ntohl(p[i]);
1170218792Snp
1171218792Snp	if (csum != 0xffffffff) {
1172218792Snp		CH_ERR(adap, "corrupted firmware image, checksum %#x\n",
1173218792Snp		       csum);
1174218792Snp		return -EINVAL;
1175218792Snp	}
1176218792Snp
1177218792Snp	i = DIV_ROUND_UP(size, sf_sec_size);        /* # of sectors spanned */
1178252661Snp	ret = t4_flash_erase_sectors(adap, fw_start_sec, fw_start_sec + i - 1);
1179218792Snp	if (ret)
1180218792Snp		goto out;
1181218792Snp
1182218792Snp	/*
1183218792Snp	 * We write the correct version at the end so the driver can see a bad
1184218792Snp	 * version if the FW write fails.  Start by writing a copy of the
1185218792Snp	 * first page with a bad version.
1186218792Snp	 */
1187218792Snp	memcpy(first_page, fw_data, SF_PAGE_SIZE);
1188218792Snp	((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff);
1189252661Snp	ret = t4_write_flash(adap, fw_start, SF_PAGE_SIZE, first_page, 1);
1190218792Snp	if (ret)
1191218792Snp		goto out;
1192218792Snp
1193252661Snp	addr = fw_start;
1194218792Snp	for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) {
1195218792Snp		addr += SF_PAGE_SIZE;
1196218792Snp		fw_data += SF_PAGE_SIZE;
1197228561Snp		ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, fw_data, 1);
1198218792Snp		if (ret)
1199218792Snp			goto out;
1200218792Snp	}
1201218792Snp
1202218792Snp	ret = t4_write_flash(adap,
1203252661Snp			     fw_start + offsetof(struct fw_hdr, fw_ver),
1204228561Snp			     sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver, 1);
1205218792Snpout:
1206218792Snp	if (ret)
1207218792Snp		CH_ERR(adap, "firmware download failed, error %d\n", ret);
1208218792Snp	return ret;
1209218792Snp}
1210218792Snp
1211237436Snp/* BIOS boot headers */
1212237436Snptypedef struct pci_expansion_rom_header {
1213237436Snp	u8	signature[2]; /* ROM Signature. Should be 0xaa55 */
1214237436Snp	u8	reserved[22]; /* Reserved per processor Architecture data */
1215237436Snp	u8	pcir_offset[2]; /* Offset to PCI Data Structure */
1216237436Snp} pci_exp_rom_header_t; /* PCI_EXPANSION_ROM_HEADER */
1217228561Snp
1218237436Snp/* Legacy PCI Expansion ROM Header */
1219237436Snptypedef struct legacy_pci_expansion_rom_header {
1220237436Snp	u8	signature[2]; /* ROM Signature. Should be 0xaa55 */
1221237436Snp	u8	size512; /* Current Image Size in units of 512 bytes */
1222237436Snp	u8	initentry_point[4];
1223237436Snp	u8	cksum; /* Checksum computed on the entire Image */
1224237436Snp	u8	reserved[16]; /* Reserved */
1225237436Snp	u8	pcir_offset[2]; /* Offset to PCI Data Struture */
1226237436Snp} legacy_pci_exp_rom_header_t; /* LEGACY_PCI_EXPANSION_ROM_HEADER */
1227237436Snp
1228237436Snp/* EFI PCI Expansion ROM Header */
1229237436Snptypedef struct efi_pci_expansion_rom_header {
1230237436Snp	u8	signature[2]; // ROM signature. The value 0xaa55
1231237436Snp	u8	initialization_size[2]; /* Units 512. Includes this header */
1232237436Snp	u8	efi_signature[4]; /* Signature from EFI image header. 0x0EF1 */
1233237436Snp	u8	efi_subsystem[2]; /* Subsystem value for EFI image header */
1234237436Snp	u8	efi_machine_type[2]; /* Machine type from EFI image header */
1235237436Snp	u8	compression_type[2]; /* Compression type. */
1236237436Snp		/*
1237237436Snp		 * Compression type definition
1238237436Snp		 * 0x0: uncompressed
1239237436Snp		 * 0x1: Compressed
1240237436Snp		 * 0x2-0xFFFF: Reserved
1241237436Snp		 */
1242237436Snp	u8	reserved[8]; /* Reserved */
1243237436Snp	u8	efi_image_header_offset[2]; /* Offset to EFI Image */
1244237436Snp	u8	pcir_offset[2]; /* Offset to PCI Data Structure */
1245237436Snp} efi_pci_exp_rom_header_t; /* EFI PCI Expansion ROM Header */
1246237436Snp
1247237436Snp/* PCI Data Structure Format */
1248237436Snptypedef struct pcir_data_structure { /* PCI Data Structure */
1249237436Snp	u8	signature[4]; /* Signature. The string "PCIR" */
1250237436Snp	u8	vendor_id[2]; /* Vendor Identification */
1251237436Snp	u8	device_id[2]; /* Device Identification */
1252237436Snp	u8	vital_product[2]; /* Pointer to Vital Product Data */
1253237436Snp	u8	length[2]; /* PCIR Data Structure Length */
1254237436Snp	u8	revision; /* PCIR Data Structure Revision */
1255237436Snp	u8	class_code[3]; /* Class Code */
1256237436Snp	u8	image_length[2]; /* Image Length. Multiple of 512B */
1257237436Snp	u8	code_revision[2]; /* Revision Level of Code/Data */
1258237436Snp	u8	code_type; /* Code Type. */
1259237436Snp		/*
1260237436Snp		 * PCI Expansion ROM Code Types
1261237436Snp		 * 0x00: Intel IA-32, PC-AT compatible. Legacy
1262237436Snp		 * 0x01: Open Firmware standard for PCI. FCODE
1263237436Snp		 * 0x02: Hewlett-Packard PA RISC. HP reserved
1264237436Snp		 * 0x03: EFI Image. EFI
1265237436Snp		 * 0x04-0xFF: Reserved.
1266237436Snp		 */
1267237436Snp	u8	indicator; /* Indicator. Identifies the last image in the ROM */
1268237436Snp	u8	reserved[2]; /* Reserved */
1269237436Snp} pcir_data_t; /* PCI__DATA_STRUCTURE */
1270237436Snp
1271237436Snp/* BOOT constants */
1272228561Snpenum {
1273228561Snp	BOOT_FLASH_BOOT_ADDR = 0x0,/* start address of boot image in flash */
1274228561Snp	BOOT_SIGNATURE = 0xaa55,   /* signature of BIOS boot ROM */
1275228561Snp	BOOT_SIZE_INC = 512,       /* image size measured in 512B chunks */
1276237436Snp	BOOT_MIN_SIZE = sizeof(pci_exp_rom_header_t), /* basic header */
1277237436Snp	BOOT_MAX_SIZE = 1024*BOOT_SIZE_INC, /* 1 byte * length increment  */
1278237436Snp	VENDOR_ID = 0x1425, /* Vendor ID */
1279237436Snp	PCIR_SIGNATURE = 0x52494350 /* PCIR signature */
1280228561Snp};
1281228561Snp
1282228561Snp/*
1283237436Snp *	modify_device_id - Modifies the device ID of the Boot BIOS image
1284237436Snp *	@adatper: the device ID to write.
1285237436Snp *	@boot_data: the boot image to modify.
1286237436Snp *
1287237436Snp *	Write the supplied device ID to the boot BIOS image.
1288237436Snp */
1289237436Snpstatic void modify_device_id(int device_id, u8 *boot_data)
1290237436Snp{
1291237436Snp	legacy_pci_exp_rom_header_t *header;
1292237436Snp	pcir_data_t *pcir_header;
1293237436Snp	u32 cur_header = 0;
1294237436Snp
1295237436Snp	/*
1296237436Snp	 * Loop through all chained images and change the device ID's
1297237436Snp	 */
1298237436Snp	while (1) {
1299237436Snp		header = (legacy_pci_exp_rom_header_t *) &boot_data[cur_header];
1300237436Snp		pcir_header = (pcir_data_t *) &boot_data[cur_header +
1301237436Snp		    le16_to_cpu(*(u16*)header->pcir_offset)];
1302237436Snp
1303237436Snp		/*
1304237436Snp		 * Only modify the Device ID if code type is Legacy or HP.
1305237436Snp		 * 0x00: Okay to modify
1306237436Snp		 * 0x01: FCODE. Do not be modify
1307237436Snp		 * 0x03: Okay to modify
1308237436Snp		 * 0x04-0xFF: Do not modify
1309237436Snp		 */
1310237436Snp		if (pcir_header->code_type == 0x00) {
1311237436Snp			u8 csum = 0;
1312237436Snp			int i;
1313237436Snp
1314237436Snp			/*
1315237436Snp			 * Modify Device ID to match current adatper
1316237436Snp			 */
1317237436Snp			*(u16*) pcir_header->device_id = device_id;
1318237436Snp
1319237436Snp			/*
1320237436Snp			 * Set checksum temporarily to 0.
1321237436Snp			 * We will recalculate it later.
1322237436Snp			 */
1323237436Snp			header->cksum = 0x0;
1324237436Snp
1325237436Snp			/*
1326237436Snp			 * Calculate and update checksum
1327237436Snp			 */
1328237436Snp			for (i = 0; i < (header->size512 * 512); i++)
1329237436Snp				csum += (u8)boot_data[cur_header + i];
1330237436Snp
1331237436Snp			/*
1332237436Snp			 * Invert summed value to create the checksum
1333237436Snp			 * Writing new checksum value directly to the boot data
1334237436Snp			 */
1335237436Snp			boot_data[cur_header + 7] = -csum;
1336237436Snp
1337237436Snp		} else if (pcir_header->code_type == 0x03) {
1338237436Snp
1339237436Snp			/*
1340237436Snp			 * Modify Device ID to match current adatper
1341237436Snp			 */
1342237436Snp			*(u16*) pcir_header->device_id = device_id;
1343237436Snp
1344237436Snp		}
1345237436Snp
1346237436Snp
1347237436Snp		/*
1348237436Snp		 * Check indicator element to identify if this is the last
1349237436Snp		 * image in the ROM.
1350237436Snp		 */
1351237436Snp		if (pcir_header->indicator & 0x80)
1352237436Snp			break;
1353237436Snp
1354237436Snp		/*
1355237436Snp		 * Move header pointer up to the next image in the ROM.
1356237436Snp		 */
1357237436Snp		cur_header += header->size512 * 512;
1358237436Snp	}
1359237436Snp}
1360237436Snp
1361237436Snp/*
1362228561Snp *	t4_load_boot - download boot flash
1363228561Snp *	@adapter: the adapter
1364228561Snp *	@boot_data: the boot image to write
1365237436Snp *	@boot_addr: offset in flash to write boot_data
1366228561Snp *	@size: image size
1367228561Snp *
1368228561Snp *	Write the supplied boot image to the card's serial flash.
1369228561Snp *	The boot image has the following sections: a 28-byte header and the
1370228561Snp *	boot image.
1371228561Snp */
1372237436Snpint t4_load_boot(struct adapter *adap, u8 *boot_data,
1373228561Snp		 unsigned int boot_addr, unsigned int size)
1374228561Snp{
1375237436Snp	pci_exp_rom_header_t *header;
1376237436Snp	int pcir_offset ;
1377237436Snp	pcir_data_t *pcir_header;
1378228561Snp	int ret, addr;
1379237436Snp	uint16_t device_id;
1380228561Snp	unsigned int i;
1381228561Snp	unsigned int boot_sector = boot_addr * 1024;
1382228561Snp	unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
1383228561Snp
1384228561Snp	/*
1385237436Snp	 * Make sure the boot image does not encroach on the firmware region
1386237436Snp	 */
1387237436Snp	if ((boot_sector + size) >> 16 > FLASH_FW_START_SEC) {
1388237436Snp		CH_ERR(adap, "boot image encroaching on firmware region\n");
1389237436Snp		return -EFBIG;
1390237436Snp	}
1391237436Snp
1392237436Snp	/*
1393237436Snp	 * Number of sectors spanned
1394237436Snp	 */
1395237436Snp	i = DIV_ROUND_UP(size ? size : FLASH_BOOTCFG_MAX_SIZE,
1396237436Snp			sf_sec_size);
1397237436Snp	ret = t4_flash_erase_sectors(adap, boot_sector >> 16,
1398237436Snp				     (boot_sector >> 16) + i - 1);
1399237436Snp
1400237436Snp	/*
1401237436Snp	 * If size == 0 then we're simply erasing the FLASH sectors associated
1402237436Snp	 * with the on-adapter option ROM file
1403237436Snp	 */
1404237436Snp	if (ret || (size == 0))
1405237436Snp		goto out;
1406237436Snp
1407237436Snp	/* Get boot header */
1408237436Snp	header = (pci_exp_rom_header_t *)boot_data;
1409237436Snp	pcir_offset = le16_to_cpu(*(u16 *)header->pcir_offset);
1410237436Snp	/* PCIR Data Structure */
1411237436Snp	pcir_header = (pcir_data_t *) &boot_data[pcir_offset];
1412237436Snp
1413237436Snp	/*
1414228561Snp	 * Perform some primitive sanity testing to avoid accidentally
1415228561Snp	 * writing garbage over the boot sectors.  We ought to check for
1416228561Snp	 * more but it's not worth it for now ...
1417228561Snp	 */
1418228561Snp	if (size < BOOT_MIN_SIZE || size > BOOT_MAX_SIZE) {
1419228561Snp		CH_ERR(adap, "boot image too small/large\n");
1420228561Snp		return -EFBIG;
1421228561Snp	}
1422228561Snp
1423228561Snp	/*
1424237436Snp	 * Check BOOT ROM header signature
1425228561Snp	 */
1426237436Snp	if (le16_to_cpu(*(u16*)header->signature) != BOOT_SIGNATURE ) {
1427237436Snp		CH_ERR(adap, "Boot image missing signature\n");
1428237436Snp		return -EINVAL;
1429228561Snp	}
1430228561Snp
1431237436Snp	/*
1432237436Snp	 * Check PCI header signature
1433237436Snp	 */
1434237436Snp	if (le32_to_cpu(*(u32*)pcir_header->signature) != PCIR_SIGNATURE) {
1435237436Snp		CH_ERR(adap, "PCI header missing signature\n");
1436237436Snp		return -EINVAL;
1437237436Snp	}
1438228561Snp
1439228561Snp	/*
1440237436Snp	 * Check Vendor ID matches Chelsio ID
1441237436Snp	 */
1442237436Snp	if (le16_to_cpu(*(u16*)pcir_header->vendor_id) != VENDOR_ID) {
1443237436Snp		CH_ERR(adap, "Vendor ID missing signature\n");
1444237436Snp		return -EINVAL;
1445237436Snp	}
1446237436Snp
1447237436Snp	/*
1448237436Snp	 * Retrieve adapter's device ID
1449237436Snp	 */
1450237436Snp	t4_os_pci_read_cfg2(adap, PCI_DEVICE_ID, &device_id);
1451237436Snp	/* Want to deal with PF 0 so I strip off PF 4 indicator */
1452237436Snp	device_id = (device_id & 0xff) | 0x4000;
1453237436Snp
1454237436Snp	/*
1455237436Snp	 * Check PCIE Device ID
1456237436Snp	 */
1457237436Snp	if (le16_to_cpu(*(u16*)pcir_header->device_id) != device_id) {
1458237436Snp		/*
1459237436Snp		 * Change the device ID in the Boot BIOS image to match
1460237436Snp		 * the Device ID of the current adapter.
1461237436Snp		 */
1462237436Snp		modify_device_id(device_id, boot_data);
1463237436Snp	}
1464237436Snp
1465237436Snp	/*
1466228561Snp	 * Skip over the first SF_PAGE_SIZE worth of data and write it after
1467228561Snp	 * we finish copying the rest of the boot image. This will ensure
1468228561Snp	 * that the BIOS boot header will only be written if the boot image
1469228561Snp	 * was written in full.
1470228561Snp	 */
1471228561Snp	addr = boot_sector;
1472228561Snp	for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) {
1473228561Snp		addr += SF_PAGE_SIZE;
1474228561Snp		boot_data += SF_PAGE_SIZE;
1475228561Snp		ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, boot_data, 0);
1476228561Snp		if (ret)
1477228561Snp			goto out;
1478228561Snp	}
1479228561Snp
1480228561Snp	ret = t4_write_flash(adap, boot_sector, SF_PAGE_SIZE, boot_data, 0);
1481228561Snp
1482228561Snpout:
1483228561Snp	if (ret)
1484228561Snp		CH_ERR(adap, "boot image download failed, error %d\n", ret);
1485228561Snp	return ret;
1486228561Snp}
1487228561Snp
1488218792Snp/**
1489218792Snp *	t4_read_cimq_cfg - read CIM queue configuration
1490218792Snp *	@adap: the adapter
1491218792Snp *	@base: holds the queue base addresses in bytes
1492218792Snp *	@size: holds the queue sizes in bytes
1493218792Snp *	@thres: holds the queue full thresholds in bytes
1494218792Snp *
1495218792Snp *	Returns the current configuration of the CIM queues, starting with
1496218792Snp *	the IBQs, then the OBQs.
1497218792Snp */
1498218792Snpvoid t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres)
1499218792Snp{
1500218792Snp	unsigned int i, v;
1501248925Snp	int cim_num_obq = is_t4(adap) ? CIM_NUM_OBQ : CIM_NUM_OBQ_T5;
1502218792Snp
1503218792Snp	for (i = 0; i < CIM_NUM_IBQ; i++) {
1504218792Snp		t4_write_reg(adap, A_CIM_QUEUE_CONFIG_REF, F_IBQSELECT |
1505218792Snp			     V_QUENUMSELECT(i));
1506218792Snp		v = t4_read_reg(adap, A_CIM_QUEUE_CONFIG_CTRL);
1507218792Snp		*base++ = G_CIMQBASE(v) * 256; /* value is in 256-byte units */
1508218792Snp		*size++ = G_CIMQSIZE(v) * 256; /* value is in 256-byte units */
1509218792Snp		*thres++ = G_QUEFULLTHRSH(v) * 8;   /* 8-byte unit */
1510218792Snp	}
1511248925Snp	for (i = 0; i < cim_num_obq; i++) {
1512218792Snp		t4_write_reg(adap, A_CIM_QUEUE_CONFIG_REF, F_OBQSELECT |
1513218792Snp			     V_QUENUMSELECT(i));
1514218792Snp		v = t4_read_reg(adap, A_CIM_QUEUE_CONFIG_CTRL);
1515218792Snp		*base++ = G_CIMQBASE(v) * 256; /* value is in 256-byte units */
1516218792Snp		*size++ = G_CIMQSIZE(v) * 256; /* value is in 256-byte units */
1517218792Snp	}
1518218792Snp}
1519218792Snp
1520218792Snp/**
1521218792Snp *	t4_read_cim_ibq - read the contents of a CIM inbound queue
1522218792Snp *	@adap: the adapter
1523218792Snp *	@qid: the queue index
1524218792Snp *	@data: where to store the queue contents
1525218792Snp *	@n: capacity of @data in 32-bit words
1526218792Snp *
1527218792Snp *	Reads the contents of the selected CIM queue starting at address 0 up
1528218792Snp *	to the capacity of @data.  @n must be a multiple of 4.  Returns < 0 on
1529218792Snp *	error and the number of 32-bit words actually read on success.
1530218792Snp */
1531218792Snpint t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data, size_t n)
1532218792Snp{
1533218792Snp	int i, err;
1534218792Snp	unsigned int addr;
1535218792Snp	const unsigned int nwords = CIM_IBQ_SIZE * 4;
1536218792Snp
1537218792Snp	if (qid > 5 || (n & 3))
1538218792Snp		return -EINVAL;
1539218792Snp
1540218792Snp	addr = qid * nwords;
1541218792Snp	if (n > nwords)
1542218792Snp		n = nwords;
1543218792Snp
1544218792Snp	for (i = 0; i < n; i++, addr++) {
1545218792Snp		t4_write_reg(adap, A_CIM_IBQ_DBG_CFG, V_IBQDBGADDR(addr) |
1546218792Snp			     F_IBQDBGEN);
1547248925Snp		/*
1548248925Snp		 * It might take 3-10ms before the IBQ debug read access is
1549248925Snp		 * allowed.  Wait for 1 Sec with a delay of 1 usec.
1550248925Snp		 */
1551218792Snp		err = t4_wait_op_done(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGBUSY, 0,
1552248925Snp				      1000000, 1);
1553218792Snp		if (err)
1554218792Snp			return err;
1555218792Snp		*data++ = t4_read_reg(adap, A_CIM_IBQ_DBG_DATA);
1556218792Snp	}
1557218792Snp	t4_write_reg(adap, A_CIM_IBQ_DBG_CFG, 0);
1558218792Snp	return i;
1559218792Snp}
1560218792Snp
1561218792Snp/**
1562218792Snp *	t4_read_cim_obq - read the contents of a CIM outbound queue
1563218792Snp *	@adap: the adapter
1564218792Snp *	@qid: the queue index
1565218792Snp *	@data: where to store the queue contents
1566218792Snp *	@n: capacity of @data in 32-bit words
1567218792Snp *
1568218792Snp *	Reads the contents of the selected CIM queue starting at address 0 up
1569218792Snp *	to the capacity of @data.  @n must be a multiple of 4.  Returns < 0 on
1570218792Snp *	error and the number of 32-bit words actually read on success.
1571218792Snp */
1572218792Snpint t4_read_cim_obq(struct adapter *adap, unsigned int qid, u32 *data, size_t n)
1573218792Snp{
1574218792Snp	int i, err;
1575218792Snp	unsigned int addr, v, nwords;
1576248925Snp	int cim_num_obq = is_t4(adap) ? CIM_NUM_OBQ : CIM_NUM_OBQ_T5;
1577218792Snp
1578248925Snp	if (qid >= cim_num_obq || (n & 3))
1579218792Snp		return -EINVAL;
1580218792Snp
1581218792Snp	t4_write_reg(adap, A_CIM_QUEUE_CONFIG_REF, F_OBQSELECT |
1582218792Snp		     V_QUENUMSELECT(qid));
1583218792Snp	v = t4_read_reg(adap, A_CIM_QUEUE_CONFIG_CTRL);
1584218792Snp
1585218792Snp	addr = G_CIMQBASE(v) * 64;    /* muliple of 256 -> muliple of 4 */
1586218792Snp	nwords = G_CIMQSIZE(v) * 64;  /* same */
1587218792Snp	if (n > nwords)
1588218792Snp		n = nwords;
1589218792Snp
1590218792Snp	for (i = 0; i < n; i++, addr++) {
1591218792Snp		t4_write_reg(adap, A_CIM_OBQ_DBG_CFG, V_OBQDBGADDR(addr) |
1592218792Snp			     F_OBQDBGEN);
1593218792Snp		err = t4_wait_op_done(adap, A_CIM_OBQ_DBG_CFG, F_OBQDBGBUSY, 0,
1594218792Snp				      2, 1);
1595218792Snp		if (err)
1596218792Snp			return err;
1597218792Snp		*data++ = t4_read_reg(adap, A_CIM_OBQ_DBG_DATA);
1598218792Snp	}
1599218792Snp	t4_write_reg(adap, A_CIM_OBQ_DBG_CFG, 0);
1600218792Snp	return i;
1601218792Snp}
1602218792Snp
1603218792Snpenum {
1604218792Snp	CIM_QCTL_BASE     = 0,
1605218792Snp	CIM_CTL_BASE      = 0x2000,
1606218792Snp	CIM_PBT_ADDR_BASE = 0x2800,
1607218792Snp	CIM_PBT_LRF_BASE  = 0x3000,
1608218792Snp	CIM_PBT_DATA_BASE = 0x3800
1609218792Snp};
1610218792Snp
1611218792Snp/**
1612218792Snp *	t4_cim_read - read a block from CIM internal address space
1613218792Snp *	@adap: the adapter
1614218792Snp *	@addr: the start address within the CIM address space
1615218792Snp *	@n: number of words to read
1616218792Snp *	@valp: where to store the result
1617218792Snp *
1618218792Snp *	Reads a block of 4-byte words from the CIM intenal address space.
1619218792Snp */
1620218792Snpint t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n,
1621218792Snp		unsigned int *valp)
1622218792Snp{
1623218792Snp	int ret = 0;
1624218792Snp
1625218792Snp	if (t4_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY)
1626218792Snp		return -EBUSY;
1627218792Snp
1628218792Snp	for ( ; !ret && n--; addr += 4) {
1629218792Snp		t4_write_reg(adap, A_CIM_HOST_ACC_CTRL, addr);
1630218792Snp		ret = t4_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY,
1631218792Snp				      0, 5, 2);
1632218792Snp		if (!ret)
1633218792Snp			*valp++ = t4_read_reg(adap, A_CIM_HOST_ACC_DATA);
1634218792Snp	}
1635218792Snp	return ret;
1636218792Snp}
1637218792Snp
1638218792Snp/**
1639218792Snp *	t4_cim_write - write a block into CIM internal address space
1640218792Snp *	@adap: the adapter
1641218792Snp *	@addr: the start address within the CIM address space
1642218792Snp *	@n: number of words to write
1643218792Snp *	@valp: set of values to write
1644218792Snp *
1645218792Snp *	Writes a block of 4-byte words into the CIM intenal address space.
1646218792Snp */
1647218792Snpint t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n,
1648218792Snp		 const unsigned int *valp)
1649218792Snp{
1650218792Snp	int ret = 0;
1651218792Snp
1652218792Snp	if (t4_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY)
1653218792Snp		return -EBUSY;
1654218792Snp
1655218792Snp	for ( ; !ret && n--; addr += 4) {
1656218792Snp		t4_write_reg(adap, A_CIM_HOST_ACC_DATA, *valp++);
1657218792Snp		t4_write_reg(adap, A_CIM_HOST_ACC_CTRL, addr | F_HOSTWRITE);
1658218792Snp		ret = t4_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY,
1659218792Snp				      0, 5, 2);
1660218792Snp	}
1661218792Snp	return ret;
1662218792Snp}
1663218792Snp
1664218792Snpstatic int t4_cim_write1(struct adapter *adap, unsigned int addr, unsigned int val)
1665218792Snp{
1666218792Snp	return t4_cim_write(adap, addr, 1, &val);
1667218792Snp}
1668218792Snp
1669218792Snp/**
1670218792Snp *	t4_cim_ctl_read - read a block from CIM control region
1671218792Snp *	@adap: the adapter
1672218792Snp *	@addr: the start address within the CIM control region
1673218792Snp *	@n: number of words to read
1674218792Snp *	@valp: where to store the result
1675218792Snp *
1676218792Snp *	Reads a block of 4-byte words from the CIM control region.
1677218792Snp */
1678218792Snpint t4_cim_ctl_read(struct adapter *adap, unsigned int addr, unsigned int n,
1679218792Snp		    unsigned int *valp)
1680218792Snp{
1681218792Snp	return t4_cim_read(adap, addr + CIM_CTL_BASE, n, valp);
1682218792Snp}
1683218792Snp
1684218792Snp/**
1685218792Snp *	t4_cim_read_la - read CIM LA capture buffer
1686218792Snp *	@adap: the adapter
1687218792Snp *	@la_buf: where to store the LA data
1688218792Snp *	@wrptr: the HW write pointer within the capture buffer
1689218792Snp *
1690218792Snp *	Reads the contents of the CIM LA buffer with the most recent entry at
1691218792Snp *	the end	of the returned data and with the entry at @wrptr first.
1692218792Snp *	We try to leave the LA in the running state we find it in.
1693218792Snp */
1694218792Snpint t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr)
1695218792Snp{
1696218792Snp	int i, ret;
1697218792Snp	unsigned int cfg, val, idx;
1698218792Snp
1699218792Snp	ret = t4_cim_read(adap, A_UP_UP_DBG_LA_CFG, 1, &cfg);
1700218792Snp	if (ret)
1701218792Snp		return ret;
1702218792Snp
1703218792Snp	if (cfg & F_UPDBGLAEN) {                /* LA is running, freeze it */
1704218792Snp		ret = t4_cim_write1(adap, A_UP_UP_DBG_LA_CFG, 0);
1705218792Snp		if (ret)
1706218792Snp			return ret;
1707218792Snp	}
1708218792Snp
1709218792Snp	ret = t4_cim_read(adap, A_UP_UP_DBG_LA_CFG, 1, &val);
1710218792Snp	if (ret)
1711218792Snp		goto restart;
1712218792Snp
1713218792Snp	idx = G_UPDBGLAWRPTR(val);
1714218792Snp	if (wrptr)
1715218792Snp		*wrptr = idx;
1716218792Snp
1717218792Snp	for (i = 0; i < adap->params.cim_la_size; i++) {
1718218792Snp		ret = t4_cim_write1(adap, A_UP_UP_DBG_LA_CFG,
1719218792Snp				    V_UPDBGLARDPTR(idx) | F_UPDBGLARDEN);
1720218792Snp		if (ret)
1721218792Snp			break;
1722218792Snp		ret = t4_cim_read(adap, A_UP_UP_DBG_LA_CFG, 1, &val);
1723218792Snp		if (ret)
1724218792Snp			break;
1725218792Snp		if (val & F_UPDBGLARDEN) {
1726218792Snp			ret = -ETIMEDOUT;
1727218792Snp			break;
1728218792Snp		}
1729218792Snp		ret = t4_cim_read(adap, A_UP_UP_DBG_LA_DATA, 1, &la_buf[i]);
1730218792Snp		if (ret)
1731218792Snp			break;
1732218792Snp		idx = (idx + 1) & M_UPDBGLARDPTR;
1733218792Snp	}
1734218792Snprestart:
1735218792Snp	if (cfg & F_UPDBGLAEN) {
1736218792Snp		int r = t4_cim_write1(adap, A_UP_UP_DBG_LA_CFG,
1737218792Snp				      cfg & ~F_UPDBGLARDEN);
1738218792Snp		if (!ret)
1739218792Snp			ret = r;
1740218792Snp	}
1741218792Snp	return ret;
1742218792Snp}
1743218792Snp
1744218792Snpvoid t4_cim_read_pif_la(struct adapter *adap, u32 *pif_req, u32 *pif_rsp,
1745218792Snp			unsigned int *pif_req_wrptr,
1746218792Snp			unsigned int *pif_rsp_wrptr)
1747218792Snp{
1748218792Snp	int i, j;
1749218792Snp	u32 cfg, val, req, rsp;
1750218792Snp
1751218792Snp	cfg = t4_read_reg(adap, A_CIM_DEBUGCFG);
1752218792Snp	if (cfg & F_LADBGEN)
1753218792Snp		t4_write_reg(adap, A_CIM_DEBUGCFG, cfg ^ F_LADBGEN);
1754218792Snp
1755218792Snp	val = t4_read_reg(adap, A_CIM_DEBUGSTS);
1756218792Snp	req = G_POLADBGWRPTR(val);
1757218792Snp	rsp = G_PILADBGWRPTR(val);
1758218792Snp	if (pif_req_wrptr)
1759218792Snp		*pif_req_wrptr = req;
1760218792Snp	if (pif_rsp_wrptr)
1761218792Snp		*pif_rsp_wrptr = rsp;
1762218792Snp
1763218792Snp	for (i = 0; i < CIM_PIFLA_SIZE; i++) {
1764218792Snp		for (j = 0; j < 6; j++) {
1765218792Snp			t4_write_reg(adap, A_CIM_DEBUGCFG, V_POLADBGRDPTR(req) |
1766218792Snp				     V_PILADBGRDPTR(rsp));
1767218792Snp			*pif_req++ = t4_read_reg(adap, A_CIM_PO_LA_DEBUGDATA);
1768218792Snp			*pif_rsp++ = t4_read_reg(adap, A_CIM_PI_LA_DEBUGDATA);
1769218792Snp			req++;
1770218792Snp			rsp++;
1771218792Snp		}
1772218792Snp		req = (req + 2) & M_POLADBGRDPTR;
1773218792Snp		rsp = (rsp + 2) & M_PILADBGRDPTR;
1774218792Snp	}
1775218792Snp	t4_write_reg(adap, A_CIM_DEBUGCFG, cfg);
1776218792Snp}
1777218792Snp
1778218792Snpvoid t4_cim_read_ma_la(struct adapter *adap, u32 *ma_req, u32 *ma_rsp)
1779218792Snp{
1780218792Snp	u32 cfg;
1781218792Snp	int i, j, idx;
1782218792Snp
1783218792Snp	cfg = t4_read_reg(adap, A_CIM_DEBUGCFG);
1784218792Snp	if (cfg & F_LADBGEN)
1785218792Snp		t4_write_reg(adap, A_CIM_DEBUGCFG, cfg ^ F_LADBGEN);
1786218792Snp
1787218792Snp	for (i = 0; i < CIM_MALA_SIZE; i++) {
1788218792Snp		for (j = 0; j < 5; j++) {
1789218792Snp			idx = 8 * i + j;
1790218792Snp			t4_write_reg(adap, A_CIM_DEBUGCFG, V_POLADBGRDPTR(idx) |
1791218792Snp				     V_PILADBGRDPTR(idx));
1792218792Snp			*ma_req++ = t4_read_reg(adap, A_CIM_PO_LA_MADEBUGDATA);
1793218792Snp			*ma_rsp++ = t4_read_reg(adap, A_CIM_PI_LA_MADEBUGDATA);
1794218792Snp		}
1795218792Snp	}
1796218792Snp	t4_write_reg(adap, A_CIM_DEBUGCFG, cfg);
1797218792Snp}
1798218792Snp
1799218792Snp/**
1800218792Snp *	t4_tp_read_la - read TP LA capture buffer
1801218792Snp *	@adap: the adapter
1802218792Snp *	@la_buf: where to store the LA data
1803218792Snp *	@wrptr: the HW write pointer within the capture buffer
1804218792Snp *
1805218792Snp *	Reads the contents of the TP LA buffer with the most recent entry at
1806218792Snp *	the end	of the returned data and with the entry at @wrptr first.
1807218792Snp *	We leave the LA in the running state we find it in.
1808218792Snp */
1809218792Snpvoid t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr)
1810218792Snp{
1811218792Snp	bool last_incomplete;
1812218792Snp	unsigned int i, cfg, val, idx;
1813218792Snp
1814218792Snp	cfg = t4_read_reg(adap, A_TP_DBG_LA_CONFIG) & 0xffff;
1815218792Snp	if (cfg & F_DBGLAENABLE)                    /* freeze LA */
1816218792Snp		t4_write_reg(adap, A_TP_DBG_LA_CONFIG,
1817218792Snp			     adap->params.tp.la_mask | (cfg ^ F_DBGLAENABLE));
1818218792Snp
1819218792Snp	val = t4_read_reg(adap, A_TP_DBG_LA_CONFIG);
1820218792Snp	idx = G_DBGLAWPTR(val);
1821218792Snp	last_incomplete = G_DBGLAMODE(val) >= 2 && (val & F_DBGLAWHLF) == 0;
1822218792Snp	if (last_incomplete)
1823218792Snp		idx = (idx + 1) & M_DBGLARPTR;
1824218792Snp	if (wrptr)
1825218792Snp		*wrptr = idx;
1826218792Snp
1827218792Snp	val &= 0xffff;
1828218792Snp	val &= ~V_DBGLARPTR(M_DBGLARPTR);
1829218792Snp	val |= adap->params.tp.la_mask;
1830218792Snp
1831218792Snp	for (i = 0; i < TPLA_SIZE; i++) {
1832218792Snp		t4_write_reg(adap, A_TP_DBG_LA_CONFIG, V_DBGLARPTR(idx) | val);
1833218792Snp		la_buf[i] = t4_read_reg64(adap, A_TP_DBG_LA_DATAL);
1834218792Snp		idx = (idx + 1) & M_DBGLARPTR;
1835218792Snp	}
1836218792Snp
1837218792Snp	/* Wipe out last entry if it isn't valid */
1838218792Snp	if (last_incomplete)
1839218792Snp		la_buf[TPLA_SIZE - 1] = ~0ULL;
1840218792Snp
1841218792Snp	if (cfg & F_DBGLAENABLE)                    /* restore running state */
1842218792Snp		t4_write_reg(adap, A_TP_DBG_LA_CONFIG,
1843218792Snp			     cfg | adap->params.tp.la_mask);
1844218792Snp}
1845218792Snp
1846218792Snpvoid t4_ulprx_read_la(struct adapter *adap, u32 *la_buf)
1847218792Snp{
1848218792Snp	unsigned int i, j;
1849218792Snp
1850218792Snp	for (i = 0; i < 8; i++) {
1851218792Snp		u32 *p = la_buf + i;
1852218792Snp
1853218792Snp		t4_write_reg(adap, A_ULP_RX_LA_CTL, i);
1854218792Snp		j = t4_read_reg(adap, A_ULP_RX_LA_WRPTR);
1855218792Snp		t4_write_reg(adap, A_ULP_RX_LA_RDPTR, j);
1856218792Snp		for (j = 0; j < ULPRX_LA_SIZE; j++, p += 8)
1857218792Snp			*p = t4_read_reg(adap, A_ULP_RX_LA_RDDATA);
1858218792Snp	}
1859218792Snp}
1860218792Snp
1861218792Snp#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
1862250090Snp		     FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \
1863250090Snp		     FW_PORT_CAP_SPEED_100G | FW_PORT_CAP_ANEG)
1864218792Snp
1865218792Snp/**
1866218792Snp *	t4_link_start - apply link configuration to MAC/PHY
1867218792Snp *	@phy: the PHY to setup
1868218792Snp *	@mac: the MAC to setup
1869218792Snp *	@lc: the requested link configuration
1870218792Snp *
1871218792Snp *	Set up a port's MAC and PHY according to a desired link configuration.
1872218792Snp *	- If the PHY can auto-negotiate first decide what to advertise, then
1873218792Snp *	  enable/disable auto-negotiation as desired, and reset.
1874218792Snp *	- If the PHY does not auto-negotiate just reset it.
1875218792Snp *	- If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
1876218792Snp *	  otherwise do it later based on the outcome of auto-negotiation.
1877218792Snp */
1878218792Snpint t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port,
1879218792Snp		  struct link_config *lc)
1880218792Snp{
1881218792Snp	struct fw_port_cmd c;
1882218792Snp	unsigned int fc = 0, mdi = V_FW_PORT_CAP_MDI(FW_PORT_CAP_MDI_AUTO);
1883218792Snp
1884218792Snp	lc->link_ok = 0;
1885218792Snp	if (lc->requested_fc & PAUSE_RX)
1886218792Snp		fc |= FW_PORT_CAP_FC_RX;
1887218792Snp	if (lc->requested_fc & PAUSE_TX)
1888218792Snp		fc |= FW_PORT_CAP_FC_TX;
1889218792Snp
1890218792Snp	memset(&c, 0, sizeof(c));
1891218792Snp	c.op_to_portid = htonl(V_FW_CMD_OP(FW_PORT_CMD) | F_FW_CMD_REQUEST |
1892218792Snp			       F_FW_CMD_EXEC | V_FW_PORT_CMD_PORTID(port));
1893218792Snp	c.action_to_len16 = htonl(V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) |
1894218792Snp				  FW_LEN16(c));
1895218792Snp
1896218792Snp	if (!(lc->supported & FW_PORT_CAP_ANEG)) {
1897218792Snp		c.u.l1cfg.rcap = htonl((lc->supported & ADVERT_MASK) | fc);
1898218792Snp		lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1899218792Snp	} else if (lc->autoneg == AUTONEG_DISABLE) {
1900218792Snp		c.u.l1cfg.rcap = htonl(lc->requested_speed | fc | mdi);
1901218792Snp		lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1902218792Snp	} else
1903218792Snp		c.u.l1cfg.rcap = htonl(lc->advertising | fc | mdi);
1904218792Snp
1905218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
1906218792Snp}
1907218792Snp
1908218792Snp/**
1909218792Snp *	t4_restart_aneg - restart autonegotiation
1910218792Snp *	@adap: the adapter
1911218792Snp *	@mbox: mbox to use for the FW command
1912218792Snp *	@port: the port id
1913218792Snp *
1914218792Snp *	Restarts autonegotiation for the selected port.
1915218792Snp */
1916218792Snpint t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port)
1917218792Snp{
1918218792Snp	struct fw_port_cmd c;
1919218792Snp
1920218792Snp	memset(&c, 0, sizeof(c));
1921218792Snp	c.op_to_portid = htonl(V_FW_CMD_OP(FW_PORT_CMD) | F_FW_CMD_REQUEST |
1922218792Snp			       F_FW_CMD_EXEC | V_FW_PORT_CMD_PORTID(port));
1923218792Snp	c.action_to_len16 = htonl(V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) |
1924218792Snp				  FW_LEN16(c));
1925218792Snp	c.u.l1cfg.rcap = htonl(FW_PORT_CAP_ANEG);
1926218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
1927218792Snp}
1928218792Snp
1929218792Snpstruct intr_info {
1930218792Snp	unsigned int mask;       /* bits to check in interrupt status */
1931218792Snp	const char *msg;         /* message to print or NULL */
1932218792Snp	short stat_idx;          /* stat counter to increment or -1 */
1933218792Snp	unsigned short fatal;    /* whether the condition reported is fatal */
1934218792Snp};
1935218792Snp
1936218792Snp/**
1937218792Snp *	t4_handle_intr_status - table driven interrupt handler
1938218792Snp *	@adapter: the adapter that generated the interrupt
1939218792Snp *	@reg: the interrupt status register to process
1940218792Snp *	@acts: table of interrupt actions
1941218792Snp *
1942218792Snp *	A table driven interrupt handler that applies a set of masks to an
1943218792Snp *	interrupt status word and performs the corresponding actions if the
1944218792Snp *	interrupts described by the mask have occured.  The actions include
1945218792Snp *	optionally emitting a warning or alert message.  The table is terminated
1946218792Snp *	by an entry specifying mask 0.  Returns the number of fatal interrupt
1947218792Snp *	conditions.
1948218792Snp */
1949218792Snpstatic int t4_handle_intr_status(struct adapter *adapter, unsigned int reg,
1950218792Snp				 const struct intr_info *acts)
1951218792Snp{
1952218792Snp	int fatal = 0;
1953218792Snp	unsigned int mask = 0;
1954218792Snp	unsigned int status = t4_read_reg(adapter, reg);
1955218792Snp
1956218792Snp	for ( ; acts->mask; ++acts) {
1957218792Snp		if (!(status & acts->mask))
1958218792Snp			continue;
1959218792Snp		if (acts->fatal) {
1960218792Snp			fatal++;
1961218792Snp			CH_ALERT(adapter, "%s (0x%x)\n",
1962218792Snp				 acts->msg, status & acts->mask);
1963218792Snp		} else if (acts->msg)
1964218792Snp			CH_WARN_RATELIMIT(adapter, "%s (0x%x)\n",
1965218792Snp					  acts->msg, status & acts->mask);
1966218792Snp		mask |= acts->mask;
1967218792Snp	}
1968218792Snp	status &= mask;
1969218792Snp	if (status)                           /* clear processed interrupts */
1970218792Snp		t4_write_reg(adapter, reg, status);
1971218792Snp	return fatal;
1972218792Snp}
1973218792Snp
1974218792Snp/*
1975218792Snp * Interrupt handler for the PCIE module.
1976218792Snp */
1977218792Snpstatic void pcie_intr_handler(struct adapter *adapter)
1978218792Snp{
1979218792Snp	static struct intr_info sysbus_intr_info[] = {
1980218792Snp		{ F_RNPP, "RXNP array parity error", -1, 1 },
1981218792Snp		{ F_RPCP, "RXPC array parity error", -1, 1 },
1982218792Snp		{ F_RCIP, "RXCIF array parity error", -1, 1 },
1983218792Snp		{ F_RCCP, "Rx completions control array parity error", -1, 1 },
1984218792Snp		{ F_RFTP, "RXFT array parity error", -1, 1 },
1985218792Snp		{ 0 }
1986218792Snp	};
1987218792Snp	static struct intr_info pcie_port_intr_info[] = {
1988218792Snp		{ F_TPCP, "TXPC array parity error", -1, 1 },
1989218792Snp		{ F_TNPP, "TXNP array parity error", -1, 1 },
1990218792Snp		{ F_TFTP, "TXFT array parity error", -1, 1 },
1991218792Snp		{ F_TCAP, "TXCA array parity error", -1, 1 },
1992218792Snp		{ F_TCIP, "TXCIF array parity error", -1, 1 },
1993218792Snp		{ F_RCAP, "RXCA array parity error", -1, 1 },
1994218792Snp		{ F_OTDD, "outbound request TLP discarded", -1, 1 },
1995218792Snp		{ F_RDPE, "Rx data parity error", -1, 1 },
1996218792Snp		{ F_TDUE, "Tx uncorrectable data error", -1, 1 },
1997218792Snp		{ 0 }
1998218792Snp	};
1999218792Snp	static struct intr_info pcie_intr_info[] = {
2000218792Snp		{ F_MSIADDRLPERR, "MSI AddrL parity error", -1, 1 },
2001218792Snp		{ F_MSIADDRHPERR, "MSI AddrH parity error", -1, 1 },
2002218792Snp		{ F_MSIDATAPERR, "MSI data parity error", -1, 1 },
2003218792Snp		{ F_MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
2004218792Snp		{ F_MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
2005218792Snp		{ F_MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
2006218792Snp		{ F_MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
2007218792Snp		{ F_PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 },
2008218792Snp		{ F_PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 },
2009218792Snp		{ F_TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
2010218792Snp		{ F_CCNTPERR, "PCI CMD channel count parity error", -1, 1 },
2011218792Snp		{ F_CREQPERR, "PCI CMD channel request parity error", -1, 1 },
2012218792Snp		{ F_CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
2013218792Snp		{ F_DCNTPERR, "PCI DMA channel count parity error", -1, 1 },
2014218792Snp		{ F_DREQPERR, "PCI DMA channel request parity error", -1, 1 },
2015218792Snp		{ F_DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
2016218792Snp		{ F_HCNTPERR, "PCI HMA channel count parity error", -1, 1 },
2017218792Snp		{ F_HREQPERR, "PCI HMA channel request parity error", -1, 1 },
2018218792Snp		{ F_HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
2019218792Snp		{ F_CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
2020218792Snp		{ F_FIDPERR, "PCI FID parity error", -1, 1 },
2021218792Snp		{ F_INTXCLRPERR, "PCI INTx clear parity error", -1, 1 },
2022218792Snp		{ F_MATAGPERR, "PCI MA tag parity error", -1, 1 },
2023218792Snp		{ F_PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
2024218792Snp		{ F_RXCPLPERR, "PCI Rx completion parity error", -1, 1 },
2025218792Snp		{ F_RXWRPERR, "PCI Rx write parity error", -1, 1 },
2026218792Snp		{ F_RPLPERR, "PCI replay buffer parity error", -1, 1 },
2027218792Snp		{ F_PCIESINT, "PCI core secondary fault", -1, 1 },
2028218792Snp		{ F_PCIEPINT, "PCI core primary fault", -1, 1 },
2029218792Snp		{ F_UNXSPLCPLERR, "PCI unexpected split completion error", -1,
2030218792Snp		  0 },
2031218792Snp		{ 0 }
2032218792Snp	};
2033218792Snp
2034248925Snp	static struct intr_info t5_pcie_intr_info[] = {
2035248925Snp		{ F_MSTGRPPERR, "Master Response Read Queue parity error",
2036248925Snp		  -1, 1 },
2037248925Snp		{ F_MSTTIMEOUTPERR, "Master Timeout FIFO parity error", -1, 1 },
2038248925Snp		{ F_MSIXSTIPERR, "MSI-X STI SRAM parity error", -1, 1 },
2039248925Snp		{ F_MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
2040248925Snp		{ F_MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
2041248925Snp		{ F_MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
2042248925Snp		{ F_MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
2043248925Snp		{ F_PIOCPLGRPPERR, "PCI PIO completion Group FIFO parity error",
2044248925Snp		  -1, 1 },
2045248925Snp		{ F_PIOREQGRPPERR, "PCI PIO request Group FIFO parity error",
2046248925Snp		  -1, 1 },
2047248925Snp		{ F_TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
2048248925Snp		{ F_MSTTAGQPERR, "PCI master tag queue parity error", -1, 1 },
2049248925Snp		{ F_CREQPERR, "PCI CMD channel request parity error", -1, 1 },
2050248925Snp		{ F_CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
2051248925Snp		{ F_DREQWRPERR, "PCI DMA channel write request parity error",
2052248925Snp		  -1, 1 },
2053248925Snp		{ F_DREQPERR, "PCI DMA channel request parity error", -1, 1 },
2054248925Snp		{ F_DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
2055248925Snp		{ F_HREQWRPERR, "PCI HMA channel count parity error", -1, 1 },
2056248925Snp		{ F_HREQPERR, "PCI HMA channel request parity error", -1, 1 },
2057248925Snp		{ F_HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
2058248925Snp		{ F_CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
2059248925Snp		{ F_FIDPERR, "PCI FID parity error", -1, 1 },
2060248925Snp		{ F_VFIDPERR, "PCI INTx clear parity error", -1, 1 },
2061248925Snp		{ F_MAGRPPERR, "PCI MA group FIFO parity error", -1, 1 },
2062248925Snp		{ F_PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
2063248925Snp		{ F_IPRXHDRGRPPERR, "PCI IP Rx header group parity error",
2064248925Snp		  -1, 1 },
2065248925Snp		{ F_IPRXDATAGRPPERR, "PCI IP Rx data group parity error",
2066248925Snp		  -1, 1 },
2067248925Snp		{ F_RPLPERR, "PCI IP replay buffer parity error", -1, 1 },
2068248925Snp		{ F_IPSOTPERR, "PCI IP SOT buffer parity error", -1, 1 },
2069248925Snp		{ F_TRGT1GRPPERR, "PCI TRGT1 group FIFOs parity error", -1, 1 },
2070248925Snp		{ F_READRSPERR, "Outbound read error", -1,
2071248925Snp		  0 },
2072248925Snp		{ 0 }
2073248925Snp	};
2074248925Snp
2075218792Snp	int fat;
2076218792Snp
2077270297Snp	if (is_t4(adapter))
2078270297Snp		fat = t4_handle_intr_status(adapter,
2079270297Snp					    A_PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
2080270297Snp					    sysbus_intr_info) +
2081270297Snp		      t4_handle_intr_status(adapter,
2082270297Snp					    A_PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
2083270297Snp					    pcie_port_intr_info) +
2084270297Snp		      t4_handle_intr_status(adapter, A_PCIE_INT_CAUSE,
2085270297Snp					    pcie_intr_info);
2086270297Snp	else
2087270297Snp		fat = t4_handle_intr_status(adapter, A_PCIE_INT_CAUSE,
2088270297Snp					    t5_pcie_intr_info);
2089218792Snp	if (fat)
2090218792Snp		t4_fatal_err(adapter);
2091218792Snp}
2092218792Snp
2093218792Snp/*
2094218792Snp * TP interrupt handler.
2095218792Snp */
2096218792Snpstatic void tp_intr_handler(struct adapter *adapter)
2097218792Snp{
2098218792Snp	static struct intr_info tp_intr_info[] = {
2099218792Snp		{ 0x3fffffff, "TP parity error", -1, 1 },
2100218792Snp		{ F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 },
2101218792Snp		{ 0 }
2102218792Snp	};
2103218792Snp
2104218792Snp	if (t4_handle_intr_status(adapter, A_TP_INT_CAUSE, tp_intr_info))
2105218792Snp		t4_fatal_err(adapter);
2106218792Snp}
2107218792Snp
2108218792Snp/*
2109218792Snp * SGE interrupt handler.
2110218792Snp */
2111218792Snpstatic void sge_intr_handler(struct adapter *adapter)
2112218792Snp{
2113218792Snp	u64 v;
2114218792Snp	u32 err;
2115218792Snp
2116218792Snp	static struct intr_info sge_intr_info[] = {
2117218792Snp		{ F_ERR_CPL_EXCEED_IQE_SIZE,
2118218792Snp		  "SGE received CPL exceeding IQE size", -1, 1 },
2119218792Snp		{ F_ERR_INVALID_CIDX_INC,
2120218792Snp		  "SGE GTS CIDX increment too large", -1, 0 },
2121218792Snp		{ F_ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 },
2122218792Snp		{ F_ERR_DROPPED_DB, "SGE doorbell dropped", -1, 0 },
2123218792Snp		{ F_ERR_DATA_CPL_ON_HIGH_QID1 | F_ERR_DATA_CPL_ON_HIGH_QID0,
2124218792Snp		  "SGE IQID > 1023 received CPL for FL", -1, 0 },
2125218792Snp		{ F_ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1,
2126218792Snp		  0 },
2127218792Snp		{ F_ERR_BAD_DB_PIDX2, "SGE DBP 2 pidx increment too large", -1,
2128218792Snp		  0 },
2129218792Snp		{ F_ERR_BAD_DB_PIDX1, "SGE DBP 1 pidx increment too large", -1,
2130218792Snp		  0 },
2131218792Snp		{ F_ERR_BAD_DB_PIDX0, "SGE DBP 0 pidx increment too large", -1,
2132218792Snp		  0 },
2133218792Snp		{ F_ERR_ING_CTXT_PRIO,
2134218792Snp		  "SGE too many priority ingress contexts", -1, 0 },
2135218792Snp		{ F_ERR_EGR_CTXT_PRIO,
2136218792Snp		  "SGE too many priority egress contexts", -1, 0 },
2137218792Snp		{ F_INGRESS_SIZE_ERR, "SGE illegal ingress QID", -1, 0 },
2138218792Snp		{ F_EGRESS_SIZE_ERR, "SGE illegal egress QID", -1, 0 },
2139218792Snp		{ 0 }
2140218792Snp	};
2141218792Snp
2142218792Snp	v = (u64)t4_read_reg(adapter, A_SGE_INT_CAUSE1) |
2143218792Snp	    ((u64)t4_read_reg(adapter, A_SGE_INT_CAUSE2) << 32);
2144218792Snp	if (v) {
2145218792Snp		CH_ALERT(adapter, "SGE parity error (%#llx)\n",
2146218792Snp			 (unsigned long long)v);
2147218792Snp		t4_write_reg(adapter, A_SGE_INT_CAUSE1, v);
2148218792Snp		t4_write_reg(adapter, A_SGE_INT_CAUSE2, v >> 32);
2149218792Snp	}
2150218792Snp
2151218792Snp	v |= t4_handle_intr_status(adapter, A_SGE_INT_CAUSE3, sge_intr_info);
2152218792Snp
2153218792Snp	err = t4_read_reg(adapter, A_SGE_ERROR_STATS);
2154218792Snp	if (err & F_ERROR_QID_VALID) {
2155218792Snp		CH_ERR(adapter, "SGE error for queue %u\n", G_ERROR_QID(err));
2156228561Snp		if (err & F_UNCAPTURED_ERROR)
2157228561Snp			CH_ERR(adapter, "SGE UNCAPTURED_ERROR set (clearing)\n");
2158228561Snp		t4_write_reg(adapter, A_SGE_ERROR_STATS, F_ERROR_QID_VALID |
2159228561Snp			     F_UNCAPTURED_ERROR);
2160218792Snp	}
2161218792Snp
2162218792Snp	if (v != 0)
2163218792Snp		t4_fatal_err(adapter);
2164218792Snp}
2165218792Snp
2166218792Snp#define CIM_OBQ_INTR (F_OBQULP0PARERR | F_OBQULP1PARERR | F_OBQULP2PARERR |\
2167218792Snp		      F_OBQULP3PARERR | F_OBQSGEPARERR | F_OBQNCSIPARERR)
2168218792Snp#define CIM_IBQ_INTR (F_IBQTP0PARERR | F_IBQTP1PARERR | F_IBQULPPARERR |\
2169218792Snp		      F_IBQSGEHIPARERR | F_IBQSGELOPARERR | F_IBQNCSIPARERR)
2170218792Snp
2171218792Snp/*
2172218792Snp * CIM interrupt handler.
2173218792Snp */
2174218792Snpstatic void cim_intr_handler(struct adapter *adapter)
2175218792Snp{
2176218792Snp	static struct intr_info cim_intr_info[] = {
2177218792Snp		{ F_PREFDROPINT, "CIM control register prefetch drop", -1, 1 },
2178218792Snp		{ CIM_OBQ_INTR, "CIM OBQ parity error", -1, 1 },
2179218792Snp		{ CIM_IBQ_INTR, "CIM IBQ parity error", -1, 1 },
2180218792Snp		{ F_MBUPPARERR, "CIM mailbox uP parity error", -1, 1 },
2181218792Snp		{ F_MBHOSTPARERR, "CIM mailbox host parity error", -1, 1 },
2182218792Snp		{ F_TIEQINPARERRINT, "CIM TIEQ outgoing parity error", -1, 1 },
2183218792Snp		{ F_TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 },
2184218792Snp		{ 0 }
2185218792Snp	};
2186218792Snp	static struct intr_info cim_upintr_info[] = {
2187218792Snp		{ F_RSVDSPACEINT, "CIM reserved space access", -1, 1 },
2188218792Snp		{ F_ILLTRANSINT, "CIM illegal transaction", -1, 1 },
2189218792Snp		{ F_ILLWRINT, "CIM illegal write", -1, 1 },
2190218792Snp		{ F_ILLRDINT, "CIM illegal read", -1, 1 },
2191218792Snp		{ F_ILLRDBEINT, "CIM illegal read BE", -1, 1 },
2192218792Snp		{ F_ILLWRBEINT, "CIM illegal write BE", -1, 1 },
2193218792Snp		{ F_SGLRDBOOTINT, "CIM single read from boot space", -1, 1 },
2194218792Snp		{ F_SGLWRBOOTINT, "CIM single write to boot space", -1, 1 },
2195218792Snp		{ F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1 },
2196218792Snp		{ F_SGLRDFLASHINT, "CIM single read from flash space", -1, 1 },
2197218792Snp		{ F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1 },
2198218792Snp		{ F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1 },
2199218792Snp		{ F_SGLRDEEPROMINT, "CIM single EEPROM read", -1, 1 },
2200218792Snp		{ F_SGLWREEPROMINT, "CIM single EEPROM write", -1, 1 },
2201218792Snp		{ F_BLKRDEEPROMINT, "CIM block EEPROM read", -1, 1 },
2202218792Snp		{ F_BLKWREEPROMINT, "CIM block EEPROM write", -1, 1 },
2203218792Snp		{ F_SGLRDCTLINT , "CIM single read from CTL space", -1, 1 },
2204218792Snp		{ F_SGLWRCTLINT , "CIM single write to CTL space", -1, 1 },
2205218792Snp		{ F_BLKRDCTLINT , "CIM block read from CTL space", -1, 1 },
2206218792Snp		{ F_BLKWRCTLINT , "CIM block write to CTL space", -1, 1 },
2207218792Snp		{ F_SGLRDPLINT , "CIM single read from PL space", -1, 1 },
2208218792Snp		{ F_SGLWRPLINT , "CIM single write to PL space", -1, 1 },
2209218792Snp		{ F_BLKRDPLINT , "CIM block read from PL space", -1, 1 },
2210218792Snp		{ F_BLKWRPLINT , "CIM block write to PL space", -1, 1 },
2211218792Snp		{ F_REQOVRLOOKUPINT , "CIM request FIFO overwrite", -1, 1 },
2212218792Snp		{ F_RSPOVRLOOKUPINT , "CIM response FIFO overwrite", -1, 1 },
2213218792Snp		{ F_TIMEOUTINT , "CIM PIF timeout", -1, 1 },
2214218792Snp		{ F_TIMEOUTMAINT , "CIM PIF MA timeout", -1, 1 },
2215218792Snp		{ 0 }
2216218792Snp	};
2217218792Snp	int fat;
2218218792Snp
2219247355Snp	if (t4_read_reg(adapter, A_PCIE_FW) & F_PCIE_FW_ERR)
2220247355Snp		t4_report_fw_error(adapter);
2221247355Snp
2222218792Snp	fat = t4_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE,
2223218792Snp				    cim_intr_info) +
2224218792Snp	      t4_handle_intr_status(adapter, A_CIM_HOST_UPACC_INT_CAUSE,
2225218792Snp				    cim_upintr_info);
2226218792Snp	if (fat)
2227218792Snp		t4_fatal_err(adapter);
2228218792Snp}
2229218792Snp
2230218792Snp/*
2231218792Snp * ULP RX interrupt handler.
2232218792Snp */
2233218792Snpstatic void ulprx_intr_handler(struct adapter *adapter)
2234218792Snp{
2235218792Snp	static struct intr_info ulprx_intr_info[] = {
2236218792Snp		{ F_CAUSE_CTX_1, "ULPRX channel 1 context error", -1, 1 },
2237218792Snp		{ F_CAUSE_CTX_0, "ULPRX channel 0 context error", -1, 1 },
2238218792Snp		{ 0x7fffff, "ULPRX parity error", -1, 1 },
2239218792Snp		{ 0 }
2240218792Snp	};
2241218792Snp
2242218792Snp	if (t4_handle_intr_status(adapter, A_ULP_RX_INT_CAUSE, ulprx_intr_info))
2243218792Snp		t4_fatal_err(adapter);
2244218792Snp}
2245218792Snp
2246218792Snp/*
2247218792Snp * ULP TX interrupt handler.
2248218792Snp */
2249218792Snpstatic void ulptx_intr_handler(struct adapter *adapter)
2250218792Snp{
2251218792Snp	static struct intr_info ulptx_intr_info[] = {
2252218792Snp		{ F_PBL_BOUND_ERR_CH3, "ULPTX channel 3 PBL out of bounds", -1,
2253218792Snp		  0 },
2254218792Snp		{ F_PBL_BOUND_ERR_CH2, "ULPTX channel 2 PBL out of bounds", -1,
2255218792Snp		  0 },
2256218792Snp		{ F_PBL_BOUND_ERR_CH1, "ULPTX channel 1 PBL out of bounds", -1,
2257218792Snp		  0 },
2258218792Snp		{ F_PBL_BOUND_ERR_CH0, "ULPTX channel 0 PBL out of bounds", -1,
2259218792Snp		  0 },
2260218792Snp		{ 0xfffffff, "ULPTX parity error", -1, 1 },
2261218792Snp		{ 0 }
2262218792Snp	};
2263218792Snp
2264218792Snp	if (t4_handle_intr_status(adapter, A_ULP_TX_INT_CAUSE, ulptx_intr_info))
2265218792Snp		t4_fatal_err(adapter);
2266218792Snp}
2267218792Snp
2268218792Snp/*
2269218792Snp * PM TX interrupt handler.
2270218792Snp */
2271218792Snpstatic void pmtx_intr_handler(struct adapter *adapter)
2272218792Snp{
2273218792Snp	static struct intr_info pmtx_intr_info[] = {
2274218792Snp		{ F_PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large", -1, 1 },
2275218792Snp		{ F_PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large", -1, 1 },
2276218792Snp		{ F_PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large", -1, 1 },
2277218792Snp		{ F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 },
2278218792Snp		{ 0xffffff0, "PMTX framing error", -1, 1 },
2279218792Snp		{ F_OESPI_PAR_ERROR, "PMTX oespi parity error", -1, 1 },
2280218792Snp		{ F_DB_OPTIONS_PAR_ERROR, "PMTX db_options parity error", -1,
2281218792Snp		  1 },
2282218792Snp		{ F_ICSPI_PAR_ERROR, "PMTX icspi parity error", -1, 1 },
2283218792Snp		{ F_C_PCMD_PAR_ERROR, "PMTX c_pcmd parity error", -1, 1},
2284218792Snp		{ 0 }
2285218792Snp	};
2286218792Snp
2287218792Snp	if (t4_handle_intr_status(adapter, A_PM_TX_INT_CAUSE, pmtx_intr_info))
2288218792Snp		t4_fatal_err(adapter);
2289218792Snp}
2290218792Snp
2291218792Snp/*
2292218792Snp * PM RX interrupt handler.
2293218792Snp */
2294218792Snpstatic void pmrx_intr_handler(struct adapter *adapter)
2295218792Snp{
2296218792Snp	static struct intr_info pmrx_intr_info[] = {
2297218792Snp		{ F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 },
2298218792Snp		{ 0x3ffff0, "PMRX framing error", -1, 1 },
2299218792Snp		{ F_OCSPI_PAR_ERROR, "PMRX ocspi parity error", -1, 1 },
2300218792Snp		{ F_DB_OPTIONS_PAR_ERROR, "PMRX db_options parity error", -1,
2301218792Snp		  1 },
2302218792Snp		{ F_IESPI_PAR_ERROR, "PMRX iespi parity error", -1, 1 },
2303218792Snp		{ F_E_PCMD_PAR_ERROR, "PMRX e_pcmd parity error", -1, 1},
2304218792Snp		{ 0 }
2305218792Snp	};
2306218792Snp
2307218792Snp	if (t4_handle_intr_status(adapter, A_PM_RX_INT_CAUSE, pmrx_intr_info))
2308218792Snp		t4_fatal_err(adapter);
2309218792Snp}
2310218792Snp
2311218792Snp/*
2312218792Snp * CPL switch interrupt handler.
2313218792Snp */
2314218792Snpstatic void cplsw_intr_handler(struct adapter *adapter)
2315218792Snp{
2316218792Snp	static struct intr_info cplsw_intr_info[] = {
2317218792Snp		{ F_CIM_OP_MAP_PERR, "CPLSW CIM op_map parity error", -1, 1 },
2318218792Snp		{ F_CIM_OVFL_ERROR, "CPLSW CIM overflow", -1, 1 },
2319218792Snp		{ F_TP_FRAMING_ERROR, "CPLSW TP framing error", -1, 1 },
2320218792Snp		{ F_SGE_FRAMING_ERROR, "CPLSW SGE framing error", -1, 1 },
2321218792Snp		{ F_CIM_FRAMING_ERROR, "CPLSW CIM framing error", -1, 1 },
2322218792Snp		{ F_ZERO_SWITCH_ERROR, "CPLSW no-switch error", -1, 1 },
2323218792Snp		{ 0 }
2324218792Snp	};
2325218792Snp
2326218792Snp	if (t4_handle_intr_status(adapter, A_CPL_INTR_CAUSE, cplsw_intr_info))
2327218792Snp		t4_fatal_err(adapter);
2328218792Snp}
2329218792Snp
2330218792Snp/*
2331218792Snp * LE interrupt handler.
2332218792Snp */
2333218792Snpstatic void le_intr_handler(struct adapter *adap)
2334218792Snp{
2335218792Snp	static struct intr_info le_intr_info[] = {
2336218792Snp		{ F_LIPMISS, "LE LIP miss", -1, 0 },
2337218792Snp		{ F_LIP0, "LE 0 LIP error", -1, 0 },
2338218792Snp		{ F_PARITYERR, "LE parity error", -1, 1 },
2339218792Snp		{ F_UNKNOWNCMD, "LE unknown command", -1, 1 },
2340218792Snp		{ F_REQQPARERR, "LE request queue parity error", -1, 1 },
2341218792Snp		{ 0 }
2342218792Snp	};
2343218792Snp
2344218792Snp	if (t4_handle_intr_status(adap, A_LE_DB_INT_CAUSE, le_intr_info))
2345218792Snp		t4_fatal_err(adap);
2346218792Snp}
2347218792Snp
2348218792Snp/*
2349218792Snp * MPS interrupt handler.
2350218792Snp */
2351218792Snpstatic void mps_intr_handler(struct adapter *adapter)
2352218792Snp{
2353218792Snp	static struct intr_info mps_rx_intr_info[] = {
2354218792Snp		{ 0xffffff, "MPS Rx parity error", -1, 1 },
2355218792Snp		{ 0 }
2356218792Snp	};
2357218792Snp	static struct intr_info mps_tx_intr_info[] = {
2358218792Snp		{ V_TPFIFO(M_TPFIFO), "MPS Tx TP FIFO parity error", -1, 1 },
2359218792Snp		{ F_NCSIFIFO, "MPS Tx NC-SI FIFO parity error", -1, 1 },
2360218792Snp		{ V_TXDATAFIFO(M_TXDATAFIFO), "MPS Tx data FIFO parity error",
2361218792Snp		  -1, 1 },
2362218792Snp		{ V_TXDESCFIFO(M_TXDESCFIFO), "MPS Tx desc FIFO parity error",
2363218792Snp		  -1, 1 },
2364218792Snp		{ F_BUBBLE, "MPS Tx underflow", -1, 1 },
2365218792Snp		{ F_SECNTERR, "MPS Tx SOP/EOP error", -1, 1 },
2366218792Snp		{ F_FRMERR, "MPS Tx framing error", -1, 1 },
2367218792Snp		{ 0 }
2368218792Snp	};
2369218792Snp	static struct intr_info mps_trc_intr_info[] = {
2370218792Snp		{ V_FILTMEM(M_FILTMEM), "MPS TRC filter parity error", -1, 1 },
2371218792Snp		{ V_PKTFIFO(M_PKTFIFO), "MPS TRC packet FIFO parity error", -1,
2372218792Snp		  1 },
2373218792Snp		{ F_MISCPERR, "MPS TRC misc parity error", -1, 1 },
2374218792Snp		{ 0 }
2375218792Snp	};
2376218792Snp	static struct intr_info mps_stat_sram_intr_info[] = {
2377218792Snp		{ 0x1fffff, "MPS statistics SRAM parity error", -1, 1 },
2378218792Snp		{ 0 }
2379218792Snp	};
2380218792Snp	static struct intr_info mps_stat_tx_intr_info[] = {
2381218792Snp		{ 0xfffff, "MPS statistics Tx FIFO parity error", -1, 1 },
2382218792Snp		{ 0 }
2383218792Snp	};
2384218792Snp	static struct intr_info mps_stat_rx_intr_info[] = {
2385218792Snp		{ 0xffffff, "MPS statistics Rx FIFO parity error", -1, 1 },
2386218792Snp		{ 0 }
2387218792Snp	};
2388218792Snp	static struct intr_info mps_cls_intr_info[] = {
2389218792Snp		{ F_MATCHSRAM, "MPS match SRAM parity error", -1, 1 },
2390218792Snp		{ F_MATCHTCAM, "MPS match TCAM parity error", -1, 1 },
2391218792Snp		{ F_HASHSRAM, "MPS hash SRAM parity error", -1, 1 },
2392218792Snp		{ 0 }
2393218792Snp	};
2394218792Snp
2395218792Snp	int fat;
2396218792Snp
2397218792Snp	fat = t4_handle_intr_status(adapter, A_MPS_RX_PERR_INT_CAUSE,
2398218792Snp				    mps_rx_intr_info) +
2399218792Snp	      t4_handle_intr_status(adapter, A_MPS_TX_INT_CAUSE,
2400218792Snp				    mps_tx_intr_info) +
2401218792Snp	      t4_handle_intr_status(adapter, A_MPS_TRC_INT_CAUSE,
2402218792Snp				    mps_trc_intr_info) +
2403218792Snp	      t4_handle_intr_status(adapter, A_MPS_STAT_PERR_INT_CAUSE_SRAM,
2404218792Snp				    mps_stat_sram_intr_info) +
2405218792Snp	      t4_handle_intr_status(adapter, A_MPS_STAT_PERR_INT_CAUSE_TX_FIFO,
2406218792Snp				    mps_stat_tx_intr_info) +
2407218792Snp	      t4_handle_intr_status(adapter, A_MPS_STAT_PERR_INT_CAUSE_RX_FIFO,
2408218792Snp				    mps_stat_rx_intr_info) +
2409218792Snp	      t4_handle_intr_status(adapter, A_MPS_CLS_INT_CAUSE,
2410218792Snp				    mps_cls_intr_info);
2411218792Snp
2412218792Snp	t4_write_reg(adapter, A_MPS_INT_CAUSE, 0);
2413218792Snp	t4_read_reg(adapter, A_MPS_INT_CAUSE);                    /* flush */
2414218792Snp	if (fat)
2415218792Snp		t4_fatal_err(adapter);
2416218792Snp}
2417218792Snp
2418218792Snp#define MEM_INT_MASK (F_PERR_INT_CAUSE | F_ECC_CE_INT_CAUSE | F_ECC_UE_INT_CAUSE)
2419218792Snp
2420218792Snp/*
2421218792Snp * EDC/MC interrupt handler.
2422218792Snp */
2423218792Snpstatic void mem_intr_handler(struct adapter *adapter, int idx)
2424218792Snp{
2425218792Snp	static const char name[3][5] = { "EDC0", "EDC1", "MC" };
2426218792Snp
2427218792Snp	unsigned int addr, cnt_addr, v;
2428218792Snp
2429218792Snp	if (idx <= MEM_EDC1) {
2430218792Snp		addr = EDC_REG(A_EDC_INT_CAUSE, idx);
2431218792Snp		cnt_addr = EDC_REG(A_EDC_ECC_STATUS, idx);
2432218792Snp	} else {
2433250090Snp		if (is_t4(adapter)) {
2434250090Snp			addr = A_MC_INT_CAUSE;
2435250090Snp			cnt_addr = A_MC_ECC_STATUS;
2436250090Snp		} else {
2437250090Snp			addr = A_MC_P_INT_CAUSE;
2438250090Snp			cnt_addr = A_MC_P_ECC_STATUS;
2439250090Snp		}
2440218792Snp	}
2441218792Snp
2442218792Snp	v = t4_read_reg(adapter, addr) & MEM_INT_MASK;
2443218792Snp	if (v & F_PERR_INT_CAUSE)
2444218792Snp		CH_ALERT(adapter, "%s FIFO parity error\n", name[idx]);
2445218792Snp	if (v & F_ECC_CE_INT_CAUSE) {
2446218792Snp		u32 cnt = G_ECC_CECNT(t4_read_reg(adapter, cnt_addr));
2447218792Snp
2448218792Snp		t4_write_reg(adapter, cnt_addr, V_ECC_CECNT(M_ECC_CECNT));
2449218792Snp		CH_WARN_RATELIMIT(adapter,
2450218792Snp				  "%u %s correctable ECC data error%s\n",
2451218792Snp				  cnt, name[idx], cnt > 1 ? "s" : "");
2452218792Snp	}
2453218792Snp	if (v & F_ECC_UE_INT_CAUSE)
2454218792Snp		CH_ALERT(adapter, "%s uncorrectable ECC data error\n",
2455218792Snp			 name[idx]);
2456218792Snp
2457218792Snp	t4_write_reg(adapter, addr, v);
2458218792Snp	if (v & (F_PERR_INT_CAUSE | F_ECC_UE_INT_CAUSE))
2459218792Snp		t4_fatal_err(adapter);
2460218792Snp}
2461218792Snp
2462218792Snp/*
2463218792Snp * MA interrupt handler.
2464218792Snp */
2465218792Snpstatic void ma_intr_handler(struct adapter *adapter)
2466218792Snp{
2467218792Snp	u32 v, status = t4_read_reg(adapter, A_MA_INT_CAUSE);
2468218792Snp
2469270297Snp	if (status & F_MEM_PERR_INT_CAUSE) {
2470218792Snp		CH_ALERT(adapter, "MA parity error, parity status %#x\n",
2471270297Snp			 t4_read_reg(adapter, A_MA_PARITY_ERROR_STATUS1));
2472270297Snp		if (is_t5(adapter))
2473270297Snp			CH_ALERT(adapter,
2474270297Snp				 "MA parity error, parity status %#x\n",
2475270297Snp				 t4_read_reg(adapter,
2476270297Snp				 	     A_MA_PARITY_ERROR_STATUS2));
2477270297Snp	}
2478218792Snp	if (status & F_MEM_WRAP_INT_CAUSE) {
2479218792Snp		v = t4_read_reg(adapter, A_MA_INT_WRAP_STATUS);
2480218792Snp		CH_ALERT(adapter, "MA address wrap-around error by client %u to"
2481218792Snp			 " address %#x\n", G_MEM_WRAP_CLIENT_NUM(v),
2482218792Snp			 G_MEM_WRAP_ADDRESS(v) << 4);
2483218792Snp	}
2484218792Snp	t4_write_reg(adapter, A_MA_INT_CAUSE, status);
2485218792Snp	t4_fatal_err(adapter);
2486218792Snp}
2487218792Snp
2488218792Snp/*
2489218792Snp * SMB interrupt handler.
2490218792Snp */
2491218792Snpstatic void smb_intr_handler(struct adapter *adap)
2492218792Snp{
2493218792Snp	static struct intr_info smb_intr_info[] = {
2494218792Snp		{ F_MSTTXFIFOPARINT, "SMB master Tx FIFO parity error", -1, 1 },
2495218792Snp		{ F_MSTRXFIFOPARINT, "SMB master Rx FIFO parity error", -1, 1 },
2496218792Snp		{ F_SLVFIFOPARINT, "SMB slave FIFO parity error", -1, 1 },
2497218792Snp		{ 0 }
2498218792Snp	};
2499218792Snp
2500218792Snp	if (t4_handle_intr_status(adap, A_SMB_INT_CAUSE, smb_intr_info))
2501218792Snp		t4_fatal_err(adap);
2502218792Snp}
2503218792Snp
2504218792Snp/*
2505218792Snp * NC-SI interrupt handler.
2506218792Snp */
2507218792Snpstatic void ncsi_intr_handler(struct adapter *adap)
2508218792Snp{
2509218792Snp	static struct intr_info ncsi_intr_info[] = {
2510218792Snp		{ F_CIM_DM_PRTY_ERR, "NC-SI CIM parity error", -1, 1 },
2511218792Snp		{ F_MPS_DM_PRTY_ERR, "NC-SI MPS parity error", -1, 1 },
2512218792Snp		{ F_TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error", -1, 1 },
2513218792Snp		{ F_RXFIFO_PRTY_ERR, "NC-SI Rx FIFO parity error", -1, 1 },
2514218792Snp		{ 0 }
2515218792Snp	};
2516218792Snp
2517218792Snp	if (t4_handle_intr_status(adap, A_NCSI_INT_CAUSE, ncsi_intr_info))
2518218792Snp		t4_fatal_err(adap);
2519218792Snp}
2520218792Snp
2521218792Snp/*
2522218792Snp * XGMAC interrupt handler.
2523218792Snp */
2524218792Snpstatic void xgmac_intr_handler(struct adapter *adap, int port)
2525218792Snp{
2526248925Snp	u32 v, int_cause_reg;
2527218792Snp
2528248925Snp	if (is_t4(adap))
2529248925Snp		int_cause_reg = PORT_REG(port, A_XGMAC_PORT_INT_CAUSE);
2530248925Snp	else
2531248925Snp		int_cause_reg = T5_PORT_REG(port, A_MAC_PORT_INT_CAUSE);
2532248925Snp
2533248925Snp	v = t4_read_reg(adap, int_cause_reg);
2534248925Snp	v &= (F_TXFIFO_PRTY_ERR | F_RXFIFO_PRTY_ERR);
2535218792Snp	if (!v)
2536218792Snp		return;
2537218792Snp
2538218792Snp	if (v & F_TXFIFO_PRTY_ERR)
2539218792Snp		CH_ALERT(adap, "XGMAC %d Tx FIFO parity error\n", port);
2540218792Snp	if (v & F_RXFIFO_PRTY_ERR)
2541218792Snp		CH_ALERT(adap, "XGMAC %d Rx FIFO parity error\n", port);
2542248925Snp	t4_write_reg(adap, int_cause_reg, v);
2543218792Snp	t4_fatal_err(adap);
2544218792Snp}
2545218792Snp
2546218792Snp/*
2547218792Snp * PL interrupt handler.
2548218792Snp */
2549218792Snpstatic void pl_intr_handler(struct adapter *adap)
2550218792Snp{
2551218792Snp	static struct intr_info pl_intr_info[] = {
2552250090Snp		{ F_FATALPERR, "Fatal parity error", -1, 1 },
2553218792Snp		{ F_PERRVFID, "PL VFID_MAP parity error", -1, 1 },
2554218792Snp		{ 0 }
2555218792Snp	};
2556218792Snp
2557250090Snp	static struct intr_info t5_pl_intr_info[] = {
2558250090Snp		{ F_PL_BUSPERR, "PL bus parity error", -1, 1 },
2559250090Snp		{ F_FATALPERR, "Fatal parity error", -1, 1 },
2560250090Snp		{ 0 }
2561250090Snp	};
2562250090Snp
2563250090Snp	if (t4_handle_intr_status(adap, A_PL_PL_INT_CAUSE,
2564250090Snp	    is_t4(adap) ?  pl_intr_info : t5_pl_intr_info))
2565218792Snp		t4_fatal_err(adap);
2566218792Snp}
2567218792Snp
2568218792Snp#define PF_INTR_MASK (F_PFSW | F_PFCIM)
2569218792Snp#define GLBL_INTR_MASK (F_CIM | F_MPS | F_PL | F_PCIE | F_MC | F_EDC0 | \
2570218792Snp		F_EDC1 | F_LE | F_TP | F_MA | F_PM_TX | F_PM_RX | F_ULP_RX | \
2571218792Snp		F_CPL_SWITCH | F_SGE | F_ULP_TX)
2572218792Snp
2573218792Snp/**
2574218792Snp *	t4_slow_intr_handler - control path interrupt handler
2575218792Snp *	@adapter: the adapter
2576218792Snp *
2577218792Snp *	T4 interrupt handler for non-data global interrupt events, e.g., errors.
2578218792Snp *	The designation 'slow' is because it involves register reads, while
2579218792Snp *	data interrupts typically don't involve any MMIOs.
2580218792Snp */
2581218792Snpint t4_slow_intr_handler(struct adapter *adapter)
2582218792Snp{
2583218792Snp	u32 cause = t4_read_reg(adapter, A_PL_INT_CAUSE);
2584218792Snp
2585218792Snp	if (!(cause & GLBL_INTR_MASK))
2586218792Snp		return 0;
2587218792Snp	if (cause & F_CIM)
2588218792Snp		cim_intr_handler(adapter);
2589218792Snp	if (cause & F_MPS)
2590218792Snp		mps_intr_handler(adapter);
2591218792Snp	if (cause & F_NCSI)
2592218792Snp		ncsi_intr_handler(adapter);
2593218792Snp	if (cause & F_PL)
2594218792Snp		pl_intr_handler(adapter);
2595218792Snp	if (cause & F_SMB)
2596218792Snp		smb_intr_handler(adapter);
2597218792Snp	if (cause & F_XGMAC0)
2598218792Snp		xgmac_intr_handler(adapter, 0);
2599218792Snp	if (cause & F_XGMAC1)
2600218792Snp		xgmac_intr_handler(adapter, 1);
2601218792Snp	if (cause & F_XGMAC_KR0)
2602218792Snp		xgmac_intr_handler(adapter, 2);
2603218792Snp	if (cause & F_XGMAC_KR1)
2604218792Snp		xgmac_intr_handler(adapter, 3);
2605218792Snp	if (cause & F_PCIE)
2606218792Snp		pcie_intr_handler(adapter);
2607218792Snp	if (cause & F_MC)
2608218792Snp		mem_intr_handler(adapter, MEM_MC);
2609218792Snp	if (cause & F_EDC0)
2610218792Snp		mem_intr_handler(adapter, MEM_EDC0);
2611218792Snp	if (cause & F_EDC1)
2612218792Snp		mem_intr_handler(adapter, MEM_EDC1);
2613218792Snp	if (cause & F_LE)
2614218792Snp		le_intr_handler(adapter);
2615218792Snp	if (cause & F_TP)
2616218792Snp		tp_intr_handler(adapter);
2617218792Snp	if (cause & F_MA)
2618218792Snp		ma_intr_handler(adapter);
2619218792Snp	if (cause & F_PM_TX)
2620218792Snp		pmtx_intr_handler(adapter);
2621218792Snp	if (cause & F_PM_RX)
2622218792Snp		pmrx_intr_handler(adapter);
2623218792Snp	if (cause & F_ULP_RX)
2624218792Snp		ulprx_intr_handler(adapter);
2625218792Snp	if (cause & F_CPL_SWITCH)
2626218792Snp		cplsw_intr_handler(adapter);
2627218792Snp	if (cause & F_SGE)
2628218792Snp		sge_intr_handler(adapter);
2629218792Snp	if (cause & F_ULP_TX)
2630218792Snp		ulptx_intr_handler(adapter);
2631218792Snp
2632218792Snp	/* Clear the interrupts just processed for which we are the master. */
2633218792Snp	t4_write_reg(adapter, A_PL_INT_CAUSE, cause & GLBL_INTR_MASK);
2634218792Snp	(void) t4_read_reg(adapter, A_PL_INT_CAUSE); /* flush */
2635218792Snp	return 1;
2636218792Snp}
2637218792Snp
2638218792Snp/**
2639218792Snp *	t4_intr_enable - enable interrupts
2640218792Snp *	@adapter: the adapter whose interrupts should be enabled
2641218792Snp *
2642218792Snp *	Enable PF-specific interrupts for the calling function and the top-level
2643218792Snp *	interrupt concentrator for global interrupts.  Interrupts are already
2644218792Snp *	enabled at each module,	here we just enable the roots of the interrupt
2645218792Snp *	hierarchies.
2646218792Snp *
2647218792Snp *	Note: this function should be called only when the driver manages
2648218792Snp *	non PF-specific interrupts from the various HW modules.  Only one PCI
2649218792Snp *	function at a time should be doing this.
2650218792Snp */
2651218792Snpvoid t4_intr_enable(struct adapter *adapter)
2652218792Snp{
2653218792Snp	u32 pf = G_SOURCEPF(t4_read_reg(adapter, A_PL_WHOAMI));
2654218792Snp
2655218792Snp	t4_write_reg(adapter, A_SGE_INT_ENABLE3, F_ERR_CPL_EXCEED_IQE_SIZE |
2656218792Snp		     F_ERR_INVALID_CIDX_INC | F_ERR_CPL_OPCODE_0 |
2657218792Snp		     F_ERR_DROPPED_DB | F_ERR_DATA_CPL_ON_HIGH_QID1 |
2658218792Snp		     F_ERR_DATA_CPL_ON_HIGH_QID0 | F_ERR_BAD_DB_PIDX3 |
2659218792Snp		     F_ERR_BAD_DB_PIDX2 | F_ERR_BAD_DB_PIDX1 |
2660218792Snp		     F_ERR_BAD_DB_PIDX0 | F_ERR_ING_CTXT_PRIO |
2661218792Snp		     F_ERR_EGR_CTXT_PRIO | F_INGRESS_SIZE_ERR |
2662218792Snp		     F_EGRESS_SIZE_ERR);
2663218792Snp	t4_write_reg(adapter, MYPF_REG(A_PL_PF_INT_ENABLE), PF_INTR_MASK);
2664218792Snp	t4_set_reg_field(adapter, A_PL_INT_MAP0, 0, 1 << pf);
2665218792Snp}
2666218792Snp
2667218792Snp/**
2668218792Snp *	t4_intr_disable - disable interrupts
2669218792Snp *	@adapter: the adapter whose interrupts should be disabled
2670218792Snp *
2671218792Snp *	Disable interrupts.  We only disable the top-level interrupt
2672218792Snp *	concentrators.  The caller must be a PCI function managing global
2673218792Snp *	interrupts.
2674218792Snp */
2675218792Snpvoid t4_intr_disable(struct adapter *adapter)
2676218792Snp{
2677218792Snp	u32 pf = G_SOURCEPF(t4_read_reg(adapter, A_PL_WHOAMI));
2678218792Snp
2679218792Snp	t4_write_reg(adapter, MYPF_REG(A_PL_PF_INT_ENABLE), 0);
2680218792Snp	t4_set_reg_field(adapter, A_PL_INT_MAP0, 1 << pf, 0);
2681218792Snp}
2682218792Snp
2683218792Snp/**
2684218792Snp *	t4_intr_clear - clear all interrupts
2685218792Snp *	@adapter: the adapter whose interrupts should be cleared
2686218792Snp *
2687218792Snp *	Clears all interrupts.  The caller must be a PCI function managing
2688218792Snp *	global interrupts.
2689218792Snp */
2690218792Snpvoid t4_intr_clear(struct adapter *adapter)
2691218792Snp{
2692218792Snp	static const unsigned int cause_reg[] = {
2693218792Snp		A_SGE_INT_CAUSE1, A_SGE_INT_CAUSE2, A_SGE_INT_CAUSE3,
2694218792Snp		A_PCIE_NONFAT_ERR, A_PCIE_INT_CAUSE,
2695270297Snp		A_MA_INT_WRAP_STATUS, A_MA_PARITY_ERROR_STATUS1, A_MA_INT_CAUSE,
2696218792Snp		A_EDC_INT_CAUSE, EDC_REG(A_EDC_INT_CAUSE, 1),
2697218792Snp		A_CIM_HOST_INT_CAUSE, A_CIM_HOST_UPACC_INT_CAUSE,
2698218792Snp		MYPF_REG(A_CIM_PF_HOST_INT_CAUSE),
2699218792Snp		A_TP_INT_CAUSE,
2700218792Snp		A_ULP_RX_INT_CAUSE, A_ULP_TX_INT_CAUSE,
2701218792Snp		A_PM_RX_INT_CAUSE, A_PM_TX_INT_CAUSE,
2702218792Snp		A_MPS_RX_PERR_INT_CAUSE,
2703218792Snp		A_CPL_INTR_CAUSE,
2704218792Snp		MYPF_REG(A_PL_PF_INT_CAUSE),
2705218792Snp		A_PL_PL_INT_CAUSE,
2706218792Snp		A_LE_DB_INT_CAUSE,
2707218792Snp	};
2708218792Snp
2709218792Snp	unsigned int i;
2710218792Snp
2711218792Snp	for (i = 0; i < ARRAY_SIZE(cause_reg); ++i)
2712218792Snp		t4_write_reg(adapter, cause_reg[i], 0xffffffff);
2713218792Snp
2714250090Snp	t4_write_reg(adapter, is_t4(adapter) ? A_MC_INT_CAUSE :
2715250090Snp				A_MC_P_INT_CAUSE, 0xffffffff);
2716250090Snp
2717270297Snp	if (is_t4(adapter)) {
2718270297Snp		t4_write_reg(adapter, A_PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
2719270297Snp				0xffffffff);
2720270297Snp		t4_write_reg(adapter, A_PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
2721270297Snp				0xffffffff);
2722270297Snp	} else
2723270297Snp		t4_write_reg(adapter, A_MA_PARITY_ERROR_STATUS2, 0xffffffff);
2724270297Snp
2725218792Snp	t4_write_reg(adapter, A_PL_INT_CAUSE, GLBL_INTR_MASK);
2726218792Snp	(void) t4_read_reg(adapter, A_PL_INT_CAUSE);          /* flush */
2727218792Snp}
2728218792Snp
2729218792Snp/**
2730218792Snp *	hash_mac_addr - return the hash value of a MAC address
2731218792Snp *	@addr: the 48-bit Ethernet MAC address
2732218792Snp *
2733218792Snp *	Hashes a MAC address according to the hash function used by HW inexact
2734218792Snp *	(hash) address matching.
2735218792Snp */
2736218792Snpstatic int hash_mac_addr(const u8 *addr)
2737218792Snp{
2738218792Snp	u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2];
2739218792Snp	u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5];
2740218792Snp	a ^= b;
2741218792Snp	a ^= (a >> 12);
2742218792Snp	a ^= (a >> 6);
2743218792Snp	return a & 0x3f;
2744218792Snp}
2745218792Snp
2746218792Snp/**
2747218792Snp *	t4_config_rss_range - configure a portion of the RSS mapping table
2748218792Snp *	@adapter: the adapter
2749218792Snp *	@mbox: mbox to use for the FW command
2750218792Snp *	@viid: virtual interface whose RSS subtable is to be written
2751218792Snp *	@start: start entry in the table to write
2752218792Snp *	@n: how many table entries to write
2753218792Snp *	@rspq: values for the "response queue" (Ingress Queue) lookup table
2754218792Snp *	@nrspq: number of values in @rspq
2755218792Snp *
2756218792Snp *	Programs the selected part of the VI's RSS mapping table with the
2757218792Snp *	provided values.  If @nrspq < @n the supplied values are used repeatedly
2758218792Snp *	until the full table range is populated.
2759218792Snp *
2760218792Snp *	The caller must ensure the values in @rspq are in the range allowed for
2761218792Snp *	@viid.
2762218792Snp */
2763218792Snpint t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid,
2764218792Snp			int start, int n, const u16 *rspq, unsigned int nrspq)
2765218792Snp{
2766218792Snp	int ret;
2767218792Snp	const u16 *rsp = rspq;
2768218792Snp	const u16 *rsp_end = rspq + nrspq;
2769218792Snp	struct fw_rss_ind_tbl_cmd cmd;
2770218792Snp
2771218792Snp	memset(&cmd, 0, sizeof(cmd));
2772218792Snp	cmd.op_to_viid = htonl(V_FW_CMD_OP(FW_RSS_IND_TBL_CMD) |
2773218792Snp			       F_FW_CMD_REQUEST | F_FW_CMD_WRITE |
2774218792Snp			       V_FW_RSS_IND_TBL_CMD_VIID(viid));
2775218792Snp	cmd.retval_len16 = htonl(FW_LEN16(cmd));
2776218792Snp
2777218792Snp
2778218792Snp	/*
2779218792Snp	 * Each firmware RSS command can accommodate up to 32 RSS Ingress
2780218792Snp	 * Queue Identifiers.  These Ingress Queue IDs are packed three to
2781218792Snp	 * a 32-bit word as 10-bit values with the upper remaining 2 bits
2782218792Snp	 * reserved.
2783218792Snp	 */
2784218792Snp	while (n > 0) {
2785218792Snp		int nq = min(n, 32);
2786228561Snp		int nq_packed = 0;
2787218792Snp		__be32 *qp = &cmd.iq0_to_iq2;
2788218792Snp
2789218792Snp		/*
2790218792Snp		 * Set up the firmware RSS command header to send the next
2791218792Snp		 * "nq" Ingress Queue IDs to the firmware.
2792218792Snp		 */
2793218792Snp		cmd.niqid = htons(nq);
2794218792Snp		cmd.startidx = htons(start);
2795218792Snp
2796218792Snp		/*
2797218792Snp		 * "nq" more done for the start of the next loop.
2798218792Snp		 */
2799218792Snp		start += nq;
2800218792Snp		n -= nq;
2801218792Snp
2802218792Snp		/*
2803218792Snp		 * While there are still Ingress Queue IDs to stuff into the
2804218792Snp		 * current firmware RSS command, retrieve them from the
2805218792Snp		 * Ingress Queue ID array and insert them into the command.
2806218792Snp		 */
2807218792Snp		while (nq > 0) {
2808218792Snp			/*
2809218792Snp			 * Grab up to the next 3 Ingress Queue IDs (wrapping
2810218792Snp			 * around the Ingress Queue ID array if necessary) and
2811218792Snp			 * insert them into the firmware RSS command at the
2812218792Snp			 * current 3-tuple position within the commad.
2813218792Snp			 */
2814228561Snp			u16 qbuf[3];
2815228561Snp			u16 *qbp = qbuf;
2816228561Snp			int nqbuf = min(3, nq);
2817218792Snp
2818228561Snp			nq -= nqbuf;
2819228561Snp			qbuf[0] = qbuf[1] = qbuf[2] = 0;
2820228561Snp			while (nqbuf && nq_packed < 32) {
2821228561Snp				nqbuf--;
2822228561Snp				nq_packed++;
2823228561Snp				*qbp++ = *rsp++;
2824228561Snp				if (rsp >= rsp_end)
2825228561Snp					rsp = rspq;
2826228561Snp			}
2827228561Snp			*qp++ = cpu_to_be32(V_FW_RSS_IND_TBL_CMD_IQ0(qbuf[0]) |
2828228561Snp					    V_FW_RSS_IND_TBL_CMD_IQ1(qbuf[1]) |
2829228561Snp					    V_FW_RSS_IND_TBL_CMD_IQ2(qbuf[2]));
2830218792Snp		}
2831218792Snp
2832218792Snp		/*
2833218792Snp		 * Send this portion of the RRS table update to the firmware;
2834218792Snp		 * bail out on any errors.
2835218792Snp		 */
2836218792Snp		ret = t4_wr_mbox(adapter, mbox, &cmd, sizeof(cmd), NULL);
2837218792Snp		if (ret)
2838218792Snp			return ret;
2839218792Snp	}
2840218792Snp
2841218792Snp	return 0;
2842218792Snp}
2843218792Snp
2844218792Snp/**
2845218792Snp *	t4_config_glbl_rss - configure the global RSS mode
2846218792Snp *	@adapter: the adapter
2847218792Snp *	@mbox: mbox to use for the FW command
2848218792Snp *	@mode: global RSS mode
2849218792Snp *	@flags: mode-specific flags
2850218792Snp *
2851218792Snp *	Sets the global RSS mode.
2852218792Snp */
2853218792Snpint t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode,
2854218792Snp		       unsigned int flags)
2855218792Snp{
2856218792Snp	struct fw_rss_glb_config_cmd c;
2857218792Snp
2858218792Snp	memset(&c, 0, sizeof(c));
2859218792Snp	c.op_to_write = htonl(V_FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) |
2860218792Snp			      F_FW_CMD_REQUEST | F_FW_CMD_WRITE);
2861218792Snp	c.retval_len16 = htonl(FW_LEN16(c));
2862218792Snp	if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL) {
2863218792Snp		c.u.manual.mode_pkd = htonl(V_FW_RSS_GLB_CONFIG_CMD_MODE(mode));
2864218792Snp	} else if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL) {
2865218792Snp		c.u.basicvirtual.mode_pkd =
2866218792Snp			htonl(V_FW_RSS_GLB_CONFIG_CMD_MODE(mode));
2867218792Snp		c.u.basicvirtual.synmapen_to_hashtoeplitz = htonl(flags);
2868218792Snp	} else
2869218792Snp		return -EINVAL;
2870218792Snp	return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL);
2871218792Snp}
2872218792Snp
2873218792Snp/**
2874218792Snp *	t4_config_vi_rss - configure per VI RSS settings
2875218792Snp *	@adapter: the adapter
2876218792Snp *	@mbox: mbox to use for the FW command
2877218792Snp *	@viid: the VI id
2878218792Snp *	@flags: RSS flags
2879218792Snp *	@defq: id of the default RSS queue for the VI.
2880218792Snp *
2881218792Snp *	Configures VI-specific RSS properties.
2882218792Snp */
2883218792Snpint t4_config_vi_rss(struct adapter *adapter, int mbox, unsigned int viid,
2884218792Snp		     unsigned int flags, unsigned int defq)
2885218792Snp{
2886218792Snp	struct fw_rss_vi_config_cmd c;
2887218792Snp
2888218792Snp	memset(&c, 0, sizeof(c));
2889218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) |
2890218792Snp			     F_FW_CMD_REQUEST | F_FW_CMD_WRITE |
2891218792Snp			     V_FW_RSS_VI_CONFIG_CMD_VIID(viid));
2892218792Snp	c.retval_len16 = htonl(FW_LEN16(c));
2893218792Snp	c.u.basicvirtual.defaultq_to_udpen = htonl(flags |
2894218792Snp					V_FW_RSS_VI_CONFIG_CMD_DEFAULTQ(defq));
2895218792Snp	return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL);
2896218792Snp}
2897218792Snp
2898218792Snp/* Read an RSS table row */
2899218792Snpstatic int rd_rss_row(struct adapter *adap, int row, u32 *val)
2900218792Snp{
2901218792Snp	t4_write_reg(adap, A_TP_RSS_LKP_TABLE, 0xfff00000 | row);
2902218792Snp	return t4_wait_op_done_val(adap, A_TP_RSS_LKP_TABLE, F_LKPTBLROWVLD, 1,
2903218792Snp				   5, 0, val);
2904218792Snp}
2905218792Snp
2906218792Snp/**
2907218792Snp *	t4_read_rss - read the contents of the RSS mapping table
2908218792Snp *	@adapter: the adapter
2909218792Snp *	@map: holds the contents of the RSS mapping table
2910218792Snp *
2911218792Snp *	Reads the contents of the RSS hash->queue mapping table.
2912218792Snp */
2913218792Snpint t4_read_rss(struct adapter *adapter, u16 *map)
2914218792Snp{
2915218792Snp	u32 val;
2916218792Snp	int i, ret;
2917218792Snp
2918218792Snp	for (i = 0; i < RSS_NENTRIES / 2; ++i) {
2919218792Snp		ret = rd_rss_row(adapter, i, &val);
2920218792Snp		if (ret)
2921218792Snp			return ret;
2922218792Snp		*map++ = G_LKPTBLQUEUE0(val);
2923218792Snp		*map++ = G_LKPTBLQUEUE1(val);
2924218792Snp	}
2925218792Snp	return 0;
2926218792Snp}
2927218792Snp
2928218792Snp/**
2929218792Snp *	t4_read_rss_key - read the global RSS key
2930218792Snp *	@adap: the adapter
2931218792Snp *	@key: 10-entry array holding the 320-bit RSS key
2932218792Snp *
2933218792Snp *	Reads the global 320-bit RSS key.
2934218792Snp */
2935218792Snpvoid t4_read_rss_key(struct adapter *adap, u32 *key)
2936218792Snp{
2937218792Snp	t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, key, 10,
2938218792Snp			 A_TP_RSS_SECRET_KEY0);
2939218792Snp}
2940218792Snp
2941218792Snp/**
2942218792Snp *	t4_write_rss_key - program one of the RSS keys
2943218792Snp *	@adap: the adapter
2944218792Snp *	@key: 10-entry array holding the 320-bit RSS key
2945218792Snp *	@idx: which RSS key to write
2946218792Snp *
2947218792Snp *	Writes one of the RSS keys with the given 320-bit value.  If @idx is
2948218792Snp *	0..15 the corresponding entry in the RSS key table is written,
2949218792Snp *	otherwise the global RSS key is written.
2950218792Snp */
2951218792Snpvoid t4_write_rss_key(struct adapter *adap, const u32 *key, int idx)
2952218792Snp{
2953218792Snp	t4_write_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, key, 10,
2954218792Snp			  A_TP_RSS_SECRET_KEY0);
2955218792Snp	if (idx >= 0 && idx < 16)
2956218792Snp		t4_write_reg(adap, A_TP_RSS_CONFIG_VRT,
2957218792Snp			     V_KEYWRADDR(idx) | F_KEYWREN);
2958218792Snp}
2959218792Snp
2960218792Snp/**
2961218792Snp *	t4_read_rss_pf_config - read PF RSS Configuration Table
2962218792Snp *	@adapter: the adapter
2963218792Snp *	@index: the entry in the PF RSS table to read
2964218792Snp *	@valp: where to store the returned value
2965218792Snp *
2966218792Snp *	Reads the PF RSS Configuration Table at the specified index and returns
2967218792Snp *	the value found there.
2968218792Snp */
2969218792Snpvoid t4_read_rss_pf_config(struct adapter *adapter, unsigned int index, u32 *valp)
2970218792Snp{
2971218792Snp	t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
2972218792Snp			 valp, 1, A_TP_RSS_PF0_CONFIG + index);
2973218792Snp}
2974218792Snp
2975218792Snp/**
2976218792Snp *	t4_write_rss_pf_config - write PF RSS Configuration Table
2977218792Snp *	@adapter: the adapter
2978218792Snp *	@index: the entry in the VF RSS table to read
2979218792Snp *	@val: the value to store
2980218792Snp *
2981218792Snp *	Writes the PF RSS Configuration Table at the specified index with the
2982218792Snp *	specified value.
2983218792Snp */
2984218792Snpvoid t4_write_rss_pf_config(struct adapter *adapter, unsigned int index, u32 val)
2985218792Snp{
2986218792Snp	t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
2987218792Snp			  &val, 1, A_TP_RSS_PF0_CONFIG + index);
2988218792Snp}
2989218792Snp
2990218792Snp/**
2991218792Snp *	t4_read_rss_vf_config - read VF RSS Configuration Table
2992218792Snp *	@adapter: the adapter
2993218792Snp *	@index: the entry in the VF RSS table to read
2994218792Snp *	@vfl: where to store the returned VFL
2995218792Snp *	@vfh: where to store the returned VFH
2996218792Snp *
2997218792Snp *	Reads the VF RSS Configuration Table at the specified index and returns
2998218792Snp *	the (VFL, VFH) values found there.
2999218792Snp */
3000218792Snpvoid t4_read_rss_vf_config(struct adapter *adapter, unsigned int index,
3001218792Snp			   u32 *vfl, u32 *vfh)
3002218792Snp{
3003218792Snp	u32 vrt;
3004218792Snp
3005218792Snp	/*
3006218792Snp	 * Request that the index'th VF Table values be read into VFL/VFH.
3007218792Snp	 */
3008218792Snp	vrt = t4_read_reg(adapter, A_TP_RSS_CONFIG_VRT);
3009218792Snp	vrt &= ~(F_VFRDRG | V_VFWRADDR(M_VFWRADDR) | F_VFWREN | F_KEYWREN);
3010218792Snp	vrt |= V_VFWRADDR(index) | F_VFRDEN;
3011218792Snp	t4_write_reg(adapter, A_TP_RSS_CONFIG_VRT, vrt);
3012218792Snp
3013218792Snp	/*
3014218792Snp	 * Grab the VFL/VFH values ...
3015218792Snp	 */
3016218792Snp	t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3017218792Snp			 vfl, 1, A_TP_RSS_VFL_CONFIG);
3018218792Snp	t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3019218792Snp			 vfh, 1, A_TP_RSS_VFH_CONFIG);
3020218792Snp}
3021218792Snp
3022218792Snp/**
3023218792Snp *	t4_write_rss_vf_config - write VF RSS Configuration Table
3024218792Snp *
3025218792Snp *	@adapter: the adapter
3026218792Snp *	@index: the entry in the VF RSS table to write
3027218792Snp *	@vfl: the VFL to store
3028218792Snp *	@vfh: the VFH to store
3029218792Snp *
3030218792Snp *	Writes the VF RSS Configuration Table at the specified index with the
3031218792Snp *	specified (VFL, VFH) values.
3032218792Snp */
3033218792Snpvoid t4_write_rss_vf_config(struct adapter *adapter, unsigned int index,
3034218792Snp			    u32 vfl, u32 vfh)
3035218792Snp{
3036218792Snp	u32 vrt;
3037218792Snp
3038218792Snp	/*
3039218792Snp	 * Load up VFL/VFH with the values to be written ...
3040218792Snp	 */
3041218792Snp	t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3042218792Snp			  &vfl, 1, A_TP_RSS_VFL_CONFIG);
3043218792Snp	t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3044218792Snp			  &vfh, 1, A_TP_RSS_VFH_CONFIG);
3045218792Snp
3046218792Snp	/*
3047218792Snp	 * Write the VFL/VFH into the VF Table at index'th location.
3048218792Snp	 */
3049218792Snp	vrt = t4_read_reg(adapter, A_TP_RSS_CONFIG_VRT);
3050218792Snp	vrt &= ~(F_VFRDRG | F_VFRDEN | V_VFWRADDR(M_VFWRADDR) | F_KEYWREN);
3051218792Snp	vrt |= V_VFWRADDR(index) | F_VFWREN;
3052218792Snp	t4_write_reg(adapter, A_TP_RSS_CONFIG_VRT, vrt);
3053218792Snp}
3054218792Snp
3055218792Snp/**
3056218792Snp *	t4_read_rss_pf_map - read PF RSS Map
3057218792Snp *	@adapter: the adapter
3058218792Snp *
3059218792Snp *	Reads the PF RSS Map register and returns its value.
3060218792Snp */
3061218792Snpu32 t4_read_rss_pf_map(struct adapter *adapter)
3062218792Snp{
3063218792Snp	u32 pfmap;
3064218792Snp
3065218792Snp	t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3066218792Snp			 &pfmap, 1, A_TP_RSS_PF_MAP);
3067218792Snp	return pfmap;
3068218792Snp}
3069218792Snp
3070218792Snp/**
3071218792Snp *	t4_write_rss_pf_map - write PF RSS Map
3072218792Snp *	@adapter: the adapter
3073218792Snp *	@pfmap: PF RSS Map value
3074218792Snp *
3075218792Snp *	Writes the specified value to the PF RSS Map register.
3076218792Snp */
3077218792Snpvoid t4_write_rss_pf_map(struct adapter *adapter, u32 pfmap)
3078218792Snp{
3079218792Snp	t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3080218792Snp			  &pfmap, 1, A_TP_RSS_PF_MAP);
3081218792Snp}
3082218792Snp
3083218792Snp/**
3084218792Snp *	t4_read_rss_pf_mask - read PF RSS Mask
3085218792Snp *	@adapter: the adapter
3086218792Snp *
3087218792Snp *	Reads the PF RSS Mask register and returns its value.
3088218792Snp */
3089218792Snpu32 t4_read_rss_pf_mask(struct adapter *adapter)
3090218792Snp{
3091218792Snp	u32 pfmask;
3092218792Snp
3093218792Snp	t4_read_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3094218792Snp			 &pfmask, 1, A_TP_RSS_PF_MSK);
3095218792Snp	return pfmask;
3096218792Snp}
3097218792Snp
3098218792Snp/**
3099218792Snp *	t4_write_rss_pf_mask - write PF RSS Mask
3100218792Snp *	@adapter: the adapter
3101218792Snp *	@pfmask: PF RSS Mask value
3102218792Snp *
3103218792Snp *	Writes the specified value to the PF RSS Mask register.
3104218792Snp */
3105218792Snpvoid t4_write_rss_pf_mask(struct adapter *adapter, u32 pfmask)
3106218792Snp{
3107218792Snp	t4_write_indirect(adapter, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3108218792Snp			  &pfmask, 1, A_TP_RSS_PF_MSK);
3109218792Snp}
3110218792Snp
3111218792Snp/**
3112218792Snp *	t4_set_filter_mode - configure the optional components of filter tuples
3113218792Snp *	@adap: the adapter
3114218792Snp *	@mode_map: a bitmap selcting which optional filter components to enable
3115218792Snp *
3116218792Snp *	Sets the filter mode by selecting the optional components to enable
3117218792Snp *	in filter tuples.  Returns 0 on success and a negative error if the
3118218792Snp *	requested mode needs more bits than are available for optional
3119218792Snp *	components.
3120218792Snp */
3121218792Snpint t4_set_filter_mode(struct adapter *adap, unsigned int mode_map)
3122218792Snp{
3123218792Snp	static u8 width[] = { 1, 3, 17, 17, 8, 8, 16, 9, 3, 1 };
3124218792Snp
3125218792Snp	int i, nbits = 0;
3126218792Snp
3127218792Snp	for (i = S_FCOE; i <= S_FRAGMENTATION; i++)
3128218792Snp		if (mode_map & (1 << i))
3129218792Snp			nbits += width[i];
3130218792Snp	if (nbits > FILTER_OPT_LEN)
3131218792Snp		return -EINVAL;
3132218792Snp	t4_write_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, &mode_map, 1,
3133218792Snp			  A_TP_VLAN_PRI_MAP);
3134218792Snp	return 0;
3135218792Snp}
3136218792Snp
3137218792Snp/**
3138218792Snp *	t4_tp_get_tcp_stats - read TP's TCP MIB counters
3139218792Snp *	@adap: the adapter
3140218792Snp *	@v4: holds the TCP/IP counter values
3141218792Snp *	@v6: holds the TCP/IPv6 counter values
3142218792Snp *
3143218792Snp *	Returns the values of TP's TCP/IP and TCP/IPv6 MIB counters.
3144218792Snp *	Either @v4 or @v6 may be %NULL to skip the corresponding stats.
3145218792Snp */
3146218792Snpvoid t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
3147218792Snp			 struct tp_tcp_stats *v6)
3148218792Snp{
3149218792Snp	u32 val[A_TP_MIB_TCP_RXT_SEG_LO - A_TP_MIB_TCP_OUT_RST + 1];
3150218792Snp
3151218792Snp#define STAT_IDX(x) ((A_TP_MIB_TCP_##x) - A_TP_MIB_TCP_OUT_RST)
3152218792Snp#define STAT(x)     val[STAT_IDX(x)]
3153218792Snp#define STAT64(x)   (((u64)STAT(x##_HI) << 32) | STAT(x##_LO))
3154218792Snp
3155218792Snp	if (v4) {
3156218792Snp		t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val,
3157218792Snp				 ARRAY_SIZE(val), A_TP_MIB_TCP_OUT_RST);
3158218792Snp		v4->tcpOutRsts = STAT(OUT_RST);
3159218792Snp		v4->tcpInSegs  = STAT64(IN_SEG);
3160218792Snp		v4->tcpOutSegs = STAT64(OUT_SEG);
3161218792Snp		v4->tcpRetransSegs = STAT64(RXT_SEG);
3162218792Snp	}
3163218792Snp	if (v6) {
3164218792Snp		t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val,
3165218792Snp				 ARRAY_SIZE(val), A_TP_MIB_TCP_V6OUT_RST);
3166218792Snp		v6->tcpOutRsts = STAT(OUT_RST);
3167218792Snp		v6->tcpInSegs  = STAT64(IN_SEG);
3168218792Snp		v6->tcpOutSegs = STAT64(OUT_SEG);
3169218792Snp		v6->tcpRetransSegs = STAT64(RXT_SEG);
3170218792Snp	}
3171218792Snp#undef STAT64
3172218792Snp#undef STAT
3173218792Snp#undef STAT_IDX
3174218792Snp}
3175218792Snp
3176218792Snp/**
3177218792Snp *	t4_tp_get_err_stats - read TP's error MIB counters
3178218792Snp *	@adap: the adapter
3179218792Snp *	@st: holds the counter values
3180218792Snp *
3181218792Snp *	Returns the values of TP's error counters.
3182218792Snp */
3183218792Snpvoid t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st)
3184218792Snp{
3185218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->macInErrs,
3186218792Snp			 12, A_TP_MIB_MAC_IN_ERR_0);
3187218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->tnlCongDrops,
3188218792Snp			 8, A_TP_MIB_TNL_CNG_DROP_0);
3189218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->tnlTxDrops,
3190218792Snp			 4, A_TP_MIB_TNL_DROP_0);
3191218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->ofldVlanDrops,
3192218792Snp			 4, A_TP_MIB_OFD_VLN_DROP_0);
3193218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->tcp6InErrs,
3194218792Snp			 4, A_TP_MIB_TCP_V6IN_ERR_0);
3195218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->ofldNoNeigh,
3196218792Snp			 2, A_TP_MIB_OFD_ARP_DROP);
3197218792Snp}
3198218792Snp
3199218792Snp/**
3200218792Snp *	t4_tp_get_proxy_stats - read TP's proxy MIB counters
3201218792Snp *	@adap: the adapter
3202218792Snp *	@st: holds the counter values
3203218792Snp *
3204218792Snp *	Returns the values of TP's proxy counters.
3205218792Snp */
3206218792Snpvoid t4_tp_get_proxy_stats(struct adapter *adap, struct tp_proxy_stats *st)
3207218792Snp{
3208218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->proxy,
3209218792Snp			 4, A_TP_MIB_TNL_LPBK_0);
3210218792Snp}
3211218792Snp
3212218792Snp/**
3213218792Snp *	t4_tp_get_cpl_stats - read TP's CPL MIB counters
3214218792Snp *	@adap: the adapter
3215218792Snp *	@st: holds the counter values
3216218792Snp *
3217218792Snp *	Returns the values of TP's CPL counters.
3218218792Snp */
3219218792Snpvoid t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st)
3220218792Snp{
3221218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->req,
3222218792Snp			 8, A_TP_MIB_CPL_IN_REQ_0);
3223218792Snp}
3224218792Snp
3225218792Snp/**
3226218792Snp *	t4_tp_get_rdma_stats - read TP's RDMA MIB counters
3227218792Snp *	@adap: the adapter
3228218792Snp *	@st: holds the counter values
3229218792Snp *
3230218792Snp *	Returns the values of TP's RDMA counters.
3231218792Snp */
3232218792Snpvoid t4_tp_get_rdma_stats(struct adapter *adap, struct tp_rdma_stats *st)
3233218792Snp{
3234218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->rqe_dfr_mod,
3235218792Snp			 2, A_TP_MIB_RQE_DFR_MOD);
3236218792Snp}
3237218792Snp
3238218792Snp/**
3239218792Snp *	t4_get_fcoe_stats - read TP's FCoE MIB counters for a port
3240218792Snp *	@adap: the adapter
3241218792Snp *	@idx: the port index
3242218792Snp *	@st: holds the counter values
3243218792Snp *
3244218792Snp *	Returns the values of TP's FCoE counters for the selected port.
3245218792Snp */
3246218792Snpvoid t4_get_fcoe_stats(struct adapter *adap, unsigned int idx,
3247218792Snp		       struct tp_fcoe_stats *st)
3248218792Snp{
3249218792Snp	u32 val[2];
3250218792Snp
3251218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->framesDDP,
3252218792Snp			 1, A_TP_MIB_FCOE_DDP_0 + idx);
3253218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->framesDrop,
3254218792Snp			 1, A_TP_MIB_FCOE_DROP_0 + idx);
3255218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val,
3256218792Snp			 2, A_TP_MIB_FCOE_BYTE_0_HI + 2 * idx);
3257218792Snp	st->octetsDDP = ((u64)val[0] << 32) | val[1];
3258218792Snp}
3259218792Snp
3260218792Snp/**
3261218792Snp *	t4_get_usm_stats - read TP's non-TCP DDP MIB counters
3262218792Snp *	@adap: the adapter
3263218792Snp *	@st: holds the counter values
3264218792Snp *
3265218792Snp *	Returns the values of TP's counters for non-TCP directly-placed packets.
3266218792Snp */
3267218792Snpvoid t4_get_usm_stats(struct adapter *adap, struct tp_usm_stats *st)
3268218792Snp{
3269218792Snp	u32 val[4];
3270218792Snp
3271218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val, 4,
3272218792Snp			 A_TP_MIB_USM_PKTS);
3273218792Snp	st->frames = val[0];
3274218792Snp	st->drops = val[1];
3275218792Snp	st->octets = ((u64)val[2] << 32) | val[3];
3276218792Snp}
3277218792Snp
3278218792Snp/**
3279218792Snp *	t4_read_mtu_tbl - returns the values in the HW path MTU table
3280218792Snp *	@adap: the adapter
3281218792Snp *	@mtus: where to store the MTU values
3282218792Snp *	@mtu_log: where to store the MTU base-2 log (may be %NULL)
3283218792Snp *
3284218792Snp *	Reads the HW path MTU table.
3285218792Snp */
3286218792Snpvoid t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log)
3287218792Snp{
3288218792Snp	u32 v;
3289218792Snp	int i;
3290218792Snp
3291218792Snp	for (i = 0; i < NMTUS; ++i) {
3292218792Snp		t4_write_reg(adap, A_TP_MTU_TABLE,
3293218792Snp			     V_MTUINDEX(0xff) | V_MTUVALUE(i));
3294218792Snp		v = t4_read_reg(adap, A_TP_MTU_TABLE);
3295218792Snp		mtus[i] = G_MTUVALUE(v);
3296218792Snp		if (mtu_log)
3297218792Snp			mtu_log[i] = G_MTUWIDTH(v);
3298218792Snp	}
3299218792Snp}
3300218792Snp
3301218792Snp/**
3302218792Snp *	t4_read_cong_tbl - reads the congestion control table
3303218792Snp *	@adap: the adapter
3304218792Snp *	@incr: where to store the alpha values
3305218792Snp *
3306218792Snp *	Reads the additive increments programmed into the HW congestion
3307218792Snp *	control table.
3308218792Snp */
3309218792Snpvoid t4_read_cong_tbl(struct adapter *adap, u16 incr[NMTUS][NCCTRL_WIN])
3310218792Snp{
3311218792Snp	unsigned int mtu, w;
3312218792Snp
3313218792Snp	for (mtu = 0; mtu < NMTUS; ++mtu)
3314218792Snp		for (w = 0; w < NCCTRL_WIN; ++w) {
3315218792Snp			t4_write_reg(adap, A_TP_CCTRL_TABLE,
3316218792Snp				     V_ROWINDEX(0xffff) | (mtu << 5) | w);
3317218792Snp			incr[mtu][w] = (u16)t4_read_reg(adap,
3318218792Snp						A_TP_CCTRL_TABLE) & 0x1fff;
3319218792Snp		}
3320218792Snp}
3321218792Snp
3322218792Snp/**
3323218792Snp *	t4_read_pace_tbl - read the pace table
3324218792Snp *	@adap: the adapter
3325218792Snp *	@pace_vals: holds the returned values
3326218792Snp *
3327218792Snp *	Returns the values of TP's pace table in microseconds.
3328218792Snp */
3329218792Snpvoid t4_read_pace_tbl(struct adapter *adap, unsigned int pace_vals[NTX_SCHED])
3330218792Snp{
3331218792Snp	unsigned int i, v;
3332218792Snp
3333218792Snp	for (i = 0; i < NTX_SCHED; i++) {
3334218792Snp		t4_write_reg(adap, A_TP_PACE_TABLE, 0xffff0000 + i);
3335218792Snp		v = t4_read_reg(adap, A_TP_PACE_TABLE);
3336218792Snp		pace_vals[i] = dack_ticks_to_usec(adap, v);
3337218792Snp	}
3338218792Snp}
3339218792Snp
3340218792Snp/**
3341218792Snp *	t4_tp_wr_bits_indirect - set/clear bits in an indirect TP register
3342218792Snp *	@adap: the adapter
3343218792Snp *	@addr: the indirect TP register address
3344218792Snp *	@mask: specifies the field within the register to modify
3345218792Snp *	@val: new value for the field
3346218792Snp *
3347218792Snp *	Sets a field of an indirect TP register to the given value.
3348218792Snp */
3349218792Snpvoid t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr,
3350218792Snp			    unsigned int mask, unsigned int val)
3351218792Snp{
3352218792Snp	t4_write_reg(adap, A_TP_PIO_ADDR, addr);
3353218792Snp	val |= t4_read_reg(adap, A_TP_PIO_DATA) & ~mask;
3354218792Snp	t4_write_reg(adap, A_TP_PIO_DATA, val);
3355218792Snp}
3356218792Snp
3357218792Snp/**
3358218792Snp *	init_cong_ctrl - initialize congestion control parameters
3359218792Snp *	@a: the alpha values for congestion control
3360218792Snp *	@b: the beta values for congestion control
3361218792Snp *
3362218792Snp *	Initialize the congestion control parameters.
3363218792Snp */
3364218792Snpstatic void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b)
3365218792Snp{
3366218792Snp	a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
3367218792Snp	a[9] = 2;
3368218792Snp	a[10] = 3;
3369218792Snp	a[11] = 4;
3370218792Snp	a[12] = 5;
3371218792Snp	a[13] = 6;
3372218792Snp	a[14] = 7;
3373218792Snp	a[15] = 8;
3374218792Snp	a[16] = 9;
3375218792Snp	a[17] = 10;
3376218792Snp	a[18] = 14;
3377218792Snp	a[19] = 17;
3378218792Snp	a[20] = 21;
3379218792Snp	a[21] = 25;
3380218792Snp	a[22] = 30;
3381218792Snp	a[23] = 35;
3382218792Snp	a[24] = 45;
3383218792Snp	a[25] = 60;
3384218792Snp	a[26] = 80;
3385218792Snp	a[27] = 100;
3386218792Snp	a[28] = 200;
3387218792Snp	a[29] = 300;
3388218792Snp	a[30] = 400;
3389218792Snp	a[31] = 500;
3390218792Snp
3391218792Snp	b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0;
3392218792Snp	b[9] = b[10] = 1;
3393218792Snp	b[11] = b[12] = 2;
3394218792Snp	b[13] = b[14] = b[15] = b[16] = 3;
3395218792Snp	b[17] = b[18] = b[19] = b[20] = b[21] = 4;
3396218792Snp	b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5;
3397218792Snp	b[28] = b[29] = 6;
3398218792Snp	b[30] = b[31] = 7;
3399218792Snp}
3400218792Snp
3401218792Snp/* The minimum additive increment value for the congestion control table */
3402218792Snp#define CC_MIN_INCR 2U
3403218792Snp
3404218792Snp/**
3405218792Snp *	t4_load_mtus - write the MTU and congestion control HW tables
3406218792Snp *	@adap: the adapter
3407218792Snp *	@mtus: the values for the MTU table
3408218792Snp *	@alpha: the values for the congestion control alpha parameter
3409218792Snp *	@beta: the values for the congestion control beta parameter
3410218792Snp *
3411218792Snp *	Write the HW MTU table with the supplied MTUs and the high-speed
3412218792Snp *	congestion control table with the supplied alpha, beta, and MTUs.
3413218792Snp *	We write the two tables together because the additive increments
3414218792Snp *	depend on the MTUs.
3415218792Snp */
3416218792Snpvoid t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
3417218792Snp		  const unsigned short *alpha, const unsigned short *beta)
3418218792Snp{
3419218792Snp	static const unsigned int avg_pkts[NCCTRL_WIN] = {
3420218792Snp		2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640,
3421218792Snp		896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480,
3422218792Snp		28672, 40960, 57344, 81920, 114688, 163840, 229376
3423218792Snp	};
3424218792Snp
3425218792Snp	unsigned int i, w;
3426218792Snp
3427218792Snp	for (i = 0; i < NMTUS; ++i) {
3428218792Snp		unsigned int mtu = mtus[i];
3429218792Snp		unsigned int log2 = fls(mtu);
3430218792Snp
3431218792Snp		if (!(mtu & ((1 << log2) >> 2)))     /* round */
3432218792Snp			log2--;
3433218792Snp		t4_write_reg(adap, A_TP_MTU_TABLE, V_MTUINDEX(i) |
3434218792Snp			     V_MTUWIDTH(log2) | V_MTUVALUE(mtu));
3435218792Snp
3436218792Snp		for (w = 0; w < NCCTRL_WIN; ++w) {
3437218792Snp			unsigned int inc;
3438218792Snp
3439218792Snp			inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w],
3440218792Snp				  CC_MIN_INCR);
3441218792Snp
3442218792Snp			t4_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) |
3443218792Snp				     (w << 16) | (beta[w] << 13) | inc);
3444218792Snp		}
3445218792Snp	}
3446218792Snp}
3447218792Snp
3448218792Snp/**
3449218792Snp *	t4_set_pace_tbl - set the pace table
3450218792Snp *	@adap: the adapter
3451218792Snp *	@pace_vals: the pace values in microseconds
3452218792Snp *	@start: index of the first entry in the HW pace table to set
3453218792Snp *	@n: how many entries to set
3454218792Snp *
3455218792Snp *	Sets (a subset of the) HW pace table.
3456218792Snp */
3457218792Snpint t4_set_pace_tbl(struct adapter *adap, const unsigned int *pace_vals,
3458218792Snp		     unsigned int start, unsigned int n)
3459218792Snp{
3460218792Snp	unsigned int vals[NTX_SCHED], i;
3461218792Snp	unsigned int tick_ns = dack_ticks_to_usec(adap, 1000);
3462218792Snp
3463218792Snp	if (n > NTX_SCHED)
3464218792Snp	    return -ERANGE;
3465218792Snp
3466218792Snp	/* convert values from us to dack ticks, rounding to closest value */
3467218792Snp	for (i = 0; i < n; i++, pace_vals++) {
3468218792Snp		vals[i] = (1000 * *pace_vals + tick_ns / 2) / tick_ns;
3469218792Snp		if (vals[i] > 0x7ff)
3470218792Snp			return -ERANGE;
3471218792Snp		if (*pace_vals && vals[i] == 0)
3472218792Snp			return -ERANGE;
3473218792Snp	}
3474218792Snp	for (i = 0; i < n; i++, start++)
3475218792Snp		t4_write_reg(adap, A_TP_PACE_TABLE, (start << 16) | vals[i]);
3476218792Snp	return 0;
3477218792Snp}
3478218792Snp
3479218792Snp/**
3480218792Snp *	t4_set_sched_bps - set the bit rate for a HW traffic scheduler
3481218792Snp *	@adap: the adapter
3482218792Snp *	@kbps: target rate in Kbps
3483218792Snp *	@sched: the scheduler index
3484218792Snp *
3485218792Snp *	Configure a Tx HW scheduler for the target rate.
3486218792Snp */
3487218792Snpint t4_set_sched_bps(struct adapter *adap, int sched, unsigned int kbps)
3488218792Snp{
3489218792Snp	unsigned int v, tps, cpt, bpt, delta, mindelta = ~0;
3490218792Snp	unsigned int clk = adap->params.vpd.cclk * 1000;
3491218792Snp	unsigned int selected_cpt = 0, selected_bpt = 0;
3492218792Snp
3493218792Snp	if (kbps > 0) {
3494218792Snp		kbps *= 125;     /* -> bytes */
3495218792Snp		for (cpt = 1; cpt <= 255; cpt++) {
3496218792Snp			tps = clk / cpt;
3497218792Snp			bpt = (kbps + tps / 2) / tps;
3498218792Snp			if (bpt > 0 && bpt <= 255) {
3499218792Snp				v = bpt * tps;
3500218792Snp				delta = v >= kbps ? v - kbps : kbps - v;
3501218792Snp				if (delta < mindelta) {
3502218792Snp					mindelta = delta;
3503218792Snp					selected_cpt = cpt;
3504218792Snp					selected_bpt = bpt;
3505218792Snp				}
3506218792Snp			} else if (selected_cpt)
3507218792Snp				break;
3508218792Snp		}
3509218792Snp		if (!selected_cpt)
3510218792Snp			return -EINVAL;
3511218792Snp	}
3512218792Snp	t4_write_reg(adap, A_TP_TM_PIO_ADDR,
3513218792Snp		     A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2);
3514218792Snp	v = t4_read_reg(adap, A_TP_TM_PIO_DATA);
3515218792Snp	if (sched & 1)
3516218792Snp		v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24);
3517218792Snp	else
3518218792Snp		v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8);
3519218792Snp	t4_write_reg(adap, A_TP_TM_PIO_DATA, v);
3520218792Snp	return 0;
3521218792Snp}
3522218792Snp
3523218792Snp/**
3524218792Snp *	t4_set_sched_ipg - set the IPG for a Tx HW packet rate scheduler
3525218792Snp *	@adap: the adapter
3526218792Snp *	@sched: the scheduler index
3527218792Snp *	@ipg: the interpacket delay in tenths of nanoseconds
3528218792Snp *
3529218792Snp *	Set the interpacket delay for a HW packet rate scheduler.
3530218792Snp */
3531218792Snpint t4_set_sched_ipg(struct adapter *adap, int sched, unsigned int ipg)
3532218792Snp{
3533218792Snp	unsigned int v, addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2;
3534218792Snp
3535218792Snp	/* convert ipg to nearest number of core clocks */
3536218792Snp	ipg *= core_ticks_per_usec(adap);
3537218792Snp	ipg = (ipg + 5000) / 10000;
3538218792Snp	if (ipg > M_TXTIMERSEPQ0)
3539218792Snp		return -EINVAL;
3540218792Snp
3541218792Snp	t4_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3542218792Snp	v = t4_read_reg(adap, A_TP_TM_PIO_DATA);
3543218792Snp	if (sched & 1)
3544218792Snp		v = (v & V_TXTIMERSEPQ0(M_TXTIMERSEPQ0)) | V_TXTIMERSEPQ1(ipg);
3545218792Snp	else
3546218792Snp		v = (v & V_TXTIMERSEPQ1(M_TXTIMERSEPQ1)) | V_TXTIMERSEPQ0(ipg);
3547218792Snp	t4_write_reg(adap, A_TP_TM_PIO_DATA, v);
3548218792Snp	t4_read_reg(adap, A_TP_TM_PIO_DATA);
3549218792Snp	return 0;
3550218792Snp}
3551218792Snp
3552218792Snp/**
3553218792Snp *	t4_get_tx_sched - get the configuration of a Tx HW traffic scheduler
3554218792Snp *	@adap: the adapter
3555218792Snp *	@sched: the scheduler index
3556218792Snp *	@kbps: the byte rate in Kbps
3557218792Snp *	@ipg: the interpacket delay in tenths of nanoseconds
3558218792Snp *
3559218792Snp *	Return the current configuration of a HW Tx scheduler.
3560218792Snp */
3561218792Snpvoid t4_get_tx_sched(struct adapter *adap, unsigned int sched, unsigned int *kbps,
3562218792Snp		     unsigned int *ipg)
3563218792Snp{
3564218792Snp	unsigned int v, addr, bpt, cpt;
3565218792Snp
3566218792Snp	if (kbps) {
3567218792Snp		addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
3568218792Snp		t4_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3569218792Snp		v = t4_read_reg(adap, A_TP_TM_PIO_DATA);
3570218792Snp		if (sched & 1)
3571218792Snp			v >>= 16;
3572218792Snp		bpt = (v >> 8) & 0xff;
3573218792Snp		cpt = v & 0xff;
3574218792Snp		if (!cpt)
3575218792Snp			*kbps = 0;        /* scheduler disabled */
3576218792Snp		else {
3577218792Snp			v = (adap->params.vpd.cclk * 1000) / cpt; /* ticks/s */
3578218792Snp			*kbps = (v * bpt) / 125;
3579218792Snp		}
3580218792Snp	}
3581218792Snp	if (ipg) {
3582218792Snp		addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2;
3583218792Snp		t4_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3584218792Snp		v = t4_read_reg(adap, A_TP_TM_PIO_DATA);
3585218792Snp		if (sched & 1)
3586218792Snp			v >>= 16;
3587218792Snp		v &= 0xffff;
3588218792Snp		*ipg = (10000 * v) / core_ticks_per_usec(adap);
3589218792Snp	}
3590218792Snp}
3591218792Snp
3592218792Snp/*
3593218792Snp * Calculates a rate in bytes/s given the number of 256-byte units per 4K core
3594218792Snp * clocks.  The formula is
3595218792Snp *
3596218792Snp * bytes/s = bytes256 * 256 * ClkFreq / 4096
3597218792Snp *
3598218792Snp * which is equivalent to
3599218792Snp *
3600218792Snp * bytes/s = 62.5 * bytes256 * ClkFreq_ms
3601218792Snp */
3602218792Snpstatic u64 chan_rate(struct adapter *adap, unsigned int bytes256)
3603218792Snp{
3604218792Snp	u64 v = bytes256 * adap->params.vpd.cclk;
3605218792Snp
3606218792Snp	return v * 62 + v / 2;
3607218792Snp}
3608218792Snp
3609218792Snp/**
3610218792Snp *	t4_get_chan_txrate - get the current per channel Tx rates
3611218792Snp *	@adap: the adapter
3612218792Snp *	@nic_rate: rates for NIC traffic
3613218792Snp *	@ofld_rate: rates for offloaded traffic
3614218792Snp *
3615218792Snp *	Return the current Tx rates in bytes/s for NIC and offloaded traffic
3616218792Snp *	for each channel.
3617218792Snp */
3618218792Snpvoid t4_get_chan_txrate(struct adapter *adap, u64 *nic_rate, u64 *ofld_rate)
3619218792Snp{
3620218792Snp	u32 v;
3621218792Snp
3622218792Snp	v = t4_read_reg(adap, A_TP_TX_TRATE);
3623218792Snp	nic_rate[0] = chan_rate(adap, G_TNLRATE0(v));
3624218792Snp	nic_rate[1] = chan_rate(adap, G_TNLRATE1(v));
3625218792Snp	nic_rate[2] = chan_rate(adap, G_TNLRATE2(v));
3626218792Snp	nic_rate[3] = chan_rate(adap, G_TNLRATE3(v));
3627218792Snp
3628218792Snp	v = t4_read_reg(adap, A_TP_TX_ORATE);
3629218792Snp	ofld_rate[0] = chan_rate(adap, G_OFDRATE0(v));
3630218792Snp	ofld_rate[1] = chan_rate(adap, G_OFDRATE1(v));
3631218792Snp	ofld_rate[2] = chan_rate(adap, G_OFDRATE2(v));
3632218792Snp	ofld_rate[3] = chan_rate(adap, G_OFDRATE3(v));
3633218792Snp}
3634218792Snp
3635218792Snp/**
3636218792Snp *	t4_set_trace_filter - configure one of the tracing filters
3637218792Snp *	@adap: the adapter
3638218792Snp *	@tp: the desired trace filter parameters
3639218792Snp *	@idx: which filter to configure
3640218792Snp *	@enable: whether to enable or disable the filter
3641218792Snp *
3642253691Snp *	Configures one of the tracing filters available in HW.  If @tp is %NULL
3643253691Snp *	it indicates that the filter is already written in the register and it
3644253691Snp *	just needs to be enabled or disabled.
3645218792Snp */
3646253691Snpint t4_set_trace_filter(struct adapter *adap, const struct trace_params *tp,
3647253691Snp    int idx, int enable)
3648218792Snp{
3649218792Snp	int i, ofst = idx * 4;
3650218792Snp	u32 data_reg, mask_reg, cfg;
3651218792Snp	u32 multitrc = F_TRCMULTIFILTER;
3652253691Snp	u32 en = is_t4(adap) ? F_TFEN : F_T5_TFEN;
3653218792Snp
3654253691Snp	if (idx < 0 || idx >= NTRACE)
3655253691Snp		return -EINVAL;
3656253691Snp
3657253691Snp	if (tp == NULL || !enable) {
3658253691Snp		t4_set_reg_field(adap, A_MPS_TRC_FILTER_MATCH_CTL_A + ofst, en,
3659253691Snp		    enable ? en : 0);
3660237436Snp		return 0;
3661218792Snp	}
3662218792Snp
3663237436Snp	/*
3664237436Snp	 * TODO - After T4 data book is updated, specify the exact
3665237436Snp	 * section below.
3666237436Snp	 *
3667237436Snp	 * See T4 data book - MPS section for a complete description
3668237436Snp	 * of the below if..else handling of A_MPS_TRC_CFG register
3669237436Snp	 * value.
3670237436Snp	 */
3671237436Snp	cfg = t4_read_reg(adap, A_MPS_TRC_CFG);
3672237436Snp	if (cfg & F_TRCMULTIFILTER) {
3673237436Snp		/*
3674237436Snp		 * If multiple tracers are enabled, then maximum
3675237436Snp		 * capture size is 2.5KB (FIFO size of a single channel)
3676237436Snp		 * minus 2 flits for CPL_TRACE_PKT header.
3677237436Snp		 */
3678237436Snp		if (tp->snap_len > ((10 * 1024 / 4) - (2 * 8)))
3679237436Snp			return -EINVAL;
3680253691Snp	} else {
3681237436Snp		/*
3682237436Snp		 * If multiple tracers are disabled, to avoid deadlocks
3683237436Snp		 * maximum packet capture size of 9600 bytes is recommended.
3684237436Snp		 * Also in this mode, only trace0 can be enabled and running.
3685237436Snp		 */
3686218792Snp		multitrc = 0;
3687237436Snp		if (tp->snap_len > 9600 || idx)
3688218792Snp			return -EINVAL;
3689218792Snp	}
3690218792Snp
3691253691Snp	if (tp->port > (is_t4(adap) ? 11 : 19) || tp->invert > 1 ||
3692253691Snp	    tp->skip_len > M_TFLENGTH || tp->skip_ofst > M_TFOFFSET ||
3693253691Snp	    tp->min_len > M_TFMINPKTSIZE)
3694237436Snp		return -EINVAL;
3695237436Snp
3696218792Snp	/* stop the tracer we'll be changing */
3697253691Snp	t4_set_reg_field(adap, A_MPS_TRC_FILTER_MATCH_CTL_A + ofst, en, 0);
3698218792Snp
3699218792Snp	idx *= (A_MPS_TRC_FILTER1_MATCH - A_MPS_TRC_FILTER0_MATCH);
3700218792Snp	data_reg = A_MPS_TRC_FILTER0_MATCH + idx;
3701218792Snp	mask_reg = A_MPS_TRC_FILTER0_DONT_CARE + idx;
3702218792Snp
3703218792Snp	for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) {
3704218792Snp		t4_write_reg(adap, data_reg, tp->data[i]);
3705218792Snp		t4_write_reg(adap, mask_reg, ~tp->mask[i]);
3706218792Snp	}
3707218792Snp	t4_write_reg(adap, A_MPS_TRC_FILTER_MATCH_CTL_B + ofst,
3708218792Snp		     V_TFCAPTUREMAX(tp->snap_len) |
3709218792Snp		     V_TFMINPKTSIZE(tp->min_len));
3710218792Snp	t4_write_reg(adap, A_MPS_TRC_FILTER_MATCH_CTL_A + ofst,
3711253691Snp		     V_TFOFFSET(tp->skip_ofst) | V_TFLENGTH(tp->skip_len) | en |
3712253691Snp		     (is_t4(adap) ?
3713253691Snp		     V_TFPORT(tp->port) | V_TFINVERTMATCH(tp->invert) :
3714253691Snp		     V_T5_TFPORT(tp->port) | V_T5_TFINVERTMATCH(tp->invert)));
3715218792Snp
3716218792Snp	return 0;
3717218792Snp}
3718218792Snp
3719218792Snp/**
3720218792Snp *	t4_get_trace_filter - query one of the tracing filters
3721218792Snp *	@adap: the adapter
3722218792Snp *	@tp: the current trace filter parameters
3723218792Snp *	@idx: which trace filter to query
3724218792Snp *	@enabled: non-zero if the filter is enabled
3725218792Snp *
3726218792Snp *	Returns the current settings of one of the HW tracing filters.
3727218792Snp */
3728218792Snpvoid t4_get_trace_filter(struct adapter *adap, struct trace_params *tp, int idx,
3729218792Snp			 int *enabled)
3730218792Snp{
3731218792Snp	u32 ctla, ctlb;
3732218792Snp	int i, ofst = idx * 4;
3733218792Snp	u32 data_reg, mask_reg;
3734218792Snp
3735218792Snp	ctla = t4_read_reg(adap, A_MPS_TRC_FILTER_MATCH_CTL_A + ofst);
3736218792Snp	ctlb = t4_read_reg(adap, A_MPS_TRC_FILTER_MATCH_CTL_B + ofst);
3737218792Snp
3738248925Snp	if (is_t4(adap)) {
3739248925Snp		*enabled = !!(ctla & F_TFEN);
3740248925Snp		tp->port =  G_TFPORT(ctla);
3741253691Snp		tp->invert = !!(ctla & F_TFINVERTMATCH);
3742248925Snp	} else {
3743248925Snp		*enabled = !!(ctla & F_T5_TFEN);
3744248925Snp		tp->port = G_T5_TFPORT(ctla);
3745253691Snp		tp->invert = !!(ctla & F_T5_TFINVERTMATCH);
3746248925Snp	}
3747218792Snp	tp->snap_len = G_TFCAPTUREMAX(ctlb);
3748218792Snp	tp->min_len = G_TFMINPKTSIZE(ctlb);
3749218792Snp	tp->skip_ofst = G_TFOFFSET(ctla);
3750218792Snp	tp->skip_len = G_TFLENGTH(ctla);
3751218792Snp
3752218792Snp	ofst = (A_MPS_TRC_FILTER1_MATCH - A_MPS_TRC_FILTER0_MATCH) * idx;
3753218792Snp	data_reg = A_MPS_TRC_FILTER0_MATCH + ofst;
3754218792Snp	mask_reg = A_MPS_TRC_FILTER0_DONT_CARE + ofst;
3755218792Snp
3756218792Snp	for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) {
3757218792Snp		tp->mask[i] = ~t4_read_reg(adap, mask_reg);
3758218792Snp		tp->data[i] = t4_read_reg(adap, data_reg) & tp->mask[i];
3759218792Snp	}
3760218792Snp}
3761218792Snp
3762218792Snp/**
3763218792Snp *	t4_pmtx_get_stats - returns the HW stats from PMTX
3764218792Snp *	@adap: the adapter
3765218792Snp *	@cnt: where to store the count statistics
3766218792Snp *	@cycles: where to store the cycle statistics
3767218792Snp *
3768218792Snp *	Returns performance statistics from PMTX.
3769218792Snp */
3770218792Snpvoid t4_pmtx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[])
3771218792Snp{
3772218792Snp	int i;
3773248925Snp	u32 data[2];
3774218792Snp
3775218792Snp	for (i = 0; i < PM_NSTATS; i++) {
3776218792Snp		t4_write_reg(adap, A_PM_TX_STAT_CONFIG, i + 1);
3777218792Snp		cnt[i] = t4_read_reg(adap, A_PM_TX_STAT_COUNT);
3778248925Snp		if (is_t4(adap))
3779248925Snp			cycles[i] = t4_read_reg64(adap, A_PM_TX_STAT_LSB);
3780248925Snp		else {
3781248925Snp			t4_read_indirect(adap, A_PM_TX_DBG_CTRL,
3782248925Snp					 A_PM_TX_DBG_DATA, data, 2,
3783248925Snp					 A_PM_TX_DBG_STAT_MSB);
3784248925Snp			cycles[i] = (((u64)data[0] << 32) | data[1]);
3785248925Snp		}
3786218792Snp	}
3787218792Snp}
3788218792Snp
3789218792Snp/**
3790218792Snp *	t4_pmrx_get_stats - returns the HW stats from PMRX
3791218792Snp *	@adap: the adapter
3792218792Snp *	@cnt: where to store the count statistics
3793218792Snp *	@cycles: where to store the cycle statistics
3794218792Snp *
3795218792Snp *	Returns performance statistics from PMRX.
3796218792Snp */
3797218792Snpvoid t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[])
3798218792Snp{
3799218792Snp	int i;
3800248925Snp	u32 data[2];
3801218792Snp
3802218792Snp	for (i = 0; i < PM_NSTATS; i++) {
3803218792Snp		t4_write_reg(adap, A_PM_RX_STAT_CONFIG, i + 1);
3804218792Snp		cnt[i] = t4_read_reg(adap, A_PM_RX_STAT_COUNT);
3805248925Snp		if (is_t4(adap))
3806248925Snp			cycles[i] = t4_read_reg64(adap, A_PM_RX_STAT_LSB);
3807248925Snp		else {
3808248925Snp			t4_read_indirect(adap, A_PM_RX_DBG_CTRL,
3809248925Snp					 A_PM_RX_DBG_DATA, data, 2,
3810248925Snp					 A_PM_RX_DBG_STAT_MSB);
3811248925Snp			cycles[i] = (((u64)data[0] << 32) | data[1]);
3812248925Snp		}
3813218792Snp	}
3814218792Snp}
3815218792Snp
3816218792Snp/**
3817218792Snp *	get_mps_bg_map - return the buffer groups associated with a port
3818218792Snp *	@adap: the adapter
3819218792Snp *	@idx: the port index
3820218792Snp *
3821218792Snp *	Returns a bitmap indicating which MPS buffer groups are associated
3822218792Snp *	with the given port.  Bit i is set if buffer group i is used by the
3823218792Snp *	port.
3824218792Snp */
3825218792Snpstatic unsigned int get_mps_bg_map(struct adapter *adap, int idx)
3826218792Snp{
3827218792Snp	u32 n = G_NUMPORTS(t4_read_reg(adap, A_MPS_CMN_CTL));
3828218792Snp
3829218792Snp	if (n == 0)
3830218792Snp		return idx == 0 ? 0xf : 0;
3831218792Snp	if (n == 1)
3832218792Snp		return idx < 2 ? (3 << (2 * idx)) : 0;
3833218792Snp	return 1 << idx;
3834218792Snp}
3835218792Snp
3836218792Snp/**
3837237436Snp *      t4_get_port_stats_offset - collect port stats relative to a previous
3838237436Snp *                                 snapshot
3839237436Snp *      @adap: The adapter
3840237436Snp *      @idx: The port
3841237436Snp *      @stats: Current stats to fill
3842237436Snp *      @offset: Previous stats snapshot
3843237436Snp */
3844237436Snpvoid t4_get_port_stats_offset(struct adapter *adap, int idx,
3845237436Snp		struct port_stats *stats,
3846237436Snp		struct port_stats *offset)
3847237436Snp{
3848237436Snp	u64 *s, *o;
3849237436Snp	int i;
3850237436Snp
3851237436Snp	t4_get_port_stats(adap, idx, stats);
3852237436Snp	for (i = 0, s = (u64 *)stats, o = (u64 *)offset ;
3853237436Snp			i < (sizeof(struct port_stats)/sizeof(u64)) ;
3854237436Snp			i++, s++, o++)
3855237436Snp		*s -= *o;
3856237436Snp}
3857237436Snp
3858237436Snp/**
3859218792Snp *	t4_get_port_stats - collect port statistics
3860218792Snp *	@adap: the adapter
3861218792Snp *	@idx: the port index
3862218792Snp *	@p: the stats structure to fill
3863218792Snp *
3864218792Snp *	Collect statistics related to the given port from HW.
3865218792Snp */
3866218792Snpvoid t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
3867218792Snp{
3868218792Snp	u32 bgmap = get_mps_bg_map(adap, idx);
3869218792Snp
3870218792Snp#define GET_STAT(name) \
3871248925Snp	t4_read_reg64(adap, \
3872248925Snp	(is_t4(adap) ? PORT_REG(idx, A_MPS_PORT_STAT_##name##_L) : \
3873248925Snp	T5_PORT_REG(idx, A_MPS_PORT_STAT_##name##_L)))
3874218792Snp#define GET_STAT_COM(name) t4_read_reg64(adap, A_MPS_STAT_##name##_L)
3875218792Snp
3876228561Snp	p->tx_pause            = GET_STAT(TX_PORT_PAUSE);
3877218792Snp	p->tx_octets           = GET_STAT(TX_PORT_BYTES);
3878218792Snp	p->tx_frames           = GET_STAT(TX_PORT_FRAMES);
3879218792Snp	p->tx_bcast_frames     = GET_STAT(TX_PORT_BCAST);
3880218792Snp	p->tx_mcast_frames     = GET_STAT(TX_PORT_MCAST);
3881218792Snp	p->tx_ucast_frames     = GET_STAT(TX_PORT_UCAST);
3882218792Snp	p->tx_error_frames     = GET_STAT(TX_PORT_ERROR);
3883218792Snp	p->tx_frames_64        = GET_STAT(TX_PORT_64B);
3884218792Snp	p->tx_frames_65_127    = GET_STAT(TX_PORT_65B_127B);
3885218792Snp	p->tx_frames_128_255   = GET_STAT(TX_PORT_128B_255B);
3886218792Snp	p->tx_frames_256_511   = GET_STAT(TX_PORT_256B_511B);
3887218792Snp	p->tx_frames_512_1023  = GET_STAT(TX_PORT_512B_1023B);
3888218792Snp	p->tx_frames_1024_1518 = GET_STAT(TX_PORT_1024B_1518B);
3889218792Snp	p->tx_frames_1519_max  = GET_STAT(TX_PORT_1519B_MAX);
3890218792Snp	p->tx_drop             = GET_STAT(TX_PORT_DROP);
3891218792Snp	p->tx_ppp0             = GET_STAT(TX_PORT_PPP0);
3892218792Snp	p->tx_ppp1             = GET_STAT(TX_PORT_PPP1);
3893218792Snp	p->tx_ppp2             = GET_STAT(TX_PORT_PPP2);
3894218792Snp	p->tx_ppp3             = GET_STAT(TX_PORT_PPP3);
3895218792Snp	p->tx_ppp4             = GET_STAT(TX_PORT_PPP4);
3896218792Snp	p->tx_ppp5             = GET_STAT(TX_PORT_PPP5);
3897218792Snp	p->tx_ppp6             = GET_STAT(TX_PORT_PPP6);
3898218792Snp	p->tx_ppp7             = GET_STAT(TX_PORT_PPP7);
3899218792Snp
3900228561Snp	p->rx_pause            = GET_STAT(RX_PORT_PAUSE);
3901218792Snp	p->rx_octets           = GET_STAT(RX_PORT_BYTES);
3902218792Snp	p->rx_frames           = GET_STAT(RX_PORT_FRAMES);
3903218792Snp	p->rx_bcast_frames     = GET_STAT(RX_PORT_BCAST);
3904218792Snp	p->rx_mcast_frames     = GET_STAT(RX_PORT_MCAST);
3905218792Snp	p->rx_ucast_frames     = GET_STAT(RX_PORT_UCAST);
3906218792Snp	p->rx_too_long         = GET_STAT(RX_PORT_MTU_ERROR);
3907218792Snp	p->rx_jabber           = GET_STAT(RX_PORT_MTU_CRC_ERROR);
3908218792Snp	p->rx_fcs_err          = GET_STAT(RX_PORT_CRC_ERROR);
3909218792Snp	p->rx_len_err          = GET_STAT(RX_PORT_LEN_ERROR);
3910218792Snp	p->rx_symbol_err       = GET_STAT(RX_PORT_SYM_ERROR);
3911218792Snp	p->rx_runt             = GET_STAT(RX_PORT_LESS_64B);
3912218792Snp	p->rx_frames_64        = GET_STAT(RX_PORT_64B);
3913218792Snp	p->rx_frames_65_127    = GET_STAT(RX_PORT_65B_127B);
3914218792Snp	p->rx_frames_128_255   = GET_STAT(RX_PORT_128B_255B);
3915218792Snp	p->rx_frames_256_511   = GET_STAT(RX_PORT_256B_511B);
3916218792Snp	p->rx_frames_512_1023  = GET_STAT(RX_PORT_512B_1023B);
3917218792Snp	p->rx_frames_1024_1518 = GET_STAT(RX_PORT_1024B_1518B);
3918218792Snp	p->rx_frames_1519_max  = GET_STAT(RX_PORT_1519B_MAX);
3919218792Snp	p->rx_ppp0             = GET_STAT(RX_PORT_PPP0);
3920218792Snp	p->rx_ppp1             = GET_STAT(RX_PORT_PPP1);
3921218792Snp	p->rx_ppp2             = GET_STAT(RX_PORT_PPP2);
3922218792Snp	p->rx_ppp3             = GET_STAT(RX_PORT_PPP3);
3923218792Snp	p->rx_ppp4             = GET_STAT(RX_PORT_PPP4);
3924218792Snp	p->rx_ppp5             = GET_STAT(RX_PORT_PPP5);
3925218792Snp	p->rx_ppp6             = GET_STAT(RX_PORT_PPP6);
3926218792Snp	p->rx_ppp7             = GET_STAT(RX_PORT_PPP7);
3927218792Snp
3928218792Snp	p->rx_ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_DROP_FRAME) : 0;
3929218792Snp	p->rx_ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_DROP_FRAME) : 0;
3930218792Snp	p->rx_ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_DROP_FRAME) : 0;
3931218792Snp	p->rx_ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_DROP_FRAME) : 0;
3932218792Snp	p->rx_trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_TRUNC_FRAME) : 0;
3933218792Snp	p->rx_trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_TRUNC_FRAME) : 0;
3934218792Snp	p->rx_trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_TRUNC_FRAME) : 0;
3935218792Snp	p->rx_trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_TRUNC_FRAME) : 0;
3936218792Snp
3937218792Snp#undef GET_STAT
3938218792Snp#undef GET_STAT_COM
3939218792Snp}
3940218792Snp
3941218792Snp/**
3942218792Snp *	t4_clr_port_stats - clear port statistics
3943218792Snp *	@adap: the adapter
3944218792Snp *	@idx: the port index
3945218792Snp *
3946218792Snp *	Clear HW statistics for the given port.
3947218792Snp */
3948218792Snpvoid t4_clr_port_stats(struct adapter *adap, int idx)
3949218792Snp{
3950218792Snp	unsigned int i;
3951218792Snp	u32 bgmap = get_mps_bg_map(adap, idx);
3952248925Snp	u32 port_base_addr;
3953218792Snp
3954248925Snp	if (is_t4(adap))
3955248925Snp		port_base_addr = PORT_BASE(idx);
3956248925Snp	else
3957248925Snp		port_base_addr = T5_PORT_BASE(idx);
3958248925Snp
3959218792Snp	for (i = A_MPS_PORT_STAT_TX_PORT_BYTES_L;
3960248925Snp			i <= A_MPS_PORT_STAT_TX_PORT_PPP7_H; i += 8)
3961248925Snp		t4_write_reg(adap, port_base_addr + i, 0);
3962218792Snp	for (i = A_MPS_PORT_STAT_RX_PORT_BYTES_L;
3963248925Snp			i <= A_MPS_PORT_STAT_RX_PORT_LESS_64B_H; i += 8)
3964248925Snp		t4_write_reg(adap, port_base_addr + i, 0);
3965218792Snp	for (i = 0; i < 4; i++)
3966218792Snp		if (bgmap & (1 << i)) {
3967218792Snp			t4_write_reg(adap,
3968218792Snp				A_MPS_STAT_RX_BG_0_MAC_DROP_FRAME_L + i * 8, 0);
3969218792Snp			t4_write_reg(adap,
3970218792Snp				A_MPS_STAT_RX_BG_0_MAC_TRUNC_FRAME_L + i * 8, 0);
3971218792Snp		}
3972218792Snp}
3973218792Snp
3974218792Snp/**
3975218792Snp *	t4_get_lb_stats - collect loopback port statistics
3976218792Snp *	@adap: the adapter
3977218792Snp *	@idx: the loopback port index
3978218792Snp *	@p: the stats structure to fill
3979218792Snp *
3980218792Snp *	Return HW statistics for the given loopback port.
3981218792Snp */
3982218792Snpvoid t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p)
3983218792Snp{
3984218792Snp	u32 bgmap = get_mps_bg_map(adap, idx);
3985218792Snp
3986218792Snp#define GET_STAT(name) \
3987248925Snp	t4_read_reg64(adap, \
3988248925Snp	(is_t4(adap) ? \
3989248925Snp	PORT_REG(idx, A_MPS_PORT_STAT_LB_PORT_##name##_L) : \
3990248925Snp	T5_PORT_REG(idx, A_MPS_PORT_STAT_LB_PORT_##name##_L)))
3991218792Snp#define GET_STAT_COM(name) t4_read_reg64(adap, A_MPS_STAT_##name##_L)
3992218792Snp
3993218792Snp	p->octets           = GET_STAT(BYTES);
3994218792Snp	p->frames           = GET_STAT(FRAMES);
3995218792Snp	p->bcast_frames     = GET_STAT(BCAST);
3996218792Snp	p->mcast_frames     = GET_STAT(MCAST);
3997218792Snp	p->ucast_frames     = GET_STAT(UCAST);
3998218792Snp	p->error_frames     = GET_STAT(ERROR);
3999218792Snp
4000218792Snp	p->frames_64        = GET_STAT(64B);
4001218792Snp	p->frames_65_127    = GET_STAT(65B_127B);
4002218792Snp	p->frames_128_255   = GET_STAT(128B_255B);
4003218792Snp	p->frames_256_511   = GET_STAT(256B_511B);
4004218792Snp	p->frames_512_1023  = GET_STAT(512B_1023B);
4005218792Snp	p->frames_1024_1518 = GET_STAT(1024B_1518B);
4006218792Snp	p->frames_1519_max  = GET_STAT(1519B_MAX);
4007248925Snp	p->drop             = GET_STAT(DROP_FRAMES);
4008218792Snp
4009218792Snp	p->ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_DROP_FRAME) : 0;
4010218792Snp	p->ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_DROP_FRAME) : 0;
4011218792Snp	p->ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_DROP_FRAME) : 0;
4012218792Snp	p->ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_DROP_FRAME) : 0;
4013218792Snp	p->trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_TRUNC_FRAME) : 0;
4014218792Snp	p->trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_TRUNC_FRAME) : 0;
4015218792Snp	p->trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_TRUNC_FRAME) : 0;
4016218792Snp	p->trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_TRUNC_FRAME) : 0;
4017218792Snp
4018218792Snp#undef GET_STAT
4019218792Snp#undef GET_STAT_COM
4020218792Snp}
4021218792Snp
4022218792Snp/**
4023218792Snp *	t4_wol_magic_enable - enable/disable magic packet WoL
4024218792Snp *	@adap: the adapter
4025218792Snp *	@port: the physical port index
4026218792Snp *	@addr: MAC address expected in magic packets, %NULL to disable
4027218792Snp *
4028218792Snp *	Enables/disables magic packet wake-on-LAN for the selected port.
4029218792Snp */
4030218792Snpvoid t4_wol_magic_enable(struct adapter *adap, unsigned int port,
4031218792Snp			 const u8 *addr)
4032218792Snp{
4033248925Snp	u32 mag_id_reg_l, mag_id_reg_h, port_cfg_reg;
4034248925Snp
4035248925Snp	if (is_t4(adap)) {
4036248925Snp		mag_id_reg_l = PORT_REG(port, A_XGMAC_PORT_MAGIC_MACID_LO);
4037248925Snp		mag_id_reg_h = PORT_REG(port, A_XGMAC_PORT_MAGIC_MACID_HI);
4038248925Snp		port_cfg_reg = PORT_REG(port, A_XGMAC_PORT_CFG2);
4039248925Snp	} else {
4040248925Snp		mag_id_reg_l = T5_PORT_REG(port, A_MAC_PORT_MAGIC_MACID_LO);
4041248925Snp		mag_id_reg_h = T5_PORT_REG(port, A_MAC_PORT_MAGIC_MACID_HI);
4042248925Snp		port_cfg_reg = T5_PORT_REG(port, A_MAC_PORT_CFG2);
4043248925Snp	}
4044248925Snp
4045218792Snp	if (addr) {
4046248925Snp		t4_write_reg(adap, mag_id_reg_l,
4047218792Snp			     (addr[2] << 24) | (addr[3] << 16) |
4048218792Snp			     (addr[4] << 8) | addr[5]);
4049248925Snp		t4_write_reg(adap, mag_id_reg_h,
4050218792Snp			     (addr[0] << 8) | addr[1]);
4051218792Snp	}
4052248925Snp	t4_set_reg_field(adap, port_cfg_reg, F_MAGICEN,
4053218792Snp			 V_MAGICEN(addr != NULL));
4054218792Snp}
4055218792Snp
4056218792Snp/**
4057218792Snp *	t4_wol_pat_enable - enable/disable pattern-based WoL
4058218792Snp *	@adap: the adapter
4059218792Snp *	@port: the physical port index
4060218792Snp *	@map: bitmap of which HW pattern filters to set
4061218792Snp *	@mask0: byte mask for bytes 0-63 of a packet
4062218792Snp *	@mask1: byte mask for bytes 64-127 of a packet
4063218792Snp *	@crc: Ethernet CRC for selected bytes
4064218792Snp *	@enable: enable/disable switch
4065218792Snp *
4066218792Snp *	Sets the pattern filters indicated in @map to mask out the bytes
4067218792Snp *	specified in @mask0/@mask1 in received packets and compare the CRC of
4068218792Snp *	the resulting packet against @crc.  If @enable is %true pattern-based
4069218792Snp *	WoL is enabled, otherwise disabled.
4070218792Snp */
4071218792Snpint t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
4072218792Snp		      u64 mask0, u64 mask1, unsigned int crc, bool enable)
4073218792Snp{
4074218792Snp	int i;
4075248925Snp	u32 port_cfg_reg;
4076218792Snp
4077248925Snp	if (is_t4(adap))
4078248925Snp		port_cfg_reg = PORT_REG(port, A_XGMAC_PORT_CFG2);
4079248925Snp	else
4080248925Snp		port_cfg_reg = T5_PORT_REG(port, A_MAC_PORT_CFG2);
4081248925Snp
4082218792Snp	if (!enable) {
4083248925Snp		t4_set_reg_field(adap, port_cfg_reg, F_PATEN, 0);
4084218792Snp		return 0;
4085218792Snp	}
4086218792Snp	if (map > 0xff)
4087218792Snp		return -EINVAL;
4088218792Snp
4089248925Snp#define EPIO_REG(name) \
4090248925Snp	(is_t4(adap) ? PORT_REG(port, A_XGMAC_PORT_EPIO_##name) : \
4091248925Snp	T5_PORT_REG(port, A_MAC_PORT_EPIO_##name))
4092218792Snp
4093218792Snp	t4_write_reg(adap, EPIO_REG(DATA1), mask0 >> 32);
4094218792Snp	t4_write_reg(adap, EPIO_REG(DATA2), mask1);
4095218792Snp	t4_write_reg(adap, EPIO_REG(DATA3), mask1 >> 32);
4096218792Snp
4097218792Snp	for (i = 0; i < NWOL_PAT; i++, map >>= 1) {
4098218792Snp		if (!(map & 1))
4099218792Snp			continue;
4100218792Snp
4101218792Snp		/* write byte masks */
4102218792Snp		t4_write_reg(adap, EPIO_REG(DATA0), mask0);
4103218792Snp		t4_write_reg(adap, EPIO_REG(OP), V_ADDRESS(i) | F_EPIOWR);
4104218792Snp		t4_read_reg(adap, EPIO_REG(OP));                /* flush */
4105218792Snp		if (t4_read_reg(adap, EPIO_REG(OP)) & F_BUSY)
4106218792Snp			return -ETIMEDOUT;
4107218792Snp
4108218792Snp		/* write CRC */
4109218792Snp		t4_write_reg(adap, EPIO_REG(DATA0), crc);
4110218792Snp		t4_write_reg(adap, EPIO_REG(OP), V_ADDRESS(i + 32) | F_EPIOWR);
4111218792Snp		t4_read_reg(adap, EPIO_REG(OP));                /* flush */
4112218792Snp		if (t4_read_reg(adap, EPIO_REG(OP)) & F_BUSY)
4113218792Snp			return -ETIMEDOUT;
4114218792Snp	}
4115218792Snp#undef EPIO_REG
4116218792Snp
4117248925Snp	t4_set_reg_field(adap, port_cfg_reg, 0, F_PATEN);
4118218792Snp	return 0;
4119218792Snp}
4120218792Snp
4121218792Snp/**
4122218792Snp *	t4_mk_filtdelwr - create a delete filter WR
4123218792Snp *	@ftid: the filter ID
4124218792Snp *	@wr: the filter work request to populate
4125218792Snp *	@qid: ingress queue to receive the delete notification
4126218792Snp *
4127218792Snp *	Creates a filter work request to delete the supplied filter.  If @qid is
4128218792Snp *	negative the delete notification is suppressed.
4129218792Snp */
4130218792Snpvoid t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid)
4131218792Snp{
4132218792Snp	memset(wr, 0, sizeof(*wr));
4133218792Snp	wr->op_pkd = htonl(V_FW_WR_OP(FW_FILTER_WR));
4134218792Snp	wr->len16_pkd = htonl(V_FW_WR_LEN16(sizeof(*wr) / 16));
4135218792Snp	wr->tid_to_iq = htonl(V_FW_FILTER_WR_TID(ftid) |
4136218792Snp			      V_FW_FILTER_WR_NOREPLY(qid < 0));
4137218792Snp	wr->del_filter_to_l2tix = htonl(F_FW_FILTER_WR_DEL_FILTER);
4138218792Snp	if (qid >= 0)
4139218792Snp		wr->rx_chan_rx_rpl_iq = htons(V_FW_FILTER_WR_RX_RPL_IQ(qid));
4140218792Snp}
4141218792Snp
4142218792Snp#define INIT_CMD(var, cmd, rd_wr) do { \
4143218792Snp	(var).op_to_write = htonl(V_FW_CMD_OP(FW_##cmd##_CMD) | \
4144218792Snp				  F_FW_CMD_REQUEST | F_FW_CMD_##rd_wr); \
4145218792Snp	(var).retval_len16 = htonl(FW_LEN16(var)); \
4146218792Snp} while (0)
4147218792Snp
4148237436Snpint t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox, u32 addr, u32 val)
4149237436Snp{
4150237436Snp	struct fw_ldst_cmd c;
4151237436Snp
4152237436Snp	memset(&c, 0, sizeof(c));
4153237436Snp	c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
4154237436Snp		F_FW_CMD_WRITE | V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FIRMWARE));
4155237436Snp	c.cycles_to_len16 = htonl(FW_LEN16(c));
4156237436Snp	c.u.addrval.addr = htonl(addr);
4157237436Snp	c.u.addrval.val = htonl(val);
4158237436Snp
4159237436Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4160237436Snp}
4161237436Snp
4162218792Snp/**
4163218792Snp *	t4_mdio_rd - read a PHY register through MDIO
4164218792Snp *	@adap: the adapter
4165218792Snp *	@mbox: mailbox to use for the FW command
4166218792Snp *	@phy_addr: the PHY address
4167218792Snp *	@mmd: the PHY MMD to access (0 for clause 22 PHYs)
4168218792Snp *	@reg: the register to read
4169218792Snp *	@valp: where to store the value
4170218792Snp *
4171218792Snp *	Issues a FW command through the given mailbox to read a PHY register.
4172218792Snp */
4173218792Snpint t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
4174218792Snp	       unsigned int mmd, unsigned int reg, unsigned int *valp)
4175218792Snp{
4176218792Snp	int ret;
4177218792Snp	struct fw_ldst_cmd c;
4178218792Snp
4179218792Snp	memset(&c, 0, sizeof(c));
4180218792Snp	c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
4181218792Snp		F_FW_CMD_READ | V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO));
4182218792Snp	c.cycles_to_len16 = htonl(FW_LEN16(c));
4183218792Snp	c.u.mdio.paddr_mmd = htons(V_FW_LDST_CMD_PADDR(phy_addr) |
4184218792Snp				   V_FW_LDST_CMD_MMD(mmd));
4185218792Snp	c.u.mdio.raddr = htons(reg);
4186218792Snp
4187218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4188218792Snp	if (ret == 0)
4189218792Snp		*valp = ntohs(c.u.mdio.rval);
4190218792Snp	return ret;
4191218792Snp}
4192218792Snp
4193218792Snp/**
4194218792Snp *	t4_mdio_wr - write 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 write
4200218792Snp *	@valp: value to write
4201218792Snp *
4202218792Snp *	Issues a FW command through the given mailbox to write a PHY register.
4203218792Snp */
4204218792Snpint t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
4205218792Snp	       unsigned int mmd, unsigned int reg, unsigned int val)
4206218792Snp{
4207218792Snp	struct fw_ldst_cmd c;
4208218792Snp
4209218792Snp	memset(&c, 0, sizeof(c));
4210218792Snp	c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
4211218792Snp		F_FW_CMD_WRITE | V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO));
4212218792Snp	c.cycles_to_len16 = htonl(FW_LEN16(c));
4213218792Snp	c.u.mdio.paddr_mmd = htons(V_FW_LDST_CMD_PADDR(phy_addr) |
4214218792Snp				   V_FW_LDST_CMD_MMD(mmd));
4215218792Snp	c.u.mdio.raddr = htons(reg);
4216218792Snp	c.u.mdio.rval = htons(val);
4217218792Snp
4218218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4219218792Snp}
4220218792Snp
4221218792Snp/**
4222269082Snp *	t4_i2c_rd - read I2C data from adapter
4223269082Snp *	@adap: the adapter
4224269082Snp *	@port: Port number if per-port device; <0 if not
4225269082Snp *	@devid: per-port device ID or absolute device ID
4226269082Snp *	@offset: byte offset into device I2C space
4227269082Snp *	@len: byte length of I2C space data
4228269082Snp *	@buf: buffer in which to return I2C data
4229269082Snp *
4230269082Snp *	Reads the I2C data from the indicated device and location.
4231269082Snp */
4232269082Snpint t4_i2c_rd(struct adapter *adap, unsigned int mbox,
4233269082Snp	      int port, unsigned int devid,
4234269082Snp	      unsigned int offset, unsigned int len,
4235269082Snp	      u8 *buf)
4236269082Snp{
4237269082Snp	struct fw_ldst_cmd ldst;
4238269082Snp	int ret;
4239269082Snp
4240269082Snp	if (port >= 4 ||
4241269082Snp	    devid >= 256 ||
4242269082Snp	    offset >= 256 ||
4243269082Snp	    len > sizeof ldst.u.i2c.data)
4244269082Snp		return -EINVAL;
4245269082Snp
4246269082Snp	memset(&ldst, 0, sizeof ldst);
4247269082Snp	ldst.op_to_addrspace =
4248269082Snp		cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) |
4249269082Snp			    F_FW_CMD_REQUEST |
4250269082Snp			    F_FW_CMD_READ |
4251269082Snp			    V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_I2C));
4252269082Snp	ldst.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst));
4253269082Snp	ldst.u.i2c.pid = (port < 0 ? 0xff : port);
4254269082Snp	ldst.u.i2c.did = devid;
4255269082Snp	ldst.u.i2c.boffset = offset;
4256269082Snp	ldst.u.i2c.blen = len;
4257269082Snp	ret = t4_wr_mbox(adap, mbox, &ldst, sizeof ldst, &ldst);
4258269082Snp	if (!ret)
4259269082Snp		memcpy(buf, ldst.u.i2c.data, len);
4260269082Snp	return ret;
4261269082Snp}
4262269082Snp
4263269082Snp/**
4264269082Snp *	t4_i2c_wr - write I2C data to adapter
4265269082Snp *	@adap: the adapter
4266269082Snp *	@port: Port number if per-port device; <0 if not
4267269082Snp *	@devid: per-port device ID or absolute device ID
4268269082Snp *	@offset: byte offset into device I2C space
4269269082Snp *	@len: byte length of I2C space data
4270269082Snp *	@buf: buffer containing new I2C data
4271269082Snp *
4272269082Snp *	Write the I2C data to the indicated device and location.
4273269082Snp */
4274269082Snpint t4_i2c_wr(struct adapter *adap, unsigned int mbox,
4275269082Snp	      int port, unsigned int devid,
4276269082Snp	      unsigned int offset, unsigned int len,
4277269082Snp	      u8 *buf)
4278269082Snp{
4279269082Snp	struct fw_ldst_cmd ldst;
4280269082Snp
4281269082Snp	if (port >= 4 ||
4282269082Snp	    devid >= 256 ||
4283269082Snp	    offset >= 256 ||
4284269082Snp	    len > sizeof ldst.u.i2c.data)
4285269082Snp		return -EINVAL;
4286269082Snp
4287269082Snp	memset(&ldst, 0, sizeof ldst);
4288269082Snp	ldst.op_to_addrspace =
4289269082Snp		cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) |
4290269082Snp			    F_FW_CMD_REQUEST |
4291269082Snp			    F_FW_CMD_WRITE |
4292269082Snp			    V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_I2C));
4293269082Snp	ldst.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst));
4294269082Snp	ldst.u.i2c.pid = (port < 0 ? 0xff : port);
4295269082Snp	ldst.u.i2c.did = devid;
4296269082Snp	ldst.u.i2c.boffset = offset;
4297269082Snp	ldst.u.i2c.blen = len;
4298269082Snp	memcpy(ldst.u.i2c.data, buf, len);
4299269082Snp	return t4_wr_mbox(adap, mbox, &ldst, sizeof ldst, &ldst);
4300269082Snp}
4301269082Snp
4302269082Snp/**
4303237436Snp *	t4_sge_ctxt_flush - flush the SGE context cache
4304237436Snp *	@adap: the adapter
4305237436Snp *	@mbox: mailbox to use for the FW command
4306237436Snp *
4307237436Snp *	Issues a FW command through the given mailbox to flush the
4308237436Snp *	SGE context cache.
4309237436Snp */
4310237436Snpint t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox)
4311237436Snp{
4312237436Snp	int ret;
4313237436Snp	struct fw_ldst_cmd c;
4314237436Snp
4315237436Snp	memset(&c, 0, sizeof(c));
4316237436Snp	c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
4317237436Snp			F_FW_CMD_READ |
4318237436Snp			V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_SGE_EGRC));
4319237436Snp	c.cycles_to_len16 = htonl(FW_LEN16(c));
4320237436Snp	c.u.idctxt.msg_ctxtflush = htonl(F_FW_LDST_CMD_CTXTFLUSH);
4321237436Snp
4322237436Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4323237436Snp	return ret;
4324237436Snp}
4325237436Snp
4326237436Snp/**
4327218792Snp *	t4_sge_ctxt_rd - read an SGE context through FW
4328218792Snp *	@adap: the adapter
4329218792Snp *	@mbox: mailbox to use for the FW command
4330218792Snp *	@cid: the context id
4331218792Snp *	@ctype: the context type
4332218792Snp *	@data: where to store the context data
4333218792Snp *
4334218792Snp *	Issues a FW command through the given mailbox to read an SGE context.
4335218792Snp */
4336218792Snpint t4_sge_ctxt_rd(struct adapter *adap, unsigned int mbox, unsigned int cid,
4337218792Snp		   enum ctxt_type ctype, u32 *data)
4338218792Snp{
4339218792Snp	int ret;
4340218792Snp	struct fw_ldst_cmd c;
4341218792Snp
4342218792Snp	if (ctype == CTXT_EGRESS)
4343218792Snp		ret = FW_LDST_ADDRSPC_SGE_EGRC;
4344218792Snp	else if (ctype == CTXT_INGRESS)
4345218792Snp		ret = FW_LDST_ADDRSPC_SGE_INGC;
4346218792Snp	else if (ctype == CTXT_FLM)
4347218792Snp		ret = FW_LDST_ADDRSPC_SGE_FLMC;
4348218792Snp	else
4349218792Snp		ret = FW_LDST_ADDRSPC_SGE_CONMC;
4350218792Snp
4351218792Snp	memset(&c, 0, sizeof(c));
4352218792Snp	c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
4353218792Snp				  F_FW_CMD_READ | V_FW_LDST_CMD_ADDRSPACE(ret));
4354218792Snp	c.cycles_to_len16 = htonl(FW_LEN16(c));
4355218792Snp	c.u.idctxt.physid = htonl(cid);
4356218792Snp
4357218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4358218792Snp	if (ret == 0) {
4359218792Snp		data[0] = ntohl(c.u.idctxt.ctxt_data0);
4360218792Snp		data[1] = ntohl(c.u.idctxt.ctxt_data1);
4361218792Snp		data[2] = ntohl(c.u.idctxt.ctxt_data2);
4362218792Snp		data[3] = ntohl(c.u.idctxt.ctxt_data3);
4363218792Snp		data[4] = ntohl(c.u.idctxt.ctxt_data4);
4364218792Snp		data[5] = ntohl(c.u.idctxt.ctxt_data5);
4365218792Snp	}
4366218792Snp	return ret;
4367218792Snp}
4368218792Snp
4369218792Snp/**
4370218792Snp *	t4_sge_ctxt_rd_bd - read an SGE context bypassing FW
4371218792Snp *	@adap: the adapter
4372218792Snp *	@cid: the context id
4373218792Snp *	@ctype: the context type
4374218792Snp *	@data: where to store the context data
4375218792Snp *
4376218792Snp *	Reads an SGE context directly, bypassing FW.  This is only for
4377218792Snp *	debugging when FW is unavailable.
4378218792Snp */
4379218792Snpint t4_sge_ctxt_rd_bd(struct adapter *adap, unsigned int cid, enum ctxt_type ctype,
4380218792Snp		      u32 *data)
4381218792Snp{
4382218792Snp	int i, ret;
4383218792Snp
4384218792Snp	t4_write_reg(adap, A_SGE_CTXT_CMD, V_CTXTQID(cid) | V_CTXTTYPE(ctype));
4385218792Snp	ret = t4_wait_op_done(adap, A_SGE_CTXT_CMD, F_BUSY, 0, 3, 1);
4386218792Snp	if (!ret)
4387218792Snp		for (i = A_SGE_CTXT_DATA0; i <= A_SGE_CTXT_DATA5; i += 4)
4388218792Snp			*data++ = t4_read_reg(adap, i);
4389218792Snp	return ret;
4390218792Snp}
4391218792Snp
4392218792Snp/**
4393218792Snp *	t4_fw_hello - establish communication with FW
4394218792Snp *	@adap: the adapter
4395218792Snp *	@mbox: mailbox to use for the FW command
4396218792Snp *	@evt_mbox: mailbox to receive async FW events
4397218792Snp *	@master: specifies the caller's willingness to be the device master
4398237436Snp *	@state: returns the current device state (if non-NULL)
4399218792Snp *
4400237436Snp *	Issues a command to establish communication with FW.  Returns either
4401237436Snp *	an error (negative integer) or the mailbox of the Master PF.
4402218792Snp */
4403218792Snpint t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox,
4404218792Snp		enum dev_master master, enum dev_state *state)
4405218792Snp{
4406218792Snp	int ret;
4407218792Snp	struct fw_hello_cmd c;
4408228561Snp	u32 v;
4409228561Snp	unsigned int master_mbox;
4410228561Snp	int retries = FW_CMD_HELLO_RETRIES;
4411218792Snp
4412228561Snpretry:
4413218792Snp	memset(&c, 0, sizeof(c));
4414218792Snp	INIT_CMD(c, HELLO, WRITE);
4415228561Snp	c.err_to_clearinit = htonl(
4416218792Snp		V_FW_HELLO_CMD_MASTERDIS(master == MASTER_CANT) |
4417218792Snp		V_FW_HELLO_CMD_MASTERFORCE(master == MASTER_MUST) |
4418218792Snp		V_FW_HELLO_CMD_MBMASTER(master == MASTER_MUST ? mbox :
4419218792Snp			M_FW_HELLO_CMD_MBMASTER) |
4420228561Snp		V_FW_HELLO_CMD_MBASYNCNOT(evt_mbox) |
4421228561Snp		V_FW_HELLO_CMD_STAGE(FW_HELLO_CMD_STAGE_OS) |
4422228561Snp		F_FW_HELLO_CMD_CLEARINIT);
4423218792Snp
4424228561Snp	/*
4425228561Snp	 * Issue the HELLO command to the firmware.  If it's not successful
4426228561Snp	 * but indicates that we got a "busy" or "timeout" condition, retry
4427247355Snp	 * the HELLO until we exhaust our retry limit.  If we do exceed our
4428247355Snp	 * retry limit, check to see if the firmware left us any error
4429247355Snp	 * information and report that if so ...
4430228561Snp	 */
4431218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4432228561Snp	if (ret != FW_SUCCESS) {
4433228561Snp		if ((ret == -EBUSY || ret == -ETIMEDOUT) && retries-- > 0)
4434228561Snp			goto retry;
4435247355Snp		if (t4_read_reg(adap, A_PCIE_FW) & F_PCIE_FW_ERR)
4436247355Snp			t4_report_fw_error(adap);
4437228561Snp		return ret;
4438228561Snp	}
4439228561Snp
4440228561Snp	v = ntohl(c.err_to_clearinit);
4441228561Snp	master_mbox = G_FW_HELLO_CMD_MBMASTER(v);
4442228561Snp	if (state) {
4443228561Snp		if (v & F_FW_HELLO_CMD_ERR)
4444228561Snp			*state = DEV_STATE_ERR;
4445228561Snp		else if (v & F_FW_HELLO_CMD_INIT)
4446218792Snp			*state = DEV_STATE_INIT;
4447218792Snp		else
4448218792Snp			*state = DEV_STATE_UNINIT;
4449218792Snp	}
4450228561Snp
4451228561Snp	/*
4452228561Snp	 * If we're not the Master PF then we need to wait around for the
4453228561Snp	 * Master PF Driver to finish setting up the adapter.
4454228561Snp	 *
4455228561Snp	 * Note that we also do this wait if we're a non-Master-capable PF and
4456228561Snp	 * there is no current Master PF; a Master PF may show up momentarily
4457228561Snp	 * and we wouldn't want to fail pointlessly.  (This can happen when an
4458228561Snp	 * OS loads lots of different drivers rapidly at the same time).  In
4459228561Snp	 * this case, the Master PF returned by the firmware will be
4460228561Snp	 * M_PCIE_FW_MASTER so the test below will work ...
4461228561Snp	 */
4462228561Snp	if ((v & (F_FW_HELLO_CMD_ERR|F_FW_HELLO_CMD_INIT)) == 0 &&
4463228561Snp	    master_mbox != mbox) {
4464228561Snp		int waiting = FW_CMD_HELLO_TIMEOUT;
4465228561Snp
4466228561Snp		/*
4467228561Snp		 * Wait for the firmware to either indicate an error or
4468228561Snp		 * initialized state.  If we see either of these we bail out
4469228561Snp		 * and report the issue to the caller.  If we exhaust the
4470228561Snp		 * "hello timeout" and we haven't exhausted our retries, try
4471228561Snp		 * again.  Otherwise bail with a timeout error.
4472228561Snp		 */
4473228561Snp		for (;;) {
4474228561Snp			u32 pcie_fw;
4475228561Snp
4476228561Snp			msleep(50);
4477228561Snp			waiting -= 50;
4478228561Snp
4479228561Snp			/*
4480228561Snp			 * If neither Error nor Initialialized are indicated
4481228561Snp			 * by the firmware keep waiting till we exhaust our
4482228561Snp			 * timeout ... and then retry if we haven't exhausted
4483228561Snp			 * our retries ...
4484228561Snp			 */
4485228561Snp			pcie_fw = t4_read_reg(adap, A_PCIE_FW);
4486228561Snp			if (!(pcie_fw & (F_PCIE_FW_ERR|F_PCIE_FW_INIT))) {
4487228561Snp				if (waiting <= 0) {
4488228561Snp					if (retries-- > 0)
4489228561Snp						goto retry;
4490228561Snp
4491228561Snp					return -ETIMEDOUT;
4492228561Snp				}
4493228561Snp				continue;
4494228561Snp			}
4495228561Snp
4496228561Snp			/*
4497228561Snp			 * We either have an Error or Initialized condition
4498228561Snp			 * report errors preferentially.
4499228561Snp			 */
4500228561Snp			if (state) {
4501228561Snp				if (pcie_fw & F_PCIE_FW_ERR)
4502228561Snp					*state = DEV_STATE_ERR;
4503228561Snp				else if (pcie_fw & F_PCIE_FW_INIT)
4504228561Snp					*state = DEV_STATE_INIT;
4505228561Snp			}
4506228561Snp
4507228561Snp			/*
4508228561Snp			 * If we arrived before a Master PF was selected and
4509228561Snp			 * there's not a valid Master PF, grab its identity
4510228561Snp			 * for our caller.
4511228561Snp			 */
4512228561Snp			if (master_mbox == M_PCIE_FW_MASTER &&
4513228561Snp			    (pcie_fw & F_PCIE_FW_MASTER_VLD))
4514228561Snp				master_mbox = G_PCIE_FW_MASTER(pcie_fw);
4515228561Snp			break;
4516228561Snp		}
4517228561Snp	}
4518228561Snp
4519228561Snp	return master_mbox;
4520218792Snp}
4521218792Snp
4522218792Snp/**
4523218792Snp *	t4_fw_bye - end communication with FW
4524218792Snp *	@adap: the adapter
4525218792Snp *	@mbox: mailbox to use for the FW command
4526218792Snp *
4527218792Snp *	Issues a command to terminate communication with FW.
4528218792Snp */
4529218792Snpint t4_fw_bye(struct adapter *adap, unsigned int mbox)
4530218792Snp{
4531218792Snp	struct fw_bye_cmd c;
4532218792Snp
4533218792Snp	memset(&c, 0, sizeof(c));
4534218792Snp	INIT_CMD(c, BYE, WRITE);
4535218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4536218792Snp}
4537218792Snp
4538218792Snp/**
4539228561Snp *	t4_fw_reset - issue a reset to FW
4540218792Snp *	@adap: the adapter
4541218792Snp *	@mbox: mailbox to use for the FW command
4542228561Snp *	@reset: specifies the type of reset to perform
4543218792Snp *
4544228561Snp *	Issues a reset command of the specified type to FW.
4545218792Snp */
4546228561Snpint t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset)
4547218792Snp{
4548228561Snp	struct fw_reset_cmd c;
4549218792Snp
4550218792Snp	memset(&c, 0, sizeof(c));
4551228561Snp	INIT_CMD(c, RESET, WRITE);
4552228561Snp	c.val = htonl(reset);
4553218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4554218792Snp}
4555218792Snp
4556218792Snp/**
4557237436Snp *	t4_fw_halt - issue a reset/halt to FW and put uP into RESET
4558237436Snp *	@adap: the adapter
4559237436Snp *	@mbox: mailbox to use for the FW RESET command (if desired)
4560237436Snp *	@force: force uP into RESET even if FW RESET command fails
4561237436Snp *
4562237436Snp *	Issues a RESET command to firmware (if desired) with a HALT indication
4563237436Snp *	and then puts the microprocessor into RESET state.  The RESET command
4564237436Snp *	will only be issued if a legitimate mailbox is provided (mbox <=
4565237436Snp *	M_PCIE_FW_MASTER).
4566237436Snp *
4567237436Snp *	This is generally used in order for the host to safely manipulate the
4568237436Snp *	adapter without fear of conflicting with whatever the firmware might
4569237436Snp *	be doing.  The only way out of this state is to RESTART the firmware
4570237436Snp *	...
4571237436Snp */
4572237436Snpint t4_fw_halt(struct adapter *adap, unsigned int mbox, int force)
4573237436Snp{
4574237436Snp	int ret = 0;
4575237436Snp
4576237436Snp	/*
4577237436Snp	 * If a legitimate mailbox is provided, issue a RESET command
4578237436Snp	 * with a HALT indication.
4579237436Snp	 */
4580237436Snp	if (mbox <= M_PCIE_FW_MASTER) {
4581237436Snp		struct fw_reset_cmd c;
4582237436Snp
4583237436Snp		memset(&c, 0, sizeof(c));
4584237436Snp		INIT_CMD(c, RESET, WRITE);
4585237436Snp		c.val = htonl(F_PIORST | F_PIORSTMODE);
4586237436Snp		c.halt_pkd = htonl(F_FW_RESET_CMD_HALT);
4587237436Snp		ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4588237436Snp	}
4589237436Snp
4590237436Snp	/*
4591237436Snp	 * Normally we won't complete the operation if the firmware RESET
4592237436Snp	 * command fails but if our caller insists we'll go ahead and put the
4593237436Snp	 * uP into RESET.  This can be useful if the firmware is hung or even
4594237436Snp	 * missing ...  We'll have to take the risk of putting the uP into
4595237436Snp	 * RESET without the cooperation of firmware in that case.
4596237436Snp	 *
4597237436Snp	 * We also force the firmware's HALT flag to be on in case we bypassed
4598237436Snp	 * the firmware RESET command above or we're dealing with old firmware
4599237436Snp	 * which doesn't have the HALT capability.  This will serve as a flag
4600237436Snp	 * for the incoming firmware to know that it's coming out of a HALT
4601237436Snp	 * rather than a RESET ... if it's new enough to understand that ...
4602237436Snp	 */
4603237436Snp	if (ret == 0 || force) {
4604237436Snp		t4_set_reg_field(adap, A_CIM_BOOT_CFG, F_UPCRST, F_UPCRST);
4605237436Snp		t4_set_reg_field(adap, A_PCIE_FW, F_PCIE_FW_HALT, F_PCIE_FW_HALT);
4606237436Snp	}
4607237436Snp
4608237436Snp	/*
4609237436Snp	 * And we always return the result of the firmware RESET command
4610237436Snp	 * even when we force the uP into RESET ...
4611237436Snp	 */
4612237436Snp	return ret;
4613237436Snp}
4614237436Snp
4615237436Snp/**
4616237436Snp *	t4_fw_restart - restart the firmware by taking the uP out of RESET
4617237436Snp *	@adap: the adapter
4618237436Snp *	@reset: if we want to do a RESET to restart things
4619237436Snp *
4620237436Snp *	Restart firmware previously halted by t4_fw_halt().  On successful
4621237436Snp *	return the previous PF Master remains as the new PF Master and there
4622237436Snp *	is no need to issue a new HELLO command, etc.
4623237436Snp *
4624237436Snp *	We do this in two ways:
4625237436Snp *
4626237436Snp *	 1. If we're dealing with newer firmware we'll simply want to take
4627237436Snp *	    the chip's microprocessor out of RESET.  This will cause the
4628237436Snp *	    firmware to start up from its start vector.  And then we'll loop
4629237436Snp *	    until the firmware indicates it's started again (PCIE_FW.HALT
4630237436Snp *	    reset to 0) or we timeout.
4631237436Snp *
4632237436Snp *	 2. If we're dealing with older firmware then we'll need to RESET
4633237436Snp *	    the chip since older firmware won't recognize the PCIE_FW.HALT
4634237436Snp *	    flag and automatically RESET itself on startup.
4635237436Snp */
4636237436Snpint t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset)
4637237436Snp{
4638237436Snp	if (reset) {
4639237436Snp		/*
4640237436Snp		 * Since we're directing the RESET instead of the firmware
4641237436Snp		 * doing it automatically, we need to clear the PCIE_FW.HALT
4642237436Snp		 * bit.
4643237436Snp		 */
4644237436Snp		t4_set_reg_field(adap, A_PCIE_FW, F_PCIE_FW_HALT, 0);
4645237436Snp
4646237436Snp		/*
4647237436Snp		 * If we've been given a valid mailbox, first try to get the
4648237436Snp		 * firmware to do the RESET.  If that works, great and we can
4649237436Snp		 * return success.  Otherwise, if we haven't been given a
4650237436Snp		 * valid mailbox or the RESET command failed, fall back to
4651237436Snp		 * hitting the chip with a hammer.
4652237436Snp		 */
4653237436Snp		if (mbox <= M_PCIE_FW_MASTER) {
4654237436Snp			t4_set_reg_field(adap, A_CIM_BOOT_CFG, F_UPCRST, 0);
4655237436Snp			msleep(100);
4656237436Snp			if (t4_fw_reset(adap, mbox,
4657237436Snp					F_PIORST | F_PIORSTMODE) == 0)
4658237436Snp				return 0;
4659237436Snp		}
4660237436Snp
4661237436Snp		t4_write_reg(adap, A_PL_RST, F_PIORST | F_PIORSTMODE);
4662237436Snp		msleep(2000);
4663237436Snp	} else {
4664237436Snp		int ms;
4665237436Snp
4666237436Snp		t4_set_reg_field(adap, A_CIM_BOOT_CFG, F_UPCRST, 0);
4667237436Snp		for (ms = 0; ms < FW_CMD_MAX_TIMEOUT; ) {
4668237436Snp			if (!(t4_read_reg(adap, A_PCIE_FW) & F_PCIE_FW_HALT))
4669237436Snp				return FW_SUCCESS;
4670237436Snp			msleep(100);
4671237436Snp			ms += 100;
4672237436Snp		}
4673237436Snp		return -ETIMEDOUT;
4674237436Snp	}
4675237436Snp	return 0;
4676237436Snp}
4677237436Snp
4678237436Snp/**
4679237436Snp *	t4_fw_upgrade - perform all of the steps necessary to upgrade FW
4680237436Snp *	@adap: the adapter
4681237436Snp *	@mbox: mailbox to use for the FW RESET command (if desired)
4682237436Snp *	@fw_data: the firmware image to write
4683237436Snp *	@size: image size
4684237436Snp *	@force: force upgrade even if firmware doesn't cooperate
4685237436Snp *
4686237436Snp *	Perform all of the steps necessary for upgrading an adapter's
4687237436Snp *	firmware image.  Normally this requires the cooperation of the
4688237436Snp *	existing firmware in order to halt all existing activities
4689237436Snp *	but if an invalid mailbox token is passed in we skip that step
4690237436Snp *	(though we'll still put the adapter microprocessor into RESET in
4691237436Snp *	that case).
4692237436Snp *
4693237436Snp *	On successful return the new firmware will have been loaded and
4694237436Snp *	the adapter will have been fully RESET losing all previous setup
4695237436Snp *	state.  On unsuccessful return the adapter may be completely hosed ...
4696237436Snp *	positive errno indicates that the adapter is ~probably~ intact, a
4697237436Snp *	negative errno indicates that things are looking bad ...
4698237436Snp */
4699237436Snpint t4_fw_upgrade(struct adapter *adap, unsigned int mbox,
4700237436Snp		  const u8 *fw_data, unsigned int size, int force)
4701237436Snp{
4702237436Snp	const struct fw_hdr *fw_hdr = (const struct fw_hdr *)fw_data;
4703252661Snp	unsigned int bootstrap = ntohl(fw_hdr->magic) == FW_HDR_MAGIC_BOOTSTRAP;
4704237436Snp	int reset, ret;
4705237436Snp
4706252661Snp	if (!bootstrap) {
4707252661Snp		ret = t4_fw_halt(adap, mbox, force);
4708252661Snp		if (ret < 0 && !force)
4709252661Snp			return ret;
4710252661Snp	}
4711237436Snp
4712237436Snp	ret = t4_load_fw(adap, fw_data, size);
4713252661Snp	if (ret < 0 || bootstrap)
4714237436Snp		return ret;
4715237436Snp
4716237436Snp	/*
4717237436Snp	 * Older versions of the firmware don't understand the new
4718237436Snp	 * PCIE_FW.HALT flag and so won't know to perform a RESET when they
4719237436Snp	 * restart.  So for newly loaded older firmware we'll have to do the
4720237436Snp	 * RESET for it so it starts up on a clean slate.  We can tell if
4721237436Snp	 * the newly loaded firmware will handle this right by checking
4722237436Snp	 * its header flags to see if it advertises the capability.
4723237436Snp	 */
4724237436Snp	reset = ((ntohl(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0);
4725237436Snp	return t4_fw_restart(adap, mbox, reset);
4726237436Snp}
4727237436Snp
4728237436Snp/**
4729228561Snp *	t4_fw_initialize - ask FW to initialize the device
4730218792Snp *	@adap: the adapter
4731218792Snp *	@mbox: mailbox to use for the FW command
4732218792Snp *
4733228561Snp *	Issues a command to FW to partially initialize the device.  This
4734228561Snp *	performs initialization that generally doesn't depend on user input.
4735218792Snp */
4736228561Snpint t4_fw_initialize(struct adapter *adap, unsigned int mbox)
4737218792Snp{
4738228561Snp	struct fw_initialize_cmd c;
4739218792Snp
4740218792Snp	memset(&c, 0, sizeof(c));
4741228561Snp	INIT_CMD(c, INITIALIZE, WRITE);
4742218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4743218792Snp}
4744218792Snp
4745218792Snp/**
4746218792Snp *	t4_query_params - query FW or device parameters
4747218792Snp *	@adap: the adapter
4748218792Snp *	@mbox: mailbox to use for the FW command
4749218792Snp *	@pf: the PF
4750218792Snp *	@vf: the VF
4751218792Snp *	@nparams: the number of parameters
4752218792Snp *	@params: the parameter names
4753218792Snp *	@val: the parameter values
4754218792Snp *
4755218792Snp *	Reads the value of FW or device parameters.  Up to 7 parameters can be
4756218792Snp *	queried at once.
4757218792Snp */
4758218792Snpint t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
4759218792Snp		    unsigned int vf, unsigned int nparams, const u32 *params,
4760218792Snp		    u32 *val)
4761218792Snp{
4762218792Snp	int i, ret;
4763218792Snp	struct fw_params_cmd c;
4764218792Snp	__be32 *p = &c.param[0].mnem;
4765218792Snp
4766218792Snp	if (nparams > 7)
4767218792Snp		return -EINVAL;
4768218792Snp
4769218792Snp	memset(&c, 0, sizeof(c));
4770218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_PARAMS_CMD) | F_FW_CMD_REQUEST |
4771218792Snp			    F_FW_CMD_READ | V_FW_PARAMS_CMD_PFN(pf) |
4772218792Snp			    V_FW_PARAMS_CMD_VFN(vf));
4773218792Snp	c.retval_len16 = htonl(FW_LEN16(c));
4774218792Snp
4775250090Snp	for (i = 0; i < nparams; i++, p += 2, params++)
4776250090Snp		*p = htonl(*params);
4777218792Snp
4778218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4779218792Snp	if (ret == 0)
4780218792Snp		for (i = 0, p = &c.param[0].val; i < nparams; i++, p += 2)
4781218792Snp			*val++ = ntohl(*p);
4782218792Snp	return ret;
4783218792Snp}
4784218792Snp
4785218792Snp/**
4786218792Snp *	t4_set_params - sets FW or device parameters
4787218792Snp *	@adap: the adapter
4788218792Snp *	@mbox: mailbox to use for the FW command
4789218792Snp *	@pf: the PF
4790218792Snp *	@vf: the VF
4791218792Snp *	@nparams: the number of parameters
4792218792Snp *	@params: the parameter names
4793218792Snp *	@val: the parameter values
4794218792Snp *
4795218792Snp *	Sets the value of FW or device parameters.  Up to 7 parameters can be
4796218792Snp *	specified at once.
4797218792Snp */
4798218792Snpint t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
4799218792Snp		  unsigned int vf, unsigned int nparams, const u32 *params,
4800218792Snp		  const u32 *val)
4801218792Snp{
4802218792Snp	struct fw_params_cmd c;
4803218792Snp	__be32 *p = &c.param[0].mnem;
4804218792Snp
4805218792Snp	if (nparams > 7)
4806218792Snp		return -EINVAL;
4807218792Snp
4808218792Snp	memset(&c, 0, sizeof(c));
4809218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_PARAMS_CMD) | F_FW_CMD_REQUEST |
4810218792Snp			    F_FW_CMD_WRITE | V_FW_PARAMS_CMD_PFN(pf) |
4811218792Snp			    V_FW_PARAMS_CMD_VFN(vf));
4812218792Snp	c.retval_len16 = htonl(FW_LEN16(c));
4813218792Snp
4814218792Snp	while (nparams--) {
4815250090Snp		*p++ = htonl(*params);
4816250090Snp		params++;
4817250090Snp		*p++ = htonl(*val);
4818250090Snp		val++;
4819218792Snp	}
4820218792Snp
4821218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4822218792Snp}
4823218792Snp
4824218792Snp/**
4825218792Snp *	t4_cfg_pfvf - configure PF/VF resource limits
4826218792Snp *	@adap: the adapter
4827218792Snp *	@mbox: mailbox to use for the FW command
4828218792Snp *	@pf: the PF being configured
4829218792Snp *	@vf: the VF being configured
4830218792Snp *	@txq: the max number of egress queues
4831218792Snp *	@txq_eth_ctrl: the max number of egress Ethernet or control queues
4832218792Snp *	@rxqi: the max number of interrupt-capable ingress queues
4833218792Snp *	@rxq: the max number of interruptless ingress queues
4834218792Snp *	@tc: the PCI traffic class
4835218792Snp *	@vi: the max number of virtual interfaces
4836218792Snp *	@cmask: the channel access rights mask for the PF/VF
4837218792Snp *	@pmask: the port access rights mask for the PF/VF
4838218792Snp *	@nexact: the maximum number of exact MPS filters
4839218792Snp *	@rcaps: read capabilities
4840218792Snp *	@wxcaps: write/execute capabilities
4841218792Snp *
4842218792Snp *	Configures resource limits and capabilities for a physical or virtual
4843218792Snp *	function.
4844218792Snp */
4845218792Snpint t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf,
4846218792Snp		unsigned int vf, unsigned int txq, unsigned int txq_eth_ctrl,
4847218792Snp		unsigned int rxqi, unsigned int rxq, unsigned int tc,
4848218792Snp		unsigned int vi, unsigned int cmask, unsigned int pmask,
4849218792Snp		unsigned int nexact, unsigned int rcaps, unsigned int wxcaps)
4850218792Snp{
4851218792Snp	struct fw_pfvf_cmd c;
4852218792Snp
4853218792Snp	memset(&c, 0, sizeof(c));
4854218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_PFVF_CMD) | F_FW_CMD_REQUEST |
4855218792Snp			    F_FW_CMD_WRITE | V_FW_PFVF_CMD_PFN(pf) |
4856218792Snp			    V_FW_PFVF_CMD_VFN(vf));
4857218792Snp	c.retval_len16 = htonl(FW_LEN16(c));
4858218792Snp	c.niqflint_niq = htonl(V_FW_PFVF_CMD_NIQFLINT(rxqi) |
4859218792Snp			       V_FW_PFVF_CMD_NIQ(rxq));
4860218792Snp	c.type_to_neq = htonl(V_FW_PFVF_CMD_CMASK(cmask) |
4861218792Snp			      V_FW_PFVF_CMD_PMASK(pmask) |
4862218792Snp			      V_FW_PFVF_CMD_NEQ(txq));
4863218792Snp	c.tc_to_nexactf = htonl(V_FW_PFVF_CMD_TC(tc) | V_FW_PFVF_CMD_NVI(vi) |
4864218792Snp				V_FW_PFVF_CMD_NEXACTF(nexact));
4865218792Snp	c.r_caps_to_nethctrl = htonl(V_FW_PFVF_CMD_R_CAPS(rcaps) |
4866218792Snp				     V_FW_PFVF_CMD_WX_CAPS(wxcaps) |
4867218792Snp				     V_FW_PFVF_CMD_NETHCTRL(txq_eth_ctrl));
4868218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4869218792Snp}
4870218792Snp
4871218792Snp/**
4872237436Snp *	t4_alloc_vi_func - allocate a virtual interface
4873218792Snp *	@adap: the adapter
4874218792Snp *	@mbox: mailbox to use for the FW command
4875218792Snp *	@port: physical port associated with the VI
4876218792Snp *	@pf: the PF owning the VI
4877218792Snp *	@vf: the VF owning the VI
4878218792Snp *	@nmac: number of MAC addresses needed (1 to 5)
4879218792Snp *	@mac: the MAC addresses of the VI
4880218792Snp *	@rss_size: size of RSS table slice associated with this VI
4881237436Snp *	@portfunc: which Port Application Function MAC Address is desired
4882237436Snp *	@idstype: Intrusion Detection Type
4883218792Snp *
4884218792Snp *	Allocates a virtual interface for the given physical port.  If @mac is
4885218792Snp *	not %NULL it contains the MAC addresses of the VI as assigned by FW.
4886218792Snp *	@mac should be large enough to hold @nmac Ethernet addresses, they are
4887218792Snp *	stored consecutively so the space needed is @nmac * 6 bytes.
4888218792Snp *	Returns a negative error number or the non-negative VI id.
4889218792Snp */
4890237436Snpint t4_alloc_vi_func(struct adapter *adap, unsigned int mbox,
4891237436Snp		     unsigned int port, unsigned int pf, unsigned int vf,
4892270297Snp		     unsigned int nmac, u8 *mac, u16 *rss_size,
4893237436Snp		     unsigned int portfunc, unsigned int idstype)
4894218792Snp{
4895218792Snp	int ret;
4896218792Snp	struct fw_vi_cmd c;
4897218792Snp
4898218792Snp	memset(&c, 0, sizeof(c));
4899218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_VI_CMD) | F_FW_CMD_REQUEST |
4900218792Snp			    F_FW_CMD_WRITE | F_FW_CMD_EXEC |
4901218792Snp			    V_FW_VI_CMD_PFN(pf) | V_FW_VI_CMD_VFN(vf));
4902218792Snp	c.alloc_to_len16 = htonl(F_FW_VI_CMD_ALLOC | FW_LEN16(c));
4903237436Snp	c.type_to_viid = htons(V_FW_VI_CMD_TYPE(idstype) |
4904237436Snp			       V_FW_VI_CMD_FUNC(portfunc));
4905218792Snp	c.portid_pkd = V_FW_VI_CMD_PORTID(port);
4906218792Snp	c.nmac = nmac - 1;
4907218792Snp
4908218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4909218792Snp	if (ret)
4910218792Snp		return ret;
4911218792Snp
4912218792Snp	if (mac) {
4913218792Snp		memcpy(mac, c.mac, sizeof(c.mac));
4914218792Snp		switch (nmac) {
4915218792Snp		case 5:
4916218792Snp			memcpy(mac + 24, c.nmac3, sizeof(c.nmac3));
4917218792Snp		case 4:
4918218792Snp			memcpy(mac + 18, c.nmac2, sizeof(c.nmac2));
4919218792Snp		case 3:
4920218792Snp			memcpy(mac + 12, c.nmac1, sizeof(c.nmac1));
4921218792Snp		case 2:
4922218792Snp			memcpy(mac + 6,  c.nmac0, sizeof(c.nmac0));
4923218792Snp		}
4924218792Snp	}
4925218792Snp	if (rss_size)
4926247289Snp		*rss_size = G_FW_VI_CMD_RSSSIZE(ntohs(c.norss_rsssize));
4927237436Snp	return G_FW_VI_CMD_VIID(htons(c.type_to_viid));
4928218792Snp}
4929218792Snp
4930218792Snp/**
4931237436Snp *	t4_alloc_vi - allocate an [Ethernet Function] virtual interface
4932237436Snp *	@adap: the adapter
4933237436Snp *	@mbox: mailbox to use for the FW command
4934237436Snp *	@port: physical port associated with the VI
4935237436Snp *	@pf: the PF owning the VI
4936237436Snp *	@vf: the VF owning the VI
4937237436Snp *	@nmac: number of MAC addresses needed (1 to 5)
4938237436Snp *	@mac: the MAC addresses of the VI
4939237436Snp *	@rss_size: size of RSS table slice associated with this VI
4940237436Snp *
4941237436Snp *	backwards compatible and convieniance routine to allocate a Virtual
4942237436Snp *	Interface with a Ethernet Port Application Function and Intrustion
4943237436Snp *	Detection System disabled.
4944237436Snp */
4945237436Snpint t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port,
4946237436Snp		unsigned int pf, unsigned int vf, unsigned int nmac, u8 *mac,
4947270297Snp		u16 *rss_size)
4948237436Snp{
4949237436Snp	return t4_alloc_vi_func(adap, mbox, port, pf, vf, nmac, mac, rss_size,
4950237436Snp				FW_VI_FUNC_ETH, 0);
4951237436Snp}
4952237436Snp
4953237436Snp/**
4954218792Snp *	t4_free_vi - free a virtual interface
4955218792Snp *	@adap: the adapter
4956218792Snp *	@mbox: mailbox to use for the FW command
4957218792Snp *	@pf: the PF owning the VI
4958218792Snp *	@vf: the VF owning the VI
4959218792Snp *	@viid: virtual interface identifiler
4960218792Snp *
4961218792Snp *	Free a previously allocated virtual interface.
4962218792Snp */
4963218792Snpint t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf,
4964218792Snp	       unsigned int vf, unsigned int viid)
4965218792Snp{
4966218792Snp	struct fw_vi_cmd c;
4967218792Snp
4968218792Snp	memset(&c, 0, sizeof(c));
4969218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_VI_CMD) |
4970218792Snp			    F_FW_CMD_REQUEST |
4971218792Snp			    F_FW_CMD_EXEC |
4972218792Snp			    V_FW_VI_CMD_PFN(pf) |
4973218792Snp			    V_FW_VI_CMD_VFN(vf));
4974218792Snp	c.alloc_to_len16 = htonl(F_FW_VI_CMD_FREE | FW_LEN16(c));
4975218792Snp	c.type_to_viid = htons(V_FW_VI_CMD_VIID(viid));
4976218792Snp
4977218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4978218792Snp}
4979218792Snp
4980218792Snp/**
4981218792Snp *	t4_set_rxmode - set Rx properties of a virtual interface
4982218792Snp *	@adap: the adapter
4983218792Snp *	@mbox: mailbox to use for the FW command
4984218792Snp *	@viid: the VI id
4985218792Snp *	@mtu: the new MTU or -1
4986218792Snp *	@promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change
4987218792Snp *	@all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change
4988218792Snp *	@bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change
4989218792Snp *	@vlanex: 1 to enable HVLAN extraction, 0 to disable it, -1 no change
4990218792Snp *	@sleep_ok: if true we may sleep while awaiting command completion
4991218792Snp *
4992218792Snp *	Sets Rx properties of a virtual interface.
4993218792Snp */
4994218792Snpint t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
4995218792Snp		  int mtu, int promisc, int all_multi, int bcast, int vlanex,
4996218792Snp		  bool sleep_ok)
4997218792Snp{
4998218792Snp	struct fw_vi_rxmode_cmd c;
4999218792Snp
5000218792Snp	/* convert to FW values */
5001218792Snp	if (mtu < 0)
5002218792Snp		mtu = M_FW_VI_RXMODE_CMD_MTU;
5003218792Snp	if (promisc < 0)
5004218792Snp		promisc = M_FW_VI_RXMODE_CMD_PROMISCEN;
5005218792Snp	if (all_multi < 0)
5006218792Snp		all_multi = M_FW_VI_RXMODE_CMD_ALLMULTIEN;
5007218792Snp	if (bcast < 0)
5008218792Snp		bcast = M_FW_VI_RXMODE_CMD_BROADCASTEN;
5009218792Snp	if (vlanex < 0)
5010218792Snp		vlanex = M_FW_VI_RXMODE_CMD_VLANEXEN;
5011218792Snp
5012218792Snp	memset(&c, 0, sizeof(c));
5013218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_RXMODE_CMD) | F_FW_CMD_REQUEST |
5014218792Snp			     F_FW_CMD_WRITE | V_FW_VI_RXMODE_CMD_VIID(viid));
5015218792Snp	c.retval_len16 = htonl(FW_LEN16(c));
5016218792Snp	c.mtu_to_vlanexen = htonl(V_FW_VI_RXMODE_CMD_MTU(mtu) |
5017218792Snp				  V_FW_VI_RXMODE_CMD_PROMISCEN(promisc) |
5018218792Snp				  V_FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) |
5019218792Snp				  V_FW_VI_RXMODE_CMD_BROADCASTEN(bcast) |
5020218792Snp				  V_FW_VI_RXMODE_CMD_VLANEXEN(vlanex));
5021218792Snp	return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok);
5022218792Snp}
5023218792Snp
5024218792Snp/**
5025218792Snp *	t4_alloc_mac_filt - allocates exact-match filters for MAC addresses
5026218792Snp *	@adap: the adapter
5027218792Snp *	@mbox: mailbox to use for the FW command
5028218792Snp *	@viid: the VI id
5029218792Snp *	@free: if true any existing filters for this VI id are first removed
5030218792Snp *	@naddr: the number of MAC addresses to allocate filters for (up to 7)
5031218792Snp *	@addr: the MAC address(es)
5032218792Snp *	@idx: where to store the index of each allocated filter
5033218792Snp *	@hash: pointer to hash address filter bitmap
5034218792Snp *	@sleep_ok: call is allowed to sleep
5035218792Snp *
5036218792Snp *	Allocates an exact-match filter for each of the supplied addresses and
5037218792Snp *	sets it to the corresponding address.  If @idx is not %NULL it should
5038218792Snp *	have at least @naddr entries, each of which will be set to the index of
5039218792Snp *	the filter allocated for the corresponding MAC address.  If a filter
5040218792Snp *	could not be allocated for an address its index is set to 0xffff.
5041218792Snp *	If @hash is not %NULL addresses that fail to allocate an exact filter
5042218792Snp *	are hashed and update the hash filter bitmap pointed at by @hash.
5043218792Snp *
5044218792Snp *	Returns a negative error number or the number of filters allocated.
5045218792Snp */
5046218792Snpint t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
5047218792Snp		      unsigned int viid, bool free, unsigned int naddr,
5048218792Snp		      const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok)
5049218792Snp{
5050218792Snp	int offset, ret = 0;
5051218792Snp	struct fw_vi_mac_cmd c;
5052218792Snp	unsigned int nfilters = 0;
5053248925Snp	unsigned int max_naddr = is_t4(adap) ?
5054248925Snp				       NUM_MPS_CLS_SRAM_L_INSTANCES :
5055248925Snp				       NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
5056218792Snp	unsigned int rem = naddr;
5057218792Snp
5058248925Snp	if (naddr > max_naddr)
5059218792Snp		return -EINVAL;
5060218792Snp
5061218792Snp	for (offset = 0; offset < naddr ; /**/) {
5062218792Snp		unsigned int fw_naddr = (rem < ARRAY_SIZE(c.u.exact)
5063218792Snp					 ? rem
5064218792Snp					 : ARRAY_SIZE(c.u.exact));
5065218792Snp		size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
5066218792Snp						     u.exact[fw_naddr]), 16);
5067218792Snp		struct fw_vi_mac_exact *p;
5068218792Snp		int i;
5069218792Snp
5070218792Snp		memset(&c, 0, sizeof(c));
5071218792Snp		c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) |
5072218792Snp				     F_FW_CMD_REQUEST |
5073218792Snp				     F_FW_CMD_WRITE |
5074218792Snp				     V_FW_CMD_EXEC(free) |
5075218792Snp				     V_FW_VI_MAC_CMD_VIID(viid));
5076218792Snp		c.freemacs_to_len16 = htonl(V_FW_VI_MAC_CMD_FREEMACS(free) |
5077218792Snp					    V_FW_CMD_LEN16(len16));
5078218792Snp
5079218792Snp		for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
5080218792Snp			p->valid_to_idx = htons(
5081218792Snp				F_FW_VI_MAC_CMD_VALID |
5082218792Snp				V_FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC));
5083218792Snp			memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr));
5084218792Snp		}
5085218792Snp
5086218792Snp		/*
5087218792Snp		 * It's okay if we run out of space in our MAC address arena.
5088218792Snp		 * Some of the addresses we submit may get stored so we need
5089218792Snp		 * to run through the reply to see what the results were ...
5090218792Snp		 */
5091218792Snp		ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok);
5092218792Snp		if (ret && ret != -FW_ENOMEM)
5093218792Snp			break;
5094218792Snp
5095218792Snp		for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
5096218792Snp			u16 index = G_FW_VI_MAC_CMD_IDX(ntohs(p->valid_to_idx));
5097218792Snp
5098218792Snp			if (idx)
5099248925Snp				idx[offset+i] = (index >=  max_naddr
5100218792Snp						 ? 0xffff
5101218792Snp						 : index);
5102248925Snp			if (index < max_naddr)
5103218792Snp				nfilters++;
5104218792Snp			else if (hash)
5105218792Snp				*hash |= (1ULL << hash_mac_addr(addr[offset+i]));
5106218792Snp		}
5107218792Snp
5108218792Snp		free = false;
5109218792Snp		offset += fw_naddr;
5110218792Snp		rem -= fw_naddr;
5111218792Snp	}
5112218792Snp
5113218792Snp	if (ret == 0 || ret == -FW_ENOMEM)
5114218792Snp		ret = nfilters;
5115218792Snp	return ret;
5116218792Snp}
5117218792Snp
5118218792Snp/**
5119218792Snp *	t4_change_mac - modifies the exact-match filter for a MAC address
5120218792Snp *	@adap: the adapter
5121218792Snp *	@mbox: mailbox to use for the FW command
5122218792Snp *	@viid: the VI id
5123218792Snp *	@idx: index of existing filter for old value of MAC address, or -1
5124218792Snp *	@addr: the new MAC address value
5125218792Snp *	@persist: whether a new MAC allocation should be persistent
5126218792Snp *	@add_smt: if true also add the address to the HW SMT
5127218792Snp *
5128218792Snp *	Modifies an exact-match filter and sets it to the new MAC address if
5129218792Snp *	@idx >= 0, or adds the MAC address to a new filter if @idx < 0.  In the
5130218792Snp *	latter case the address is added persistently if @persist is %true.
5131218792Snp *
5132218792Snp *	Note that in general it is not possible to modify the value of a given
5133218792Snp *	filter so the generic way to modify an address filter is to free the one
5134218792Snp *	being used by the old address value and allocate a new filter for the
5135218792Snp *	new address value.
5136218792Snp *
5137218792Snp *	Returns a negative error number or the index of the filter with the new
5138218792Snp *	MAC value.  Note that this index may differ from @idx.
5139218792Snp */
5140218792Snpint t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid,
5141218792Snp		  int idx, const u8 *addr, bool persist, bool add_smt)
5142218792Snp{
5143218792Snp	int ret, mode;
5144218792Snp	struct fw_vi_mac_cmd c;
5145218792Snp	struct fw_vi_mac_exact *p = c.u.exact;
5146248925Snp	unsigned int max_mac_addr = is_t4(adap) ?
5147248925Snp				    NUM_MPS_CLS_SRAM_L_INSTANCES :
5148248925Snp				    NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
5149218792Snp
5150218792Snp	if (idx < 0)                             /* new allocation */
5151218792Snp		idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC;
5152218792Snp	mode = add_smt ? FW_VI_MAC_SMT_AND_MPSTCAM : FW_VI_MAC_MPS_TCAM_ENTRY;
5153218792Snp
5154218792Snp	memset(&c, 0, sizeof(c));
5155218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) | F_FW_CMD_REQUEST |
5156218792Snp			     F_FW_CMD_WRITE | V_FW_VI_MAC_CMD_VIID(viid));
5157218792Snp	c.freemacs_to_len16 = htonl(V_FW_CMD_LEN16(1));
5158218792Snp	p->valid_to_idx = htons(F_FW_VI_MAC_CMD_VALID |
5159218792Snp				V_FW_VI_MAC_CMD_SMAC_RESULT(mode) |
5160218792Snp				V_FW_VI_MAC_CMD_IDX(idx));
5161218792Snp	memcpy(p->macaddr, addr, sizeof(p->macaddr));
5162218792Snp
5163248925Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
5164218792Snp	if (ret == 0) {
5165218792Snp		ret = G_FW_VI_MAC_CMD_IDX(ntohs(p->valid_to_idx));
5166248925Snp		if (ret >= max_mac_addr)
5167218792Snp			ret = -ENOMEM;
5168218792Snp	}
5169218792Snp	return ret;
5170218792Snp}
5171218792Snp
5172218792Snp/**
5173218792Snp *	t4_set_addr_hash - program the MAC inexact-match hash filter
5174218792Snp *	@adap: the adapter
5175218792Snp *	@mbox: mailbox to use for the FW command
5176218792Snp *	@viid: the VI id
5177218792Snp *	@ucast: whether the hash filter should also match unicast addresses
5178218792Snp *	@vec: the value to be written to the hash filter
5179218792Snp *	@sleep_ok: call is allowed to sleep
5180218792Snp *
5181218792Snp *	Sets the 64-bit inexact-match hash filter for a virtual interface.
5182218792Snp */
5183218792Snpint t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid,
5184218792Snp		     bool ucast, u64 vec, bool sleep_ok)
5185218792Snp{
5186218792Snp	struct fw_vi_mac_cmd c;
5187218792Snp
5188218792Snp	memset(&c, 0, sizeof(c));
5189218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) | F_FW_CMD_REQUEST |
5190218792Snp			     F_FW_CMD_WRITE | V_FW_VI_ENABLE_CMD_VIID(viid));
5191218792Snp	c.freemacs_to_len16 = htonl(F_FW_VI_MAC_CMD_HASHVECEN |
5192218792Snp				    V_FW_VI_MAC_CMD_HASHUNIEN(ucast) |
5193218792Snp				    V_FW_CMD_LEN16(1));
5194218792Snp	c.u.hash.hashvec = cpu_to_be64(vec);
5195218792Snp	return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok);
5196218792Snp}
5197218792Snp
5198218792Snp/**
5199218792Snp *	t4_enable_vi - enable/disable a virtual interface
5200218792Snp *	@adap: the adapter
5201218792Snp *	@mbox: mailbox to use for the FW command
5202218792Snp *	@viid: the VI id
5203218792Snp *	@rx_en: 1=enable Rx, 0=disable Rx
5204218792Snp *	@tx_en: 1=enable Tx, 0=disable Tx
5205218792Snp *
5206218792Snp *	Enables/disables a virtual interface.
5207218792Snp */
5208218792Snpint t4_enable_vi(struct adapter *adap, unsigned int mbox, unsigned int viid,
5209218792Snp		 bool rx_en, bool tx_en)
5210218792Snp{
5211218792Snp	struct fw_vi_enable_cmd c;
5212218792Snp
5213218792Snp	memset(&c, 0, sizeof(c));
5214218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_ENABLE_CMD) | F_FW_CMD_REQUEST |
5215218792Snp			     F_FW_CMD_EXEC | V_FW_VI_ENABLE_CMD_VIID(viid));
5216218792Snp	c.ien_to_len16 = htonl(V_FW_VI_ENABLE_CMD_IEN(rx_en) |
5217218792Snp			       V_FW_VI_ENABLE_CMD_EEN(tx_en) | FW_LEN16(c));
5218218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5219218792Snp}
5220218792Snp
5221218792Snp/**
5222218792Snp *	t4_identify_port - identify a VI's port by blinking its LED
5223218792Snp *	@adap: the adapter
5224218792Snp *	@mbox: mailbox to use for the FW command
5225218792Snp *	@viid: the VI id
5226218792Snp *	@nblinks: how many times to blink LED at 2.5 Hz
5227218792Snp *
5228218792Snp *	Identifies a VI's port by blinking its LED.
5229218792Snp */
5230218792Snpint t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid,
5231218792Snp		     unsigned int nblinks)
5232218792Snp{
5233218792Snp	struct fw_vi_enable_cmd c;
5234218792Snp
5235218792Snp	memset(&c, 0, sizeof(c));
5236218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_ENABLE_CMD) | F_FW_CMD_REQUEST |
5237218792Snp			     F_FW_CMD_EXEC | V_FW_VI_ENABLE_CMD_VIID(viid));
5238218792Snp	c.ien_to_len16 = htonl(F_FW_VI_ENABLE_CMD_LED | FW_LEN16(c));
5239218792Snp	c.blinkdur = htons(nblinks);
5240218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5241218792Snp}
5242218792Snp
5243218792Snp/**
5244218792Snp *	t4_iq_start_stop - enable/disable an ingress queue and its FLs
5245218792Snp *	@adap: the adapter
5246218792Snp *	@mbox: mailbox to use for the FW command
5247218792Snp *	@start: %true to enable the queues, %false to disable them
5248218792Snp *	@pf: the PF owning the queues
5249218792Snp *	@vf: the VF owning the queues
5250218792Snp *	@iqid: ingress queue id
5251218792Snp *	@fl0id: FL0 queue id or 0xffff if no attached FL0
5252218792Snp *	@fl1id: FL1 queue id or 0xffff if no attached FL1
5253218792Snp *
5254218792Snp *	Starts or stops an ingress queue and its associated FLs, if any.
5255218792Snp */
5256218792Snpint t4_iq_start_stop(struct adapter *adap, unsigned int mbox, bool start,
5257218792Snp		     unsigned int pf, unsigned int vf, unsigned int iqid,
5258218792Snp		     unsigned int fl0id, unsigned int fl1id)
5259218792Snp{
5260218792Snp	struct fw_iq_cmd c;
5261218792Snp
5262218792Snp	memset(&c, 0, sizeof(c));
5263218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_IQ_CMD) | F_FW_CMD_REQUEST |
5264218792Snp			    F_FW_CMD_EXEC | V_FW_IQ_CMD_PFN(pf) |
5265218792Snp			    V_FW_IQ_CMD_VFN(vf));
5266218792Snp	c.alloc_to_len16 = htonl(V_FW_IQ_CMD_IQSTART(start) |
5267218792Snp				 V_FW_IQ_CMD_IQSTOP(!start) | FW_LEN16(c));
5268218792Snp	c.iqid = htons(iqid);
5269218792Snp	c.fl0id = htons(fl0id);
5270218792Snp	c.fl1id = htons(fl1id);
5271218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5272218792Snp}
5273218792Snp
5274218792Snp/**
5275218792Snp *	t4_iq_free - free an ingress queue and its FLs
5276218792Snp *	@adap: the adapter
5277218792Snp *	@mbox: mailbox to use for the FW command
5278218792Snp *	@pf: the PF owning the queues
5279218792Snp *	@vf: the VF owning the queues
5280218792Snp *	@iqtype: the ingress queue type (FW_IQ_TYPE_FL_INT_CAP, etc.)
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 *	Frees an ingress queue and its associated FLs, if any.
5286218792Snp */
5287218792Snpint t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
5288218792Snp	       unsigned int vf, unsigned int iqtype, 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(F_FW_IQ_CMD_FREE | FW_LEN16(c));
5298218792Snp	c.type_to_iqandstindex = htonl(V_FW_IQ_CMD_TYPE(iqtype));
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_eth_eq_free - free an Ethernet egress queue
5307218792Snp *	@adap: the adapter
5308218792Snp *	@mbox: mailbox to use for the FW command
5309218792Snp *	@pf: the PF owning the queue
5310218792Snp *	@vf: the VF owning the queue
5311218792Snp *	@eqid: egress queue id
5312218792Snp *
5313218792Snp *	Frees an Ethernet egress queue.
5314218792Snp */
5315218792Snpint t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
5316218792Snp		   unsigned int vf, unsigned int eqid)
5317218792Snp{
5318218792Snp	struct fw_eq_eth_cmd c;
5319218792Snp
5320218792Snp	memset(&c, 0, sizeof(c));
5321218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_EQ_ETH_CMD) | F_FW_CMD_REQUEST |
5322218792Snp			    F_FW_CMD_EXEC | V_FW_EQ_ETH_CMD_PFN(pf) |
5323218792Snp			    V_FW_EQ_ETH_CMD_VFN(vf));
5324218792Snp	c.alloc_to_len16 = htonl(F_FW_EQ_ETH_CMD_FREE | FW_LEN16(c));
5325218792Snp	c.eqid_pkd = htonl(V_FW_EQ_ETH_CMD_EQID(eqid));
5326218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5327218792Snp}
5328218792Snp
5329218792Snp/**
5330218792Snp *	t4_ctrl_eq_free - free a control egress queue
5331218792Snp *	@adap: the adapter
5332218792Snp *	@mbox: mailbox to use for the FW command
5333218792Snp *	@pf: the PF owning the queue
5334218792Snp *	@vf: the VF owning the queue
5335218792Snp *	@eqid: egress queue id
5336218792Snp *
5337218792Snp *	Frees a control egress queue.
5338218792Snp */
5339218792Snpint t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
5340218792Snp		    unsigned int vf, unsigned int eqid)
5341218792Snp{
5342218792Snp	struct fw_eq_ctrl_cmd c;
5343218792Snp
5344218792Snp	memset(&c, 0, sizeof(c));
5345218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_EQ_CTRL_CMD) | F_FW_CMD_REQUEST |
5346218792Snp			    F_FW_CMD_EXEC | V_FW_EQ_CTRL_CMD_PFN(pf) |
5347218792Snp			    V_FW_EQ_CTRL_CMD_VFN(vf));
5348218792Snp	c.alloc_to_len16 = htonl(F_FW_EQ_CTRL_CMD_FREE | FW_LEN16(c));
5349218792Snp	c.cmpliqid_eqid = htonl(V_FW_EQ_CTRL_CMD_EQID(eqid));
5350218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5351218792Snp}
5352218792Snp
5353218792Snp/**
5354218792Snp *	t4_ofld_eq_free - free an offload egress queue
5355218792Snp *	@adap: the adapter
5356218792Snp *	@mbox: mailbox to use for the FW command
5357218792Snp *	@pf: the PF owning the queue
5358218792Snp *	@vf: the VF owning the queue
5359218792Snp *	@eqid: egress queue id
5360218792Snp *
5361218792Snp *	Frees a control egress queue.
5362218792Snp */
5363218792Snpint t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
5364218792Snp		    unsigned int vf, unsigned int eqid)
5365218792Snp{
5366218792Snp	struct fw_eq_ofld_cmd c;
5367218792Snp
5368218792Snp	memset(&c, 0, sizeof(c));
5369218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_EQ_OFLD_CMD) | F_FW_CMD_REQUEST |
5370218792Snp			    F_FW_CMD_EXEC | V_FW_EQ_OFLD_CMD_PFN(pf) |
5371218792Snp			    V_FW_EQ_OFLD_CMD_VFN(vf));
5372218792Snp	c.alloc_to_len16 = htonl(F_FW_EQ_OFLD_CMD_FREE | FW_LEN16(c));
5373218792Snp	c.eqid_pkd = htonl(V_FW_EQ_OFLD_CMD_EQID(eqid));
5374218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5375218792Snp}
5376218792Snp
5377218792Snp/**
5378218792Snp *	t4_handle_fw_rpl - process a FW reply message
5379218792Snp *	@adap: the adapter
5380218792Snp *	@rpl: start of the FW message
5381218792Snp *
5382218792Snp *	Processes a FW message, such as link state change messages.
5383218792Snp */
5384218792Snpint t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl)
5385218792Snp{
5386218792Snp	u8 opcode = *(const u8 *)rpl;
5387237436Snp	const struct fw_port_cmd *p = (const void *)rpl;
5388237436Snp	unsigned int action = G_FW_PORT_CMD_ACTION(ntohl(p->action_to_len16));
5389218792Snp
5390237436Snp	if (opcode == FW_PORT_CMD && action == FW_PORT_ACTION_GET_PORT_INFO) {
5391237436Snp		/* link/module state change message */
5392218792Snp		int speed = 0, fc = 0, i;
5393218792Snp		int chan = G_FW_PORT_CMD_PORTID(ntohl(p->op_to_portid));
5394218792Snp		struct port_info *pi = NULL;
5395218792Snp		struct link_config *lc;
5396218792Snp		u32 stat = ntohl(p->u.info.lstatus_to_modtype);
5397218792Snp		int link_ok = (stat & F_FW_PORT_CMD_LSTATUS) != 0;
5398218792Snp		u32 mod = G_FW_PORT_CMD_MODTYPE(stat);
5399218792Snp
5400218792Snp		if (stat & F_FW_PORT_CMD_RXPAUSE)
5401218792Snp			fc |= PAUSE_RX;
5402218792Snp		if (stat & F_FW_PORT_CMD_TXPAUSE)
5403218792Snp			fc |= PAUSE_TX;
5404218792Snp		if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M))
5405218792Snp			speed = SPEED_100;
5406218792Snp		else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G))
5407218792Snp			speed = SPEED_1000;
5408218792Snp		else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G))
5409218792Snp			speed = SPEED_10000;
5410250090Snp		else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G))
5411250090Snp			speed = SPEED_40000;
5412218792Snp
5413218792Snp		for_each_port(adap, i) {
5414218792Snp			pi = adap2pinfo(adap, i);
5415218792Snp			if (pi->tx_chan == chan)
5416218792Snp				break;
5417218792Snp		}
5418218792Snp		lc = &pi->link_cfg;
5419218792Snp
5420281207Snp		if (mod != pi->mod_type) {
5421281207Snp			pi->mod_type = mod;
5422281207Snp			t4_os_portmod_changed(adap, i);
5423281207Snp		}
5424218792Snp		if (link_ok != lc->link_ok || speed != lc->speed ||
5425218792Snp		    fc != lc->fc) {                    /* something changed */
5426252747Snp			int reason;
5427252747Snp
5428252747Snp			if (!link_ok && lc->link_ok)
5429252747Snp				reason = G_FW_PORT_CMD_LINKDNRC(stat);
5430252747Snp			else
5431252747Snp				reason = -1;
5432252747Snp
5433218792Snp			lc->link_ok = link_ok;
5434218792Snp			lc->speed = speed;
5435218792Snp			lc->fc = fc;
5436250090Snp			lc->supported = ntohs(p->u.info.pcap);
5437252747Snp			t4_os_link_changed(adap, i, link_ok, reason);
5438218792Snp		}
5439237436Snp	} else {
5440237436Snp		CH_WARN_RATELIMIT(adap,
5441237436Snp		    "Unknown firmware reply 0x%x (0x%x)\n", opcode, action);
5442237436Snp		return -EINVAL;
5443218792Snp	}
5444218792Snp	return 0;
5445218792Snp}
5446218792Snp
5447218792Snp/**
5448218792Snp *	get_pci_mode - determine a card's PCI mode
5449218792Snp *	@adapter: the adapter
5450218792Snp *	@p: where to store the PCI settings
5451218792Snp *
5452218792Snp *	Determines a card's PCI mode and associated parameters, such as speed
5453218792Snp *	and width.
5454218792Snp */
5455218792Snpstatic void __devinit get_pci_mode(struct adapter *adapter,
5456218792Snp				   struct pci_params *p)
5457218792Snp{
5458218792Snp	u16 val;
5459218792Snp	u32 pcie_cap;
5460218792Snp
5461218792Snp	pcie_cap = t4_os_find_pci_capability(adapter, PCI_CAP_ID_EXP);
5462218792Snp	if (pcie_cap) {
5463218792Snp		t4_os_pci_read_cfg2(adapter, pcie_cap + PCI_EXP_LNKSTA, &val);
5464218792Snp		p->speed = val & PCI_EXP_LNKSTA_CLS;
5465218792Snp		p->width = (val & PCI_EXP_LNKSTA_NLW) >> 4;
5466218792Snp	}
5467218792Snp}
5468218792Snp
5469218792Snp/**
5470218792Snp *	init_link_config - initialize a link's SW state
5471218792Snp *	@lc: structure holding the link state
5472218792Snp *	@caps: link capabilities
5473218792Snp *
5474218792Snp *	Initializes the SW state maintained for each link, including the link's
5475218792Snp *	capabilities and default speed/flow-control/autonegotiation settings.
5476218792Snp */
5477218792Snpstatic void __devinit init_link_config(struct link_config *lc,
5478218792Snp				       unsigned int caps)
5479218792Snp{
5480218792Snp	lc->supported = caps;
5481218792Snp	lc->requested_speed = 0;
5482218792Snp	lc->speed = 0;
5483218792Snp	lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
5484218792Snp	if (lc->supported & FW_PORT_CAP_ANEG) {
5485218792Snp		lc->advertising = lc->supported & ADVERT_MASK;
5486218792Snp		lc->autoneg = AUTONEG_ENABLE;
5487218792Snp		lc->requested_fc |= PAUSE_AUTONEG;
5488218792Snp	} else {
5489218792Snp		lc->advertising = 0;
5490218792Snp		lc->autoneg = AUTONEG_DISABLE;
5491218792Snp	}
5492218792Snp}
5493218792Snp
5494218792Snpstatic int __devinit get_flash_params(struct adapter *adapter)
5495218792Snp{
5496218792Snp	int ret;
5497218792Snp	u32 info = 0;
5498218792Snp
5499218792Snp	ret = sf1_write(adapter, 1, 1, 0, SF_RD_ID);
5500218792Snp	if (!ret)
5501218792Snp		ret = sf1_read(adapter, 3, 0, 1, &info);
5502218792Snp	t4_write_reg(adapter, A_SF_OP, 0);               /* unlock SF */
5503218792Snp	if (ret < 0)
5504218792Snp		return ret;
5505218792Snp
5506218792Snp	if ((info & 0xff) != 0x20)             /* not a Numonix flash */
5507218792Snp		return -EINVAL;
5508218792Snp	info >>= 16;                           /* log2 of size */
5509218792Snp	if (info >= 0x14 && info < 0x18)
5510218792Snp		adapter->params.sf_nsec = 1 << (info - 16);
5511218792Snp	else if (info == 0x18)
5512218792Snp		adapter->params.sf_nsec = 64;
5513218792Snp	else
5514218792Snp		return -EINVAL;
5515218792Snp	adapter->params.sf_size = 1 << info;
5516218792Snp	return 0;
5517218792Snp}
5518218792Snp
5519228561Snpstatic void __devinit set_pcie_completion_timeout(struct adapter *adapter,
5520228561Snp						  u8 range)
5521228561Snp{
5522228561Snp	u16 val;
5523228561Snp	u32 pcie_cap;
5524228561Snp
5525228561Snp	pcie_cap = t4_os_find_pci_capability(adapter, PCI_CAP_ID_EXP);
5526228561Snp	if (pcie_cap) {
5527228561Snp		t4_os_pci_read_cfg2(adapter, pcie_cap + PCI_EXP_DEVCTL2, &val);
5528228561Snp		val &= 0xfff0;
5529228561Snp		val |= range ;
5530228561Snp		t4_os_pci_write_cfg2(adapter, pcie_cap + PCI_EXP_DEVCTL2, val);
5531228561Snp	}
5532228561Snp}
5533228561Snp
5534218792Snp/**
5535218792Snp *	t4_prep_adapter - prepare SW and HW for operation
5536218792Snp *	@adapter: the adapter
5537218792Snp *	@reset: if true perform a HW reset
5538218792Snp *
5539218792Snp *	Initialize adapter SW state for the various HW modules, set initial
5540218792Snp *	values for some adapter tunables, take PHYs out of reset, and
5541218792Snp *	initialize the MDIO interface.
5542218792Snp */
5543218792Snpint __devinit t4_prep_adapter(struct adapter *adapter)
5544218792Snp{
5545218792Snp	int ret;
5546248925Snp	uint16_t device_id;
5547248925Snp	uint32_t pl_rev;
5548218792Snp
5549218792Snp	get_pci_mode(adapter, &adapter->params.pci);
5550218792Snp
5551248925Snp	pl_rev = t4_read_reg(adapter, A_PL_REV);
5552248925Snp	adapter->params.chipid = G_CHIPID(pl_rev);
5553248925Snp	adapter->params.rev = G_REV(pl_rev);
5554248925Snp	if (adapter->params.chipid == 0) {
5555248925Snp		/* T4 did not have chipid in PL_REV (T5 onwards do) */
5556248925Snp		adapter->params.chipid = CHELSIO_T4;
5557248925Snp
5558248925Snp		/* T4A1 chip is not supported */
5559248925Snp		if (adapter->params.rev == 1) {
5560248925Snp			CH_ALERT(adapter, "T4 rev 1 chip is not supported.\n");
5561248925Snp			return -EINVAL;
5562248925Snp		}
5563237436Snp	}
5564218792Snp	adapter->params.pci.vpd_cap_addr =
5565248925Snp	    t4_os_find_pci_capability(adapter, PCI_CAP_ID_VPD);
5566218792Snp
5567218792Snp	ret = get_flash_params(adapter);
5568218792Snp	if (ret < 0)
5569218792Snp		return ret;
5570218792Snp
5571218792Snp	ret = get_vpd_params(adapter, &adapter->params.vpd);
5572218792Snp	if (ret < 0)
5573218792Snp		return ret;
5574218792Snp
5575248925Snp	/* Cards with real ASICs have the chipid in the PCIe device id */
5576248925Snp	t4_os_pci_read_cfg2(adapter, PCI_DEVICE_ID, &device_id);
5577248925Snp	if (device_id >> 12 == adapter->params.chipid)
5578248925Snp		adapter->params.cim_la_size = CIMLA_SIZE;
5579248925Snp	else {
5580237436Snp		/* FPGA */
5581248925Snp		adapter->params.fpga = 1;
5582218792Snp		adapter->params.cim_la_size = 2 * CIMLA_SIZE;
5583218792Snp	}
5584218792Snp
5585218792Snp	init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
5586218792Snp
5587218792Snp	/*
5588218792Snp	 * Default port and clock for debugging in case we can't reach FW.
5589218792Snp	 */
5590218792Snp	adapter->params.nports = 1;
5591218792Snp	adapter->params.portvec = 1;
5592218792Snp	adapter->params.vpd.cclk = 50000;
5593218792Snp
5594228561Snp	/* Set pci completion timeout value to 4 seconds. */
5595228561Snp	set_pcie_completion_timeout(adapter, 0xd);
5596218792Snp	return 0;
5597218792Snp}
5598218792Snp
5599252705Snp/**
5600252705Snp *	t4_init_tp_params - initialize adap->params.tp
5601252705Snp *	@adap: the adapter
5602252705Snp *
5603252705Snp *	Initialize various fields of the adapter's TP Parameters structure.
5604252705Snp */
5605252705Snpint __devinit t4_init_tp_params(struct adapter *adap)
5606252705Snp{
5607252705Snp	int chan;
5608252705Snp	u32 v;
5609252705Snp
5610252705Snp	v = t4_read_reg(adap, A_TP_TIMER_RESOLUTION);
5611252705Snp	adap->params.tp.tre = G_TIMERRESOLUTION(v);
5612252705Snp	adap->params.tp.dack_re = G_DELAYEDACKRESOLUTION(v);
5613252705Snp
5614252705Snp	/* MODQ_REQ_MAP defaults to setting queues 0-3 to chan 0-3 */
5615252705Snp	for (chan = 0; chan < NCHAN; chan++)
5616252705Snp		adap->params.tp.tx_modq[chan] = chan;
5617252705Snp
5618252705Snp	/*
5619252705Snp	 * Cache the adapter's Compressed Filter Mode and global Incress
5620252705Snp	 * Configuration.
5621252705Snp	 */
5622252705Snp        t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA,
5623252705Snp                         &adap->params.tp.vlan_pri_map, 1,
5624252705Snp                         A_TP_VLAN_PRI_MAP);
5625252705Snp	t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA,
5626252705Snp			 &adap->params.tp.ingress_config, 1,
5627252705Snp			 A_TP_INGRESS_CONFIG);
5628252705Snp
5629252705Snp	/*
5630252705Snp	 * Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field
5631252705Snp	 * shift positions of several elements of the Compressed Filter Tuple
5632252705Snp	 * for this adapter which we need frequently ...
5633252705Snp	 */
5634252705Snp	adap->params.tp.vlan_shift = t4_filter_field_shift(adap, F_VLAN);
5635252705Snp	adap->params.tp.vnic_shift = t4_filter_field_shift(adap, F_VNIC_ID);
5636252705Snp	adap->params.tp.port_shift = t4_filter_field_shift(adap, F_PORT);
5637252705Snp	adap->params.tp.protocol_shift = t4_filter_field_shift(adap, F_PROTOCOL);
5638252705Snp
5639252705Snp	/*
5640252705Snp	 * If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID
5641252705Snp	 * represents the presense of an Outer VLAN instead of a VNIC ID.
5642252705Snp	 */
5643252705Snp	if ((adap->params.tp.ingress_config & F_VNIC) == 0)
5644252705Snp		adap->params.tp.vnic_shift = -1;
5645252705Snp
5646252705Snp	return 0;
5647252705Snp}
5648252705Snp
5649252705Snp/**
5650252705Snp *	t4_filter_field_shift - calculate filter field shift
5651252705Snp *	@adap: the adapter
5652252705Snp *	@filter_sel: the desired field (from TP_VLAN_PRI_MAP bits)
5653252705Snp *
5654252705Snp *	Return the shift position of a filter field within the Compressed
5655252705Snp *	Filter Tuple.  The filter field is specified via its selection bit
5656252705Snp *	within TP_VLAN_PRI_MAL (filter mode).  E.g. F_VLAN.
5657252705Snp */
5658252705Snpint t4_filter_field_shift(const struct adapter *adap, int filter_sel)
5659252705Snp{
5660252705Snp	unsigned int filter_mode = adap->params.tp.vlan_pri_map;
5661252705Snp	unsigned int sel;
5662252705Snp	int field_shift;
5663252705Snp
5664252705Snp	if ((filter_mode & filter_sel) == 0)
5665252705Snp		return -1;
5666252705Snp
5667252705Snp	for (sel = 1, field_shift = 0; sel < filter_sel; sel <<= 1) {
5668252705Snp	    switch (filter_mode & sel) {
5669252705Snp		case F_FCOE:          field_shift += W_FT_FCOE;          break;
5670252705Snp		case F_PORT:          field_shift += W_FT_PORT;          break;
5671252705Snp		case F_VNIC_ID:       field_shift += W_FT_VNIC_ID;       break;
5672252705Snp		case F_VLAN:          field_shift += W_FT_VLAN;          break;
5673252705Snp		case F_TOS:           field_shift += W_FT_TOS;           break;
5674252705Snp		case F_PROTOCOL:      field_shift += W_FT_PROTOCOL;      break;
5675252705Snp		case F_ETHERTYPE:     field_shift += W_FT_ETHERTYPE;     break;
5676252705Snp		case F_MACMATCH:      field_shift += W_FT_MACMATCH;      break;
5677252705Snp		case F_MPSHITTYPE:    field_shift += W_FT_MPSHITTYPE;    break;
5678252705Snp		case F_FRAGMENTATION: field_shift += W_FT_FRAGMENTATION; break;
5679252705Snp	    }
5680252705Snp	}
5681252705Snp	return field_shift;
5682252705Snp}
5683252705Snp
5684218792Snpint __devinit t4_port_init(struct port_info *p, int mbox, int pf, int vf)
5685218792Snp{
5686218792Snp	u8 addr[6];
5687218792Snp	int ret, i, j;
5688218792Snp	struct fw_port_cmd c;
5689270297Snp	u16 rss_size;
5690218792Snp	adapter_t *adap = p->adapter;
5691218792Snp
5692218792Snp	memset(&c, 0, sizeof(c));
5693218792Snp
5694218792Snp	for (i = 0, j = -1; i <= p->port_id; i++) {
5695218792Snp		do {
5696218792Snp			j++;
5697218792Snp		} while ((adap->params.portvec & (1 << j)) == 0);
5698218792Snp	}
5699218792Snp
5700218792Snp	c.op_to_portid = htonl(V_FW_CMD_OP(FW_PORT_CMD) |
5701218792Snp			       F_FW_CMD_REQUEST | F_FW_CMD_READ |
5702218792Snp			       V_FW_PORT_CMD_PORTID(j));
5703218792Snp	c.action_to_len16 = htonl(
5704218792Snp		V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) |
5705218792Snp		FW_LEN16(c));
5706218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
5707218792Snp	if (ret)
5708218792Snp		return ret;
5709218792Snp
5710218792Snp	ret = t4_alloc_vi(adap, mbox, j, pf, vf, 1, addr, &rss_size);
5711218792Snp	if (ret < 0)
5712218792Snp		return ret;
5713218792Snp
5714218792Snp	p->viid = ret;
5715218792Snp	p->tx_chan = j;
5716265410Snp	p->rx_chan_map = get_mps_bg_map(adap, j);
5717218792Snp	p->lport = j;
5718218792Snp	p->rss_size = rss_size;
5719218792Snp	t4_os_set_hw_addr(adap, p->port_id, addr);
5720218792Snp
5721218792Snp	ret = ntohl(c.u.info.lstatus_to_modtype);
5722218792Snp	p->mdio_addr = (ret & F_FW_PORT_CMD_MDIOCAP) ?
5723218792Snp		G_FW_PORT_CMD_MDIOADDR(ret) : -1;
5724218792Snp	p->port_type = G_FW_PORT_CMD_PTYPE(ret);
5725218792Snp	p->mod_type = G_FW_PORT_CMD_MODTYPE(ret);
5726218792Snp
5727218792Snp	init_link_config(&p->link_cfg, ntohs(c.u.info.pcap));
5728218792Snp
5729218792Snp	return 0;
5730218792Snp}
5731259142Snp
5732270297Snpint t4_sched_config(struct adapter *adapter, int type, int minmaxen,
5733270297Snp    		    int sleep_ok)
5734259142Snp{
5735259142Snp	struct fw_sched_cmd cmd;
5736259142Snp
5737259142Snp	memset(&cmd, 0, sizeof(cmd));
5738259142Snp	cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_SCHED_CMD) |
5739259142Snp				      F_FW_CMD_REQUEST |
5740259142Snp				      F_FW_CMD_WRITE);
5741259142Snp	cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
5742259142Snp
5743259142Snp	cmd.u.config.sc = FW_SCHED_SC_CONFIG;
5744259142Snp	cmd.u.config.type = type;
5745259142Snp	cmd.u.config.minmaxen = minmaxen;
5746259142Snp
5747259142Snp	return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd),
5748270297Snp			       NULL, sleep_ok);
5749259142Snp}
5750259142Snp
5751259142Snpint t4_sched_params(struct adapter *adapter, int type, int level, int mode,
5752259142Snp		    int rateunit, int ratemode, int channel, int cl,
5753270297Snp		    int minrate, int maxrate, int weight, int pktsize,
5754270297Snp		    int sleep_ok)
5755259142Snp{
5756259142Snp	struct fw_sched_cmd cmd;
5757259142Snp
5758259142Snp	memset(&cmd, 0, sizeof(cmd));
5759259142Snp	cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_SCHED_CMD) |
5760259142Snp				      F_FW_CMD_REQUEST |
5761259142Snp				      F_FW_CMD_WRITE);
5762259142Snp	cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
5763259142Snp
5764259142Snp	cmd.u.params.sc = FW_SCHED_SC_PARAMS;
5765259142Snp	cmd.u.params.type = type;
5766259142Snp	cmd.u.params.level = level;
5767259142Snp	cmd.u.params.mode = mode;
5768259142Snp	cmd.u.params.ch = channel;
5769259142Snp	cmd.u.params.cl = cl;
5770259142Snp	cmd.u.params.unit = rateunit;
5771259142Snp	cmd.u.params.rate = ratemode;
5772259142Snp	cmd.u.params.min = cpu_to_be32(minrate);
5773259142Snp	cmd.u.params.max = cpu_to_be32(maxrate);
5774259142Snp	cmd.u.params.weight = cpu_to_be16(weight);
5775259142Snp	cmd.u.params.pktsize = cpu_to_be16(pktsize);
5776259142Snp
5777259142Snp	return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd),
5778270297Snp			       NULL, sleep_ok);
5779259142Snp}
5780