bnx2x_main.c 366 KB
Newer Older
1
/* bnx2x_main.c: Broadcom Everest network driver.
Eliezer Tamir's avatar
Eliezer Tamir committed
2
 *
3
 * Copyright (c) 2007-2013 Broadcom Corporation
Eliezer Tamir's avatar
Eliezer Tamir committed
4
5
6
7
8
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
9
10
 * Maintained by: Eilon Greenstein <eilong@broadcom.com>
 * Written by: Eliezer Tamir
Eliezer Tamir's avatar
Eliezer Tamir committed
11
12
 * Based on code from Michael Chan's bnx2 driver
 * UDP CSUM errata workaround by Arik Gendelman
Eilon Greenstein's avatar
Eilon Greenstein committed
13
 * Slowpath and fastpath rework by Vladislav Zolotarov
Eliezer Tamir's avatar
Eliezer Tamir committed
14
 * Statistics and Link management by Yitchak Gertner
Eliezer Tamir's avatar
Eliezer Tamir committed
15
16
17
 *
 */

18
19
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

Eliezer Tamir's avatar
Eliezer Tamir committed
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/device.h>  /* for dev_info() */
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/dma-mapping.h>
#include <linux/bitops.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <asm/byteorder.h>
#include <linux/time.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
42
#include <linux/if_vlan.h>
Eliezer Tamir's avatar
Eliezer Tamir committed
43
#include <net/ip.h>
44
#include <net/ipv6.h>
Eliezer Tamir's avatar
Eliezer Tamir committed
45
46
#include <net/tcp.h>
#include <net/checksum.h>
47
#include <net/ip6_checksum.h>
Eliezer Tamir's avatar
Eliezer Tamir committed
48
49
#include <linux/workqueue.h>
#include <linux/crc32.h>
50
#include <linux/crc32c.h>
Eliezer Tamir's avatar
Eliezer Tamir committed
51
52
53
#include <linux/prefetch.h>
#include <linux/zlib.h>
#include <linux/io.h>
54
#include <linux/semaphore.h>
Ben Hutchings's avatar
Ben Hutchings committed
55
#include <linux/stringify.h>
56
#include <linux/vmalloc.h>
Eliezer Tamir's avatar
Eliezer Tamir committed
57
58
59

#include "bnx2x.h"
#include "bnx2x_init.h"
60
#include "bnx2x_init_ops.h"
61
#include "bnx2x_cmn.h"
62
#include "bnx2x_vfpf.h"
Vladislav Zolotarov's avatar
Vladislav Zolotarov committed
63
#include "bnx2x_dcb.h"
Vladislav Zolotarov's avatar
Vladislav Zolotarov committed
64
#include "bnx2x_sp.h"
Eliezer Tamir's avatar
Eliezer Tamir committed
65

66
67
68
#include <linux/firmware.h>
#include "bnx2x_fw_file_hdr.h"
/* FW files */
Ben Hutchings's avatar
Ben Hutchings committed
69
70
71
72
73
#define FW_FILE_VERSION					\
	__stringify(BCM_5710_FW_MAJOR_VERSION) "."	\
	__stringify(BCM_5710_FW_MINOR_VERSION) "."	\
	__stringify(BCM_5710_FW_REVISION_VERSION) "."	\
	__stringify(BCM_5710_FW_ENGINEERING_VERSION)
74
75
#define FW_FILE_NAME_E1		"bnx2x/bnx2x-e1-" FW_FILE_VERSION ".fw"
#define FW_FILE_NAME_E1H	"bnx2x/bnx2x-e1h-" FW_FILE_VERSION ".fw"
Dmitry Kravkov's avatar
Dmitry Kravkov committed
76
#define FW_FILE_NAME_E2		"bnx2x/bnx2x-e2-" FW_FILE_VERSION ".fw"
77

78
79
/* Time in jiffies before concluding the transmitter is hung */
#define TX_TIMEOUT		(5*HZ)
Eliezer Tamir's avatar
Eliezer Tamir committed
80

81
static char version[] =
82
	"Broadcom NetXtreme II 5771x/578xx 10/20-Gigabit Ethernet Driver "
Eliezer Tamir's avatar
Eliezer Tamir committed
83
84
	DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";

85
MODULE_AUTHOR("Eliezer Tamir");
Dmitry Kravkov's avatar
Dmitry Kravkov committed
86
MODULE_DESCRIPTION("Broadcom NetXtreme II "
87
88
89
		   "BCM57710/57711/57711E/"
		   "57712/57712_MF/57800/57800_MF/57810/57810_MF/"
		   "57840/57840_MF Driver");
Eliezer Tamir's avatar
Eliezer Tamir committed
90
91
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
Ben Hutchings's avatar
Ben Hutchings committed
92
93
MODULE_FIRMWARE(FW_FILE_NAME_E1);
MODULE_FIRMWARE(FW_FILE_NAME_E1H);
Dmitry Kravkov's avatar
Dmitry Kravkov committed
94
MODULE_FIRMWARE(FW_FILE_NAME_E2);
Eliezer Tamir's avatar
Eliezer Tamir committed
95

Eilon Greenstein's avatar
Eilon Greenstein committed
96

97
int num_queues;
98
module_param(num_queues, int, 0);
99
100
MODULE_PARM_DESC(num_queues,
		 " Set number of queues (default is as a number of CPUs)");
Eilon Greenstein's avatar
Eilon Greenstein committed
101

102
103
static int disable_tpa;
module_param(disable_tpa, int, 0);
104
MODULE_PARM_DESC(disable_tpa, " Disable the TPA (LRO) feature");
Eilon Greenstein's avatar
Eilon Greenstein committed
105

106
107
#define INT_MODE_INTx			1
#define INT_MODE_MSI			2
108
int int_mode;
Eilon Greenstein's avatar
Eilon Greenstein committed
109
module_param(int_mode, int, 0);
110
MODULE_PARM_DESC(int_mode, " Force interrupt mode other than MSI-X "
Vladislav Zolotarov's avatar
Vladislav Zolotarov committed
111
				"(1 INT#x; 2 MSI)");
Eilon Greenstein's avatar
Eilon Greenstein committed
112

113
114
115
116
static int dropless_fc;
module_param(dropless_fc, int, 0);
MODULE_PARM_DESC(dropless_fc, " Pause on exhausted host ring");

117
118
119
120
static int mrrs = -1;
module_param(mrrs, int, 0);
MODULE_PARM_DESC(mrrs, " Force Max Read Req Size (0..3) (for debug)");

121
static int debug;
Eliezer Tamir's avatar
Eliezer Tamir committed
122
module_param(debug, int, 0);
123
124
MODULE_PARM_DESC(debug, " Default debug msglevel");

Eliezer Tamir's avatar
Eliezer Tamir committed
125

126
127

struct workqueue_struct *bnx2x_wq;
Vladislav Zolotarov's avatar
Vladislav Zolotarov committed
128

129
130
131
132
133
134
135
136
137
138
139
struct bnx2x_mac_vals {
	u32 xmac_addr;
	u32 xmac_val;
	u32 emac_addr;
	u32 emac_val;
	u32 umac_addr;
	u32 umac_val;
	u32 bmac_addr;
	u32 bmac_val[2];
};

Eliezer Tamir's avatar
Eliezer Tamir committed
140
141
enum bnx2x_board_type {
	BCM57710 = 0,
142
143
144
145
	BCM57711,
	BCM57711E,
	BCM57712,
	BCM57712_MF,
146
	BCM57712_VF,
147
148
	BCM57800,
	BCM57800_MF,
149
	BCM57800_VF,
150
151
	BCM57810,
	BCM57810_MF,
152
	BCM57810_VF,
Yuval Mintz's avatar
Yuval Mintz committed
153
154
	BCM57840_4_10,
	BCM57840_2_20,
155
	BCM57840_MF,
156
	BCM57840_VF,
157
	BCM57811,
158
159
160
161
	BCM57811_MF,
	BCM57840_O,
	BCM57840_MFO,
	BCM57811_VF
Eliezer Tamir's avatar
Eliezer Tamir committed
162
163
};

