t4_hw.c revision 281259
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 281259 2015-04-08 03:55:02Z 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
3111281259Snpstatic void refresh_vlan_pri_map(struct adapter *adap)
3112281259Snp{
3113281259Snp
3114281259Snp        t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA,
3115281259Snp                         &adap->params.tp.vlan_pri_map, 1,
3116281259Snp                         A_TP_VLAN_PRI_MAP);
3117281259Snp
3118281259Snp	/*
3119281259Snp	 * Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field
3120281259Snp	 * shift positions of several elements of the Compressed Filter Tuple
3121281259Snp	 * for this adapter which we need frequently ...
3122281259Snp	 */
3123281259Snp	adap->params.tp.vlan_shift = t4_filter_field_shift(adap, F_VLAN);
3124281259Snp	adap->params.tp.vnic_shift = t4_filter_field_shift(adap, F_VNIC_ID);
3125281259Snp	adap->params.tp.port_shift = t4_filter_field_shift(adap, F_PORT);
3126281259Snp	adap->params.tp.protocol_shift = t4_filter_field_shift(adap, F_PROTOCOL);
3127281259Snp
3128281259Snp	/*
3129281259Snp	 * If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID
3130281259Snp	 * represents the presense of an Outer VLAN instead of a VNIC ID.
3131281259Snp	 */
3132281259Snp	if ((adap->params.tp.ingress_config & F_VNIC) == 0)
3133281259Snp		adap->params.tp.vnic_shift = -1;
3134281259Snp}
3135281259Snp
3136218792Snp/**
3137218792Snp *	t4_set_filter_mode - configure the optional components of filter tuples
3138218792Snp *	@adap: the adapter
3139218792Snp *	@mode_map: a bitmap selcting which optional filter components to enable
3140218792Snp *
3141218792Snp *	Sets the filter mode by selecting the optional components to enable
3142218792Snp *	in filter tuples.  Returns 0 on success and a negative error if the
3143218792Snp *	requested mode needs more bits than are available for optional
3144218792Snp *	components.
3145218792Snp */
3146218792Snpint t4_set_filter_mode(struct adapter *adap, unsigned int mode_map)
3147218792Snp{
3148218792Snp	static u8 width[] = { 1, 3, 17, 17, 8, 8, 16, 9, 3, 1 };
3149218792Snp
3150218792Snp	int i, nbits = 0;
3151218792Snp
3152218792Snp	for (i = S_FCOE; i <= S_FRAGMENTATION; i++)
3153218792Snp		if (mode_map & (1 << i))
3154218792Snp			nbits += width[i];
3155218792Snp	if (nbits > FILTER_OPT_LEN)
3156218792Snp		return -EINVAL;
3157218792Snp	t4_write_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA, &mode_map, 1,
3158218792Snp			  A_TP_VLAN_PRI_MAP);
3159281259Snp	refresh_vlan_pri_map(adap);
3160281259Snp
3161218792Snp	return 0;
3162218792Snp}
3163218792Snp
3164218792Snp/**
3165218792Snp *	t4_tp_get_tcp_stats - read TP's TCP MIB counters
3166218792Snp *	@adap: the adapter
3167218792Snp *	@v4: holds the TCP/IP counter values
3168218792Snp *	@v6: holds the TCP/IPv6 counter values
3169218792Snp *
3170218792Snp *	Returns the values of TP's TCP/IP and TCP/IPv6 MIB counters.
3171218792Snp *	Either @v4 or @v6 may be %NULL to skip the corresponding stats.
3172218792Snp */
3173218792Snpvoid t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
3174218792Snp			 struct tp_tcp_stats *v6)
3175218792Snp{
3176218792Snp	u32 val[A_TP_MIB_TCP_RXT_SEG_LO - A_TP_MIB_TCP_OUT_RST + 1];
3177218792Snp
3178218792Snp#define STAT_IDX(x) ((A_TP_MIB_TCP_##x) - A_TP_MIB_TCP_OUT_RST)
3179218792Snp#define STAT(x)     val[STAT_IDX(x)]
3180218792Snp#define STAT64(x)   (((u64)STAT(x##_HI) << 32) | STAT(x##_LO))
3181218792Snp
3182218792Snp	if (v4) {
3183218792Snp		t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val,
3184218792Snp				 ARRAY_SIZE(val), A_TP_MIB_TCP_OUT_RST);
3185218792Snp		v4->tcpOutRsts = STAT(OUT_RST);
3186218792Snp		v4->tcpInSegs  = STAT64(IN_SEG);
3187218792Snp		v4->tcpOutSegs = STAT64(OUT_SEG);
3188218792Snp		v4->tcpRetransSegs = STAT64(RXT_SEG);
3189218792Snp	}
3190218792Snp	if (v6) {
3191218792Snp		t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val,
3192218792Snp				 ARRAY_SIZE(val), A_TP_MIB_TCP_V6OUT_RST);
3193218792Snp		v6->tcpOutRsts = STAT(OUT_RST);
3194218792Snp		v6->tcpInSegs  = STAT64(IN_SEG);
3195218792Snp		v6->tcpOutSegs = STAT64(OUT_SEG);
3196218792Snp		v6->tcpRetransSegs = STAT64(RXT_SEG);
3197218792Snp	}
3198218792Snp#undef STAT64
3199218792Snp#undef STAT
3200218792Snp#undef STAT_IDX
3201218792Snp}
3202218792Snp
3203218792Snp/**
3204218792Snp *	t4_tp_get_err_stats - read TP's error MIB counters
3205218792Snp *	@adap: the adapter
3206218792Snp *	@st: holds the counter values
3207218792Snp *
3208218792Snp *	Returns the values of TP's error counters.
3209218792Snp */
3210218792Snpvoid t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st)
3211218792Snp{
3212218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->macInErrs,
3213218792Snp			 12, A_TP_MIB_MAC_IN_ERR_0);
3214218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->tnlCongDrops,
3215218792Snp			 8, A_TP_MIB_TNL_CNG_DROP_0);
3216218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->tnlTxDrops,
3217218792Snp			 4, A_TP_MIB_TNL_DROP_0);
3218218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->ofldVlanDrops,
3219218792Snp			 4, A_TP_MIB_OFD_VLN_DROP_0);
3220218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->tcp6InErrs,
3221218792Snp			 4, A_TP_MIB_TCP_V6IN_ERR_0);
3222218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->ofldNoNeigh,
3223218792Snp			 2, A_TP_MIB_OFD_ARP_DROP);
3224218792Snp}
3225218792Snp
3226218792Snp/**
3227218792Snp *	t4_tp_get_proxy_stats - read TP's proxy MIB counters
3228218792Snp *	@adap: the adapter
3229218792Snp *	@st: holds the counter values
3230218792Snp *
3231218792Snp *	Returns the values of TP's proxy counters.
3232218792Snp */
3233218792Snpvoid t4_tp_get_proxy_stats(struct adapter *adap, struct tp_proxy_stats *st)
3234218792Snp{
3235218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->proxy,
3236218792Snp			 4, A_TP_MIB_TNL_LPBK_0);
3237218792Snp}
3238218792Snp
3239218792Snp/**
3240218792Snp *	t4_tp_get_cpl_stats - read TP's CPL MIB counters
3241218792Snp *	@adap: the adapter
3242218792Snp *	@st: holds the counter values
3243218792Snp *
3244218792Snp *	Returns the values of TP's CPL counters.
3245218792Snp */
3246218792Snpvoid t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st)
3247218792Snp{
3248218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, st->req,
3249218792Snp			 8, A_TP_MIB_CPL_IN_REQ_0);
3250218792Snp}
3251218792Snp
3252218792Snp/**
3253218792Snp *	t4_tp_get_rdma_stats - read TP's RDMA MIB counters
3254218792Snp *	@adap: the adapter
3255218792Snp *	@st: holds the counter values
3256218792Snp *
3257218792Snp *	Returns the values of TP's RDMA counters.
3258218792Snp */
3259218792Snpvoid t4_tp_get_rdma_stats(struct adapter *adap, struct tp_rdma_stats *st)
3260218792Snp{
3261218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->rqe_dfr_mod,
3262218792Snp			 2, A_TP_MIB_RQE_DFR_MOD);
3263218792Snp}
3264218792Snp
3265218792Snp/**
3266218792Snp *	t4_get_fcoe_stats - read TP's FCoE MIB counters for a port
3267218792Snp *	@adap: the adapter
3268218792Snp *	@idx: the port index
3269218792Snp *	@st: holds the counter values
3270218792Snp *
3271218792Snp *	Returns the values of TP's FCoE counters for the selected port.
3272218792Snp */
3273218792Snpvoid t4_get_fcoe_stats(struct adapter *adap, unsigned int idx,
3274218792Snp		       struct tp_fcoe_stats *st)
3275218792Snp{
3276218792Snp	u32 val[2];
3277218792Snp
3278218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->framesDDP,
3279218792Snp			 1, A_TP_MIB_FCOE_DDP_0 + idx);
3280218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, &st->framesDrop,
3281218792Snp			 1, A_TP_MIB_FCOE_DROP_0 + idx);
3282218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val,
3283218792Snp			 2, A_TP_MIB_FCOE_BYTE_0_HI + 2 * idx);
3284218792Snp	st->octetsDDP = ((u64)val[0] << 32) | val[1];
3285218792Snp}
3286218792Snp
3287218792Snp/**
3288218792Snp *	t4_get_usm_stats - read TP's non-TCP DDP MIB counters
3289218792Snp *	@adap: the adapter
3290218792Snp *	@st: holds the counter values
3291218792Snp *
3292218792Snp *	Returns the values of TP's counters for non-TCP directly-placed packets.
3293218792Snp */
3294218792Snpvoid t4_get_usm_stats(struct adapter *adap, struct tp_usm_stats *st)
3295218792Snp{
3296218792Snp	u32 val[4];
3297218792Snp
3298218792Snp	t4_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_DATA, val, 4,
3299218792Snp			 A_TP_MIB_USM_PKTS);
3300218792Snp	st->frames = val[0];
3301218792Snp	st->drops = val[1];
3302218792Snp	st->octets = ((u64)val[2] << 32) | val[3];
3303218792Snp}
3304218792Snp
3305218792Snp/**
3306218792Snp *	t4_read_mtu_tbl - returns the values in the HW path MTU table
3307218792Snp *	@adap: the adapter
3308218792Snp *	@mtus: where to store the MTU values
3309218792Snp *	@mtu_log: where to store the MTU base-2 log (may be %NULL)
3310218792Snp *
3311218792Snp *	Reads the HW path MTU table.
3312218792Snp */
3313218792Snpvoid t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log)
3314218792Snp{
3315218792Snp	u32 v;
3316218792Snp	int i;
3317218792Snp
3318218792Snp	for (i = 0; i < NMTUS; ++i) {
3319218792Snp		t4_write_reg(adap, A_TP_MTU_TABLE,
3320218792Snp			     V_MTUINDEX(0xff) | V_MTUVALUE(i));
3321218792Snp		v = t4_read_reg(adap, A_TP_MTU_TABLE);
3322218792Snp		mtus[i] = G_MTUVALUE(v);
3323218792Snp		if (mtu_log)
3324218792Snp			mtu_log[i] = G_MTUWIDTH(v);
3325218792Snp	}
3326218792Snp}
3327218792Snp
3328218792Snp/**
3329218792Snp *	t4_read_cong_tbl - reads the congestion control table
3330218792Snp *	@adap: the adapter
3331218792Snp *	@incr: where to store the alpha values
3332218792Snp *
3333218792Snp *	Reads the additive increments programmed into the HW congestion
3334218792Snp *	control table.
3335218792Snp */
3336218792Snpvoid t4_read_cong_tbl(struct adapter *adap, u16 incr[NMTUS][NCCTRL_WIN])
3337218792Snp{
3338218792Snp	unsigned int mtu, w;
3339218792Snp
3340218792Snp	for (mtu = 0; mtu < NMTUS; ++mtu)
3341218792Snp		for (w = 0; w < NCCTRL_WIN; ++w) {
3342218792Snp			t4_write_reg(adap, A_TP_CCTRL_TABLE,
3343218792Snp				     V_ROWINDEX(0xffff) | (mtu << 5) | w);
3344218792Snp			incr[mtu][w] = (u16)t4_read_reg(adap,
3345218792Snp						A_TP_CCTRL_TABLE) & 0x1fff;
3346218792Snp		}
3347218792Snp}
3348218792Snp
3349218792Snp/**
3350218792Snp *	t4_read_pace_tbl - read the pace table
3351218792Snp *	@adap: the adapter
3352218792Snp *	@pace_vals: holds the returned values
3353218792Snp *
3354218792Snp *	Returns the values of TP's pace table in microseconds.
3355218792Snp */
3356218792Snpvoid t4_read_pace_tbl(struct adapter *adap, unsigned int pace_vals[NTX_SCHED])
3357218792Snp{
3358218792Snp	unsigned int i, v;
3359218792Snp
3360218792Snp	for (i = 0; i < NTX_SCHED; i++) {
3361218792Snp		t4_write_reg(adap, A_TP_PACE_TABLE, 0xffff0000 + i);
3362218792Snp		v = t4_read_reg(adap, A_TP_PACE_TABLE);
3363218792Snp		pace_vals[i] = dack_ticks_to_usec(adap, v);
3364218792Snp	}
3365218792Snp}
3366218792Snp
3367218792Snp/**
3368218792Snp *	t4_tp_wr_bits_indirect - set/clear bits in an indirect TP register
3369218792Snp *	@adap: the adapter
3370218792Snp *	@addr: the indirect TP register address
3371218792Snp *	@mask: specifies the field within the register to modify
3372218792Snp *	@val: new value for the field
3373218792Snp *
3374218792Snp *	Sets a field of an indirect TP register to the given value.
3375218792Snp */
3376218792Snpvoid t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr,
3377218792Snp			    unsigned int mask, unsigned int val)
3378218792Snp{
3379218792Snp	t4_write_reg(adap, A_TP_PIO_ADDR, addr);
3380218792Snp	val |= t4_read_reg(adap, A_TP_PIO_DATA) & ~mask;
3381218792Snp	t4_write_reg(adap, A_TP_PIO_DATA, val);
3382218792Snp}
3383218792Snp
3384218792Snp/**
3385218792Snp *	init_cong_ctrl - initialize congestion control parameters
3386218792Snp *	@a: the alpha values for congestion control
3387218792Snp *	@b: the beta values for congestion control
3388218792Snp *
3389218792Snp *	Initialize the congestion control parameters.
3390218792Snp */
3391218792Snpstatic void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b)
3392218792Snp{
3393218792Snp	a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
3394218792Snp	a[9] = 2;
3395218792Snp	a[10] = 3;
3396218792Snp	a[11] = 4;
3397218792Snp	a[12] = 5;
3398218792Snp	a[13] = 6;
3399218792Snp	a[14] = 7;
3400218792Snp	a[15] = 8;
3401218792Snp	a[16] = 9;
3402218792Snp	a[17] = 10;
3403218792Snp	a[18] = 14;
3404218792Snp	a[19] = 17;
3405218792Snp	a[20] = 21;
3406218792Snp	a[21] = 25;
3407218792Snp	a[22] = 30;
3408218792Snp	a[23] = 35;
3409218792Snp	a[24] = 45;
3410218792Snp	a[25] = 60;
3411218792Snp	a[26] = 80;
3412218792Snp	a[27] = 100;
3413218792Snp	a[28] = 200;
3414218792Snp	a[29] = 300;
3415218792Snp	a[30] = 400;
3416218792Snp	a[31] = 500;
3417218792Snp
3418218792Snp	b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0;
3419218792Snp	b[9] = b[10] = 1;
3420218792Snp	b[11] = b[12] = 2;
3421218792Snp	b[13] = b[14] = b[15] = b[16] = 3;
3422218792Snp	b[17] = b[18] = b[19] = b[20] = b[21] = 4;
3423218792Snp	b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5;
3424218792Snp	b[28] = b[29] = 6;
3425218792Snp	b[30] = b[31] = 7;
3426218792Snp}
3427218792Snp
3428218792Snp/* The minimum additive increment value for the congestion control table */
3429218792Snp#define CC_MIN_INCR 2U
3430218792Snp
3431218792Snp/**
3432218792Snp *	t4_load_mtus - write the MTU and congestion control HW tables
3433218792Snp *	@adap: the adapter
3434218792Snp *	@mtus: the values for the MTU table
3435218792Snp *	@alpha: the values for the congestion control alpha parameter
3436218792Snp *	@beta: the values for the congestion control beta parameter
3437218792Snp *
3438218792Snp *	Write the HW MTU table with the supplied MTUs and the high-speed
3439218792Snp *	congestion control table with the supplied alpha, beta, and MTUs.
3440218792Snp *	We write the two tables together because the additive increments
3441218792Snp *	depend on the MTUs.
3442218792Snp */
3443218792Snpvoid t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
3444218792Snp		  const unsigned short *alpha, const unsigned short *beta)
3445218792Snp{
3446218792Snp	static const unsigned int avg_pkts[NCCTRL_WIN] = {
3447218792Snp		2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640,
3448218792Snp		896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480,
3449218792Snp		28672, 40960, 57344, 81920, 114688, 163840, 229376
3450218792Snp	};
3451218792Snp
3452218792Snp	unsigned int i, w;
3453218792Snp
3454218792Snp	for (i = 0; i < NMTUS; ++i) {
3455218792Snp		unsigned int mtu = mtus[i];
3456218792Snp		unsigned int log2 = fls(mtu);
3457218792Snp
3458218792Snp		if (!(mtu & ((1 << log2) >> 2)))     /* round */
3459218792Snp			log2--;
3460218792Snp		t4_write_reg(adap, A_TP_MTU_TABLE, V_MTUINDEX(i) |
3461218792Snp			     V_MTUWIDTH(log2) | V_MTUVALUE(mtu));
3462218792Snp
3463218792Snp		for (w = 0; w < NCCTRL_WIN; ++w) {
3464218792Snp			unsigned int inc;
3465218792Snp
3466218792Snp			inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w],
3467218792Snp				  CC_MIN_INCR);
3468218792Snp
3469218792Snp			t4_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) |
3470218792Snp				     (w << 16) | (beta[w] << 13) | inc);
3471218792Snp		}
3472218792Snp	}
3473218792Snp}
3474218792Snp
3475218792Snp/**
3476218792Snp *	t4_set_pace_tbl - set the pace table
3477218792Snp *	@adap: the adapter
3478218792Snp *	@pace_vals: the pace values in microseconds
3479218792Snp *	@start: index of the first entry in the HW pace table to set
3480218792Snp *	@n: how many entries to set
3481218792Snp *
3482218792Snp *	Sets (a subset of the) HW pace table.
3483218792Snp */
3484218792Snpint t4_set_pace_tbl(struct adapter *adap, const unsigned int *pace_vals,
3485218792Snp		     unsigned int start, unsigned int n)
3486218792Snp{
3487218792Snp	unsigned int vals[NTX_SCHED], i;
3488218792Snp	unsigned int tick_ns = dack_ticks_to_usec(adap, 1000);
3489218792Snp
3490218792Snp	if (n > NTX_SCHED)
3491218792Snp	    return -ERANGE;
3492218792Snp
3493218792Snp	/* convert values from us to dack ticks, rounding to closest value */
3494218792Snp	for (i = 0; i < n; i++, pace_vals++) {
3495218792Snp		vals[i] = (1000 * *pace_vals + tick_ns / 2) / tick_ns;
3496218792Snp		if (vals[i] > 0x7ff)
3497218792Snp			return -ERANGE;
3498218792Snp		if (*pace_vals && vals[i] == 0)
3499218792Snp			return -ERANGE;
3500218792Snp	}
3501218792Snp	for (i = 0; i < n; i++, start++)
3502218792Snp		t4_write_reg(adap, A_TP_PACE_TABLE, (start << 16) | vals[i]);
3503218792Snp	return 0;
3504218792Snp}
3505218792Snp
3506218792Snp/**
3507218792Snp *	t4_set_sched_bps - set the bit rate for a HW traffic scheduler
3508218792Snp *	@adap: the adapter
3509218792Snp *	@kbps: target rate in Kbps
3510218792Snp *	@sched: the scheduler index
3511218792Snp *
3512218792Snp *	Configure a Tx HW scheduler for the target rate.
3513218792Snp */
3514218792Snpint t4_set_sched_bps(struct adapter *adap, int sched, unsigned int kbps)
3515218792Snp{
3516218792Snp	unsigned int v, tps, cpt, bpt, delta, mindelta = ~0;
3517218792Snp	unsigned int clk = adap->params.vpd.cclk * 1000;
3518218792Snp	unsigned int selected_cpt = 0, selected_bpt = 0;
3519218792Snp
3520218792Snp	if (kbps > 0) {
3521218792Snp		kbps *= 125;     /* -> bytes */
3522218792Snp		for (cpt = 1; cpt <= 255; cpt++) {
3523218792Snp			tps = clk / cpt;
3524218792Snp			bpt = (kbps + tps / 2) / tps;
3525218792Snp			if (bpt > 0 && bpt <= 255) {
3526218792Snp				v = bpt * tps;
3527218792Snp				delta = v >= kbps ? v - kbps : kbps - v;
3528218792Snp				if (delta < mindelta) {
3529218792Snp					mindelta = delta;
3530218792Snp					selected_cpt = cpt;
3531218792Snp					selected_bpt = bpt;
3532218792Snp				}
3533218792Snp			} else if (selected_cpt)
3534218792Snp				break;
3535218792Snp		}
3536218792Snp		if (!selected_cpt)
3537218792Snp			return -EINVAL;
3538218792Snp	}
3539218792Snp	t4_write_reg(adap, A_TP_TM_PIO_ADDR,
3540218792Snp		     A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2);
3541218792Snp	v = t4_read_reg(adap, A_TP_TM_PIO_DATA);
3542218792Snp	if (sched & 1)
3543218792Snp		v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24);
3544218792Snp	else
3545218792Snp		v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8);
3546218792Snp	t4_write_reg(adap, A_TP_TM_PIO_DATA, v);
3547218792Snp	return 0;
3548218792Snp}
3549218792Snp
3550218792Snp/**
3551218792Snp *	t4_set_sched_ipg - set the IPG for a Tx HW packet rate scheduler
3552218792Snp *	@adap: the adapter
3553218792Snp *	@sched: the scheduler index
3554218792Snp *	@ipg: the interpacket delay in tenths of nanoseconds
3555218792Snp *
3556218792Snp *	Set the interpacket delay for a HW packet rate scheduler.
3557218792Snp */
3558218792Snpint t4_set_sched_ipg(struct adapter *adap, int sched, unsigned int ipg)
3559218792Snp{
3560218792Snp	unsigned int v, addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2;
3561218792Snp
3562218792Snp	/* convert ipg to nearest number of core clocks */
3563218792Snp	ipg *= core_ticks_per_usec(adap);
3564218792Snp	ipg = (ipg + 5000) / 10000;
3565218792Snp	if (ipg > M_TXTIMERSEPQ0)
3566218792Snp		return -EINVAL;
3567218792Snp
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 = (v & V_TXTIMERSEPQ0(M_TXTIMERSEPQ0)) | V_TXTIMERSEPQ1(ipg);
3572218792Snp	else
3573218792Snp		v = (v & V_TXTIMERSEPQ1(M_TXTIMERSEPQ1)) | V_TXTIMERSEPQ0(ipg);
3574218792Snp	t4_write_reg(adap, A_TP_TM_PIO_DATA, v);
3575218792Snp	t4_read_reg(adap, A_TP_TM_PIO_DATA);
3576218792Snp	return 0;
3577218792Snp}
3578218792Snp
3579218792Snp/**
3580218792Snp *	t4_get_tx_sched - get the configuration of a Tx HW traffic scheduler
3581218792Snp *	@adap: the adapter
3582218792Snp *	@sched: the scheduler index
3583218792Snp *	@kbps: the byte rate in Kbps
3584218792Snp *	@ipg: the interpacket delay in tenths of nanoseconds
3585218792Snp *
3586218792Snp *	Return the current configuration of a HW Tx scheduler.
3587218792Snp */
3588218792Snpvoid t4_get_tx_sched(struct adapter *adap, unsigned int sched, unsigned int *kbps,
3589218792Snp		     unsigned int *ipg)
3590218792Snp{
3591218792Snp	unsigned int v, addr, bpt, cpt;
3592218792Snp
3593218792Snp	if (kbps) {
3594218792Snp		addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
3595218792Snp		t4_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3596218792Snp		v = t4_read_reg(adap, A_TP_TM_PIO_DATA);
3597218792Snp		if (sched & 1)
3598218792Snp			v >>= 16;
3599218792Snp		bpt = (v >> 8) & 0xff;
3600218792Snp		cpt = v & 0xff;
3601218792Snp		if (!cpt)
3602218792Snp			*kbps = 0;        /* scheduler disabled */
3603218792Snp		else {
3604218792Snp			v = (adap->params.vpd.cclk * 1000) / cpt; /* ticks/s */
3605218792Snp			*kbps = (v * bpt) / 125;
3606218792Snp		}
3607218792Snp	}
3608218792Snp	if (ipg) {
3609218792Snp		addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2;
3610218792Snp		t4_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3611218792Snp		v = t4_read_reg(adap, A_TP_TM_PIO_DATA);
3612218792Snp		if (sched & 1)
3613218792Snp			v >>= 16;
3614218792Snp		v &= 0xffff;
3615218792Snp		*ipg = (10000 * v) / core_ticks_per_usec(adap);
3616218792Snp	}
3617218792Snp}
3618218792Snp
3619218792Snp/*
3620218792Snp * Calculates a rate in bytes/s given the number of 256-byte units per 4K core
3621218792Snp * clocks.  The formula is
3622218792Snp *
3623218792Snp * bytes/s = bytes256 * 256 * ClkFreq / 4096
3624218792Snp *
3625218792Snp * which is equivalent to
3626218792Snp *
3627218792Snp * bytes/s = 62.5 * bytes256 * ClkFreq_ms
3628218792Snp */
3629218792Snpstatic u64 chan_rate(struct adapter *adap, unsigned int bytes256)
3630218792Snp{
3631218792Snp	u64 v = bytes256 * adap->params.vpd.cclk;
3632218792Snp
3633218792Snp	return v * 62 + v / 2;
3634218792Snp}
3635218792Snp
3636218792Snp/**
3637218792Snp *	t4_get_chan_txrate - get the current per channel Tx rates
3638218792Snp *	@adap: the adapter
3639218792Snp *	@nic_rate: rates for NIC traffic
3640218792Snp *	@ofld_rate: rates for offloaded traffic
3641218792Snp *
3642218792Snp *	Return the current Tx rates in bytes/s for NIC and offloaded traffic
3643218792Snp *	for each channel.
3644218792Snp */
3645218792Snpvoid t4_get_chan_txrate(struct adapter *adap, u64 *nic_rate, u64 *ofld_rate)
3646218792Snp{
3647218792Snp	u32 v;
3648218792Snp
3649218792Snp	v = t4_read_reg(adap, A_TP_TX_TRATE);
3650218792Snp	nic_rate[0] = chan_rate(adap, G_TNLRATE0(v));
3651218792Snp	nic_rate[1] = chan_rate(adap, G_TNLRATE1(v));
3652218792Snp	nic_rate[2] = chan_rate(adap, G_TNLRATE2(v));
3653218792Snp	nic_rate[3] = chan_rate(adap, G_TNLRATE3(v));
3654218792Snp
3655218792Snp	v = t4_read_reg(adap, A_TP_TX_ORATE);
3656218792Snp	ofld_rate[0] = chan_rate(adap, G_OFDRATE0(v));
3657218792Snp	ofld_rate[1] = chan_rate(adap, G_OFDRATE1(v));
3658218792Snp	ofld_rate[2] = chan_rate(adap, G_OFDRATE2(v));
3659218792Snp	ofld_rate[3] = chan_rate(adap, G_OFDRATE3(v));
3660218792Snp}
3661218792Snp
3662218792Snp/**
3663218792Snp *	t4_set_trace_filter - configure one of the tracing filters
3664218792Snp *	@adap: the adapter
3665218792Snp *	@tp: the desired trace filter parameters
3666218792Snp *	@idx: which filter to configure
3667218792Snp *	@enable: whether to enable or disable the filter
3668218792Snp *
3669253691Snp *	Configures one of the tracing filters available in HW.  If @tp is %NULL
3670253691Snp *	it indicates that the filter is already written in the register and it
3671253691Snp *	just needs to be enabled or disabled.
3672218792Snp */
3673253691Snpint t4_set_trace_filter(struct adapter *adap, const struct trace_params *tp,
3674253691Snp    int idx, int enable)
3675218792Snp{
3676218792Snp	int i, ofst = idx * 4;
3677218792Snp	u32 data_reg, mask_reg, cfg;
3678218792Snp	u32 multitrc = F_TRCMULTIFILTER;
3679253691Snp	u32 en = is_t4(adap) ? F_TFEN : F_T5_TFEN;
3680218792Snp
3681253691Snp	if (idx < 0 || idx >= NTRACE)
3682253691Snp		return -EINVAL;
3683253691Snp
3684253691Snp	if (tp == NULL || !enable) {
3685253691Snp		t4_set_reg_field(adap, A_MPS_TRC_FILTER_MATCH_CTL_A + ofst, en,
3686253691Snp		    enable ? en : 0);
3687237436Snp		return 0;
3688218792Snp	}
3689218792Snp
3690237436Snp	/*
3691237436Snp	 * TODO - After T4 data book is updated, specify the exact
3692237436Snp	 * section below.
3693237436Snp	 *
3694237436Snp	 * See T4 data book - MPS section for a complete description
3695237436Snp	 * of the below if..else handling of A_MPS_TRC_CFG register
3696237436Snp	 * value.
3697237436Snp	 */
3698237436Snp	cfg = t4_read_reg(adap, A_MPS_TRC_CFG);
3699237436Snp	if (cfg & F_TRCMULTIFILTER) {
3700237436Snp		/*
3701237436Snp		 * If multiple tracers are enabled, then maximum
3702237436Snp		 * capture size is 2.5KB (FIFO size of a single channel)
3703237436Snp		 * minus 2 flits for CPL_TRACE_PKT header.
3704237436Snp		 */
3705237436Snp		if (tp->snap_len > ((10 * 1024 / 4) - (2 * 8)))
3706237436Snp			return -EINVAL;
3707253691Snp	} else {
3708237436Snp		/*
3709237436Snp		 * If multiple tracers are disabled, to avoid deadlocks
3710237436Snp		 * maximum packet capture size of 9600 bytes is recommended.
3711237436Snp		 * Also in this mode, only trace0 can be enabled and running.
3712237436Snp		 */
3713218792Snp		multitrc = 0;
3714237436Snp		if (tp->snap_len > 9600 || idx)
3715218792Snp			return -EINVAL;
3716218792Snp	}
3717218792Snp
3718253691Snp	if (tp->port > (is_t4(adap) ? 11 : 19) || tp->invert > 1 ||
3719253691Snp	    tp->skip_len > M_TFLENGTH || tp->skip_ofst > M_TFOFFSET ||
3720253691Snp	    tp->min_len > M_TFMINPKTSIZE)
3721237436Snp		return -EINVAL;
3722237436Snp
3723218792Snp	/* stop the tracer we'll be changing */
3724253691Snp	t4_set_reg_field(adap, A_MPS_TRC_FILTER_MATCH_CTL_A + ofst, en, 0);
3725218792Snp
3726218792Snp	idx *= (A_MPS_TRC_FILTER1_MATCH - A_MPS_TRC_FILTER0_MATCH);
3727218792Snp	data_reg = A_MPS_TRC_FILTER0_MATCH + idx;
3728218792Snp	mask_reg = A_MPS_TRC_FILTER0_DONT_CARE + idx;
3729218792Snp
3730218792Snp	for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) {
3731218792Snp		t4_write_reg(adap, data_reg, tp->data[i]);
3732218792Snp		t4_write_reg(adap, mask_reg, ~tp->mask[i]);
3733218792Snp	}
3734218792Snp	t4_write_reg(adap, A_MPS_TRC_FILTER_MATCH_CTL_B + ofst,
3735218792Snp		     V_TFCAPTUREMAX(tp->snap_len) |
3736218792Snp		     V_TFMINPKTSIZE(tp->min_len));
3737218792Snp	t4_write_reg(adap, A_MPS_TRC_FILTER_MATCH_CTL_A + ofst,
3738253691Snp		     V_TFOFFSET(tp->skip_ofst) | V_TFLENGTH(tp->skip_len) | en |
3739253691Snp		     (is_t4(adap) ?
3740253691Snp		     V_TFPORT(tp->port) | V_TFINVERTMATCH(tp->invert) :
3741253691Snp		     V_T5_TFPORT(tp->port) | V_T5_TFINVERTMATCH(tp->invert)));
3742218792Snp
3743218792Snp	return 0;
3744218792Snp}
3745218792Snp
3746218792Snp/**
3747218792Snp *	t4_get_trace_filter - query one of the tracing filters
3748218792Snp *	@adap: the adapter
3749218792Snp *	@tp: the current trace filter parameters
3750218792Snp *	@idx: which trace filter to query
3751218792Snp *	@enabled: non-zero if the filter is enabled
3752218792Snp *
3753218792Snp *	Returns the current settings of one of the HW tracing filters.
3754218792Snp */
3755218792Snpvoid t4_get_trace_filter(struct adapter *adap, struct trace_params *tp, int idx,
3756218792Snp			 int *enabled)
3757218792Snp{
3758218792Snp	u32 ctla, ctlb;
3759218792Snp	int i, ofst = idx * 4;
3760218792Snp	u32 data_reg, mask_reg;
3761218792Snp
3762218792Snp	ctla = t4_read_reg(adap, A_MPS_TRC_FILTER_MATCH_CTL_A + ofst);
3763218792Snp	ctlb = t4_read_reg(adap, A_MPS_TRC_FILTER_MATCH_CTL_B + ofst);
3764218792Snp
3765248925Snp	if (is_t4(adap)) {
3766248925Snp		*enabled = !!(ctla & F_TFEN);
3767248925Snp		tp->port =  G_TFPORT(ctla);
3768253691Snp		tp->invert = !!(ctla & F_TFINVERTMATCH);
3769248925Snp	} else {
3770248925Snp		*enabled = !!(ctla & F_T5_TFEN);
3771248925Snp		tp->port = G_T5_TFPORT(ctla);
3772253691Snp		tp->invert = !!(ctla & F_T5_TFINVERTMATCH);
3773248925Snp	}
3774218792Snp	tp->snap_len = G_TFCAPTUREMAX(ctlb);
3775218792Snp	tp->min_len = G_TFMINPKTSIZE(ctlb);
3776218792Snp	tp->skip_ofst = G_TFOFFSET(ctla);
3777218792Snp	tp->skip_len = G_TFLENGTH(ctla);
3778218792Snp
3779218792Snp	ofst = (A_MPS_TRC_FILTER1_MATCH - A_MPS_TRC_FILTER0_MATCH) * idx;
3780218792Snp	data_reg = A_MPS_TRC_FILTER0_MATCH + ofst;
3781218792Snp	mask_reg = A_MPS_TRC_FILTER0_DONT_CARE + ofst;
3782218792Snp
3783218792Snp	for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) {
3784218792Snp		tp->mask[i] = ~t4_read_reg(adap, mask_reg);
3785218792Snp		tp->data[i] = t4_read_reg(adap, data_reg) & tp->mask[i];
3786218792Snp	}
3787218792Snp}
3788218792Snp
3789218792Snp/**
3790218792Snp *	t4_pmtx_get_stats - returns the HW stats from PMTX
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 PMTX.
3796218792Snp */
3797218792Snpvoid t4_pmtx_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_TX_STAT_CONFIG, i + 1);
3804218792Snp		cnt[i] = t4_read_reg(adap, A_PM_TX_STAT_COUNT);
3805248925Snp		if (is_t4(adap))
3806248925Snp			cycles[i] = t4_read_reg64(adap, A_PM_TX_STAT_LSB);
3807248925Snp		else {
3808248925Snp			t4_read_indirect(adap, A_PM_TX_DBG_CTRL,
3809248925Snp					 A_PM_TX_DBG_DATA, data, 2,
3810248925Snp					 A_PM_TX_DBG_STAT_MSB);
3811248925Snp			cycles[i] = (((u64)data[0] << 32) | data[1]);
3812248925Snp		}
3813218792Snp	}
3814218792Snp}
3815218792Snp
3816218792Snp/**
3817218792Snp *	t4_pmrx_get_stats - returns the HW stats from PMRX
3818218792Snp *	@adap: the adapter
3819218792Snp *	@cnt: where to store the count statistics
3820218792Snp *	@cycles: where to store the cycle statistics
3821218792Snp *
3822218792Snp *	Returns performance statistics from PMRX.
3823218792Snp */
3824218792Snpvoid t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[])
3825218792Snp{
3826218792Snp	int i;
3827248925Snp	u32 data[2];
3828218792Snp
3829218792Snp	for (i = 0; i < PM_NSTATS; i++) {
3830218792Snp		t4_write_reg(adap, A_PM_RX_STAT_CONFIG, i + 1);
3831218792Snp		cnt[i] = t4_read_reg(adap, A_PM_RX_STAT_COUNT);
3832248925Snp		if (is_t4(adap))
3833248925Snp			cycles[i] = t4_read_reg64(adap, A_PM_RX_STAT_LSB);
3834248925Snp		else {
3835248925Snp			t4_read_indirect(adap, A_PM_RX_DBG_CTRL,
3836248925Snp					 A_PM_RX_DBG_DATA, data, 2,
3837248925Snp					 A_PM_RX_DBG_STAT_MSB);
3838248925Snp			cycles[i] = (((u64)data[0] << 32) | data[1]);
3839248925Snp		}
3840218792Snp	}
3841218792Snp}
3842218792Snp
3843218792Snp/**
3844218792Snp *	get_mps_bg_map - return the buffer groups associated with a port
3845218792Snp *	@adap: the adapter
3846218792Snp *	@idx: the port index
3847218792Snp *
3848218792Snp *	Returns a bitmap indicating which MPS buffer groups are associated
3849218792Snp *	with the given port.  Bit i is set if buffer group i is used by the
3850218792Snp *	port.
3851218792Snp */
3852218792Snpstatic unsigned int get_mps_bg_map(struct adapter *adap, int idx)
3853218792Snp{
3854218792Snp	u32 n = G_NUMPORTS(t4_read_reg(adap, A_MPS_CMN_CTL));
3855218792Snp
3856218792Snp	if (n == 0)
3857218792Snp		return idx == 0 ? 0xf : 0;
3858218792Snp	if (n == 1)
3859218792Snp		return idx < 2 ? (3 << (2 * idx)) : 0;
3860218792Snp	return 1 << idx;
3861218792Snp}
3862218792Snp
3863218792Snp/**
3864237436Snp *      t4_get_port_stats_offset - collect port stats relative to a previous
3865237436Snp *                                 snapshot
3866237436Snp *      @adap: The adapter
3867237436Snp *      @idx: The port
3868237436Snp *      @stats: Current stats to fill
3869237436Snp *      @offset: Previous stats snapshot
3870237436Snp */
3871237436Snpvoid t4_get_port_stats_offset(struct adapter *adap, int idx,
3872237436Snp		struct port_stats *stats,
3873237436Snp		struct port_stats *offset)
3874237436Snp{
3875237436Snp	u64 *s, *o;
3876237436Snp	int i;
3877237436Snp
3878237436Snp	t4_get_port_stats(adap, idx, stats);
3879237436Snp	for (i = 0, s = (u64 *)stats, o = (u64 *)offset ;
3880237436Snp			i < (sizeof(struct port_stats)/sizeof(u64)) ;
3881237436Snp			i++, s++, o++)
3882237436Snp		*s -= *o;
3883237436Snp}
3884237436Snp
3885237436Snp/**
3886218792Snp *	t4_get_port_stats - collect port statistics
3887218792Snp *	@adap: the adapter
3888218792Snp *	@idx: the port index
3889218792Snp *	@p: the stats structure to fill
3890218792Snp *
3891218792Snp *	Collect statistics related to the given port from HW.
3892218792Snp */
3893218792Snpvoid t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
3894218792Snp{
3895218792Snp	u32 bgmap = get_mps_bg_map(adap, idx);
3896218792Snp
3897218792Snp#define GET_STAT(name) \
3898248925Snp	t4_read_reg64(adap, \
3899248925Snp	(is_t4(adap) ? PORT_REG(idx, A_MPS_PORT_STAT_##name##_L) : \
3900248925Snp	T5_PORT_REG(idx, A_MPS_PORT_STAT_##name##_L)))
3901218792Snp#define GET_STAT_COM(name) t4_read_reg64(adap, A_MPS_STAT_##name##_L)
3902218792Snp
3903228561Snp	p->tx_pause            = GET_STAT(TX_PORT_PAUSE);
3904218792Snp	p->tx_octets           = GET_STAT(TX_PORT_BYTES);
3905218792Snp	p->tx_frames           = GET_STAT(TX_PORT_FRAMES);
3906218792Snp	p->tx_bcast_frames     = GET_STAT(TX_PORT_BCAST);
3907218792Snp	p->tx_mcast_frames     = GET_STAT(TX_PORT_MCAST);
3908218792Snp	p->tx_ucast_frames     = GET_STAT(TX_PORT_UCAST);
3909218792Snp	p->tx_error_frames     = GET_STAT(TX_PORT_ERROR);
3910218792Snp	p->tx_frames_64        = GET_STAT(TX_PORT_64B);
3911218792Snp	p->tx_frames_65_127    = GET_STAT(TX_PORT_65B_127B);
3912218792Snp	p->tx_frames_128_255   = GET_STAT(TX_PORT_128B_255B);
3913218792Snp	p->tx_frames_256_511   = GET_STAT(TX_PORT_256B_511B);
3914218792Snp	p->tx_frames_512_1023  = GET_STAT(TX_PORT_512B_1023B);
3915218792Snp	p->tx_frames_1024_1518 = GET_STAT(TX_PORT_1024B_1518B);
3916218792Snp	p->tx_frames_1519_max  = GET_STAT(TX_PORT_1519B_MAX);
3917218792Snp	p->tx_drop             = GET_STAT(TX_PORT_DROP);
3918218792Snp	p->tx_ppp0             = GET_STAT(TX_PORT_PPP0);
3919218792Snp	p->tx_ppp1             = GET_STAT(TX_PORT_PPP1);
3920218792Snp	p->tx_ppp2             = GET_STAT(TX_PORT_PPP2);
3921218792Snp	p->tx_ppp3             = GET_STAT(TX_PORT_PPP3);
3922218792Snp	p->tx_ppp4             = GET_STAT(TX_PORT_PPP4);
3923218792Snp	p->tx_ppp5             = GET_STAT(TX_PORT_PPP5);
3924218792Snp	p->tx_ppp6             = GET_STAT(TX_PORT_PPP6);
3925218792Snp	p->tx_ppp7             = GET_STAT(TX_PORT_PPP7);
3926218792Snp
3927228561Snp	p->rx_pause            = GET_STAT(RX_PORT_PAUSE);
3928218792Snp	p->rx_octets           = GET_STAT(RX_PORT_BYTES);
3929218792Snp	p->rx_frames           = GET_STAT(RX_PORT_FRAMES);
3930218792Snp	p->rx_bcast_frames     = GET_STAT(RX_PORT_BCAST);
3931218792Snp	p->rx_mcast_frames     = GET_STAT(RX_PORT_MCAST);
3932218792Snp	p->rx_ucast_frames     = GET_STAT(RX_PORT_UCAST);
3933218792Snp	p->rx_too_long         = GET_STAT(RX_PORT_MTU_ERROR);
3934218792Snp	p->rx_jabber           = GET_STAT(RX_PORT_MTU_CRC_ERROR);
3935218792Snp	p->rx_fcs_err          = GET_STAT(RX_PORT_CRC_ERROR);
3936218792Snp	p->rx_len_err          = GET_STAT(RX_PORT_LEN_ERROR);
3937218792Snp	p->rx_symbol_err       = GET_STAT(RX_PORT_SYM_ERROR);
3938218792Snp	p->rx_runt             = GET_STAT(RX_PORT_LESS_64B);
3939218792Snp	p->rx_frames_64        = GET_STAT(RX_PORT_64B);
3940218792Snp	p->rx_frames_65_127    = GET_STAT(RX_PORT_65B_127B);
3941218792Snp	p->rx_frames_128_255   = GET_STAT(RX_PORT_128B_255B);
3942218792Snp	p->rx_frames_256_511   = GET_STAT(RX_PORT_256B_511B);
3943218792Snp	p->rx_frames_512_1023  = GET_STAT(RX_PORT_512B_1023B);
3944218792Snp	p->rx_frames_1024_1518 = GET_STAT(RX_PORT_1024B_1518B);
3945218792Snp	p->rx_frames_1519_max  = GET_STAT(RX_PORT_1519B_MAX);
3946218792Snp	p->rx_ppp0             = GET_STAT(RX_PORT_PPP0);
3947218792Snp	p->rx_ppp1             = GET_STAT(RX_PORT_PPP1);
3948218792Snp	p->rx_ppp2             = GET_STAT(RX_PORT_PPP2);
3949218792Snp	p->rx_ppp3             = GET_STAT(RX_PORT_PPP3);
3950218792Snp	p->rx_ppp4             = GET_STAT(RX_PORT_PPP4);
3951218792Snp	p->rx_ppp5             = GET_STAT(RX_PORT_PPP5);
3952218792Snp	p->rx_ppp6             = GET_STAT(RX_PORT_PPP6);
3953218792Snp	p->rx_ppp7             = GET_STAT(RX_PORT_PPP7);
3954218792Snp
3955218792Snp	p->rx_ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_DROP_FRAME) : 0;
3956218792Snp	p->rx_ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_DROP_FRAME) : 0;
3957218792Snp	p->rx_ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_DROP_FRAME) : 0;
3958218792Snp	p->rx_ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_DROP_FRAME) : 0;
3959218792Snp	p->rx_trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_TRUNC_FRAME) : 0;
3960218792Snp	p->rx_trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_TRUNC_FRAME) : 0;
3961218792Snp	p->rx_trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_TRUNC_FRAME) : 0;
3962218792Snp	p->rx_trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_TRUNC_FRAME) : 0;
3963218792Snp
3964218792Snp#undef GET_STAT
3965218792Snp#undef GET_STAT_COM
3966218792Snp}
3967218792Snp
3968218792Snp/**
3969218792Snp *	t4_clr_port_stats - clear port statistics
3970218792Snp *	@adap: the adapter
3971218792Snp *	@idx: the port index
3972218792Snp *
3973218792Snp *	Clear HW statistics for the given port.
3974218792Snp */
3975218792Snpvoid t4_clr_port_stats(struct adapter *adap, int idx)
3976218792Snp{
3977218792Snp	unsigned int i;
3978218792Snp	u32 bgmap = get_mps_bg_map(adap, idx);
3979248925Snp	u32 port_base_addr;
3980218792Snp
3981248925Snp	if (is_t4(adap))
3982248925Snp		port_base_addr = PORT_BASE(idx);
3983248925Snp	else
3984248925Snp		port_base_addr = T5_PORT_BASE(idx);
3985248925Snp
3986218792Snp	for (i = A_MPS_PORT_STAT_TX_PORT_BYTES_L;
3987248925Snp			i <= A_MPS_PORT_STAT_TX_PORT_PPP7_H; i += 8)
3988248925Snp		t4_write_reg(adap, port_base_addr + i, 0);
3989218792Snp	for (i = A_MPS_PORT_STAT_RX_PORT_BYTES_L;
3990248925Snp			i <= A_MPS_PORT_STAT_RX_PORT_LESS_64B_H; i += 8)
3991248925Snp		t4_write_reg(adap, port_base_addr + i, 0);
3992218792Snp	for (i = 0; i < 4; i++)
3993218792Snp		if (bgmap & (1 << i)) {
3994218792Snp			t4_write_reg(adap,
3995218792Snp				A_MPS_STAT_RX_BG_0_MAC_DROP_FRAME_L + i * 8, 0);
3996218792Snp			t4_write_reg(adap,
3997218792Snp				A_MPS_STAT_RX_BG_0_MAC_TRUNC_FRAME_L + i * 8, 0);
3998218792Snp		}
3999218792Snp}
4000218792Snp
4001218792Snp/**
4002218792Snp *	t4_get_lb_stats - collect loopback port statistics
4003218792Snp *	@adap: the adapter
4004218792Snp *	@idx: the loopback port index
4005218792Snp *	@p: the stats structure to fill
4006218792Snp *
4007218792Snp *	Return HW statistics for the given loopback port.
4008218792Snp */
4009218792Snpvoid t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p)
4010218792Snp{
4011218792Snp	u32 bgmap = get_mps_bg_map(adap, idx);
4012218792Snp
4013218792Snp#define GET_STAT(name) \
4014248925Snp	t4_read_reg64(adap, \
4015248925Snp	(is_t4(adap) ? \
4016248925Snp	PORT_REG(idx, A_MPS_PORT_STAT_LB_PORT_##name##_L) : \
4017248925Snp	T5_PORT_REG(idx, A_MPS_PORT_STAT_LB_PORT_##name##_L)))
4018218792Snp#define GET_STAT_COM(name) t4_read_reg64(adap, A_MPS_STAT_##name##_L)
4019218792Snp
4020218792Snp	p->octets           = GET_STAT(BYTES);
4021218792Snp	p->frames           = GET_STAT(FRAMES);
4022218792Snp	p->bcast_frames     = GET_STAT(BCAST);
4023218792Snp	p->mcast_frames     = GET_STAT(MCAST);
4024218792Snp	p->ucast_frames     = GET_STAT(UCAST);
4025218792Snp	p->error_frames     = GET_STAT(ERROR);
4026218792Snp
4027218792Snp	p->frames_64        = GET_STAT(64B);
4028218792Snp	p->frames_65_127    = GET_STAT(65B_127B);
4029218792Snp	p->frames_128_255   = GET_STAT(128B_255B);
4030218792Snp	p->frames_256_511   = GET_STAT(256B_511B);
4031218792Snp	p->frames_512_1023  = GET_STAT(512B_1023B);
4032218792Snp	p->frames_1024_1518 = GET_STAT(1024B_1518B);
4033218792Snp	p->frames_1519_max  = GET_STAT(1519B_MAX);
4034248925Snp	p->drop             = GET_STAT(DROP_FRAMES);
4035218792Snp
4036218792Snp	p->ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_DROP_FRAME) : 0;
4037218792Snp	p->ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_DROP_FRAME) : 0;
4038218792Snp	p->ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_DROP_FRAME) : 0;
4039218792Snp	p->ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_DROP_FRAME) : 0;
4040218792Snp	p->trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_LB_TRUNC_FRAME) : 0;
4041218792Snp	p->trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_LB_TRUNC_FRAME) : 0;
4042218792Snp	p->trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_LB_TRUNC_FRAME) : 0;
4043218792Snp	p->trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_LB_TRUNC_FRAME) : 0;
4044218792Snp
4045218792Snp#undef GET_STAT
4046218792Snp#undef GET_STAT_COM
4047218792Snp}
4048218792Snp
4049218792Snp/**
4050218792Snp *	t4_wol_magic_enable - enable/disable magic packet WoL
4051218792Snp *	@adap: the adapter
4052218792Snp *	@port: the physical port index
4053218792Snp *	@addr: MAC address expected in magic packets, %NULL to disable
4054218792Snp *
4055218792Snp *	Enables/disables magic packet wake-on-LAN for the selected port.
4056218792Snp */
4057218792Snpvoid t4_wol_magic_enable(struct adapter *adap, unsigned int port,
4058218792Snp			 const u8 *addr)
4059218792Snp{
4060248925Snp	u32 mag_id_reg_l, mag_id_reg_h, port_cfg_reg;
4061248925Snp
4062248925Snp	if (is_t4(adap)) {
4063248925Snp		mag_id_reg_l = PORT_REG(port, A_XGMAC_PORT_MAGIC_MACID_LO);
4064248925Snp		mag_id_reg_h = PORT_REG(port, A_XGMAC_PORT_MAGIC_MACID_HI);
4065248925Snp		port_cfg_reg = PORT_REG(port, A_XGMAC_PORT_CFG2);
4066248925Snp	} else {
4067248925Snp		mag_id_reg_l = T5_PORT_REG(port, A_MAC_PORT_MAGIC_MACID_LO);
4068248925Snp		mag_id_reg_h = T5_PORT_REG(port, A_MAC_PORT_MAGIC_MACID_HI);
4069248925Snp		port_cfg_reg = T5_PORT_REG(port, A_MAC_PORT_CFG2);
4070248925Snp	}
4071248925Snp
4072218792Snp	if (addr) {
4073248925Snp		t4_write_reg(adap, mag_id_reg_l,
4074218792Snp			     (addr[2] << 24) | (addr[3] << 16) |
4075218792Snp			     (addr[4] << 8) | addr[5]);
4076248925Snp		t4_write_reg(adap, mag_id_reg_h,
4077218792Snp			     (addr[0] << 8) | addr[1]);
4078218792Snp	}
4079248925Snp	t4_set_reg_field(adap, port_cfg_reg, F_MAGICEN,
4080218792Snp			 V_MAGICEN(addr != NULL));
4081218792Snp}
4082218792Snp
4083218792Snp/**
4084218792Snp *	t4_wol_pat_enable - enable/disable pattern-based WoL
4085218792Snp *	@adap: the adapter
4086218792Snp *	@port: the physical port index
4087218792Snp *	@map: bitmap of which HW pattern filters to set
4088218792Snp *	@mask0: byte mask for bytes 0-63 of a packet
4089218792Snp *	@mask1: byte mask for bytes 64-127 of a packet
4090218792Snp *	@crc: Ethernet CRC for selected bytes
4091218792Snp *	@enable: enable/disable switch
4092218792Snp *
4093218792Snp *	Sets the pattern filters indicated in @map to mask out the bytes
4094218792Snp *	specified in @mask0/@mask1 in received packets and compare the CRC of
4095218792Snp *	the resulting packet against @crc.  If @enable is %true pattern-based
4096218792Snp *	WoL is enabled, otherwise disabled.
4097218792Snp */
4098218792Snpint t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
4099218792Snp		      u64 mask0, u64 mask1, unsigned int crc, bool enable)
4100218792Snp{
4101218792Snp	int i;
4102248925Snp	u32 port_cfg_reg;
4103218792Snp
4104248925Snp	if (is_t4(adap))
4105248925Snp		port_cfg_reg = PORT_REG(port, A_XGMAC_PORT_CFG2);
4106248925Snp	else
4107248925Snp		port_cfg_reg = T5_PORT_REG(port, A_MAC_PORT_CFG2);
4108248925Snp
4109218792Snp	if (!enable) {
4110248925Snp		t4_set_reg_field(adap, port_cfg_reg, F_PATEN, 0);
4111218792Snp		return 0;
4112218792Snp	}
4113218792Snp	if (map > 0xff)
4114218792Snp		return -EINVAL;
4115218792Snp
4116248925Snp#define EPIO_REG(name) \
4117248925Snp	(is_t4(adap) ? PORT_REG(port, A_XGMAC_PORT_EPIO_##name) : \
4118248925Snp	T5_PORT_REG(port, A_MAC_PORT_EPIO_##name))
4119218792Snp
4120218792Snp	t4_write_reg(adap, EPIO_REG(DATA1), mask0 >> 32);
4121218792Snp	t4_write_reg(adap, EPIO_REG(DATA2), mask1);
4122218792Snp	t4_write_reg(adap, EPIO_REG(DATA3), mask1 >> 32);
4123218792Snp
4124218792Snp	for (i = 0; i < NWOL_PAT; i++, map >>= 1) {
4125218792Snp		if (!(map & 1))
4126218792Snp			continue;
4127218792Snp
4128218792Snp		/* write byte masks */
4129218792Snp		t4_write_reg(adap, EPIO_REG(DATA0), mask0);
4130218792Snp		t4_write_reg(adap, EPIO_REG(OP), V_ADDRESS(i) | F_EPIOWR);
4131218792Snp		t4_read_reg(adap, EPIO_REG(OP));                /* flush */
4132218792Snp		if (t4_read_reg(adap, EPIO_REG(OP)) & F_BUSY)
4133218792Snp			return -ETIMEDOUT;
4134218792Snp
4135218792Snp		/* write CRC */
4136218792Snp		t4_write_reg(adap, EPIO_REG(DATA0), crc);
4137218792Snp		t4_write_reg(adap, EPIO_REG(OP), V_ADDRESS(i + 32) | F_EPIOWR);
4138218792Snp		t4_read_reg(adap, EPIO_REG(OP));                /* flush */
4139218792Snp		if (t4_read_reg(adap, EPIO_REG(OP)) & F_BUSY)
4140218792Snp			return -ETIMEDOUT;
4141218792Snp	}
4142218792Snp#undef EPIO_REG
4143218792Snp
4144248925Snp	t4_set_reg_field(adap, port_cfg_reg, 0, F_PATEN);
4145218792Snp	return 0;
4146218792Snp}
4147218792Snp
4148218792Snp/**
4149218792Snp *	t4_mk_filtdelwr - create a delete filter WR
4150218792Snp *	@ftid: the filter ID
4151218792Snp *	@wr: the filter work request to populate
4152218792Snp *	@qid: ingress queue to receive the delete notification
4153218792Snp *
4154218792Snp *	Creates a filter work request to delete the supplied filter.  If @qid is
4155218792Snp *	negative the delete notification is suppressed.
4156218792Snp */
4157218792Snpvoid t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid)
4158218792Snp{
4159218792Snp	memset(wr, 0, sizeof(*wr));
4160218792Snp	wr->op_pkd = htonl(V_FW_WR_OP(FW_FILTER_WR));
4161218792Snp	wr->len16_pkd = htonl(V_FW_WR_LEN16(sizeof(*wr) / 16));
4162218792Snp	wr->tid_to_iq = htonl(V_FW_FILTER_WR_TID(ftid) |
4163218792Snp			      V_FW_FILTER_WR_NOREPLY(qid < 0));
4164218792Snp	wr->del_filter_to_l2tix = htonl(F_FW_FILTER_WR_DEL_FILTER);
4165218792Snp	if (qid >= 0)
4166218792Snp		wr->rx_chan_rx_rpl_iq = htons(V_FW_FILTER_WR_RX_RPL_IQ(qid));
4167218792Snp}
4168218792Snp
4169218792Snp#define INIT_CMD(var, cmd, rd_wr) do { \
4170218792Snp	(var).op_to_write = htonl(V_FW_CMD_OP(FW_##cmd##_CMD) | \
4171218792Snp				  F_FW_CMD_REQUEST | F_FW_CMD_##rd_wr); \
4172218792Snp	(var).retval_len16 = htonl(FW_LEN16(var)); \
4173218792Snp} while (0)
4174218792Snp
4175237436Snpint t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox, u32 addr, u32 val)
4176237436Snp{
4177237436Snp	struct fw_ldst_cmd c;
4178237436Snp
4179237436Snp	memset(&c, 0, sizeof(c));
4180237436Snp	c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
4181237436Snp		F_FW_CMD_WRITE | V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FIRMWARE));
4182237436Snp	c.cycles_to_len16 = htonl(FW_LEN16(c));
4183237436Snp	c.u.addrval.addr = htonl(addr);
4184237436Snp	c.u.addrval.val = htonl(val);
4185237436Snp
4186237436Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4187237436Snp}
4188237436Snp
4189218792Snp/**
4190218792Snp *	t4_mdio_rd - read a PHY register through MDIO
4191218792Snp *	@adap: the adapter
4192218792Snp *	@mbox: mailbox to use for the FW command
4193218792Snp *	@phy_addr: the PHY address
4194218792Snp *	@mmd: the PHY MMD to access (0 for clause 22 PHYs)
4195218792Snp *	@reg: the register to read
4196218792Snp *	@valp: where to store the value
4197218792Snp *
4198218792Snp *	Issues a FW command through the given mailbox to read a PHY register.
4199218792Snp */
4200218792Snpint t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
4201218792Snp	       unsigned int mmd, unsigned int reg, unsigned int *valp)
4202218792Snp{
4203218792Snp	int ret;
4204218792Snp	struct fw_ldst_cmd c;
4205218792Snp
4206218792Snp	memset(&c, 0, sizeof(c));
4207218792Snp	c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
4208218792Snp		F_FW_CMD_READ | V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO));
4209218792Snp	c.cycles_to_len16 = htonl(FW_LEN16(c));
4210218792Snp	c.u.mdio.paddr_mmd = htons(V_FW_LDST_CMD_PADDR(phy_addr) |
4211218792Snp				   V_FW_LDST_CMD_MMD(mmd));
4212218792Snp	c.u.mdio.raddr = htons(reg);
4213218792Snp
4214218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4215218792Snp	if (ret == 0)
4216218792Snp		*valp = ntohs(c.u.mdio.rval);
4217218792Snp	return ret;
4218218792Snp}
4219218792Snp
4220218792Snp/**
4221218792Snp *	t4_mdio_wr - write a PHY register through MDIO
4222218792Snp *	@adap: the adapter
4223218792Snp *	@mbox: mailbox to use for the FW command
4224218792Snp *	@phy_addr: the PHY address
4225218792Snp *	@mmd: the PHY MMD to access (0 for clause 22 PHYs)
4226218792Snp *	@reg: the register to write
4227218792Snp *	@valp: value to write
4228218792Snp *
4229218792Snp *	Issues a FW command through the given mailbox to write a PHY register.
4230218792Snp */
4231218792Snpint t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
4232218792Snp	       unsigned int mmd, unsigned int reg, unsigned int val)
4233218792Snp{
4234218792Snp	struct fw_ldst_cmd c;
4235218792Snp
4236218792Snp	memset(&c, 0, sizeof(c));
4237218792Snp	c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
4238218792Snp		F_FW_CMD_WRITE | V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO));
4239218792Snp	c.cycles_to_len16 = htonl(FW_LEN16(c));
4240218792Snp	c.u.mdio.paddr_mmd = htons(V_FW_LDST_CMD_PADDR(phy_addr) |
4241218792Snp				   V_FW_LDST_CMD_MMD(mmd));
4242218792Snp	c.u.mdio.raddr = htons(reg);
4243218792Snp	c.u.mdio.rval = htons(val);
4244218792Snp
4245218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4246218792Snp}
4247218792Snp
4248218792Snp/**
4249269082Snp *	t4_i2c_rd - read I2C data from adapter
4250269082Snp *	@adap: the adapter
4251269082Snp *	@port: Port number if per-port device; <0 if not
4252269082Snp *	@devid: per-port device ID or absolute device ID
4253269082Snp *	@offset: byte offset into device I2C space
4254269082Snp *	@len: byte length of I2C space data
4255269082Snp *	@buf: buffer in which to return I2C data
4256269082Snp *
4257269082Snp *	Reads the I2C data from the indicated device and location.
4258269082Snp */
4259269082Snpint t4_i2c_rd(struct adapter *adap, unsigned int mbox,
4260269082Snp	      int port, unsigned int devid,
4261269082Snp	      unsigned int offset, unsigned int len,
4262269082Snp	      u8 *buf)
4263269082Snp{
4264269082Snp	struct fw_ldst_cmd ldst;
4265269082Snp	int ret;
4266269082Snp
4267269082Snp	if (port >= 4 ||
4268269082Snp	    devid >= 256 ||
4269269082Snp	    offset >= 256 ||
4270269082Snp	    len > sizeof ldst.u.i2c.data)
4271269082Snp		return -EINVAL;
4272269082Snp
4273269082Snp	memset(&ldst, 0, sizeof ldst);
4274269082Snp	ldst.op_to_addrspace =
4275269082Snp		cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) |
4276269082Snp			    F_FW_CMD_REQUEST |
4277269082Snp			    F_FW_CMD_READ |
4278269082Snp			    V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_I2C));
4279269082Snp	ldst.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst));
4280269082Snp	ldst.u.i2c.pid = (port < 0 ? 0xff : port);
4281269082Snp	ldst.u.i2c.did = devid;
4282269082Snp	ldst.u.i2c.boffset = offset;
4283269082Snp	ldst.u.i2c.blen = len;
4284269082Snp	ret = t4_wr_mbox(adap, mbox, &ldst, sizeof ldst, &ldst);
4285269082Snp	if (!ret)
4286269082Snp		memcpy(buf, ldst.u.i2c.data, len);
4287269082Snp	return ret;
4288269082Snp}
4289269082Snp
4290269082Snp/**
4291269082Snp *	t4_i2c_wr - write I2C data to adapter
4292269082Snp *	@adap: the adapter
4293269082Snp *	@port: Port number if per-port device; <0 if not
4294269082Snp *	@devid: per-port device ID or absolute device ID
4295269082Snp *	@offset: byte offset into device I2C space
4296269082Snp *	@len: byte length of I2C space data
4297269082Snp *	@buf: buffer containing new I2C data
4298269082Snp *
4299269082Snp *	Write the I2C data to the indicated device and location.
4300269082Snp */
4301269082Snpint t4_i2c_wr(struct adapter *adap, unsigned int mbox,
4302269082Snp	      int port, unsigned int devid,
4303269082Snp	      unsigned int offset, unsigned int len,
4304269082Snp	      u8 *buf)
4305269082Snp{
4306269082Snp	struct fw_ldst_cmd ldst;
4307269082Snp
4308269082Snp	if (port >= 4 ||
4309269082Snp	    devid >= 256 ||
4310269082Snp	    offset >= 256 ||
4311269082Snp	    len > sizeof ldst.u.i2c.data)
4312269082Snp		return -EINVAL;
4313269082Snp
4314269082Snp	memset(&ldst, 0, sizeof ldst);
4315269082Snp	ldst.op_to_addrspace =
4316269082Snp		cpu_to_be32(V_FW_CMD_OP(FW_LDST_CMD) |
4317269082Snp			    F_FW_CMD_REQUEST |
4318269082Snp			    F_FW_CMD_WRITE |
4319269082Snp			    V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_I2C));
4320269082Snp	ldst.cycles_to_len16 = cpu_to_be32(FW_LEN16(ldst));
4321269082Snp	ldst.u.i2c.pid = (port < 0 ? 0xff : port);
4322269082Snp	ldst.u.i2c.did = devid;
4323269082Snp	ldst.u.i2c.boffset = offset;
4324269082Snp	ldst.u.i2c.blen = len;
4325269082Snp	memcpy(ldst.u.i2c.data, buf, len);
4326269082Snp	return t4_wr_mbox(adap, mbox, &ldst, sizeof ldst, &ldst);
4327269082Snp}
4328269082Snp
4329269082Snp/**
4330237436Snp *	t4_sge_ctxt_flush - flush the SGE context cache
4331237436Snp *	@adap: the adapter
4332237436Snp *	@mbox: mailbox to use for the FW command
4333237436Snp *
4334237436Snp *	Issues a FW command through the given mailbox to flush the
4335237436Snp *	SGE context cache.
4336237436Snp */
4337237436Snpint t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox)
4338237436Snp{
4339237436Snp	int ret;
4340237436Snp	struct fw_ldst_cmd c;
4341237436Snp
4342237436Snp	memset(&c, 0, sizeof(c));
4343237436Snp	c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
4344237436Snp			F_FW_CMD_READ |
4345237436Snp			V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_SGE_EGRC));
4346237436Snp	c.cycles_to_len16 = htonl(FW_LEN16(c));
4347237436Snp	c.u.idctxt.msg_ctxtflush = htonl(F_FW_LDST_CMD_CTXTFLUSH);
4348237436Snp
4349237436Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4350237436Snp	return ret;
4351237436Snp}
4352237436Snp
4353237436Snp/**
4354218792Snp *	t4_sge_ctxt_rd - read an SGE context through FW
4355218792Snp *	@adap: the adapter
4356218792Snp *	@mbox: mailbox to use for the FW command
4357218792Snp *	@cid: the context id
4358218792Snp *	@ctype: the context type
4359218792Snp *	@data: where to store the context data
4360218792Snp *
4361218792Snp *	Issues a FW command through the given mailbox to read an SGE context.
4362218792Snp */
4363218792Snpint t4_sge_ctxt_rd(struct adapter *adap, unsigned int mbox, unsigned int cid,
4364218792Snp		   enum ctxt_type ctype, u32 *data)
4365218792Snp{
4366218792Snp	int ret;
4367218792Snp	struct fw_ldst_cmd c;
4368218792Snp
4369218792Snp	if (ctype == CTXT_EGRESS)
4370218792Snp		ret = FW_LDST_ADDRSPC_SGE_EGRC;
4371218792Snp	else if (ctype == CTXT_INGRESS)
4372218792Snp		ret = FW_LDST_ADDRSPC_SGE_INGC;
4373218792Snp	else if (ctype == CTXT_FLM)
4374218792Snp		ret = FW_LDST_ADDRSPC_SGE_FLMC;
4375218792Snp	else
4376218792Snp		ret = FW_LDST_ADDRSPC_SGE_CONMC;
4377218792Snp
4378218792Snp	memset(&c, 0, sizeof(c));
4379218792Snp	c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
4380218792Snp				  F_FW_CMD_READ | V_FW_LDST_CMD_ADDRSPACE(ret));
4381218792Snp	c.cycles_to_len16 = htonl(FW_LEN16(c));
4382218792Snp	c.u.idctxt.physid = htonl(cid);
4383218792Snp
4384218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4385218792Snp	if (ret == 0) {
4386218792Snp		data[0] = ntohl(c.u.idctxt.ctxt_data0);
4387218792Snp		data[1] = ntohl(c.u.idctxt.ctxt_data1);
4388218792Snp		data[2] = ntohl(c.u.idctxt.ctxt_data2);
4389218792Snp		data[3] = ntohl(c.u.idctxt.ctxt_data3);
4390218792Snp		data[4] = ntohl(c.u.idctxt.ctxt_data4);
4391218792Snp		data[5] = ntohl(c.u.idctxt.ctxt_data5);
4392218792Snp	}
4393218792Snp	return ret;
4394218792Snp}
4395218792Snp
4396218792Snp/**
4397218792Snp *	t4_sge_ctxt_rd_bd - read an SGE context bypassing FW
4398218792Snp *	@adap: the adapter
4399218792Snp *	@cid: the context id
4400218792Snp *	@ctype: the context type
4401218792Snp *	@data: where to store the context data
4402218792Snp *
4403218792Snp *	Reads an SGE context directly, bypassing FW.  This is only for
4404218792Snp *	debugging when FW is unavailable.
4405218792Snp */
4406218792Snpint t4_sge_ctxt_rd_bd(struct adapter *adap, unsigned int cid, enum ctxt_type ctype,
4407218792Snp		      u32 *data)
4408218792Snp{
4409218792Snp	int i, ret;
4410218792Snp
4411218792Snp	t4_write_reg(adap, A_SGE_CTXT_CMD, V_CTXTQID(cid) | V_CTXTTYPE(ctype));
4412218792Snp	ret = t4_wait_op_done(adap, A_SGE_CTXT_CMD, F_BUSY, 0, 3, 1);
4413218792Snp	if (!ret)
4414218792Snp		for (i = A_SGE_CTXT_DATA0; i <= A_SGE_CTXT_DATA5; i += 4)
4415218792Snp			*data++ = t4_read_reg(adap, i);
4416218792Snp	return ret;
4417218792Snp}
4418218792Snp
4419218792Snp/**
4420218792Snp *	t4_fw_hello - establish communication with FW
4421218792Snp *	@adap: the adapter
4422218792Snp *	@mbox: mailbox to use for the FW command
4423218792Snp *	@evt_mbox: mailbox to receive async FW events
4424218792Snp *	@master: specifies the caller's willingness to be the device master
4425237436Snp *	@state: returns the current device state (if non-NULL)
4426218792Snp *
4427237436Snp *	Issues a command to establish communication with FW.  Returns either
4428237436Snp *	an error (negative integer) or the mailbox of the Master PF.
4429218792Snp */
4430218792Snpint t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox,
4431218792Snp		enum dev_master master, enum dev_state *state)
4432218792Snp{
4433218792Snp	int ret;
4434218792Snp	struct fw_hello_cmd c;
4435228561Snp	u32 v;
4436228561Snp	unsigned int master_mbox;
4437228561Snp	int retries = FW_CMD_HELLO_RETRIES;
4438218792Snp
4439228561Snpretry:
4440218792Snp	memset(&c, 0, sizeof(c));
4441218792Snp	INIT_CMD(c, HELLO, WRITE);
4442228561Snp	c.err_to_clearinit = htonl(
4443218792Snp		V_FW_HELLO_CMD_MASTERDIS(master == MASTER_CANT) |
4444218792Snp		V_FW_HELLO_CMD_MASTERFORCE(master == MASTER_MUST) |
4445218792Snp		V_FW_HELLO_CMD_MBMASTER(master == MASTER_MUST ? mbox :
4446218792Snp			M_FW_HELLO_CMD_MBMASTER) |
4447228561Snp		V_FW_HELLO_CMD_MBASYNCNOT(evt_mbox) |
4448228561Snp		V_FW_HELLO_CMD_STAGE(FW_HELLO_CMD_STAGE_OS) |
4449228561Snp		F_FW_HELLO_CMD_CLEARINIT);
4450218792Snp
4451228561Snp	/*
4452228561Snp	 * Issue the HELLO command to the firmware.  If it's not successful
4453228561Snp	 * but indicates that we got a "busy" or "timeout" condition, retry
4454247355Snp	 * the HELLO until we exhaust our retry limit.  If we do exceed our
4455247355Snp	 * retry limit, check to see if the firmware left us any error
4456247355Snp	 * information and report that if so ...
4457228561Snp	 */
4458218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4459228561Snp	if (ret != FW_SUCCESS) {
4460228561Snp		if ((ret == -EBUSY || ret == -ETIMEDOUT) && retries-- > 0)
4461228561Snp			goto retry;
4462247355Snp		if (t4_read_reg(adap, A_PCIE_FW) & F_PCIE_FW_ERR)
4463247355Snp			t4_report_fw_error(adap);
4464228561Snp		return ret;
4465228561Snp	}
4466228561Snp
4467228561Snp	v = ntohl(c.err_to_clearinit);
4468228561Snp	master_mbox = G_FW_HELLO_CMD_MBMASTER(v);
4469228561Snp	if (state) {
4470228561Snp		if (v & F_FW_HELLO_CMD_ERR)
4471228561Snp			*state = DEV_STATE_ERR;
4472228561Snp		else if (v & F_FW_HELLO_CMD_INIT)
4473218792Snp			*state = DEV_STATE_INIT;
4474218792Snp		else
4475218792Snp			*state = DEV_STATE_UNINIT;
4476218792Snp	}
4477228561Snp
4478228561Snp	/*
4479228561Snp	 * If we're not the Master PF then we need to wait around for the
4480228561Snp	 * Master PF Driver to finish setting up the adapter.
4481228561Snp	 *
4482228561Snp	 * Note that we also do this wait if we're a non-Master-capable PF and
4483228561Snp	 * there is no current Master PF; a Master PF may show up momentarily
4484228561Snp	 * and we wouldn't want to fail pointlessly.  (This can happen when an
4485228561Snp	 * OS loads lots of different drivers rapidly at the same time).  In
4486228561Snp	 * this case, the Master PF returned by the firmware will be
4487228561Snp	 * M_PCIE_FW_MASTER so the test below will work ...
4488228561Snp	 */
4489228561Snp	if ((v & (F_FW_HELLO_CMD_ERR|F_FW_HELLO_CMD_INIT)) == 0 &&
4490228561Snp	    master_mbox != mbox) {
4491228561Snp		int waiting = FW_CMD_HELLO_TIMEOUT;
4492228561Snp
4493228561Snp		/*
4494228561Snp		 * Wait for the firmware to either indicate an error or
4495228561Snp		 * initialized state.  If we see either of these we bail out
4496228561Snp		 * and report the issue to the caller.  If we exhaust the
4497228561Snp		 * "hello timeout" and we haven't exhausted our retries, try
4498228561Snp		 * again.  Otherwise bail with a timeout error.
4499228561Snp		 */
4500228561Snp		for (;;) {
4501228561Snp			u32 pcie_fw;
4502228561Snp
4503228561Snp			msleep(50);
4504228561Snp			waiting -= 50;
4505228561Snp
4506228561Snp			/*
4507228561Snp			 * If neither Error nor Initialialized are indicated
4508228561Snp			 * by the firmware keep waiting till we exhaust our
4509228561Snp			 * timeout ... and then retry if we haven't exhausted
4510228561Snp			 * our retries ...
4511228561Snp			 */
4512228561Snp			pcie_fw = t4_read_reg(adap, A_PCIE_FW);
4513228561Snp			if (!(pcie_fw & (F_PCIE_FW_ERR|F_PCIE_FW_INIT))) {
4514228561Snp				if (waiting <= 0) {
4515228561Snp					if (retries-- > 0)
4516228561Snp						goto retry;
4517228561Snp
4518228561Snp					return -ETIMEDOUT;
4519228561Snp				}
4520228561Snp				continue;
4521228561Snp			}
4522228561Snp
4523228561Snp			/*
4524228561Snp			 * We either have an Error or Initialized condition
4525228561Snp			 * report errors preferentially.
4526228561Snp			 */
4527228561Snp			if (state) {
4528228561Snp				if (pcie_fw & F_PCIE_FW_ERR)
4529228561Snp					*state = DEV_STATE_ERR;
4530228561Snp				else if (pcie_fw & F_PCIE_FW_INIT)
4531228561Snp					*state = DEV_STATE_INIT;
4532228561Snp			}
4533228561Snp
4534228561Snp			/*
4535228561Snp			 * If we arrived before a Master PF was selected and
4536228561Snp			 * there's not a valid Master PF, grab its identity
4537228561Snp			 * for our caller.
4538228561Snp			 */
4539228561Snp			if (master_mbox == M_PCIE_FW_MASTER &&
4540228561Snp			    (pcie_fw & F_PCIE_FW_MASTER_VLD))
4541228561Snp				master_mbox = G_PCIE_FW_MASTER(pcie_fw);
4542228561Snp			break;
4543228561Snp		}
4544228561Snp	}
4545228561Snp
4546228561Snp	return master_mbox;
4547218792Snp}
4548218792Snp
4549218792Snp/**
4550218792Snp *	t4_fw_bye - end communication with FW
4551218792Snp *	@adap: the adapter
4552218792Snp *	@mbox: mailbox to use for the FW command
4553218792Snp *
4554218792Snp *	Issues a command to terminate communication with FW.
4555218792Snp */
4556218792Snpint t4_fw_bye(struct adapter *adap, unsigned int mbox)
4557218792Snp{
4558218792Snp	struct fw_bye_cmd c;
4559218792Snp
4560218792Snp	memset(&c, 0, sizeof(c));
4561218792Snp	INIT_CMD(c, BYE, WRITE);
4562218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4563218792Snp}
4564218792Snp
4565218792Snp/**
4566228561Snp *	t4_fw_reset - issue a reset to FW
4567218792Snp *	@adap: the adapter
4568218792Snp *	@mbox: mailbox to use for the FW command
4569228561Snp *	@reset: specifies the type of reset to perform
4570218792Snp *
4571228561Snp *	Issues a reset command of the specified type to FW.
4572218792Snp */
4573228561Snpint t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset)
4574218792Snp{
4575228561Snp	struct fw_reset_cmd c;
4576218792Snp
4577218792Snp	memset(&c, 0, sizeof(c));
4578228561Snp	INIT_CMD(c, RESET, WRITE);
4579228561Snp	c.val = htonl(reset);
4580218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4581218792Snp}
4582218792Snp
4583218792Snp/**
4584237436Snp *	t4_fw_halt - issue a reset/halt to FW and put uP into RESET
4585237436Snp *	@adap: the adapter
4586237436Snp *	@mbox: mailbox to use for the FW RESET command (if desired)
4587237436Snp *	@force: force uP into RESET even if FW RESET command fails
4588237436Snp *
4589237436Snp *	Issues a RESET command to firmware (if desired) with a HALT indication
4590237436Snp *	and then puts the microprocessor into RESET state.  The RESET command
4591237436Snp *	will only be issued if a legitimate mailbox is provided (mbox <=
4592237436Snp *	M_PCIE_FW_MASTER).
4593237436Snp *
4594237436Snp *	This is generally used in order for the host to safely manipulate the
4595237436Snp *	adapter without fear of conflicting with whatever the firmware might
4596237436Snp *	be doing.  The only way out of this state is to RESTART the firmware
4597237436Snp *	...
4598237436Snp */
4599237436Snpint t4_fw_halt(struct adapter *adap, unsigned int mbox, int force)
4600237436Snp{
4601237436Snp	int ret = 0;
4602237436Snp
4603237436Snp	/*
4604237436Snp	 * If a legitimate mailbox is provided, issue a RESET command
4605237436Snp	 * with a HALT indication.
4606237436Snp	 */
4607237436Snp	if (mbox <= M_PCIE_FW_MASTER) {
4608237436Snp		struct fw_reset_cmd c;
4609237436Snp
4610237436Snp		memset(&c, 0, sizeof(c));
4611237436Snp		INIT_CMD(c, RESET, WRITE);
4612237436Snp		c.val = htonl(F_PIORST | F_PIORSTMODE);
4613237436Snp		c.halt_pkd = htonl(F_FW_RESET_CMD_HALT);
4614237436Snp		ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4615237436Snp	}
4616237436Snp
4617237436Snp	/*
4618237436Snp	 * Normally we won't complete the operation if the firmware RESET
4619237436Snp	 * command fails but if our caller insists we'll go ahead and put the
4620237436Snp	 * uP into RESET.  This can be useful if the firmware is hung or even
4621237436Snp	 * missing ...  We'll have to take the risk of putting the uP into
4622237436Snp	 * RESET without the cooperation of firmware in that case.
4623237436Snp	 *
4624237436Snp	 * We also force the firmware's HALT flag to be on in case we bypassed
4625237436Snp	 * the firmware RESET command above or we're dealing with old firmware
4626237436Snp	 * which doesn't have the HALT capability.  This will serve as a flag
4627237436Snp	 * for the incoming firmware to know that it's coming out of a HALT
4628237436Snp	 * rather than a RESET ... if it's new enough to understand that ...
4629237436Snp	 */
4630237436Snp	if (ret == 0 || force) {
4631237436Snp		t4_set_reg_field(adap, A_CIM_BOOT_CFG, F_UPCRST, F_UPCRST);
4632237436Snp		t4_set_reg_field(adap, A_PCIE_FW, F_PCIE_FW_HALT, F_PCIE_FW_HALT);
4633237436Snp	}
4634237436Snp
4635237436Snp	/*
4636237436Snp	 * And we always return the result of the firmware RESET command
4637237436Snp	 * even when we force the uP into RESET ...
4638237436Snp	 */
4639237436Snp	return ret;
4640237436Snp}
4641237436Snp
4642237436Snp/**
4643237436Snp *	t4_fw_restart - restart the firmware by taking the uP out of RESET
4644237436Snp *	@adap: the adapter
4645237436Snp *	@reset: if we want to do a RESET to restart things
4646237436Snp *
4647237436Snp *	Restart firmware previously halted by t4_fw_halt().  On successful
4648237436Snp *	return the previous PF Master remains as the new PF Master and there
4649237436Snp *	is no need to issue a new HELLO command, etc.
4650237436Snp *
4651237436Snp *	We do this in two ways:
4652237436Snp *
4653237436Snp *	 1. If we're dealing with newer firmware we'll simply want to take
4654237436Snp *	    the chip's microprocessor out of RESET.  This will cause the
4655237436Snp *	    firmware to start up from its start vector.  And then we'll loop
4656237436Snp *	    until the firmware indicates it's started again (PCIE_FW.HALT
4657237436Snp *	    reset to 0) or we timeout.
4658237436Snp *
4659237436Snp *	 2. If we're dealing with older firmware then we'll need to RESET
4660237436Snp *	    the chip since older firmware won't recognize the PCIE_FW.HALT
4661237436Snp *	    flag and automatically RESET itself on startup.
4662237436Snp */
4663237436Snpint t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset)
4664237436Snp{
4665237436Snp	if (reset) {
4666237436Snp		/*
4667237436Snp		 * Since we're directing the RESET instead of the firmware
4668237436Snp		 * doing it automatically, we need to clear the PCIE_FW.HALT
4669237436Snp		 * bit.
4670237436Snp		 */
4671237436Snp		t4_set_reg_field(adap, A_PCIE_FW, F_PCIE_FW_HALT, 0);
4672237436Snp
4673237436Snp		/*
4674237436Snp		 * If we've been given a valid mailbox, first try to get the
4675237436Snp		 * firmware to do the RESET.  If that works, great and we can
4676237436Snp		 * return success.  Otherwise, if we haven't been given a
4677237436Snp		 * valid mailbox or the RESET command failed, fall back to
4678237436Snp		 * hitting the chip with a hammer.
4679237436Snp		 */
4680237436Snp		if (mbox <= M_PCIE_FW_MASTER) {
4681237436Snp			t4_set_reg_field(adap, A_CIM_BOOT_CFG, F_UPCRST, 0);
4682237436Snp			msleep(100);
4683237436Snp			if (t4_fw_reset(adap, mbox,
4684237436Snp					F_PIORST | F_PIORSTMODE) == 0)
4685237436Snp				return 0;
4686237436Snp		}
4687237436Snp
4688237436Snp		t4_write_reg(adap, A_PL_RST, F_PIORST | F_PIORSTMODE);
4689237436Snp		msleep(2000);
4690237436Snp	} else {
4691237436Snp		int ms;
4692237436Snp
4693237436Snp		t4_set_reg_field(adap, A_CIM_BOOT_CFG, F_UPCRST, 0);
4694237436Snp		for (ms = 0; ms < FW_CMD_MAX_TIMEOUT; ) {
4695237436Snp			if (!(t4_read_reg(adap, A_PCIE_FW) & F_PCIE_FW_HALT))
4696237436Snp				return FW_SUCCESS;
4697237436Snp			msleep(100);
4698237436Snp			ms += 100;
4699237436Snp		}
4700237436Snp		return -ETIMEDOUT;
4701237436Snp	}
4702237436Snp	return 0;
4703237436Snp}
4704237436Snp
4705237436Snp/**
4706237436Snp *	t4_fw_upgrade - perform all of the steps necessary to upgrade FW
4707237436Snp *	@adap: the adapter
4708237436Snp *	@mbox: mailbox to use for the FW RESET command (if desired)
4709237436Snp *	@fw_data: the firmware image to write
4710237436Snp *	@size: image size
4711237436Snp *	@force: force upgrade even if firmware doesn't cooperate
4712237436Snp *
4713237436Snp *	Perform all of the steps necessary for upgrading an adapter's
4714237436Snp *	firmware image.  Normally this requires the cooperation of the
4715237436Snp *	existing firmware in order to halt all existing activities
4716237436Snp *	but if an invalid mailbox token is passed in we skip that step
4717237436Snp *	(though we'll still put the adapter microprocessor into RESET in
4718237436Snp *	that case).
4719237436Snp *
4720237436Snp *	On successful return the new firmware will have been loaded and
4721237436Snp *	the adapter will have been fully RESET losing all previous setup
4722237436Snp *	state.  On unsuccessful return the adapter may be completely hosed ...
4723237436Snp *	positive errno indicates that the adapter is ~probably~ intact, a
4724237436Snp *	negative errno indicates that things are looking bad ...
4725237436Snp */
4726237436Snpint t4_fw_upgrade(struct adapter *adap, unsigned int mbox,
4727237436Snp		  const u8 *fw_data, unsigned int size, int force)
4728237436Snp{
4729237436Snp	const struct fw_hdr *fw_hdr = (const struct fw_hdr *)fw_data;
4730252661Snp	unsigned int bootstrap = ntohl(fw_hdr->magic) == FW_HDR_MAGIC_BOOTSTRAP;
4731237436Snp	int reset, ret;
4732237436Snp
4733252661Snp	if (!bootstrap) {
4734252661Snp		ret = t4_fw_halt(adap, mbox, force);
4735252661Snp		if (ret < 0 && !force)
4736252661Snp			return ret;
4737252661Snp	}
4738237436Snp
4739237436Snp	ret = t4_load_fw(adap, fw_data, size);
4740252661Snp	if (ret < 0 || bootstrap)
4741237436Snp		return ret;
4742237436Snp
4743237436Snp	/*
4744237436Snp	 * Older versions of the firmware don't understand the new
4745237436Snp	 * PCIE_FW.HALT flag and so won't know to perform a RESET when they
4746237436Snp	 * restart.  So for newly loaded older firmware we'll have to do the
4747237436Snp	 * RESET for it so it starts up on a clean slate.  We can tell if
4748237436Snp	 * the newly loaded firmware will handle this right by checking
4749237436Snp	 * its header flags to see if it advertises the capability.
4750237436Snp	 */
4751237436Snp	reset = ((ntohl(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0);
4752237436Snp	return t4_fw_restart(adap, mbox, reset);
4753237436Snp}
4754237436Snp
4755237436Snp/**
4756228561Snp *	t4_fw_initialize - ask FW to initialize the device
4757218792Snp *	@adap: the adapter
4758218792Snp *	@mbox: mailbox to use for the FW command
4759218792Snp *
4760228561Snp *	Issues a command to FW to partially initialize the device.  This
4761228561Snp *	performs initialization that generally doesn't depend on user input.
4762218792Snp */
4763228561Snpint t4_fw_initialize(struct adapter *adap, unsigned int mbox)
4764218792Snp{
4765228561Snp	struct fw_initialize_cmd c;
4766218792Snp
4767218792Snp	memset(&c, 0, sizeof(c));
4768228561Snp	INIT_CMD(c, INITIALIZE, WRITE);
4769218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4770218792Snp}
4771218792Snp
4772218792Snp/**
4773218792Snp *	t4_query_params - query FW or device parameters
4774218792Snp *	@adap: the adapter
4775218792Snp *	@mbox: mailbox to use for the FW command
4776218792Snp *	@pf: the PF
4777218792Snp *	@vf: the VF
4778218792Snp *	@nparams: the number of parameters
4779218792Snp *	@params: the parameter names
4780218792Snp *	@val: the parameter values
4781218792Snp *
4782218792Snp *	Reads the value of FW or device parameters.  Up to 7 parameters can be
4783218792Snp *	queried at once.
4784218792Snp */
4785218792Snpint t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
4786218792Snp		    unsigned int vf, unsigned int nparams, const u32 *params,
4787218792Snp		    u32 *val)
4788218792Snp{
4789218792Snp	int i, ret;
4790218792Snp	struct fw_params_cmd c;
4791218792Snp	__be32 *p = &c.param[0].mnem;
4792218792Snp
4793218792Snp	if (nparams > 7)
4794218792Snp		return -EINVAL;
4795218792Snp
4796218792Snp	memset(&c, 0, sizeof(c));
4797218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_PARAMS_CMD) | F_FW_CMD_REQUEST |
4798218792Snp			    F_FW_CMD_READ | V_FW_PARAMS_CMD_PFN(pf) |
4799218792Snp			    V_FW_PARAMS_CMD_VFN(vf));
4800218792Snp	c.retval_len16 = htonl(FW_LEN16(c));
4801218792Snp
4802250090Snp	for (i = 0; i < nparams; i++, p += 2, params++)
4803250090Snp		*p = htonl(*params);
4804218792Snp
4805218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4806218792Snp	if (ret == 0)
4807218792Snp		for (i = 0, p = &c.param[0].val; i < nparams; i++, p += 2)
4808218792Snp			*val++ = ntohl(*p);
4809218792Snp	return ret;
4810218792Snp}
4811218792Snp
4812218792Snp/**
4813218792Snp *	t4_set_params - sets FW or device parameters
4814218792Snp *	@adap: the adapter
4815218792Snp *	@mbox: mailbox to use for the FW command
4816218792Snp *	@pf: the PF
4817218792Snp *	@vf: the VF
4818218792Snp *	@nparams: the number of parameters
4819218792Snp *	@params: the parameter names
4820218792Snp *	@val: the parameter values
4821218792Snp *
4822218792Snp *	Sets the value of FW or device parameters.  Up to 7 parameters can be
4823218792Snp *	specified at once.
4824218792Snp */
4825218792Snpint t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
4826218792Snp		  unsigned int vf, unsigned int nparams, const u32 *params,
4827218792Snp		  const u32 *val)
4828218792Snp{
4829218792Snp	struct fw_params_cmd c;
4830218792Snp	__be32 *p = &c.param[0].mnem;
4831218792Snp
4832218792Snp	if (nparams > 7)
4833218792Snp		return -EINVAL;
4834218792Snp
4835218792Snp	memset(&c, 0, sizeof(c));
4836218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_PARAMS_CMD) | F_FW_CMD_REQUEST |
4837218792Snp			    F_FW_CMD_WRITE | V_FW_PARAMS_CMD_PFN(pf) |
4838218792Snp			    V_FW_PARAMS_CMD_VFN(vf));
4839218792Snp	c.retval_len16 = htonl(FW_LEN16(c));
4840218792Snp
4841218792Snp	while (nparams--) {
4842250090Snp		*p++ = htonl(*params);
4843250090Snp		params++;
4844250090Snp		*p++ = htonl(*val);
4845250090Snp		val++;
4846218792Snp	}
4847218792Snp
4848218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4849218792Snp}
4850218792Snp
4851218792Snp/**
4852218792Snp *	t4_cfg_pfvf - configure PF/VF resource limits
4853218792Snp *	@adap: the adapter
4854218792Snp *	@mbox: mailbox to use for the FW command
4855218792Snp *	@pf: the PF being configured
4856218792Snp *	@vf: the VF being configured
4857218792Snp *	@txq: the max number of egress queues
4858218792Snp *	@txq_eth_ctrl: the max number of egress Ethernet or control queues
4859218792Snp *	@rxqi: the max number of interrupt-capable ingress queues
4860218792Snp *	@rxq: the max number of interruptless ingress queues
4861218792Snp *	@tc: the PCI traffic class
4862218792Snp *	@vi: the max number of virtual interfaces
4863218792Snp *	@cmask: the channel access rights mask for the PF/VF
4864218792Snp *	@pmask: the port access rights mask for the PF/VF
4865218792Snp *	@nexact: the maximum number of exact MPS filters
4866218792Snp *	@rcaps: read capabilities
4867218792Snp *	@wxcaps: write/execute capabilities
4868218792Snp *
4869218792Snp *	Configures resource limits and capabilities for a physical or virtual
4870218792Snp *	function.
4871218792Snp */
4872218792Snpint t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf,
4873218792Snp		unsigned int vf, unsigned int txq, unsigned int txq_eth_ctrl,
4874218792Snp		unsigned int rxqi, unsigned int rxq, unsigned int tc,
4875218792Snp		unsigned int vi, unsigned int cmask, unsigned int pmask,
4876218792Snp		unsigned int nexact, unsigned int rcaps, unsigned int wxcaps)
4877218792Snp{
4878218792Snp	struct fw_pfvf_cmd c;
4879218792Snp
4880218792Snp	memset(&c, 0, sizeof(c));
4881218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_PFVF_CMD) | F_FW_CMD_REQUEST |
4882218792Snp			    F_FW_CMD_WRITE | V_FW_PFVF_CMD_PFN(pf) |
4883218792Snp			    V_FW_PFVF_CMD_VFN(vf));
4884218792Snp	c.retval_len16 = htonl(FW_LEN16(c));
4885218792Snp	c.niqflint_niq = htonl(V_FW_PFVF_CMD_NIQFLINT(rxqi) |
4886218792Snp			       V_FW_PFVF_CMD_NIQ(rxq));
4887218792Snp	c.type_to_neq = htonl(V_FW_PFVF_CMD_CMASK(cmask) |
4888218792Snp			      V_FW_PFVF_CMD_PMASK(pmask) |
4889218792Snp			      V_FW_PFVF_CMD_NEQ(txq));
4890218792Snp	c.tc_to_nexactf = htonl(V_FW_PFVF_CMD_TC(tc) | V_FW_PFVF_CMD_NVI(vi) |
4891218792Snp				V_FW_PFVF_CMD_NEXACTF(nexact));
4892218792Snp	c.r_caps_to_nethctrl = htonl(V_FW_PFVF_CMD_R_CAPS(rcaps) |
4893218792Snp				     V_FW_PFVF_CMD_WX_CAPS(wxcaps) |
4894218792Snp				     V_FW_PFVF_CMD_NETHCTRL(txq_eth_ctrl));
4895218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
4896218792Snp}
4897218792Snp
4898218792Snp/**
4899237436Snp *	t4_alloc_vi_func - allocate a virtual interface
4900218792Snp *	@adap: the adapter
4901218792Snp *	@mbox: mailbox to use for the FW command
4902218792Snp *	@port: physical port associated with the VI
4903218792Snp *	@pf: the PF owning the VI
4904218792Snp *	@vf: the VF owning the VI
4905218792Snp *	@nmac: number of MAC addresses needed (1 to 5)
4906218792Snp *	@mac: the MAC addresses of the VI
4907218792Snp *	@rss_size: size of RSS table slice associated with this VI
4908237436Snp *	@portfunc: which Port Application Function MAC Address is desired
4909237436Snp *	@idstype: Intrusion Detection Type
4910218792Snp *
4911218792Snp *	Allocates a virtual interface for the given physical port.  If @mac is
4912218792Snp *	not %NULL it contains the MAC addresses of the VI as assigned by FW.
4913218792Snp *	@mac should be large enough to hold @nmac Ethernet addresses, they are
4914218792Snp *	stored consecutively so the space needed is @nmac * 6 bytes.
4915218792Snp *	Returns a negative error number or the non-negative VI id.
4916218792Snp */
4917237436Snpint t4_alloc_vi_func(struct adapter *adap, unsigned int mbox,
4918237436Snp		     unsigned int port, unsigned int pf, unsigned int vf,
4919270297Snp		     unsigned int nmac, u8 *mac, u16 *rss_size,
4920237436Snp		     unsigned int portfunc, unsigned int idstype)
4921218792Snp{
4922218792Snp	int ret;
4923218792Snp	struct fw_vi_cmd c;
4924218792Snp
4925218792Snp	memset(&c, 0, sizeof(c));
4926218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_VI_CMD) | F_FW_CMD_REQUEST |
4927218792Snp			    F_FW_CMD_WRITE | F_FW_CMD_EXEC |
4928218792Snp			    V_FW_VI_CMD_PFN(pf) | V_FW_VI_CMD_VFN(vf));
4929218792Snp	c.alloc_to_len16 = htonl(F_FW_VI_CMD_ALLOC | FW_LEN16(c));
4930237436Snp	c.type_to_viid = htons(V_FW_VI_CMD_TYPE(idstype) |
4931237436Snp			       V_FW_VI_CMD_FUNC(portfunc));
4932218792Snp	c.portid_pkd = V_FW_VI_CMD_PORTID(port);
4933218792Snp	c.nmac = nmac - 1;
4934218792Snp
4935218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
4936218792Snp	if (ret)
4937218792Snp		return ret;
4938218792Snp
4939218792Snp	if (mac) {
4940218792Snp		memcpy(mac, c.mac, sizeof(c.mac));
4941218792Snp		switch (nmac) {
4942218792Snp		case 5:
4943218792Snp			memcpy(mac + 24, c.nmac3, sizeof(c.nmac3));
4944218792Snp		case 4:
4945218792Snp			memcpy(mac + 18, c.nmac2, sizeof(c.nmac2));
4946218792Snp		case 3:
4947218792Snp			memcpy(mac + 12, c.nmac1, sizeof(c.nmac1));
4948218792Snp		case 2:
4949218792Snp			memcpy(mac + 6,  c.nmac0, sizeof(c.nmac0));
4950218792Snp		}
4951218792Snp	}
4952218792Snp	if (rss_size)
4953247289Snp		*rss_size = G_FW_VI_CMD_RSSSIZE(ntohs(c.norss_rsssize));
4954237436Snp	return G_FW_VI_CMD_VIID(htons(c.type_to_viid));
4955218792Snp}
4956218792Snp
4957218792Snp/**
4958237436Snp *	t4_alloc_vi - allocate an [Ethernet Function] virtual interface
4959237436Snp *	@adap: the adapter
4960237436Snp *	@mbox: mailbox to use for the FW command
4961237436Snp *	@port: physical port associated with the VI
4962237436Snp *	@pf: the PF owning the VI
4963237436Snp *	@vf: the VF owning the VI
4964237436Snp *	@nmac: number of MAC addresses needed (1 to 5)
4965237436Snp *	@mac: the MAC addresses of the VI
4966237436Snp *	@rss_size: size of RSS table slice associated with this VI
4967237436Snp *
4968237436Snp *	backwards compatible and convieniance routine to allocate a Virtual
4969237436Snp *	Interface with a Ethernet Port Application Function and Intrustion
4970237436Snp *	Detection System disabled.
4971237436Snp */
4972237436Snpint t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port,
4973237436Snp		unsigned int pf, unsigned int vf, unsigned int nmac, u8 *mac,
4974270297Snp		u16 *rss_size)
4975237436Snp{
4976237436Snp	return t4_alloc_vi_func(adap, mbox, port, pf, vf, nmac, mac, rss_size,
4977237436Snp				FW_VI_FUNC_ETH, 0);
4978237436Snp}
4979237436Snp
4980237436Snp/**
4981218792Snp *	t4_free_vi - free a virtual interface
4982218792Snp *	@adap: the adapter
4983218792Snp *	@mbox: mailbox to use for the FW command
4984218792Snp *	@pf: the PF owning the VI
4985218792Snp *	@vf: the VF owning the VI
4986218792Snp *	@viid: virtual interface identifiler
4987218792Snp *
4988218792Snp *	Free a previously allocated virtual interface.
4989218792Snp */
4990218792Snpint t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf,
4991218792Snp	       unsigned int vf, unsigned int viid)
4992218792Snp{
4993218792Snp	struct fw_vi_cmd c;
4994218792Snp
4995218792Snp	memset(&c, 0, sizeof(c));
4996218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_VI_CMD) |
4997218792Snp			    F_FW_CMD_REQUEST |
4998218792Snp			    F_FW_CMD_EXEC |
4999218792Snp			    V_FW_VI_CMD_PFN(pf) |
5000218792Snp			    V_FW_VI_CMD_VFN(vf));
5001218792Snp	c.alloc_to_len16 = htonl(F_FW_VI_CMD_FREE | FW_LEN16(c));
5002218792Snp	c.type_to_viid = htons(V_FW_VI_CMD_VIID(viid));
5003218792Snp
5004218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
5005218792Snp}
5006218792Snp
5007218792Snp/**
5008218792Snp *	t4_set_rxmode - set Rx properties of a virtual interface
5009218792Snp *	@adap: the adapter
5010218792Snp *	@mbox: mailbox to use for the FW command
5011218792Snp *	@viid: the VI id
5012218792Snp *	@mtu: the new MTU or -1
5013218792Snp *	@promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change
5014218792Snp *	@all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change
5015218792Snp *	@bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change
5016218792Snp *	@vlanex: 1 to enable HVLAN extraction, 0 to disable it, -1 no change
5017218792Snp *	@sleep_ok: if true we may sleep while awaiting command completion
5018218792Snp *
5019218792Snp *	Sets Rx properties of a virtual interface.
5020218792Snp */
5021218792Snpint t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
5022218792Snp		  int mtu, int promisc, int all_multi, int bcast, int vlanex,
5023218792Snp		  bool sleep_ok)
5024218792Snp{
5025218792Snp	struct fw_vi_rxmode_cmd c;
5026218792Snp
5027218792Snp	/* convert to FW values */
5028218792Snp	if (mtu < 0)
5029218792Snp		mtu = M_FW_VI_RXMODE_CMD_MTU;
5030218792Snp	if (promisc < 0)
5031218792Snp		promisc = M_FW_VI_RXMODE_CMD_PROMISCEN;
5032218792Snp	if (all_multi < 0)
5033218792Snp		all_multi = M_FW_VI_RXMODE_CMD_ALLMULTIEN;
5034218792Snp	if (bcast < 0)
5035218792Snp		bcast = M_FW_VI_RXMODE_CMD_BROADCASTEN;
5036218792Snp	if (vlanex < 0)
5037218792Snp		vlanex = M_FW_VI_RXMODE_CMD_VLANEXEN;
5038218792Snp
5039218792Snp	memset(&c, 0, sizeof(c));
5040218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_RXMODE_CMD) | F_FW_CMD_REQUEST |
5041218792Snp			     F_FW_CMD_WRITE | V_FW_VI_RXMODE_CMD_VIID(viid));
5042218792Snp	c.retval_len16 = htonl(FW_LEN16(c));
5043218792Snp	c.mtu_to_vlanexen = htonl(V_FW_VI_RXMODE_CMD_MTU(mtu) |
5044218792Snp				  V_FW_VI_RXMODE_CMD_PROMISCEN(promisc) |
5045218792Snp				  V_FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) |
5046218792Snp				  V_FW_VI_RXMODE_CMD_BROADCASTEN(bcast) |
5047218792Snp				  V_FW_VI_RXMODE_CMD_VLANEXEN(vlanex));
5048218792Snp	return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok);
5049218792Snp}
5050218792Snp
5051218792Snp/**
5052218792Snp *	t4_alloc_mac_filt - allocates exact-match filters for MAC addresses
5053218792Snp *	@adap: the adapter
5054218792Snp *	@mbox: mailbox to use for the FW command
5055218792Snp *	@viid: the VI id
5056218792Snp *	@free: if true any existing filters for this VI id are first removed
5057218792Snp *	@naddr: the number of MAC addresses to allocate filters for (up to 7)
5058218792Snp *	@addr: the MAC address(es)
5059218792Snp *	@idx: where to store the index of each allocated filter
5060218792Snp *	@hash: pointer to hash address filter bitmap
5061218792Snp *	@sleep_ok: call is allowed to sleep
5062218792Snp *
5063218792Snp *	Allocates an exact-match filter for each of the supplied addresses and
5064218792Snp *	sets it to the corresponding address.  If @idx is not %NULL it should
5065218792Snp *	have at least @naddr entries, each of which will be set to the index of
5066218792Snp *	the filter allocated for the corresponding MAC address.  If a filter
5067218792Snp *	could not be allocated for an address its index is set to 0xffff.
5068218792Snp *	If @hash is not %NULL addresses that fail to allocate an exact filter
5069218792Snp *	are hashed and update the hash filter bitmap pointed at by @hash.
5070218792Snp *
5071218792Snp *	Returns a negative error number or the number of filters allocated.
5072218792Snp */
5073218792Snpint t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
5074218792Snp		      unsigned int viid, bool free, unsigned int naddr,
5075218792Snp		      const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok)
5076218792Snp{
5077218792Snp	int offset, ret = 0;
5078218792Snp	struct fw_vi_mac_cmd c;
5079218792Snp	unsigned int nfilters = 0;
5080248925Snp	unsigned int max_naddr = is_t4(adap) ?
5081248925Snp				       NUM_MPS_CLS_SRAM_L_INSTANCES :
5082248925Snp				       NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
5083218792Snp	unsigned int rem = naddr;
5084218792Snp
5085248925Snp	if (naddr > max_naddr)
5086218792Snp		return -EINVAL;
5087218792Snp
5088218792Snp	for (offset = 0; offset < naddr ; /**/) {
5089218792Snp		unsigned int fw_naddr = (rem < ARRAY_SIZE(c.u.exact)
5090218792Snp					 ? rem
5091218792Snp					 : ARRAY_SIZE(c.u.exact));
5092218792Snp		size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
5093218792Snp						     u.exact[fw_naddr]), 16);
5094218792Snp		struct fw_vi_mac_exact *p;
5095218792Snp		int i;
5096218792Snp
5097218792Snp		memset(&c, 0, sizeof(c));
5098218792Snp		c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) |
5099218792Snp				     F_FW_CMD_REQUEST |
5100218792Snp				     F_FW_CMD_WRITE |
5101218792Snp				     V_FW_CMD_EXEC(free) |
5102218792Snp				     V_FW_VI_MAC_CMD_VIID(viid));
5103218792Snp		c.freemacs_to_len16 = htonl(V_FW_VI_MAC_CMD_FREEMACS(free) |
5104218792Snp					    V_FW_CMD_LEN16(len16));
5105218792Snp
5106218792Snp		for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
5107218792Snp			p->valid_to_idx = htons(
5108218792Snp				F_FW_VI_MAC_CMD_VALID |
5109218792Snp				V_FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC));
5110218792Snp			memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr));
5111218792Snp		}
5112218792Snp
5113218792Snp		/*
5114218792Snp		 * It's okay if we run out of space in our MAC address arena.
5115218792Snp		 * Some of the addresses we submit may get stored so we need
5116218792Snp		 * to run through the reply to see what the results were ...
5117218792Snp		 */
5118218792Snp		ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok);
5119218792Snp		if (ret && ret != -FW_ENOMEM)
5120218792Snp			break;
5121218792Snp
5122218792Snp		for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
5123218792Snp			u16 index = G_FW_VI_MAC_CMD_IDX(ntohs(p->valid_to_idx));
5124218792Snp
5125218792Snp			if (idx)
5126248925Snp				idx[offset+i] = (index >=  max_naddr
5127218792Snp						 ? 0xffff
5128218792Snp						 : index);
5129248925Snp			if (index < max_naddr)
5130218792Snp				nfilters++;
5131218792Snp			else if (hash)
5132218792Snp				*hash |= (1ULL << hash_mac_addr(addr[offset+i]));
5133218792Snp		}
5134218792Snp
5135218792Snp		free = false;
5136218792Snp		offset += fw_naddr;
5137218792Snp		rem -= fw_naddr;
5138218792Snp	}
5139218792Snp
5140218792Snp	if (ret == 0 || ret == -FW_ENOMEM)
5141218792Snp		ret = nfilters;
5142218792Snp	return ret;
5143218792Snp}
5144218792Snp
5145218792Snp/**
5146218792Snp *	t4_change_mac - modifies the exact-match filter for a MAC address
5147218792Snp *	@adap: the adapter
5148218792Snp *	@mbox: mailbox to use for the FW command
5149218792Snp *	@viid: the VI id
5150218792Snp *	@idx: index of existing filter for old value of MAC address, or -1
5151218792Snp *	@addr: the new MAC address value
5152218792Snp *	@persist: whether a new MAC allocation should be persistent
5153218792Snp *	@add_smt: if true also add the address to the HW SMT
5154218792Snp *
5155218792Snp *	Modifies an exact-match filter and sets it to the new MAC address if
5156218792Snp *	@idx >= 0, or adds the MAC address to a new filter if @idx < 0.  In the
5157218792Snp *	latter case the address is added persistently if @persist is %true.
5158218792Snp *
5159218792Snp *	Note that in general it is not possible to modify the value of a given
5160218792Snp *	filter so the generic way to modify an address filter is to free the one
5161218792Snp *	being used by the old address value and allocate a new filter for the
5162218792Snp *	new address value.
5163218792Snp *
5164218792Snp *	Returns a negative error number or the index of the filter with the new
5165218792Snp *	MAC value.  Note that this index may differ from @idx.
5166218792Snp */
5167218792Snpint t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid,
5168218792Snp		  int idx, const u8 *addr, bool persist, bool add_smt)
5169218792Snp{
5170218792Snp	int ret, mode;
5171218792Snp	struct fw_vi_mac_cmd c;
5172218792Snp	struct fw_vi_mac_exact *p = c.u.exact;
5173248925Snp	unsigned int max_mac_addr = is_t4(adap) ?
5174248925Snp				    NUM_MPS_CLS_SRAM_L_INSTANCES :
5175248925Snp				    NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
5176218792Snp
5177218792Snp	if (idx < 0)                             /* new allocation */
5178218792Snp		idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC;
5179218792Snp	mode = add_smt ? FW_VI_MAC_SMT_AND_MPSTCAM : FW_VI_MAC_MPS_TCAM_ENTRY;
5180218792Snp
5181218792Snp	memset(&c, 0, sizeof(c));
5182218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) | F_FW_CMD_REQUEST |
5183218792Snp			     F_FW_CMD_WRITE | V_FW_VI_MAC_CMD_VIID(viid));
5184218792Snp	c.freemacs_to_len16 = htonl(V_FW_CMD_LEN16(1));
5185218792Snp	p->valid_to_idx = htons(F_FW_VI_MAC_CMD_VALID |
5186218792Snp				V_FW_VI_MAC_CMD_SMAC_RESULT(mode) |
5187218792Snp				V_FW_VI_MAC_CMD_IDX(idx));
5188218792Snp	memcpy(p->macaddr, addr, sizeof(p->macaddr));
5189218792Snp
5190248925Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
5191218792Snp	if (ret == 0) {
5192218792Snp		ret = G_FW_VI_MAC_CMD_IDX(ntohs(p->valid_to_idx));
5193248925Snp		if (ret >= max_mac_addr)
5194218792Snp			ret = -ENOMEM;
5195218792Snp	}
5196218792Snp	return ret;
5197218792Snp}
5198218792Snp
5199218792Snp/**
5200218792Snp *	t4_set_addr_hash - program the MAC inexact-match hash filter
5201218792Snp *	@adap: the adapter
5202218792Snp *	@mbox: mailbox to use for the FW command
5203218792Snp *	@viid: the VI id
5204218792Snp *	@ucast: whether the hash filter should also match unicast addresses
5205218792Snp *	@vec: the value to be written to the hash filter
5206218792Snp *	@sleep_ok: call is allowed to sleep
5207218792Snp *
5208218792Snp *	Sets the 64-bit inexact-match hash filter for a virtual interface.
5209218792Snp */
5210218792Snpint t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid,
5211218792Snp		     bool ucast, u64 vec, bool sleep_ok)
5212218792Snp{
5213218792Snp	struct fw_vi_mac_cmd c;
5214218792Snp
5215218792Snp	memset(&c, 0, sizeof(c));
5216218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) | F_FW_CMD_REQUEST |
5217218792Snp			     F_FW_CMD_WRITE | V_FW_VI_ENABLE_CMD_VIID(viid));
5218218792Snp	c.freemacs_to_len16 = htonl(F_FW_VI_MAC_CMD_HASHVECEN |
5219218792Snp				    V_FW_VI_MAC_CMD_HASHUNIEN(ucast) |
5220218792Snp				    V_FW_CMD_LEN16(1));
5221218792Snp	c.u.hash.hashvec = cpu_to_be64(vec);
5222218792Snp	return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok);
5223218792Snp}
5224218792Snp
5225218792Snp/**
5226218792Snp *	t4_enable_vi - enable/disable a virtual interface
5227218792Snp *	@adap: the adapter
5228218792Snp *	@mbox: mailbox to use for the FW command
5229218792Snp *	@viid: the VI id
5230218792Snp *	@rx_en: 1=enable Rx, 0=disable Rx
5231218792Snp *	@tx_en: 1=enable Tx, 0=disable Tx
5232218792Snp *
5233218792Snp *	Enables/disables a virtual interface.
5234218792Snp */
5235218792Snpint t4_enable_vi(struct adapter *adap, unsigned int mbox, unsigned int viid,
5236218792Snp		 bool rx_en, bool tx_en)
5237218792Snp{
5238218792Snp	struct fw_vi_enable_cmd c;
5239218792Snp
5240218792Snp	memset(&c, 0, sizeof(c));
5241218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_ENABLE_CMD) | F_FW_CMD_REQUEST |
5242218792Snp			     F_FW_CMD_EXEC | V_FW_VI_ENABLE_CMD_VIID(viid));
5243218792Snp	c.ien_to_len16 = htonl(V_FW_VI_ENABLE_CMD_IEN(rx_en) |
5244218792Snp			       V_FW_VI_ENABLE_CMD_EEN(tx_en) | FW_LEN16(c));
5245218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5246218792Snp}
5247218792Snp
5248218792Snp/**
5249218792Snp *	t4_identify_port - identify a VI's port by blinking its LED
5250218792Snp *	@adap: the adapter
5251218792Snp *	@mbox: mailbox to use for the FW command
5252218792Snp *	@viid: the VI id
5253218792Snp *	@nblinks: how many times to blink LED at 2.5 Hz
5254218792Snp *
5255218792Snp *	Identifies a VI's port by blinking its LED.
5256218792Snp */
5257218792Snpint t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid,
5258218792Snp		     unsigned int nblinks)
5259218792Snp{
5260218792Snp	struct fw_vi_enable_cmd c;
5261218792Snp
5262218792Snp	memset(&c, 0, sizeof(c));
5263218792Snp	c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_ENABLE_CMD) | F_FW_CMD_REQUEST |
5264218792Snp			     F_FW_CMD_EXEC | V_FW_VI_ENABLE_CMD_VIID(viid));
5265218792Snp	c.ien_to_len16 = htonl(F_FW_VI_ENABLE_CMD_LED | FW_LEN16(c));
5266218792Snp	c.blinkdur = htons(nblinks);
5267218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5268218792Snp}
5269218792Snp
5270218792Snp/**
5271218792Snp *	t4_iq_start_stop - enable/disable an ingress queue and its FLs
5272218792Snp *	@adap: the adapter
5273218792Snp *	@mbox: mailbox to use for the FW command
5274218792Snp *	@start: %true to enable the queues, %false to disable them
5275218792Snp *	@pf: the PF owning the queues
5276218792Snp *	@vf: the VF owning the queues
5277218792Snp *	@iqid: ingress queue id
5278218792Snp *	@fl0id: FL0 queue id or 0xffff if no attached FL0
5279218792Snp *	@fl1id: FL1 queue id or 0xffff if no attached FL1
5280218792Snp *
5281218792Snp *	Starts or stops an ingress queue and its associated FLs, if any.
5282218792Snp */
5283218792Snpint t4_iq_start_stop(struct adapter *adap, unsigned int mbox, bool start,
5284218792Snp		     unsigned int pf, unsigned int vf, unsigned int iqid,
5285218792Snp		     unsigned int fl0id, unsigned int fl1id)
5286218792Snp{
5287218792Snp	struct fw_iq_cmd c;
5288218792Snp
5289218792Snp	memset(&c, 0, sizeof(c));
5290218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_IQ_CMD) | F_FW_CMD_REQUEST |
5291218792Snp			    F_FW_CMD_EXEC | V_FW_IQ_CMD_PFN(pf) |
5292218792Snp			    V_FW_IQ_CMD_VFN(vf));
5293218792Snp	c.alloc_to_len16 = htonl(V_FW_IQ_CMD_IQSTART(start) |
5294218792Snp				 V_FW_IQ_CMD_IQSTOP(!start) | FW_LEN16(c));
5295218792Snp	c.iqid = htons(iqid);
5296218792Snp	c.fl0id = htons(fl0id);
5297218792Snp	c.fl1id = htons(fl1id);
5298218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5299218792Snp}
5300218792Snp
5301218792Snp/**
5302218792Snp *	t4_iq_free - free an ingress queue and its FLs
5303218792Snp *	@adap: the adapter
5304218792Snp *	@mbox: mailbox to use for the FW command
5305218792Snp *	@pf: the PF owning the queues
5306218792Snp *	@vf: the VF owning the queues
5307218792Snp *	@iqtype: the ingress queue type (FW_IQ_TYPE_FL_INT_CAP, etc.)
5308218792Snp *	@iqid: ingress queue id
5309218792Snp *	@fl0id: FL0 queue id or 0xffff if no attached FL0
5310218792Snp *	@fl1id: FL1 queue id or 0xffff if no attached FL1
5311218792Snp *
5312218792Snp *	Frees an ingress queue and its associated FLs, if any.
5313218792Snp */
5314218792Snpint t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
5315218792Snp	       unsigned int vf, unsigned int iqtype, unsigned int iqid,
5316218792Snp	       unsigned int fl0id, unsigned int fl1id)
5317218792Snp{
5318218792Snp	struct fw_iq_cmd c;
5319218792Snp
5320218792Snp	memset(&c, 0, sizeof(c));
5321218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_IQ_CMD) | F_FW_CMD_REQUEST |
5322218792Snp			    F_FW_CMD_EXEC | V_FW_IQ_CMD_PFN(pf) |
5323218792Snp			    V_FW_IQ_CMD_VFN(vf));
5324218792Snp	c.alloc_to_len16 = htonl(F_FW_IQ_CMD_FREE | FW_LEN16(c));
5325218792Snp	c.type_to_iqandstindex = htonl(V_FW_IQ_CMD_TYPE(iqtype));
5326218792Snp	c.iqid = htons(iqid);
5327218792Snp	c.fl0id = htons(fl0id);
5328218792Snp	c.fl1id = htons(fl1id);
5329218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5330218792Snp}
5331218792Snp
5332218792Snp/**
5333218792Snp *	t4_eth_eq_free - free an Ethernet egress queue
5334218792Snp *	@adap: the adapter
5335218792Snp *	@mbox: mailbox to use for the FW command
5336218792Snp *	@pf: the PF owning the queue
5337218792Snp *	@vf: the VF owning the queue
5338218792Snp *	@eqid: egress queue id
5339218792Snp *
5340218792Snp *	Frees an Ethernet egress queue.
5341218792Snp */
5342218792Snpint t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
5343218792Snp		   unsigned int vf, unsigned int eqid)
5344218792Snp{
5345218792Snp	struct fw_eq_eth_cmd c;
5346218792Snp
5347218792Snp	memset(&c, 0, sizeof(c));
5348218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_EQ_ETH_CMD) | F_FW_CMD_REQUEST |
5349218792Snp			    F_FW_CMD_EXEC | V_FW_EQ_ETH_CMD_PFN(pf) |
5350218792Snp			    V_FW_EQ_ETH_CMD_VFN(vf));
5351218792Snp	c.alloc_to_len16 = htonl(F_FW_EQ_ETH_CMD_FREE | FW_LEN16(c));
5352218792Snp	c.eqid_pkd = htonl(V_FW_EQ_ETH_CMD_EQID(eqid));
5353218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5354218792Snp}
5355218792Snp
5356218792Snp/**
5357218792Snp *	t4_ctrl_eq_free - free a control egress queue
5358218792Snp *	@adap: the adapter
5359218792Snp *	@mbox: mailbox to use for the FW command
5360218792Snp *	@pf: the PF owning the queue
5361218792Snp *	@vf: the VF owning the queue
5362218792Snp *	@eqid: egress queue id
5363218792Snp *
5364218792Snp *	Frees a control egress queue.
5365218792Snp */
5366218792Snpint t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
5367218792Snp		    unsigned int vf, unsigned int eqid)
5368218792Snp{
5369218792Snp	struct fw_eq_ctrl_cmd c;
5370218792Snp
5371218792Snp	memset(&c, 0, sizeof(c));
5372218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_EQ_CTRL_CMD) | F_FW_CMD_REQUEST |
5373218792Snp			    F_FW_CMD_EXEC | V_FW_EQ_CTRL_CMD_PFN(pf) |
5374218792Snp			    V_FW_EQ_CTRL_CMD_VFN(vf));
5375218792Snp	c.alloc_to_len16 = htonl(F_FW_EQ_CTRL_CMD_FREE | FW_LEN16(c));
5376218792Snp	c.cmpliqid_eqid = htonl(V_FW_EQ_CTRL_CMD_EQID(eqid));
5377218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5378218792Snp}
5379218792Snp
5380218792Snp/**
5381218792Snp *	t4_ofld_eq_free - free an offload egress queue
5382218792Snp *	@adap: the adapter
5383218792Snp *	@mbox: mailbox to use for the FW command
5384218792Snp *	@pf: the PF owning the queue
5385218792Snp *	@vf: the VF owning the queue
5386218792Snp *	@eqid: egress queue id
5387218792Snp *
5388218792Snp *	Frees a control egress queue.
5389218792Snp */
5390218792Snpint t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
5391218792Snp		    unsigned int vf, unsigned int eqid)
5392218792Snp{
5393218792Snp	struct fw_eq_ofld_cmd c;
5394218792Snp
5395218792Snp	memset(&c, 0, sizeof(c));
5396218792Snp	c.op_to_vfn = htonl(V_FW_CMD_OP(FW_EQ_OFLD_CMD) | F_FW_CMD_REQUEST |
5397218792Snp			    F_FW_CMD_EXEC | V_FW_EQ_OFLD_CMD_PFN(pf) |
5398218792Snp			    V_FW_EQ_OFLD_CMD_VFN(vf));
5399218792Snp	c.alloc_to_len16 = htonl(F_FW_EQ_OFLD_CMD_FREE | FW_LEN16(c));
5400218792Snp	c.eqid_pkd = htonl(V_FW_EQ_OFLD_CMD_EQID(eqid));
5401218792Snp	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
5402218792Snp}
5403218792Snp
5404218792Snp/**
5405218792Snp *	t4_handle_fw_rpl - process a FW reply message
5406218792Snp *	@adap: the adapter
5407218792Snp *	@rpl: start of the FW message
5408218792Snp *
5409218792Snp *	Processes a FW message, such as link state change messages.
5410218792Snp */
5411218792Snpint t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl)
5412218792Snp{
5413218792Snp	u8 opcode = *(const u8 *)rpl;
5414237436Snp	const struct fw_port_cmd *p = (const void *)rpl;
5415237436Snp	unsigned int action = G_FW_PORT_CMD_ACTION(ntohl(p->action_to_len16));
5416218792Snp
5417237436Snp	if (opcode == FW_PORT_CMD && action == FW_PORT_ACTION_GET_PORT_INFO) {
5418237436Snp		/* link/module state change message */
5419218792Snp		int speed = 0, fc = 0, i;
5420218792Snp		int chan = G_FW_PORT_CMD_PORTID(ntohl(p->op_to_portid));
5421218792Snp		struct port_info *pi = NULL;
5422218792Snp		struct link_config *lc;
5423218792Snp		u32 stat = ntohl(p->u.info.lstatus_to_modtype);
5424218792Snp		int link_ok = (stat & F_FW_PORT_CMD_LSTATUS) != 0;
5425218792Snp		u32 mod = G_FW_PORT_CMD_MODTYPE(stat);
5426218792Snp
5427218792Snp		if (stat & F_FW_PORT_CMD_RXPAUSE)
5428218792Snp			fc |= PAUSE_RX;
5429218792Snp		if (stat & F_FW_PORT_CMD_TXPAUSE)
5430218792Snp			fc |= PAUSE_TX;
5431218792Snp		if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M))
5432218792Snp			speed = SPEED_100;
5433218792Snp		else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G))
5434218792Snp			speed = SPEED_1000;
5435218792Snp		else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G))
5436218792Snp			speed = SPEED_10000;
5437250090Snp		else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G))
5438250090Snp			speed = SPEED_40000;
5439218792Snp
5440218792Snp		for_each_port(adap, i) {
5441218792Snp			pi = adap2pinfo(adap, i);
5442218792Snp			if (pi->tx_chan == chan)
5443218792Snp				break;
5444218792Snp		}
5445218792Snp		lc = &pi->link_cfg;
5446218792Snp
5447281207Snp		if (mod != pi->mod_type) {
5448281207Snp			pi->mod_type = mod;
5449281207Snp			t4_os_portmod_changed(adap, i);
5450281207Snp		}
5451218792Snp		if (link_ok != lc->link_ok || speed != lc->speed ||
5452218792Snp		    fc != lc->fc) {                    /* something changed */
5453252747Snp			int reason;
5454252747Snp
5455252747Snp			if (!link_ok && lc->link_ok)
5456252747Snp				reason = G_FW_PORT_CMD_LINKDNRC(stat);
5457252747Snp			else
5458252747Snp				reason = -1;
5459252747Snp
5460218792Snp			lc->link_ok = link_ok;
5461218792Snp			lc->speed = speed;
5462218792Snp			lc->fc = fc;
5463250090Snp			lc->supported = ntohs(p->u.info.pcap);
5464252747Snp			t4_os_link_changed(adap, i, link_ok, reason);
5465218792Snp		}
5466237436Snp	} else {
5467237436Snp		CH_WARN_RATELIMIT(adap,
5468237436Snp		    "Unknown firmware reply 0x%x (0x%x)\n", opcode, action);
5469237436Snp		return -EINVAL;
5470218792Snp	}
5471218792Snp	return 0;
5472218792Snp}
5473218792Snp
5474218792Snp/**
5475218792Snp *	get_pci_mode - determine a card's PCI mode
5476218792Snp *	@adapter: the adapter
5477218792Snp *	@p: where to store the PCI settings
5478218792Snp *
5479218792Snp *	Determines a card's PCI mode and associated parameters, such as speed
5480218792Snp *	and width.
5481218792Snp */
5482218792Snpstatic void __devinit get_pci_mode(struct adapter *adapter,
5483218792Snp				   struct pci_params *p)
5484218792Snp{
5485218792Snp	u16 val;
5486218792Snp	u32 pcie_cap;
5487218792Snp
5488218792Snp	pcie_cap = t4_os_find_pci_capability(adapter, PCI_CAP_ID_EXP);
5489218792Snp	if (pcie_cap) {
5490218792Snp		t4_os_pci_read_cfg2(adapter, pcie_cap + PCI_EXP_LNKSTA, &val);
5491218792Snp		p->speed = val & PCI_EXP_LNKSTA_CLS;
5492218792Snp		p->width = (val & PCI_EXP_LNKSTA_NLW) >> 4;
5493218792Snp	}
5494218792Snp}
5495218792Snp
5496218792Snp/**
5497218792Snp *	init_link_config - initialize a link's SW state
5498218792Snp *	@lc: structure holding the link state
5499218792Snp *	@caps: link capabilities
5500218792Snp *
5501218792Snp *	Initializes the SW state maintained for each link, including the link's
5502218792Snp *	capabilities and default speed/flow-control/autonegotiation settings.
5503218792Snp */
5504218792Snpstatic void __devinit init_link_config(struct link_config *lc,
5505218792Snp				       unsigned int caps)
5506218792Snp{
5507218792Snp	lc->supported = caps;
5508218792Snp	lc->requested_speed = 0;
5509218792Snp	lc->speed = 0;
5510218792Snp	lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
5511218792Snp	if (lc->supported & FW_PORT_CAP_ANEG) {
5512218792Snp		lc->advertising = lc->supported & ADVERT_MASK;
5513218792Snp		lc->autoneg = AUTONEG_ENABLE;
5514218792Snp		lc->requested_fc |= PAUSE_AUTONEG;
5515218792Snp	} else {
5516218792Snp		lc->advertising = 0;
5517218792Snp		lc->autoneg = AUTONEG_DISABLE;
5518218792Snp	}
5519218792Snp}
5520218792Snp
5521218792Snpstatic int __devinit get_flash_params(struct adapter *adapter)
5522218792Snp{
5523218792Snp	int ret;
5524218792Snp	u32 info = 0;
5525218792Snp
5526218792Snp	ret = sf1_write(adapter, 1, 1, 0, SF_RD_ID);
5527218792Snp	if (!ret)
5528218792Snp		ret = sf1_read(adapter, 3, 0, 1, &info);
5529218792Snp	t4_write_reg(adapter, A_SF_OP, 0);               /* unlock SF */
5530218792Snp	if (ret < 0)
5531218792Snp		return ret;
5532218792Snp
5533218792Snp	if ((info & 0xff) != 0x20)             /* not a Numonix flash */
5534218792Snp		return -EINVAL;
5535218792Snp	info >>= 16;                           /* log2 of size */
5536218792Snp	if (info >= 0x14 && info < 0x18)
5537218792Snp		adapter->params.sf_nsec = 1 << (info - 16);
5538218792Snp	else if (info == 0x18)
5539218792Snp		adapter->params.sf_nsec = 64;
5540218792Snp	else
5541218792Snp		return -EINVAL;
5542218792Snp	adapter->params.sf_size = 1 << info;
5543218792Snp	return 0;
5544218792Snp}
5545218792Snp
5546228561Snpstatic void __devinit set_pcie_completion_timeout(struct adapter *adapter,
5547228561Snp						  u8 range)
5548228561Snp{
5549228561Snp	u16 val;
5550228561Snp	u32 pcie_cap;
5551228561Snp
5552228561Snp	pcie_cap = t4_os_find_pci_capability(adapter, PCI_CAP_ID_EXP);
5553228561Snp	if (pcie_cap) {
5554228561Snp		t4_os_pci_read_cfg2(adapter, pcie_cap + PCI_EXP_DEVCTL2, &val);
5555228561Snp		val &= 0xfff0;
5556228561Snp		val |= range ;
5557228561Snp		t4_os_pci_write_cfg2(adapter, pcie_cap + PCI_EXP_DEVCTL2, val);
5558228561Snp	}
5559228561Snp}
5560228561Snp
5561218792Snp/**
5562218792Snp *	t4_prep_adapter - prepare SW and HW for operation
5563218792Snp *	@adapter: the adapter
5564218792Snp *	@reset: if true perform a HW reset
5565218792Snp *
5566218792Snp *	Initialize adapter SW state for the various HW modules, set initial
5567218792Snp *	values for some adapter tunables, take PHYs out of reset, and
5568218792Snp *	initialize the MDIO interface.
5569218792Snp */
5570218792Snpint __devinit t4_prep_adapter(struct adapter *adapter)
5571218792Snp{
5572218792Snp	int ret;
5573248925Snp	uint16_t device_id;
5574248925Snp	uint32_t pl_rev;
5575218792Snp
5576218792Snp	get_pci_mode(adapter, &adapter->params.pci);
5577218792Snp
5578248925Snp	pl_rev = t4_read_reg(adapter, A_PL_REV);
5579248925Snp	adapter->params.chipid = G_CHIPID(pl_rev);
5580248925Snp	adapter->params.rev = G_REV(pl_rev);
5581248925Snp	if (adapter->params.chipid == 0) {
5582248925Snp		/* T4 did not have chipid in PL_REV (T5 onwards do) */
5583248925Snp		adapter->params.chipid = CHELSIO_T4;
5584248925Snp
5585248925Snp		/* T4A1 chip is not supported */
5586248925Snp		if (adapter->params.rev == 1) {
5587248925Snp			CH_ALERT(adapter, "T4 rev 1 chip is not supported.\n");
5588248925Snp			return -EINVAL;
5589248925Snp		}
5590237436Snp	}
5591218792Snp	adapter->params.pci.vpd_cap_addr =
5592248925Snp	    t4_os_find_pci_capability(adapter, PCI_CAP_ID_VPD);
5593218792Snp
5594218792Snp	ret = get_flash_params(adapter);
5595218792Snp	if (ret < 0)
5596218792Snp		return ret;
5597218792Snp
5598218792Snp	ret = get_vpd_params(adapter, &adapter->params.vpd);
5599218792Snp	if (ret < 0)
5600218792Snp		return ret;
5601218792Snp
5602248925Snp	/* Cards with real ASICs have the chipid in the PCIe device id */
5603248925Snp	t4_os_pci_read_cfg2(adapter, PCI_DEVICE_ID, &device_id);
5604248925Snp	if (device_id >> 12 == adapter->params.chipid)
5605248925Snp		adapter->params.cim_la_size = CIMLA_SIZE;
5606248925Snp	else {
5607237436Snp		/* FPGA */
5608248925Snp		adapter->params.fpga = 1;
5609218792Snp		adapter->params.cim_la_size = 2 * CIMLA_SIZE;
5610218792Snp	}
5611218792Snp
5612218792Snp	init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
5613218792Snp
5614218792Snp	/*
5615218792Snp	 * Default port and clock for debugging in case we can't reach FW.
5616218792Snp	 */
5617218792Snp	adapter->params.nports = 1;
5618218792Snp	adapter->params.portvec = 1;
5619218792Snp	adapter->params.vpd.cclk = 50000;
5620218792Snp
5621228561Snp	/* Set pci completion timeout value to 4 seconds. */
5622228561Snp	set_pcie_completion_timeout(adapter, 0xd);
5623218792Snp	return 0;
5624218792Snp}
5625218792Snp
5626252705Snp/**
5627252705Snp *	t4_init_tp_params - initialize adap->params.tp
5628252705Snp *	@adap: the adapter
5629252705Snp *
5630252705Snp *	Initialize various fields of the adapter's TP Parameters structure.
5631252705Snp */
5632252705Snpint __devinit t4_init_tp_params(struct adapter *adap)
5633252705Snp{
5634252705Snp	int chan;
5635252705Snp	u32 v;
5636252705Snp
5637252705Snp	v = t4_read_reg(adap, A_TP_TIMER_RESOLUTION);
5638252705Snp	adap->params.tp.tre = G_TIMERRESOLUTION(v);
5639252705Snp	adap->params.tp.dack_re = G_DELAYEDACKRESOLUTION(v);
5640252705Snp
5641252705Snp	/* MODQ_REQ_MAP defaults to setting queues 0-3 to chan 0-3 */
5642252705Snp	for (chan = 0; chan < NCHAN; chan++)
5643252705Snp		adap->params.tp.tx_modq[chan] = chan;
5644252705Snp
5645252705Snp	t4_read_indirect(adap, A_TP_PIO_ADDR, A_TP_PIO_DATA,
5646252705Snp			 &adap->params.tp.ingress_config, 1,
5647252705Snp			 A_TP_INGRESS_CONFIG);
5648281259Snp	refresh_vlan_pri_map(adap);
5649252705Snp
5650252705Snp	return 0;
5651252705Snp}
5652252705Snp
5653252705Snp/**
5654252705Snp *	t4_filter_field_shift - calculate filter field shift
5655252705Snp *	@adap: the adapter
5656252705Snp *	@filter_sel: the desired field (from TP_VLAN_PRI_MAP bits)
5657252705Snp *
5658252705Snp *	Return the shift position of a filter field within the Compressed
5659252705Snp *	Filter Tuple.  The filter field is specified via its selection bit
5660252705Snp *	within TP_VLAN_PRI_MAL (filter mode).  E.g. F_VLAN.
5661252705Snp */
5662252705Snpint t4_filter_field_shift(const struct adapter *adap, int filter_sel)
5663252705Snp{
5664252705Snp	unsigned int filter_mode = adap->params.tp.vlan_pri_map;
5665252705Snp	unsigned int sel;
5666252705Snp	int field_shift;
5667252705Snp
5668252705Snp	if ((filter_mode & filter_sel) == 0)
5669252705Snp		return -1;
5670252705Snp
5671252705Snp	for (sel = 1, field_shift = 0; sel < filter_sel; sel <<= 1) {
5672252705Snp	    switch (filter_mode & sel) {
5673252705Snp		case F_FCOE:          field_shift += W_FT_FCOE;          break;
5674252705Snp		case F_PORT:          field_shift += W_FT_PORT;          break;
5675252705Snp		case F_VNIC_ID:       field_shift += W_FT_VNIC_ID;       break;
5676252705Snp		case F_VLAN:          field_shift += W_FT_VLAN;          break;
5677252705Snp		case F_TOS:           field_shift += W_FT_TOS;           break;
5678252705Snp		case F_PROTOCOL:      field_shift += W_FT_PROTOCOL;      break;
5679252705Snp		case F_ETHERTYPE:     field_shift += W_FT_ETHERTYPE;     break;
5680252705Snp		case F_MACMATCH:      field_shift += W_FT_MACMATCH;      break;
5681252705Snp		case F_MPSHITTYPE:    field_shift += W_FT_MPSHITTYPE;    break;
5682252705Snp		case F_FRAGMENTATION: field_shift += W_FT_FRAGMENTATION; break;
5683252705Snp	    }
5684252705Snp	}
5685252705Snp	return field_shift;
5686252705Snp}
5687252705Snp
5688218792Snpint __devinit t4_port_init(struct port_info *p, int mbox, int pf, int vf)
5689218792Snp{
5690218792Snp	u8 addr[6];
5691218792Snp	int ret, i, j;
5692218792Snp	struct fw_port_cmd c;
5693270297Snp	u16 rss_size;
5694218792Snp	adapter_t *adap = p->adapter;
5695218792Snp
5696218792Snp	memset(&c, 0, sizeof(c));
5697218792Snp
5698218792Snp	for (i = 0, j = -1; i <= p->port_id; i++) {
5699218792Snp		do {
5700218792Snp			j++;
5701218792Snp		} while ((adap->params.portvec & (1 << j)) == 0);
5702218792Snp	}
5703218792Snp
5704218792Snp	c.op_to_portid = htonl(V_FW_CMD_OP(FW_PORT_CMD) |
5705218792Snp			       F_FW_CMD_REQUEST | F_FW_CMD_READ |
5706218792Snp			       V_FW_PORT_CMD_PORTID(j));
5707218792Snp	c.action_to_len16 = htonl(
5708218792Snp		V_FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) |
5709218792Snp		FW_LEN16(c));
5710218792Snp	ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
5711218792Snp	if (ret)
5712218792Snp		return ret;
5713218792Snp
5714218792Snp	ret = t4_alloc_vi(adap, mbox, j, pf, vf, 1, addr, &rss_size);
5715218792Snp	if (ret < 0)
5716218792Snp		return ret;
5717218792Snp
5718218792Snp	p->viid = ret;
5719218792Snp	p->tx_chan = j;
5720265410Snp	p->rx_chan_map = get_mps_bg_map(adap, j);
5721218792Snp	p->lport = j;
5722218792Snp	p->rss_size = rss_size;
5723218792Snp	t4_os_set_hw_addr(adap, p->port_id, addr);
5724218792Snp
5725218792Snp	ret = ntohl(c.u.info.lstatus_to_modtype);
5726218792Snp	p->mdio_addr = (ret & F_FW_PORT_CMD_MDIOCAP) ?
5727218792Snp		G_FW_PORT_CMD_MDIOADDR(ret) : -1;
5728218792Snp	p->port_type = G_FW_PORT_CMD_PTYPE(ret);
5729218792Snp	p->mod_type = G_FW_PORT_CMD_MODTYPE(ret);
5730218792Snp
5731218792Snp	init_link_config(&p->link_cfg, ntohs(c.u.info.pcap));
5732218792Snp
5733218792Snp	return 0;
5734218792Snp}
5735259142Snp
5736270297Snpint t4_sched_config(struct adapter *adapter, int type, int minmaxen,
5737270297Snp    		    int sleep_ok)
5738259142Snp{
5739259142Snp	struct fw_sched_cmd cmd;
5740259142Snp
5741259142Snp	memset(&cmd, 0, sizeof(cmd));
5742259142Snp	cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_SCHED_CMD) |
5743259142Snp				      F_FW_CMD_REQUEST |
5744259142Snp				      F_FW_CMD_WRITE);
5745259142Snp	cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
5746259142Snp
5747259142Snp	cmd.u.config.sc = FW_SCHED_SC_CONFIG;
5748259142Snp	cmd.u.config.type = type;
5749259142Snp	cmd.u.config.minmaxen = minmaxen;
5750259142Snp
5751259142Snp	return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd),
5752270297Snp			       NULL, sleep_ok);
5753259142Snp}
5754259142Snp
5755259142Snpint t4_sched_params(struct adapter *adapter, int type, int level, int mode,
5756259142Snp		    int rateunit, int ratemode, int channel, int cl,
5757270297Snp		    int minrate, int maxrate, int weight, int pktsize,
5758270297Snp		    int sleep_ok)
5759259142Snp{
5760259142Snp	struct fw_sched_cmd cmd;
5761259142Snp
5762259142Snp	memset(&cmd, 0, sizeof(cmd));
5763259142Snp	cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_SCHED_CMD) |
5764259142Snp				      F_FW_CMD_REQUEST |
5765259142Snp				      F_FW_CMD_WRITE);
5766259142Snp	cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
5767259142Snp
5768259142Snp	cmd.u.params.sc = FW_SCHED_SC_PARAMS;
5769259142Snp	cmd.u.params.type = type;
5770259142Snp	cmd.u.params.level = level;
5771259142Snp	cmd.u.params.mode = mode;
5772259142Snp	cmd.u.params.ch = channel;
5773259142Snp	cmd.u.params.cl = cl;
5774259142Snp	cmd.u.params.unit = rateunit;
5775259142Snp	cmd.u.params.rate = ratemode;
5776259142Snp	cmd.u.params.min = cpu_to_be32(minrate);
5777259142Snp	cmd.u.params.max = cpu_to_be32(maxrate);
5778259142Snp	cmd.u.params.weight = cpu_to_be16(weight);
5779259142Snp	cmd.u.params.pktsize = cpu_to_be16(pktsize);
5780259142Snp
5781259142Snp	return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd),
5782270297Snp			       NULL, sleep_ok);
5783259142Snp}
5784