164
/* indexed by board_type, above */
Andrew Morton's avatar
Andrew Morton committed
165
static struct {
Eliezer Tamir's avatar
Eliezer Tamir committed
166
	char *name;
167
} board_info[] = {
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
	[BCM57710]	= { "Broadcom NetXtreme II BCM57710 10 Gigabit PCIe [Everest]" },
	[BCM57711]	= { "Broadcom NetXtreme II BCM57711 10 Gigabit PCIe" },
	[BCM57711E]	= { "Broadcom NetXtreme II BCM57711E 10 Gigabit PCIe" },
	[BCM57712]	= { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet" },
	[BCM57712_MF]	= { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Multi Function" },
	[BCM57712_VF]	= { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Virtual Function" },
	[BCM57800]	= { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet" },
	[BCM57800_MF]	= { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Multi Function" },
	[BCM57800_VF]	= { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Virtual Function" },
	[BCM57810]	= { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet" },
	[BCM57810_MF]	= { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Multi Function" },
	[BCM57810_VF]	= { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Virtual Function" },
	[BCM57840_4_10]	= { "Broadcom NetXtreme II BCM57840 10 Gigabit Ethernet" },
	[BCM57840_2_20]	= { "Broadcom NetXtreme II BCM57840 20 Gigabit Ethernet" },
	[BCM57840_MF]	= { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function" },
	[BCM57840_VF]	= { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function" },
	[BCM57811]	= { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet" },
	[BCM57811_MF]	= { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet Multi Function" },
	[BCM57840_O]	= { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet" },
	[BCM57840_MFO]	= { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function" },
	[BCM57811_VF]	= { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function" }
Eliezer Tamir's avatar
Eliezer Tamir committed
189
190
};

191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#ifndef PCI_DEVICE_ID_NX2_57710
#define PCI_DEVICE_ID_NX2_57710		CHIP_NUM_57710
#endif
#ifndef PCI_DEVICE_ID_NX2_57711
#define PCI_DEVICE_ID_NX2_57711		CHIP_NUM_57711
#endif
#ifndef PCI_DEVICE_ID_NX2_57711E
#define PCI_DEVICE_ID_NX2_57711E	CHIP_NUM_57711E
#endif
#ifndef PCI_DEVICE_ID_NX2_57712
#define PCI_DEVICE_ID_NX2_57712		CHIP_NUM_57712
#endif
#ifndef PCI_DEVICE_ID_NX2_57712_MF
#define PCI_DEVICE_ID_NX2_57712_MF	CHIP_NUM_57712_MF
#endif
206
207
208
#ifndef PCI_DEVICE_ID_NX2_57712_VF
#define PCI_DEVICE_ID_NX2_57712_VF	CHIP_NUM_57712_VF
#endif
209
210
211
212
213
214
#ifndef PCI_DEVICE_ID_NX2_57800
#define PCI_DEVICE_ID_NX2_57800		CHIP_NUM_57800
#endif
#ifndef PCI_DEVICE_ID_NX2_57800_MF
#define PCI_DEVICE_ID_NX2_57800_MF	CHIP_NUM_57800_MF
#endif
215
216
217
#ifndef PCI_DEVICE_ID_NX2_57800_VF
#define PCI_DEVICE_ID_NX2_57800_VF	CHIP_NUM_57800_VF
#endif
218
219
220
221
222
223
#ifndef PCI_DEVICE_ID_NX2_57810
#define PCI_DEVICE_ID_NX2_57810		CHIP_NUM_57810
#endif
#ifndef PCI_DEVICE_ID_NX2_57810_MF
#define PCI_DEVICE_ID_NX2_57810_MF	CHIP_NUM_57810_MF
#endif
Yuval Mintz's avatar
Yuval Mintz committed
224
225
226
#ifndef PCI_DEVICE_ID_NX2_57840_O
#define PCI_DEVICE_ID_NX2_57840_O	CHIP_NUM_57840_OBSOLETE
#endif
227
228
229
#ifndef PCI_DEVICE_ID_NX2_57810_VF
#define PCI_DEVICE_ID_NX2_57810_VF	CHIP_NUM_57810_VF
#endif
Yuval Mintz's avatar
Yuval Mintz committed
230
231
232
233
234
235
236
237
#ifndef PCI_DEVICE_ID_NX2_57840_4_10
#define PCI_DEVICE_ID_NX2_57840_4_10	CHIP_NUM_57840_4_10
#endif
#ifndef PCI_DEVICE_ID_NX2_57840_2_20
#define PCI_DEVICE_ID_NX2_57840_2_20	CHIP_NUM_57840_2_20
#endif
#ifndef PCI_DEVICE_ID_NX2_57840_MFO
#define PCI_DEVICE_ID_NX2_57840_MFO	CHIP_NUM_57840_MF_OBSOLETE
238
239
240
241
#endif
#ifndef PCI_DEVICE_ID_NX2_57840_MF
#define PCI_DEVICE_ID_NX2_57840_MF	CHIP_NUM_57840_MF
#endif
242
243
244
#ifndef PCI_DEVICE_ID_NX2_57840_VF
#define PCI_DEVICE_ID_NX2_57840_VF	CHIP_NUM_57840_VF
#endif
245
246
247
248
249
250
#ifndef PCI_DEVICE_ID_NX2_57811
#define PCI_DEVICE_ID_NX2_57811		CHIP_NUM_57811
#endif
#ifndef PCI_DEVICE_ID_NX2_57811_MF
#define PCI_DEVICE_ID_NX2_57811_MF	CHIP_NUM_57811_MF
#endif
251
252
253
254
#ifndef PCI_DEVICE_ID_NX2_57811_VF
#define PCI_DEVICE_ID_NX2_57811_VF	CHIP_NUM_57811_VF
#endif

255
static DEFINE_PCI_DEVICE_TABLE(bnx2x_pci_tbl) = {
256
257
258
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57710), BCM57710 },
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711), BCM57711 },
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711E), BCM57711E },
Dmitry Kravkov's avatar
Dmitry Kravkov committed
259
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712), BCM57712 },
260
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712_MF), BCM57712_MF },
261
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712_VF), BCM57712_VF },
262
263
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800), BCM57800 },
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800_MF), BCM57800_MF },
264
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800_VF), BCM57800_VF },
265
266
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810), BCM57810 },
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810_MF), BCM57810_MF },
Yuval Mintz's avatar
Yuval Mintz committed
267
268
269
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_O), BCM57840_O },
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_4_10), BCM57840_4_10 },
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_2_20), BCM57840_2_20 },
270
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810_VF), BCM57810_VF },
Yuval Mintz's avatar
Yuval Mintz committed
271
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_MFO), BCM57840_MFO },
272
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_MF), BCM57840_MF },
273
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_VF), BCM57840_VF },
274
275
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811), BCM57811 },
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811_MF), BCM57811_MF },
276
	{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811_VF), BCM57811_VF },
Eliezer Tamir's avatar
Eliezer Tamir committed
277
278
279
280
281
	{ 0 }
};

MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl);

282
283
284
285
/* Global resources for unloading a previously loaded device */
#define BNX2X_PREV_WAIT_NEEDED 1
static DEFINE_SEMAPHORE(bnx2x_prev_sem);
static LIST_HEAD(bnx2x_prev_list);
Eliezer Tamir's avatar
Eliezer Tamir committed
286
287
288
289
/****************************************************************************
* General service functions
****************************************************************************/

Eric Dumazet's avatar
Eric Dumazet committed
290
static void __storm_memset_dma_mapping(struct bnx2x *bp,
291
292
293
294
295
296
				       u32 addr, dma_addr_t mapping)
{
	REG_WR(bp,  addr, U64_LO(mapping));
	REG_WR(bp,  addr + 4, U64_HI(mapping));
}

Eric Dumazet's avatar
Eric Dumazet committed
297
298
static void storm_memset_spq_addr(struct bnx2x *bp,
				  dma_addr_t mapping, u16 abs_fid)
299
300
301
302
303
304
305
{
	u32 addr = XSEM_REG_FAST_MEMORY +
			XSTORM_SPQ_PAGE_BASE_OFFSET(abs_fid);

	__storm_memset_dma_mapping(bp, addr, mapping);
}

Eric Dumazet's avatar
Eric Dumazet committed
306
307
static void storm_memset_vf_to_pf(struct bnx2x *bp, u16 abs_fid,
				  u16 pf_id)
308
{
309
310
311
312
313
314
315
316
	REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_VF_TO_PF_OFFSET(abs_fid),
		pf_id);
	REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_VF_TO_PF_OFFSET(abs_fid),
		pf_id);
	REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_VF_TO_PF_OFFSET(abs_fid),
		pf_id);
	REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_VF_TO_PF_OFFSET(abs_fid),
		pf_id);
317
318
}

Eric Dumazet's avatar
Eric Dumazet committed
319
320
static void storm_memset_func_en(struct bnx2x *bp, u16 abs_fid,
				 u8 enable)
321
322
323
324
325
326
327
328
329
330
{
	REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_FUNC_EN_OFFSET(abs_fid),
		enable);
	REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_FUNC_EN_OFFSET(abs_fid),
		enable);
	REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_FUNC_EN_OFFSET(abs_fid),
		enable);
	REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNC_EN_OFFSET(abs_fid),
		enable);
}
331

Eric Dumazet's avatar
Eric Dumazet committed
332
333
static void storm_memset_eq_data(struct bnx2x *bp,
				 struct event_ring_data *eq_data,
334
335
336
337
338
339
340
341
342
				u16 pfid)
{
	size_t size = sizeof(struct event_ring_data);

	u32 addr = BAR_CSTRORM_INTMEM + CSTORM_EVENT_RING_DATA_OFFSET(pfid);

	__storm_memset_struct(bp, addr, size, (u32 *)eq_data);
}

Eric Dumazet's avatar
Eric Dumazet committed
343
344
static void storm_memset_eq_prod(struct bnx2x *bp, u16 eq_prod,
				 u16 pfid)
345
346
347
348
349
{
	u32 addr = BAR_CSTRORM_INTMEM + CSTORM_EVENT_RING_PROD_OFFSET(pfid);
	REG_WR16(bp, addr, eq_prod);
}

Eliezer Tamir's avatar
Eliezer Tamir committed
350
351
352
/* used only at init
 * locking is done by mcp
 */
353
static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val)
Eliezer Tamir's avatar
Eliezer Tamir committed
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
{
	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr);
	pci_write_config_dword(bp->pdev, PCICFG_GRC_DATA, val);
	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
			       PCICFG_VENDOR_ID_OFFSET);
}

static u32 bnx2x_reg_rd_ind(struct bnx2x *bp, u32 addr)
{
	u32 val;

	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr);
	pci_read_config_dword(bp->pdev, PCICFG_GRC_DATA, &val);
	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
			       PCICFG_VENDOR_ID_OFFSET);

	return val;
}

Dmitry Kravkov's avatar
Dmitry Kravkov committed
373
374
375
376
377
378
#define DMAE_DP_SRC_GRC		"grc src_addr [%08x]"
#define DMAE_DP_SRC_PCI		"pci src_addr [%x:%08x]"
#define DMAE_DP_DST_GRC		"grc dst_addr [%08x]"
#define DMAE_DP_DST_PCI		"pci dst_addr [%x:%08x]"
#define DMAE_DP_DST_NONE	"dst_addr [none]"

379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
void bnx2x_dp_dmae(struct bnx2x *bp, struct dmae_command *dmae, int msglvl)
{
	u32 src_type = dmae->opcode & DMAE_COMMAND_SRC;

	switch (dmae->opcode & DMAE_COMMAND_DST) {
	case DMAE_CMD_DST_PCI:
		if (src_type == DMAE_CMD_SRC_PCI)
			DP(msglvl, "DMAE: opcode 0x%08x\n"
			   "src [%x:%08x], len [%d*4], dst [%x:%08x]\n"
			   "comp_addr [%x:%08x], comp_val 0x%08x\n",
			   dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
			   dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo,
			   dmae->comp_addr_hi, dmae->comp_addr_lo,
			   dmae->comp_val);
		else
			DP(msglvl, "DMAE: opcode 0x%08x\n"
			   "src [%08x], len [%d*4], dst [%x:%08x]\n"
			   "comp_addr [%x:%08x], comp_val 0x%08x\n",
			   dmae->opcode, dmae->src_addr_lo >> 2,
			   dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo,
			   dmae->comp_addr_hi, dmae->comp_addr_lo,
			   dmae->comp_val);
		break;
	case DMAE_CMD_DST_GRC:
		if (src_type == DMAE_CMD_SRC_PCI)
			DP(msglvl, "DMAE: opcode 0x%08x\n"
			   "src [%x:%08x], len [%d*4], dst_addr [%08x]\n"
			   "comp_addr [%x:%08x], comp_val 0x%08x\n",
			   dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
			   dmae->len, dmae->dst_addr_lo >> 2,
			   dmae->comp_addr_hi, dmae->comp_addr_lo,
			   dmae->comp_val);
		else
			DP(msglvl, "DMAE: opcode 0x%08x\n"
			   "src [%08x], len [%d*4], dst [%08x]\n"
			   "comp_addr [%x:%08x], comp_val 0x%08x\n",
			   dmae->opcode, dmae->src_addr_lo >> 2,
			   dmae->len, dmae->dst_addr_lo >> 2,
			   dmae->comp_addr_hi, dmae->comp_addr_lo,
			   dmae->comp_val);
		break;
	default:
		if (src_type == DMAE_CMD_SRC_PCI)
			DP(msglvl, "DMAE: opcode 0x%08x\n"
			   "src_addr [%x:%08x]  len [%d * 4]  dst_addr [none]\n"
			   "comp_addr [%x:%08x]  comp_val 0x%08x\n",
			   dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
			   dmae->len, dmae->comp_addr_hi, dmae->comp_addr_lo,
			   dmae->comp_val);
		else
			DP(msglvl, "DMAE: opcode 0x%08x\n"
			   "src_addr [%08x]  len [%d * 4]  dst_addr [none]\n"
			   "comp_addr [%x:%08x]  comp_val 0x%08x\n",
			   dmae->opcode, dmae->src_addr_lo >> 2,
			   dmae->len, dmae->comp_addr_hi, dmae->comp_addr_lo,
			   dmae->comp_val);
		break;
	}
}
Dmitry Kravkov's avatar
Dmitry Kravkov committed
438

Eliezer Tamir's avatar
Eliezer Tamir committed
439
/* copy command into DMAE command memory and set DMAE command go */
440
void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, int idx)
Eliezer Tamir's avatar
Eliezer Tamir committed
441
442
443
444
445
446
447
448
449
450
451
{
	u32 cmd_offset;
	int i;

	cmd_offset = (DMAE_REG_CMD_MEM + sizeof(struct dmae_command) * idx);
	for (i = 0; i < (sizeof(struct dmae_command)/4); i++) {
		REG_WR(bp, cmd_offset + i*4, *(((u32 *)dmae) + i));
	}
	REG_WR(bp, dmae_reg_go_c[idx], 1);
}

Dmitry Kravkov's avatar
Dmitry Kravkov committed
452
u32 bnx2x_dmae_opcode_add_comp(u32 opcode, u8 comp_type)
Eliezer Tamir's avatar
Eliezer Tamir committed
453
{
Dmitry Kravkov's avatar
Dmitry Kravkov committed
454
455
456
	return opcode | ((comp_type << DMAE_COMMAND_C_DST_SHIFT) |
			   DMAE_CMD_C_ENABLE);
}
457

Dmitry Kravkov's avatar
Dmitry Kravkov committed
458
459
460
461
u32 bnx2x_dmae_opcode_clr_src_reset(u32 opcode)
{
	return opcode & ~DMAE_CMD_SRC_RESET;
}
462

Dmitry Kravkov's avatar
Dmitry Kravkov committed
463
464
465
466
467
468
469
u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
			     bool with_comp, u8 comp_type)
{
	u32 opcode = 0;

	opcode |= ((src_type << DMAE_COMMAND_SRC_SHIFT) |
		   (dst_type << DMAE_COMMAND_DST_SHIFT));
470

Dmitry Kravkov's avatar
Dmitry Kravkov committed
471
472
473
	opcode |= (DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET);

	opcode |= (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0);
474
475
	opcode |= ((BP_VN(bp) << DMAE_CMD_E1HVN_SHIFT) |
		   (BP_VN(bp) << DMAE_COMMAND_DST_VN_SHIFT));
Dmitry Kravkov's avatar
Dmitry Kravkov committed
476
	opcode |= (DMAE_COM_SET_ERR << DMAE_COMMAND_ERR_POLICY_SHIFT);
Eliezer Tamir's avatar
Eliezer Tamir committed
477
478

#ifdef __BIG_ENDIAN
Dmitry Kravkov's avatar
Dmitry Kravkov committed
479
	opcode |= DMAE_CMD_ENDIANITY_B_DW_SWAP;
Eliezer Tamir's avatar
Eliezer Tamir committed
480
#else
Dmitry Kravkov's avatar
Dmitry Kravkov committed
481
	opcode |= DMAE_CMD_ENDIANITY_DW_SWAP;
Eliezer Tamir's avatar
Eliezer Tamir committed
482
#endif
Dmitry Kravkov's avatar
Dmitry Kravkov committed
483
484
485
486
487
	if (with_comp)
		opcode = bnx2x_dmae_opcode_add_comp(opcode, comp_type);
	return opcode;
}

488
void bnx2x_prep_dmae_with_comp(struct bnx2x *bp,
489
490
				      struct dmae_command *dmae,
				      u8 src_type, u8 dst_type)
Dmitry Kravkov's avatar
Dmitry Kravkov committed
491
492
493
494
495
496
497
498
499
500
501
502
503
{
	memset(dmae, 0, sizeof(struct dmae_command));

	/* set the opcode */
	dmae->opcode = bnx2x_dmae_opcode(bp, src_type, dst_type,
					 true, DMAE_COMP_PCI);

	/* fill in the completion parameters */
	dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
	dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
	dmae->comp_val = DMAE_COMP_VAL;
}

504
505
/* issue a dmae command over the init-channel and wait for completion */
int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae)
Dmitry Kravkov's avatar
Dmitry Kravkov committed
506
507
{
	u32 *wb_comp = bnx2x_sp(bp, wb_comp);
508
	int cnt = CHIP_REV_IS_SLOW(bp) ? (400000) : 4000;
Dmitry Kravkov's avatar
Dmitry Kravkov committed
509
510
	int rc = 0;

511
512
513
514
515
	/*
	 * Lock the dmae channel. Disable BHs to prevent a dead-lock
	 * as long as this code is called both from syscall context and
	 * from ndo_set_rx_mode() flow that may be called from BH.
	 */
516
	spin_lock_bh(&bp->dmae_lock);
517

Dmitry Kravkov's avatar
Dmitry Kravkov committed
518
	/* reset completion */
Eliezer Tamir's avatar
Eliezer Tamir committed
519
520
	*wb_comp = 0;

Dmitry Kravkov's avatar
Dmitry Kravkov committed
521
522
	/* post the command on the channel used for initializations */
	bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp));
Eliezer Tamir's avatar
Eliezer Tamir committed
523

Dmitry Kravkov's avatar
Dmitry Kravkov committed
524
	/* wait for completion */
Eliezer Tamir's avatar
Eliezer Tamir committed
525
	udelay(5);
Dmitry Kravkov's avatar
Dmitry Kravkov committed
526
	while ((*wb_comp & ~DMAE_PCI_ERR_FLAG) != DMAE_COMP_VAL) {
527

Ariel Elior's avatar
Ariel Elior committed
528
529
530
		if (!cnt ||
		    (bp->recovery_state != BNX2X_RECOVERY_DONE &&
		     bp->recovery_state != BNX2X_RECOVERY_NIC_LOADING)) {
Eilon Greenstein's avatar
Eilon Greenstein committed
531
			BNX2X_ERR("DMAE timeout!\n");
Dmitry Kravkov's avatar
Dmitry Kravkov committed
532
533
			rc = DMAE_TIMEOUT;
			goto unlock;
Eliezer Tamir's avatar
Eliezer Tamir committed
534
		}
535
		cnt--;
Dmitry Kravkov's avatar
Dmitry Kravkov committed
536
		udelay(50);
Eliezer Tamir's avatar
Eliezer Tamir committed
537
	}
Dmitry Kravkov's avatar
Dmitry Kravkov committed
538
539
540
541
542
543
	if (*wb_comp & DMAE_PCI_ERR_FLAG) {
		BNX2X_ERR("DMAE PCI error!\n");
		rc = DMAE_PCI_ERROR;
	}

unlock:
544
	spin_unlock_bh(&bp->dmae_lock);
Dmitry Kravkov's avatar
Dmitry Kravkov committed
545
546
547
548
549
550
551
552
553
554
555
	return rc;
}

void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
		      u32 len32)
{
	struct dmae_command dmae;

	if (!bp->dmae_ready) {
		u32 *data = bnx2x_sp(bp, wb_data[0]);

556
557
558
559
		if (CHIP_IS_E1(bp))
			bnx2x_init_ind_wr(bp, dst_addr, data, len32);
		else
			bnx2x_init_str_wr(bp, dst_addr, data, len32);
Dmitry Kravkov's avatar
Dmitry Kravkov committed
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
		return;
	}

	/* set opcode and fixed command fields */
	bnx2x_prep_dmae_with_comp(bp, &dmae, DMAE_SRC_PCI, DMAE_DST_GRC);

	/* fill in addresses and len */
	dmae.src_addr_lo = U64_LO(dma_addr);
	dmae.src_addr_hi = U64_HI(dma_addr);
	dmae.dst_addr_lo = dst_addr >> 2;
	dmae.dst_addr_hi = 0;
	dmae.len = len32;

	/* issue the command and wait for completion */
	bnx2x_issue_dmae_with_comp(bp, &dmae);
Eliezer Tamir's avatar
Eliezer Tamir committed
575
576
}

Yaniv Rosner's avatar
Yaniv Rosner committed
577
void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
Eliezer Tamir's avatar
Eliezer Tamir committed
578
{
579
	struct dmae_command dmae;
580
581
582
583
584

	if (!bp->dmae_ready) {
		u32 *data = bnx2x_sp(bp, wb_data[0]);
		int i;

Merav Sicron's avatar
Merav Sicron committed
585
		if (CHIP_IS_E1(bp))
586
587
			for (i = 0; i < len32; i++)
				data[i] = bnx2x_reg_rd_ind(bp, src_addr + i*4);
Merav Sicron's avatar
Merav Sicron committed
588
		else
589
590
591
			for (i = 0; i < len32; i++)
				data[i] = REG_RD(bp, src_addr + i*4);

592
593
594
		return;
	}

Dmitry Kravkov's avatar
Dmitry Kravkov committed
595
596
	/* set opcode and fixed command fields */
	bnx2x_prep_dmae_with_comp(bp, &dmae, DMAE_SRC_GRC, DMAE_DST_PCI);
Eliezer Tamir's avatar
Eliezer Tamir committed
597

Dmitry Kravkov's avatar
Dmitry Kravkov committed
598
	/* fill in addresses and len */
599
600
601
602
603
	dmae.src_addr_lo = src_addr >> 2;
	dmae.src_addr_hi = 0;
	dmae.dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data));
	dmae.dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data));
	dmae.len = len32;
604

Dmitry Kravkov's avatar
Dmitry Kravkov committed
605
606
	/* issue the command and wait for completion */
	bnx2x_issue_dmae_with_comp(bp, &dmae);
607
608
}

609
610
static void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
				      u32 addr, u32 len)
611
{
612
	int dmae_wr_max = DMAE_LEN32_WR_MAX(bp);
613
614
	int offset = 0;

615
	while (len > dmae_wr_max) {
616
		bnx2x_write_dmae(bp, phys_addr + offset,
617
618
619
				 addr + offset, dmae_wr_max);
		offset += dmae_wr_max * 4;
		len -= dmae_wr_max;
620
621
622
623
624
	}

	bnx2x_write_dmae(bp, phys_addr + offset, addr + offset, len);
}

Eliezer Tamir's avatar
Eliezer Tamir committed
625
626
627
static int bnx2x_mc_assert(struct bnx2x *bp)
{
	char last_idx;
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
	int i, rc = 0;
	u32 row0, row1, row2, row3;

	/* XSTORM */
	last_idx = REG_RD8(bp, BAR_XSTRORM_INTMEM +
			   XSTORM_ASSERT_LIST_INDEX_OFFSET);
	if (last_idx)
		BNX2X_ERR("XSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);

	/* print the asserts */
	for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {

		row0 = REG_RD(bp, BAR_XSTRORM_INTMEM +
			      XSTORM_ASSERT_LIST_OFFSET(i));
		row1 = REG_RD(bp, BAR_XSTRORM_INTMEM +
			      XSTORM_ASSERT_LIST_OFFSET(i) + 4);
		row2 = REG_RD(bp, BAR_XSTRORM_INTMEM +
			      XSTORM_ASSERT_LIST_OFFSET(i) + 8);
		row3 = REG_RD(bp, BAR_XSTRORM_INTMEM +
			      XSTORM_ASSERT_LIST_OFFSET(i) + 12);

		if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
Merav Sicron's avatar
Merav Sicron committed
650
			BNX2X_ERR("XSTORM_ASSERT_INDEX 0x%x = 0x%08x 0x%08x 0x%08x 0x%08x\n",
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
				  i, row3, row2, row1, row0);
			rc++;
		} else {
			break;
		}
	}

	/* TSTORM */
	last_idx = REG_RD8(bp, BAR_TSTRORM_INTMEM +
			   TSTORM_ASSERT_LIST_INDEX_OFFSET);
	if (last_idx)
		BNX2X_ERR("TSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);

	/* print the asserts */
	for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {

		row0 = REG_RD(bp, BAR_TSTRORM_INTMEM +
			      TSTORM_ASSERT_LIST_OFFSET(i));
		row1 = REG_RD(bp, BAR_TSTRORM_INTMEM +
			      TSTORM_ASSERT_LIST_OFFSET(i) + 4);
		row2 = REG_RD(bp, BAR_TSTRORM_INTMEM +
			      TSTORM_ASSERT_LIST_OFFSET(i) + 8);
		row3 = REG_RD(bp, BAR_TSTRORM_INTMEM +
			      TSTORM_ASSERT_LIST_OFFSET(i) + 12);

		if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
Merav Sicron's avatar
Merav Sicron committed
677
			BNX2X_ERR("TSTORM_ASSERT_INDEX 0x%x = 0x%08x 0x%08x 0x%08x 0x%08x\n",
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
				  i, row3, row2, row1, row0);
			rc++;
		} else {
			break;
		}
	}

	/* CSTORM */
	last_idx = REG_RD8(bp, BAR_CSTRORM_INTMEM +
			   CSTORM_ASSERT_LIST_INDEX_OFFSET);
	if (last_idx)
		BNX2X_ERR("CSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);

	/* print the asserts */
	for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {

		row0 = REG_RD(bp, BAR_CSTRORM_INTMEM +
			      CSTORM_ASSERT_LIST_OFFSET(i));
		row1 = REG_RD(bp, BAR_CSTRORM_INTMEM +
			      CSTORM_ASSERT_LIST_OFFSET(i) + 4);
		row2 = REG_RD(bp, BAR_CSTRORM_INTMEM +
			      CSTORM_ASSERT_LIST_OFFSET(i) + 8);
		row3 = REG_RD(bp, BAR_CSTRORM_INTMEM +
			      CSTORM_ASSERT_LIST_OFFSET(i) + 12);

		if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
Merav Sicron's avatar
Merav Sicron committed
704
			BNX2X_ERR("CSTORM_ASSERT_INDEX 0x%x = 0x%08x 0x%08x 0x%08x 0x%08x\n",
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
				  i, row3, row2, row1, row0);
			rc++;
		} else {
			break;
		}
	}

	/* USTORM */
	last_idx = REG_RD8(bp, BAR_USTRORM_INTMEM +
			   USTORM_ASSERT_LIST_INDEX_OFFSET);
	if (last_idx)
		BNX2X_ERR("USTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);

	/* print the asserts */
	for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {

		row0 = REG_RD(bp, BAR_USTRORM_INTMEM +
			      USTORM_ASSERT_LIST_OFFSET(i));
		row1 = REG_RD(bp, BAR_USTRORM_INTMEM +
			      USTORM_ASSERT_LIST_OFFSET(i) + 4);
		row2 = REG_RD(bp, BAR_USTRORM_INTMEM +
			      USTORM_ASSERT_LIST_OFFSET(i) + 8);
		row3 = REG_RD(bp, BAR_USTRORM_INTMEM +
			      USTORM_ASSERT_LIST_OFFSET(i) + 12);

		if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
Merav Sicron's avatar
Merav Sicron committed
731
			BNX2X_ERR("USTORM_ASSERT_INDEX 0x%x = 0x%08x 0x%08x 0x%08x 0x%08x\n",
732
733
734
735
				  i, row3, row2, row1, row0);
			rc++;
		} else {
			break;
Eliezer Tamir's avatar
Eliezer Tamir committed
736
737
		}
	}
738

Eliezer Tamir's avatar
Eliezer Tamir committed
739
740
	return rc;
}
Eliezer Tamir's avatar
Eliezer Tamir committed
741

742
void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl)
Eliezer Tamir's avatar
Eliezer Tamir committed
743
{
744
	u32 addr, val;
Eliezer Tamir's avatar
Eliezer Tamir committed
745
	u32 mark, offset;
746
	__be32 data[9];
Eliezer Tamir's avatar
Eliezer Tamir committed
747
	int word;
Dmitry Kravkov's avatar
Dmitry Kravkov committed
748
	u32 trace_shmem_base;
749
750
751
752
	if (BP_NOMCP(bp)) {
		BNX2X_ERR("NO MCP - can not dump\n");
		return;
	}
753
754
755
756
757
758
759
	netdev_printk(lvl, bp->dev, "bc %d.%d.%d\n",
		(bp->common.bc_ver & 0xff0000) >> 16,
		(bp->common.bc_ver & 0xff00) >> 8,
		(bp->common.bc_ver & 0xff));

	val = REG_RD(bp, MCP_REG_MCPR_CPU_PROGRAM_COUNTER);
	if (val == REG_RD(bp, MCP_REG_MCPR_CPU_PROGRAM_COUNTER))
Merav Sicron's avatar
Merav Sicron committed
760
		BNX2X_ERR("%s" "MCP PC at 0x%x\n", lvl, val);
Vladislav Zolotarov's avatar
Vladislav Zolotarov committed
761

Dmitry Kravkov's avatar
Dmitry Kravkov committed
762
763
764
765
	if (BP_PATH(bp) == 0)
		trace_shmem_base = bp->common.shmem_base;
	else
		trace_shmem_base = SHMEM2_RD(bp, other_shmem_base_addr);
766
767
768
769
770
771
772
773
774
775
776
	addr = trace_shmem_base - 0x800;

	/* validate TRCB signature */
	mark = REG_RD(bp, addr);
	if (mark != MFW_TRACE_SIGNATURE) {
		BNX2X_ERR("Trace buffer signature is missing.");
		return ;
	}

	/* read cyclic buffer pointer */
	addr += 4;
Vladislav Zolotarov's avatar
Vladislav Zolotarov committed
777
	mark = REG_RD(bp, addr);
Dmitry Kravkov's avatar
Dmitry Kravkov committed
778
779
	mark = (CHIP_IS_E1x(bp) ? MCP_REG_MCPR_SCRATCH : MCP_A_REG_MCPR_SCRATCH)
			+ ((mark + 0x3) & ~0x3) - 0x08000000;
780
	printk("%s" "begin fw dump (mark 0x%x)\n", lvl, mark);
Eliezer Tamir's avatar
Eliezer Tamir committed
781

782
	printk("%s", lvl);
Yuval Mintz's avatar
Yuval Mintz committed
783
784

	/* dump buffer after the mark */
Dmitry Kravkov's avatar
Dmitry Kravkov committed
785
	for (offset = mark; offset <= trace_shmem_base; offset += 0x8*4) {
Eliezer Tamir's avatar
Eliezer Tamir committed
786
		for (word = 0; word < 8; word++)
Vladislav Zolotarov's avatar
Vladislav Zolotarov committed
787
			data[word] = htonl(REG_RD(bp, offset + 4*word));
Eliezer Tamir's avatar
Eliezer Tamir committed
788
		data[8] = 0x0;
789
		pr_cont("%s", (char *)data);
Eliezer Tamir's avatar
Eliezer Tamir committed
790
	}
Yuval Mintz's avatar
Yuval Mintz committed
791
792

	/* dump buffer before the mark */
Vladislav Zolotarov's avatar
Vladislav Zolotarov committed
793
	for (offset = addr + 4; offset <= mark; offset += 0x8*4) {
Eliezer Tamir's avatar
Eliezer Tamir committed
794
		for (word = 0; word < 8; word++)
Vladislav Zolotarov's avatar
Vladislav Zolotarov committed
795
			data[word] = htonl(REG_RD(bp, offset + 4*word));
Eliezer Tamir's avatar
Eliezer Tamir committed
796
		data[8] = 0x0;
797
		pr_cont("%s", (char *)data);
Eliezer Tamir's avatar
Eliezer Tamir committed
798
	}
799
800
801
	printk("%s" "end of fw dump\n", lvl);
}

Eric Dumazet's avatar
Eric Dumazet committed
802
static void bnx2x_fw_dump(struct bnx2x *bp)
803
804
{
	bnx2x_fw_dump_lvl(bp, KERN_ERR);
Eliezer Tamir's avatar
Eliezer Tamir committed
805
806
}

Yuval Mintz's avatar
Yuval Mintz committed
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
static void bnx2x_hc_int_disable(struct bnx2x *bp)
{
	int port = BP_PORT(bp);
	u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
	u32 val = REG_RD(bp, addr);

	/* in E1 we must use only PCI configuration space to disable
	 * MSI/MSIX capablility
	 * It's forbitten to disable IGU_PF_CONF_MSI_MSIX_EN in HC block
	 */
	if (CHIP_IS_E1(bp)) {
		/* Since IGU_PF_CONF_MSI_MSIX_EN still always on
		 * Use mask register to prevent from HC sending interrupts
		 * after we exit the function
		 */
		REG_WR(bp, HC_REG_INT_MASK + port*4, 0);

		val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
			 HC_CONFIG_0_REG_INT_LINE_EN_0 |
			 HC_CONFIG_0_REG_ATTN_BIT_EN_0);
	} else
		val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
			 HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
			 HC_CONFIG_0_REG_INT_LINE_EN_0 |
			 HC_CONFIG_0_REG_ATTN_BIT_EN_0);

	DP(NETIF_MSG_IFDOWN,
	   "write %x to HC %d (addr 0x%x)\n",
	   val, port, addr);

	/* flush all outstanding writes */
	mmiowb();

	REG_WR(bp, addr, val);
	if (REG_RD(bp, addr) != val)
		BNX2X_ERR("BUG! proper val not read from IGU!\n");
}

static void bnx2x_igu_int_disable(struct bnx2x *bp)
{
	u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);

	val &= ~(IGU_PF_CONF_MSI_MSIX_EN |
		 IGU_PF_CONF_INT_LINE_EN |
		 IGU_PF_CONF_ATTN_BIT_EN);

	DP(NETIF_MSG_IFDOWN, "write %x to IGU\n", val);

	/* flush all outstanding writes */
	mmiowb();

	REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
	if (REG_RD(bp, IGU_REG_PF_CONFIGURATION) != val)
		BNX2X_ERR("BUG! proper val not read from IGU!\n");
}

static void bnx2x_int_disable(struct bnx2x *bp)
{
	if (bp->common.int_block == INT_BLOCK_HC)
		bnx2x_hc_int_disable(bp);
	else
		bnx2x_igu_int_disable(bp);
}

void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
Eliezer Tamir's avatar
Eliezer Tamir committed
872
873
{
	int i;
874
875
876
877
878
	u16 j;
	struct hc_sp_status_block_data sp_sb_data;
	int func = BP_FUNC(bp);
#ifdef BNX2X_STOP_ON_ERROR
	u16 start = 0, end = 0;
879
	u8 cos;
880
#endif
Yuval Mintz's avatar
Yuval Mintz committed
881
882
	if (disable_int)
		bnx2x_int_disable(bp);
Eliezer Tamir's avatar
Eliezer Tamir committed
883

Yitchak Gertner's avatar
Yitchak Gertner committed
884
	bp->stats_state = STATS_STATE_DISABLED;
885
	bp->eth_stats.unrecoverable_error++;
Yitchak Gertner's avatar
Yitchak Gertner committed
886
887
	DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n");

Eliezer Tamir's avatar
Eliezer Tamir committed
888
889
	BNX2X_ERR("begin crash dump -----------------\n");

Eilon Greenstein's avatar
Eilon Greenstein committed
890
891
	/* Indices */
	/* Common */
Merav Sicron's avatar
Merav Sicron committed
892
	BNX2X_ERR("def_idx(0x%x)  def_att_idx(0x%x)  attn_state(0x%x)  spq_prod_idx(0x%x) next_stats_cnt(0x%x)\n",
893
894
		  bp->def_idx, bp->def_att_idx, bp->attn_state,
		  bp->spq_prod_idx, bp->stats_counter);
895
896
897
898
899
900
901
902
	BNX2X_ERR("DSB: attn bits(0x%x)  ack(0x%x)  id(0x%x)  idx(0x%x)\n",
		  bp->def_status_blk->atten_status_block.attn_bits,
		  bp->def_status_blk->atten_status_block.attn_bits_ack,
		  bp->def_status_blk->atten_status_block.status_block_id,
		  bp->def_status_blk->atten_status_block.attn_bits_index);
	BNX2X_ERR("     def (");
	for (i = 0; i < HC_SP_SB_MAX_INDICES; i++)
		pr_cont("0x%x%s",
903
904
			bp->def_status_blk->sp_sb.index_values[i],
			(i == HC_SP_SB_MAX_INDICES - 1) ? ")  " : " ");
905
906
907
908
909
910

	for (i = 0; i < sizeof(struct hc_sp_status_block_data)/sizeof(u32); i++)
		*((u32 *)&sp_sb_data + i) = REG_RD(bp, BAR_CSTRORM_INTMEM +
			CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(func) +
			i*sizeof(u32));

911
	pr_cont("igu_sb_id(0x%x)  igu_seg_id(0x%x) pf_id(0x%x)  vnic_id(0x%x)  vf_id(0x%x)  vf_valid (0x%x) state(0x%x)\n",
912
913
914
915
916
	       sp_sb_data.igu_sb_id,
	       sp_sb_data.igu_seg_id,
	       sp_sb_data.p_func.pf_id,
	       sp_sb_data.p_func.vnic_id,
	       sp_sb_data.p_func.vf_id,
917
918
	       sp_sb_data.p_func.vf_valid,
	       sp_sb_data.state);
919

Eilon Greenstein's avatar
Eilon Greenstein committed
920

Vladislav Zolotarov's avatar
Vladislav Zolotarov committed
921
	for_each_eth_queue(bp, i) {
Eliezer Tamir's avatar
Eliezer Tamir committed
922
		struct bnx2x_fastpath *fp = &bp->fp[i];
923
		int loop;
Dmitry Kravkov's avatar
Dmitry Kravkov committed
924
		struct hc_status_block_data_e2 sb_data_e2;
925
926
		struct hc_status_block_data_e1x sb_data_e1x;
		struct hc_status_block_sm  *hc_sm_p =
927
928
929
			CHIP_IS_E1x(bp) ?
			sb_data_e1x.common.state_machine :
			sb_data_e2.common.state_machine;
930
		struct hc_index_data *hc_index_p =
931
932
933
			CHIP_IS_E1x(bp) ?
			sb_data_e1x.index_data :
			sb_data_e2.index_data;
934
		u8 data_size, cos;
935
		u32 *sb_data_p;
936
		struct bnx2x_fp_txdata txdata;
937
938

		/* Rx */
Merav Sicron's avatar
Merav Sicron committed
939
		BNX2X_ERR("fp%d: rx_bd_prod(0x%x)  rx_bd_cons(0x%x)  rx_comp_prod(0x%x)  rx_comp_cons(0x%x)  *rx_cons_sb(0x%x)\n",
Eilon Greenstein's avatar
Eilon Greenstein committed
940
			  i, fp->rx_bd_prod, fp->rx_bd_cons,
941
			  fp->rx_comp_prod,
Yitchak Gertner's avatar
Yitchak Gertner committed
942
			  fp->rx_comp_cons, le16_to_cpu(*fp->rx_cons_sb));
Merav Sicron's avatar
Merav Sicron committed
943
		BNX2X_ERR("     rx_sge_prod(0x%x)  last_max_sge(0x%x)  fp_hc_idx(0x%x)\n",
Eilon Greenstein's avatar
Eilon Greenstein committed
944
			  fp->rx_sge_prod, fp->last_max_sge,
945
			  le16_to_cpu(fp->fp_hc_idx));
Eliezer Tamir's avatar
Eliezer Tamir committed
946

947
		/* Tx */
948
949
		for_each_cos_in_tx_queue(fp, cos)
		{
950
			txdata = *fp->txdata_ptr[cos];
Merav Sicron's avatar
Merav Sicron committed
951
			BNX2X_ERR("fp%d: tx_pkt_prod(0x%x)  tx_pkt_cons(0x%x)  tx_bd_prod(0x%x)  tx_bd_cons(0x%x)  *tx_cons_sb(0x%x)\n",
952
953
954
955
956
				  i, txdata.tx_pkt_prod,
				  txdata.tx_pkt_cons, txdata.tx_bd_prod,
				  txdata.tx_bd_cons,
				  le16_to_cpu(*txdata.tx_cons_sb));
		}
957

958
959
		loop = CHIP_IS_E1x(bp) ?
			HC_SB_MAX_INDICES_E1X : HC_SB_MAX_INDICES_E2;
960
961
962

		/* host sb data */

Vladislav Zolotarov's avatar
Vladislav Zolotarov committed
963
964
		if (IS_FCOE_FP(fp))
			continue;
965

966
967
968
969
970
971
972
973
974
975
976
977
		BNX2X_ERR("     run indexes (");
		for (j = 0; j < HC_SB_MAX_SM; j++)
			pr_cont("0x%x%s",
			       fp->sb_running_index[j],
			       (j == HC_SB_MAX_SM - 1) ? ")" : " ");

		BNX2X_ERR("     indexes (");
		for (j = 0; j < loop; j++)
			pr_cont("0x%x%s",
			       fp->sb_index_values[j],
			       (j == loop - 1) ? ")" : " ");
		/* fw sb data */
978
979
980
		data_size = CHIP_IS_E1x(bp) ?
			sizeof(struct hc_status_block_data_e1x) :
			sizeof(struct hc_status_block_data_e2);
981
		data_size /= sizeof(u32);
982
983
984
		sb_data_p = CHIP_IS_E1x(bp) ?
			(u32 *)&sb_data_e1x :
			(u32 *)&sb_data_e2;
985
986
987
988
989
990
		/* copy sb data in here */
		for (j = 0; j < data_size; j++)
			*(sb_data_p + j) = REG_RD(bp, BAR_CSTRORM_INTMEM +
				CSTORM_STATUS_BLOCK_DATA_OFFSET(fp->fw_sb_id) +
				j * sizeof(u32));

991
		if (!CHIP_IS_E1x(bp)) {
Merav Sicron's avatar
Merav Sicron committed
992
			pr_cont("pf_id(0x%x)  vf_id(0x%x)  vf_valid(0x%x) vnic_id(0x%x)  same_igu_sb_1b(0x%x) state(0x%x)\n",
Dmitry Kravkov's avatar
Dmitry Kravkov committed
993
994
995
996
				sb_data_e2.common.p_func.pf_id,
				sb_data_e2.common.p_func.vf_id,
				sb_data_e2.common.p_func.vf_valid,
				sb_data_e2.common.p_func.vnic_id,
997
998
				sb_data_e2.common.same_igu_sb_1b,
				sb_data_e2.common.state);
Dmitry Kravkov's avatar
Dmitry Kravkov committed
999
		} else {
Merav Sicron's avatar
Merav Sicron committed
1000
			pr_cont("pf_id(0x%x)  vf_id(0x%x)  vf_valid(0x%x) vnic_id(0x%x)  same_igu_sb_1b(0x%x) state(0x%x)\n",
Dmitry Kravkov's avatar
Dmitry Kravkov committed
1001
1002
1003
1004
				sb_data_e1x.common.p_func.pf_id,
				sb_data_e1x.common.p_func.vf_id,
				sb_data_e1x.common.p_func.vf_valid,
				sb_data_e1x.common.p_func.vnic_id,
1005
1006
				sb_data_e1x.common.same_igu_sb_1b,
				sb_data_e1x.common.state);
Dmitry Kravkov's avatar
Dmitry Kravkov committed
1007
		}
1008
1009
1010

		/* SB_SMs data */
		for (j = 0; j < HC_SB_MAX_SM; j++) {
Merav Sicron's avatar
Merav Sicron committed
1011
1012
1013
1014
1015
1016
			pr_cont("SM[%d] __flags (0x%x) igu_sb_id (0x%x)  igu_seg_id(0x%x) time_to_expire (0x%x) timer_value(0x%x)\n",
				j, hc_sm_p[j].__flags,
				hc_sm_p[j].igu_sb_id,
				hc_sm_p[j].igu_seg_id,
				hc_sm_p[j].time_to_expire,
				hc_sm_p[j].timer_value);
1017
1018
1019
1020
		}

		/* Indecies data */
		for (j = 0; j < loop; j++) {
Merav Sicron's avatar
Merav Sicron committed
1021
			pr_cont("INDEX[%d] flags (0x%x) timeout (0x%x)\n", j,
1022
1023
1024
			       hc_index_p[j].flags,
			       hc_index_p[j].timeout);
		}
Eilon Greenstein's avatar
Eilon Greenstein committed
1025
	}
Eliezer Tamir's avatar
Eliezer Tamir committed
1026

1027
#ifdef BNX2X_STOP_ON_ERROR
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038

	/* event queue */
	for (i = 0; i < NUM_EQ_DESC; i++) {
		u32 *data = (u32 *)&bp->eq_ring[i].message.data;

		BNX2X_ERR("event queue [%d]: header: opcode %d, error %d\n",
			  i, bp->eq_ring[i].message.opcode,
			  bp->eq_ring[i].message.error);
		BNX2X_ERR("data: %x %x %x\n", data[0], data[1], data[2]);
	}

Eilon Greenstein's avatar
Eilon Greenstein committed
1039
1040
	/* Rings */
	/* Rx */
1041
	for_each_valid_rx_queue(bp, i) {
Eilon Greenstein's avatar
Eilon Greenstein committed
1042
		struct bnx2x_fastpath *fp = &bp->fp[i];
Eliezer Tamir's avatar
Eliezer Tamir committed
1043
1044
1045

		start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10);
		end = RX_BD(le16_to_cpu(*fp->rx_cons_sb) + 503);
Eilon Greenstein's avatar
Eilon Greenstein committed
1046
		for (j = start; j != end; j = RX_BD(j + 1)) {
Eliezer Tamir's avatar
Eliezer Tamir committed
1047
1048
1049
			u32 *rx_bd = (u32 *)&fp->rx_desc_ring[j];
			struct sw_rx_bd *sw_bd = &fp->rx_buf_ring[j];

Eilon Greenstein's avatar
Eilon Greenstein committed
1050
			BNX2X_ERR("fp%d: rx_bd[%x]=[%x:%x]  sw_bd=[%p]\n",
1051
				  i, j, rx_bd[1], rx_bd[0], sw_bd->data);
Eliezer Tamir's avatar
Eliezer Tamir committed
1052
1053
		}

1054
1055
		start = RX_SGE(fp->rx_sge_prod);
		end = RX_SGE(fp->last_max_sge);
Eilon Greenstein's avatar
Eilon Greenstein committed
1056
		for (j = start; j != end; j = RX_SGE(j + 1)) {
1057
1058
1059
			u32 *rx_sge = (u32 *)&fp->rx_sge_ring[j];
			struct sw_rx_page *sw_page = &fp->rx_page_ring[j];

Eilon Greenstein's avatar
Eilon Greenstein committed
1060
1061
			BNX2X_ERR("fp%d: rx_sge[%x]=[%x:%x]  sw_page=[%p]\n",
				  i, j, rx_sge[1], rx_sge[0], sw_page->page);
1062
1063
		}

Eliezer Tamir's avatar
Eliezer Tamir committed
1064
1065
		start = RCQ_BD(fp->rx_comp_cons - 10);
		end = RCQ_BD(fp->rx_comp_cons + 503);
Eilon Greenstein's avatar
Eilon Greenstein committed
1066
		for (j = start; j != end; j = RCQ_BD(j + 1)) {
Eliezer Tamir's avatar
Eliezer Tamir committed
1067
1068
			u32 *cqe = (u32 *)&fp->rx_comp_ring[j];

Eilon Greenstein's avatar
Eilon Greenstein committed
1069
1070
			BNX2X_ERR("fp%d: cqe[%x]=[%x:%x:%x:%x]\n",
				  i, j, cqe[0], cqe[1], cqe[2], cqe[3]);
Eliezer Tamir's avatar
Eliezer Tamir committed
1071
1072
1073
		}
	}

Eilon Greenstein's avatar
Eilon Greenstein committed
1074
	/* Tx */
1075
	for_each_valid_tx_queue(bp, i) {
Eilon Greenstein's avatar
Eilon Greenstein committed
1076
		struct bnx2x_fastpath *fp = &bp->fp[i];
1077
		for_each_cos_in_tx_queue(fp, cos) {
1078
			struct bnx2x_fp_txdata *txdata = fp->txdata_ptr[cos];
1079
1080
1081
1082
1083
1084
1085

			start = TX_BD(le16_to_cpu(*txdata->tx_cons_sb) - 10);
			end = TX_BD(le16_to_cpu(*txdata->tx_cons_sb) + 245);
			for (j = start; j != end; j = TX_BD(j + 1)) {
				struct sw_tx_bd *sw_bd =
					&txdata->tx_buf_ring[j];

Merav Sicron's avatar
Merav Sicron committed
1086
				BNX2X_ERR("fp%d: txdata %d, packet[%x]=[%p,%x]\n",
1087
1088
1089
					  i, cos, j, sw_bd->skb,
					  sw_bd->first_bd);
			}
Eilon Greenstein's avatar
Eilon Greenstein committed
1090

1091
1092
1093
1094
			start = TX_BD(txdata->tx_bd_cons - 10);
			end = TX_BD(txdata->tx_bd_cons + 254);
			for (j = start; j != end; j = TX_BD(j + 1)) {
				u32 *tx_bd = (u32 *)&txdata->tx_desc_ring[j];
Eilon Greenstein's avatar
Eilon Greenstein committed
1095

Merav Sicron's avatar
Merav Sicron committed
1096
				BNX2X_ERR("fp%d: txdata %d, tx_bd[%x]=[%x:%x:%x:%x]\n",
1097
1098
1099
					  i, cos, j, tx_bd[0], tx_bd[1],
					  tx_bd[2], tx_bd[3]);
			}
Eilon Greenstein's avatar
Eilon Greenstein committed
1100
1101
		}
	}
1102
#endif
1103
	bnx2x_fw_dump(bp);
Eliezer Tamir's avatar
Eliezer Tamir committed
1104
1105
1106
1107
	bnx2x_mc_assert(bp);
	BNX2X_ERR("end crash dump -----------------\n");
}

1108
1109
1110
1111
1112
1113
1114
/*
 * FLR Support for E2
 *
 * bnx2x_pf_flr_clnup() is called during nic_load in the per function HW
 * initialization.
 */
#define FLR_WAIT_USEC		10000	/* 10 miliseconds */
1115
1116
#define FLR_WAIT_INTERVAL	50	/* usec */
#define	FLR_POLL_CNT		(FLR_WAIT_USEC/FLR_WAIT_INTERVAL) /* 200 */
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148

struct pbf_pN_buf_regs {
	int pN;
	u32 init_crd;
	u32 crd;
	u32 crd_freed;
};

struct pbf_pN_cmd_regs {
	int pN;
	u32 lines_occup;
	u32 lines_freed;
};

static void bnx2x_pbf_pN_buf_flushed(struct bnx2x *bp,
				     struct pbf_pN_buf_regs *regs,
				     u32 poll_count)
{
	u32 init_crd, crd, crd_start, crd_freed, crd_freed_start;
	u32 cur_cnt = poll_count;

	crd_freed = crd_freed_start = REG_RD(bp, regs->crd_freed);
	crd = crd_start = REG_RD(bp, regs->crd);
	init_crd = REG_RD(bp, regs->init_crd);

	DP(BNX2X_MSG_SP, "INIT CREDIT[%d] : %x\n", regs->pN, init_crd);
	DP(BNX2X_MSG_SP, "CREDIT[%d]      : s:%x\n", regs->pN, crd);
	DP(BNX2X_MSG_SP, "CREDIT_FREED[%d]: s:%x\n", regs->pN, crd_freed);

	while ((crd != init_crd) && ((u32)SUB_S32(crd_freed, crd_freed_start) <
	       (init_crd - crd_start))) {
		if (cur_cnt--) {
1149
			udelay(FLR_WAIT_INTERVAL);
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
			crd = REG_RD(bp, regs->crd);
			crd_freed = REG_RD(bp, regs->crd_freed);
		} else {
			DP(BNX2X_MSG_SP, "PBF tx buffer[%d] timed out\n",
			   regs->pN);
			DP(BNX2X_MSG_SP, "CREDIT[%d]      : c:%x\n",
			   regs->pN, crd);
			DP(BNX2X_MSG_SP, "CREDIT_FREED[%d]: c:%x\n",
			   regs->pN, crd_freed);
			break;
		}
	}
	DP(BNX2X_MSG_SP, "Waited %d*%d usec for PBF tx buffer[%d]\n",
1163
	   poll_count-cur_cnt, FLR_WAIT_INTERVAL, regs->pN);
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
}

static void bnx2x_pbf_pN_cmd_flushed(struct bnx2x *bp,
				     struct pbf_pN_cmd_regs *regs,
				     u32 poll_count)
{
	u32 occup, to_free, freed, freed_start;
	u32 cur_cnt = poll_count;

	occup = to_free = REG_RD(bp, regs->lines_occup);
	freed = freed_start = REG_RD(bp, regs->lines_freed);

	DP(BNX2X_MSG_SP, "OCCUPANCY[%d]   : s:%x\n", regs->pN, occup);
	DP(BNX2X_MSG_SP, "LINES_FREED[%d] : s:%x\n", regs->pN, freed);

	while (occup && ((u32)SUB_S32(freed, freed_start) < to_free)) {
		if (cur_cnt--) {
1181
			udelay(FLR_WAIT_INTERVAL);
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
			occup = REG_RD(bp, regs->lines_occup);
			freed = REG_RD(bp, regs->lines_freed);
		} else {
			DP(BNX2X_MSG_SP, "PBF cmd queue[%d] timed out\n",
			   regs->pN);
			DP(BNX2X_MSG_SP, "OCCUPANCY[%d]   : s:%x\n",
			   regs->pN, occup);
			DP(BNX2X_MSG_SP, "LINES_FREED[%d] : s:%x\n",
			   regs->pN, freed);
			break;
		}
	}
	DP(BNX2X_MSG_SP, "Waited %d*%d usec for PBF cmd queue[%d]\n",
1195
	   poll_count-cur_cnt, FLR_WAIT_INTERVAL, regs->pN);
1196
1197
}

Eric Dumazet's avatar
Eric Dumazet committed
1198
1199
static u32 bnx2x_flr_clnup_reg_poll(struct bnx2x *bp, u32 reg,
				    u32 expected, u32 poll_count)
1200
1201
1202
1203
1204
{
	u32 cur_cnt = poll_count;
	u32 val;

	while ((val = REG_RD(bp, reg)) != expected && cur_cnt--)
1205
		udelay(FLR_WAIT_INTERVAL);
1206
1207
1208
1209

	return val;
}

Ariel Elior's avatar
Ariel Elior committed
1210
1211
int bnx2x_flr_clnup_poll_hw_counter(struct bnx2x *bp, u32 reg,
				    char *msg, u32 poll_cnt)
1212
1213
1214
1215
1216
1217
1218
1219
1220
{
	u32 val = bnx2x_flr_clnup_reg_poll(bp, reg, 0, poll_cnt);
	if (val != 0) {
		BNX2X_ERR("%s usage count=%d\n", msg, val);
		return 1;
	}
	return 0;
}

Ariel Elior's avatar
Ariel Elior committed
1221
1222
/* Common routines with VF FLR cleanup */
u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp)
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
{
	/* adjust polling timeout */
	if (CHIP_REV_IS_EMUL(bp))
		return FLR_POLL_CNT * 2000;

	if (CHIP_REV_IS_FPGA(bp))
		return FLR_POLL_CNT * 120;

	return FLR_POLL_CNT;
}

Ariel Elior's avatar
Ariel Elior committed
1234
void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count)
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
{
	struct pbf_pN_cmd_regs cmd_regs[] = {
		{0, (CHIP_IS_E3B0(bp)) ?
			PBF_REG_TQ_OCCUPANCY_Q0 :
			PBF_REG_P0_TQ_OCCUPANCY,
		    (CHIP_IS_E3B0(bp)) ?
			PBF_REG_TQ_LINES_FREED_CNT_Q0 :
			PBF_REG_P0_TQ_LINES_FREED_CNT},
		{1, (CHIP_IS_E3B0(bp)) ?
			PBF_REG_TQ_OCCUPANCY_Q1 :
			PBF_REG_P1_TQ_OCCUPANCY,
		    (CHIP_IS_E3B0(bp)) ?
			PBF_REG_TQ_LINES_FREED_CNT_Q1 :
			PBF_REG_P1_TQ_LINES_FREED_CNT},
		{4, (CHIP_IS_E3B0(bp)) ?
			PBF_REG_TQ_OCCUPANCY_LB_Q :
			PBF_REG_P4_TQ_OCCUPANCY,
		    (CHIP_IS_E3B0(bp)) ?
			PBF_REG_TQ_LINES_FREED_CNT_LB_Q :
			PBF_REG_P4_TQ_LINES_FREED_CNT}
	};

	struct pbf_pN_buf_regs buf_regs[] = {
		{0, (CHIP_IS_E3B0(bp)) ?
			PBF_REG_INIT_CRD_Q0 :
			PBF_REG_P0_INIT_CRD ,
		    (CHIP_IS_E3B0(bp)) ?
			PBF_REG_CREDIT_Q0 :
			PBF_REG_P0_CREDIT,
		    (CHIP_IS_E3B0(bp)) ?
			PBF_REG_INTERNAL_CRD_FREED_CNT_Q0 :
			PBF_REG_P0_INTERNAL_CRD_FREED_CNT},
		{1, (CHIP_IS_E3B0(bp)) ?
			PBF_REG_INIT_CRD_Q1 :
			PBF_REG_P1_INIT_CRD,
		    (CHIP_IS_E3B0(bp)) ?
			PBF_REG_CREDIT_Q1 :
			PBF_REG_P1_CREDIT,
		    (CHIP_IS_E3B0(bp)) ?
			PBF_REG_INTERNAL_CRD_FREED_CNT_Q1 :
			PBF_REG_P1_INTERNAL_CRD_FREED_CNT},
		{4, (CHIP_IS_E3B0(bp)) ?
			PBF_REG_INIT_CRD_LB_Q :
			PBF_REG_P4_INIT_CRD,
		    (CHIP_IS_E3B0(bp)) ?
			PBF_REG_CREDIT_LB_Q :
			PBF_REG_P4_CREDIT,
		    (CHIP_IS_E3B0(bp)) ?
			PBF_REG_INTERNAL_CRD_FREED_CNT_LB_Q :
			PBF_REG_P4_INTERNAL_CRD_FREED_CNT},
	};

	int i;

	/* Verify the command queues are flushed P0, P1, P4 */
	for (i = 0; i < ARRAY_SIZE(cmd_regs); i++)
		bnx2x_pbf_pN_cmd_flushed(bp, &cmd_regs[i], poll_count);


	/* Verify the transmission buffers are flushed P0, P1, P4 */
	for (i = 0; i < ARRAY_SIZE(buf_regs); i++)
		bnx2x_pbf_pN_buf_flushed(bp, &buf_regs[i], poll_count);
}

#define OP_GEN_PARAM(param) \
	(((param) << SDM_OP_GEN_COMP_PARAM_SHIFT) & SDM_OP_GEN_COMP_PARAM)

#define OP_GEN_TYPE(type) \
	(((type) << SDM_OP_GEN_COMP_TYPE_SHIFT) & SDM_OP_GEN_COMP_TYPE)

#define OP_GEN_AGG_VECT(index) \
	(((index) << SDM_OP_GEN_AGG_VECT_IDX_SHIFT) & SDM_OP_GEN_AGG_VECT_IDX)


Ariel Elior's avatar
Ariel Elior committed
1309
int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func, u32 poll_cnt)
1310
{
1311
	u32 op_gen_command = 0;
1312
1313
1314
1315
1316
1317

	u32 comp_addr = BAR_CSTRORM_INTMEM +
			CSTORM_FINAL_CLEANUP_COMPLETE_OFFSET(clnup_func);
	int ret = 0;

	if (REG_RD(bp, comp_addr)) {
1318
		BNX2X_ERR("Cleanup complete was not 0 before sending\n");
1319
1320
1321
		return 1;
	}

1322
1323
1324
1325
	op_gen_command |= OP_GEN_PARAM(XSTORM_AGG_INT_FINAL_CLEANUP_INDEX);
	op_gen_command |= OP_GEN_TYPE(XSTORM_AGG_INT_FINAL_CLEANUP_COMP_TYPE);
	op_gen_command |= OP_GEN_AGG_VECT(clnup_func);
	op_gen_command |= 1 << SDM_OP_GEN_AGG_VECT_IDX_VALID_SHIFT;
1326

1327
	DP(BNX2X_MSG_SP, "sending FW Final cleanup\n");
1328
	REG_WR(bp, XSDM_REG_OPERATION_GEN, op_gen_command);
1329
1330
1331

	if (bnx2x_flr_clnup_reg_poll(bp, comp_addr, 1, poll_cnt) != 1) {
		BNX2X_ERR("FW final cleanup did not succeed\n");
Merav Sicron's avatar
Merav Sicron committed
1332
1333
		DP(BNX2X_MSG_SP, "At timeout completion address contained %x\n",
		   (REG_RD(bp, comp_addr)));
Ariel Elior's avatar
Ariel Elior committed
1334
1335
		bnx2x_panic();
		return 1;
1336
1337
1338
1339
1340
1341
1342
	}
	/* Zero completion for nxt FLR */
	REG_WR(bp, comp_addr, 0);

	return ret;
}

1343
u8 bnx2x_is_pcie_pending(struct pci_dev *dev)
1344
1345
1346
{
	u16 status;

1347
	pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
	return status & PCI_EXP_DEVSTA_TRPND;
}

/* PF FLR specific routines
*/
static int bnx2x_poll_hw_usage_counters(struct bnx2x *bp, u32 poll_cnt)
{

	/* wait for CFC PF usage-counter to zero (includes all the VFs) */
	if (bnx2x_flr_clnup_poll_hw_counter(bp,
			CFC_REG_NUM_LCIDS_INSIDE_PF,
			"CFC PF usage counter timed out",
			poll_cnt))
		return 1;


	/* Wait for DQ PF usage-counter to zero (until DQ cleanup) */
	if (bnx2x_flr_clnup_poll_hw_counter(bp,
			DORQ_REG_PF_USAGE_CNT,
			"DQ PF usage counter timed out",
			poll_cnt))
		return 1;

	/* Wait for QM PF usage-counter to zero (until DQ cleanup) */
	if (bnx2x_flr_clnup_poll_hw_counter(bp,
			QM_REG_PF_USG_CNT_0 + 4*BP_FUNC(bp),
			"QM PF usage counter timed out",
			poll_cnt))
		return 1;

	/* Wait for Timer PF usage-counters to zero (until DQ cleanup) */
	if (bnx2x_flr_clnup_poll_hw_counter(bp,
			TM_REG_LIN0_VNIC_UC + 4*BP_PORT(bp),
			"Timers VNIC usage counter timed out",
			poll_cnt))
		return 1;
	if (bnx2x_flr_clnup_poll_hw_counter(bp,
			TM_REG_LIN0_NUM_SCANS + 4*BP_PORT(bp),
			"Timers NUM_SCANS usage counter timed out",
			poll_cnt))
		return 1;

	/* Wait DMAE PF usage counter to zero */
	if (bnx2x_flr_clnup_poll_hw_counter(bp,
			dmae_reg_go_c[INIT_DMAE_C(bp)],
			"DMAE dommand register timed out",
			poll_cnt))
		return 1;

	return 0;
}

static void bnx2x_hw_enable_status(struct bnx2x *bp)
{
	u32 val;

	val = REG_RD(bp, CFC_REG_WEAK_ENABLE_PF);
	DP(BNX2X_MSG_SP, "CFC_REG_WEAK_ENABLE_PF is 0x%x\n", val);

	val = REG_RD(bp, PBF_REG_DISABLE_PF);
	DP(BNX2X_MSG_SP, "PBF_REG_DISABLE_PF is 0x%x\n", val);

	val = REG_RD(bp, IGU_REG_PCI_PF_MSI_EN);
	DP(BNX2X_MSG_SP, "IGU_REG_PCI_PF_MSI_EN is 0x%x\n", val);

	val = REG_RD(bp, IGU_REG_PCI_PF_MSIX_EN);
	DP(BNX2X_MSG_SP, "IGU_REG_PCI_PF_MSIX_EN is 0x%x\n", val);

	val = REG_RD(bp, IGU_REG_PCI_PF_MSIX_FUNC_MASK);
	DP(BNX2X_MSG_SP, "IGU_REG_PCI_PF_MSIX_FUNC_MASK is 0x%x\n", val);

	val = REG_RD(bp, PGLUE_B_REG_SHADOW_BME_PF_7_0_CLR);
	DP(BNX2X_MSG_SP, "PGLUE_B_REG_SHADOW_BME_PF_7_0_CLR is 0x%x\n", val);

	val = REG_RD(bp, PGLUE_B_REG_FLR_REQUEST_PF_7_0_CLR);
	DP(BNX2X_MSG_SP, "PGLUE_B_REG_FLR_REQUEST_PF_7_0_CLR is 0x%x\n", val);

	val = REG_RD(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER);
	DP(BNX2X_MSG_SP, "PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER is 0x%x\n",
	   val);
}

static int bnx2x_pf_flr_clnup(struct bnx2x *bp)
{
	u32 poll_cnt = bnx2x_flr_clnup_poll_count(bp);

	DP(BNX2X_MSG_SP, "Cleanup after FLR PF[%d]\n", BP_ABS_FUNC(bp));

	/* Re-enable PF target read access */
	REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);

	/* Poll HW usage counters */
1440
	DP(BNX2X_MSG_SP, "Polling usage counters\n");
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
	if (bnx2x_poll_hw_usage_counters(bp, poll_cnt))
		return -EBUSY;

	/* Zero the igu 'trailing edge' and 'leading edge' */

	/* Send the FW cleanup command */
	if (bnx2x_send_final_clnup(bp, (u8)BP_FUNC(bp), poll_cnt))
		return -EBUSY;

	/* ATC cleanup */

	/* Verify TX hw is flushed */
	bnx2x_tx_hw_flushed(bp, poll_cnt);

	/* Wait 100ms (not adjusted according to platform) */
	msleep(100);

	/* Verify no pending pci transactions */
	if (bnx2x_is_pcie_pending(bp->pdev))
		BNX2X_ERR("PCIE Transactions still pending\n");

	/* Debug */
	bnx2x_hw_enable_status(bp);