xref: /openbmc/linux/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c (revision ea68a3e9d14e9e0bf017d178fb4bd53b6deb1482)
1004b26b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2577ae39dSJitendra Kalsaria /*
3577ae39dSJitendra Kalsaria  * QLogic qlcnic NIC Driver
4577ae39dSJitendra Kalsaria  * Copyright (c) 2009-2013 QLogic Corporation
5577ae39dSJitendra Kalsaria  */
6577ae39dSJitendra Kalsaria 
7f8468331SRajesh Borundia #include "qlcnic_sriov.h"
8629263acSSony Chacko #include "qlcnic.h"
9629263acSSony Chacko #include "qlcnic_hw.h"
10629263acSSony Chacko 
1181d0aeb0SSony Chacko /* Reset template definitions */
1281d0aeb0SSony Chacko #define QLC_83XX_RESTART_TEMPLATE_SIZE		0x2000
1381d0aeb0SSony Chacko #define QLC_83XX_RESET_TEMPLATE_ADDR		0x4F0000
1481d0aeb0SSony Chacko #define QLC_83XX_RESET_SEQ_VERSION		0x0101
1581d0aeb0SSony Chacko 
1681d0aeb0SSony Chacko #define QLC_83XX_OPCODE_NOP			0x0000
1781d0aeb0SSony Chacko #define QLC_83XX_OPCODE_WRITE_LIST		0x0001
1881d0aeb0SSony Chacko #define QLC_83XX_OPCODE_READ_WRITE_LIST		0x0002
1981d0aeb0SSony Chacko #define QLC_83XX_OPCODE_POLL_LIST		0x0004
2081d0aeb0SSony Chacko #define QLC_83XX_OPCODE_POLL_WRITE_LIST		0x0008
2181d0aeb0SSony Chacko #define QLC_83XX_OPCODE_READ_MODIFY_WRITE	0x0010
2281d0aeb0SSony Chacko #define QLC_83XX_OPCODE_SEQ_PAUSE		0x0020
2381d0aeb0SSony Chacko #define QLC_83XX_OPCODE_SEQ_END			0x0040
2481d0aeb0SSony Chacko #define QLC_83XX_OPCODE_TMPL_END		0x0080
2581d0aeb0SSony Chacko #define QLC_83XX_OPCODE_POLL_READ_LIST		0x0100
2681d0aeb0SSony Chacko 
27c0d79cd0SManish Chopra /* EPORT control registers */
28c0d79cd0SManish Chopra #define QLC_83XX_RESET_CONTROL			0x28084E50
29c0d79cd0SManish Chopra #define QLC_83XX_RESET_REG			0x28084E60
30c0d79cd0SManish Chopra #define QLC_83XX_RESET_PORT0			0x28084E70
31c0d79cd0SManish Chopra #define QLC_83XX_RESET_PORT1			0x28084E80
32c0d79cd0SManish Chopra #define QLC_83XX_RESET_PORT2			0x28084E90
33c0d79cd0SManish Chopra #define QLC_83XX_RESET_PORT3			0x28084EA0
34c0d79cd0SManish Chopra #define QLC_83XX_RESET_SRESHIM			0x28084EB0
35c0d79cd0SManish Chopra #define QLC_83XX_RESET_EPGSHIM			0x28084EC0
36c0d79cd0SManish Chopra #define QLC_83XX_RESET_ETHERPCS			0x28084ED0
37c0d79cd0SManish Chopra 
38629263acSSony Chacko static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter);
39629263acSSony Chacko static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev);
40629263acSSony Chacko static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter);
4121041400Sstephen hemminger static int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev);
4221041400Sstephen hemminger static int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *);
4321041400Sstephen hemminger static void qlcnic_83xx_stop_hw(struct qlcnic_adapter *);
44629263acSSony Chacko 
4581d0aeb0SSony Chacko /* Template header */
4681d0aeb0SSony Chacko struct qlc_83xx_reset_hdr {
47a96227e6SShahed Shaikh #if defined(__LITTLE_ENDIAN)
4881d0aeb0SSony Chacko 	u16	version;
4981d0aeb0SSony Chacko 	u16	signature;
5081d0aeb0SSony Chacko 	u16	size;
5181d0aeb0SSony Chacko 	u16	entries;
5281d0aeb0SSony Chacko 	u16	hdr_size;
5381d0aeb0SSony Chacko 	u16	checksum;
5481d0aeb0SSony Chacko 	u16	init_offset;
5581d0aeb0SSony Chacko 	u16	start_offset;
56a96227e6SShahed Shaikh #elif defined(__BIG_ENDIAN)
57a96227e6SShahed Shaikh 	u16	signature;
58a96227e6SShahed Shaikh 	u16	version;
59a96227e6SShahed Shaikh 	u16	entries;
60a96227e6SShahed Shaikh 	u16	size;
61a96227e6SShahed Shaikh 	u16	checksum;
62a96227e6SShahed Shaikh 	u16	hdr_size;
63a96227e6SShahed Shaikh 	u16	start_offset;
64a96227e6SShahed Shaikh 	u16	init_offset;
65a96227e6SShahed Shaikh #endif
6681d0aeb0SSony Chacko } __packed;
6781d0aeb0SSony Chacko 
6881d0aeb0SSony Chacko /* Command entry header. */
6981d0aeb0SSony Chacko struct qlc_83xx_entry_hdr {
70a96227e6SShahed Shaikh #if defined(__LITTLE_ENDIAN)
7181d0aeb0SSony Chacko 	u16	cmd;
7281d0aeb0SSony Chacko 	u16	size;
7381d0aeb0SSony Chacko 	u16	count;
7481d0aeb0SSony Chacko 	u16	delay;
75a96227e6SShahed Shaikh #elif defined(__BIG_ENDIAN)
76a96227e6SShahed Shaikh 	u16	size;
77a96227e6SShahed Shaikh 	u16	cmd;
78a96227e6SShahed Shaikh 	u16	delay;
79a96227e6SShahed Shaikh 	u16	count;
80a96227e6SShahed Shaikh #endif
8181d0aeb0SSony Chacko } __packed;
8281d0aeb0SSony Chacko 
8381d0aeb0SSony Chacko /* Generic poll command */
8481d0aeb0SSony Chacko struct qlc_83xx_poll {
8581d0aeb0SSony Chacko 	u32	mask;
8681d0aeb0SSony Chacko 	u32	status;
8781d0aeb0SSony Chacko } __packed;
8881d0aeb0SSony Chacko 
8981d0aeb0SSony Chacko /* Read modify write command */
9081d0aeb0SSony Chacko struct qlc_83xx_rmw {
9181d0aeb0SSony Chacko 	u32	mask;
9281d0aeb0SSony Chacko 	u32	xor_value;
9381d0aeb0SSony Chacko 	u32	or_value;
94a96227e6SShahed Shaikh #if defined(__LITTLE_ENDIAN)
9581d0aeb0SSony Chacko 	u8	shl;
9681d0aeb0SSony Chacko 	u8	shr;
9781d0aeb0SSony Chacko 	u8	index_a;
9881d0aeb0SSony Chacko 	u8	rsvd;
99a96227e6SShahed Shaikh #elif defined(__BIG_ENDIAN)
100a96227e6SShahed Shaikh 	u8	rsvd;
101a96227e6SShahed Shaikh 	u8	index_a;
102a96227e6SShahed Shaikh 	u8	shr;
103a96227e6SShahed Shaikh 	u8	shl;
104a96227e6SShahed Shaikh #endif
10581d0aeb0SSony Chacko } __packed;
10681d0aeb0SSony Chacko 
10781d0aeb0SSony Chacko /* Generic command with 2 DWORD */
10881d0aeb0SSony Chacko struct qlc_83xx_entry {
10981d0aeb0SSony Chacko 	u32 arg1;
11081d0aeb0SSony Chacko 	u32 arg2;
11181d0aeb0SSony Chacko } __packed;
11281d0aeb0SSony Chacko 
11381d0aeb0SSony Chacko /* Generic command with 4 DWORD */
11481d0aeb0SSony Chacko struct qlc_83xx_quad_entry {
11581d0aeb0SSony Chacko 	u32 dr_addr;
11681d0aeb0SSony Chacko 	u32 dr_value;
11781d0aeb0SSony Chacko 	u32 ar_addr;
11881d0aeb0SSony Chacko 	u32 ar_value;
11981d0aeb0SSony Chacko } __packed;
120629263acSSony Chacko static const char *const qlc_83xx_idc_states[] = {
121629263acSSony Chacko 	"Unknown",
122629263acSSony Chacko 	"Cold",
123629263acSSony Chacko 	"Init",
124629263acSSony Chacko 	"Ready",
125629263acSSony Chacko 	"Need Reset",
126629263acSSony Chacko 	"Need Quiesce",
127629263acSSony Chacko 	"Failed",
128629263acSSony Chacko 	"Quiesce"
129629263acSSony Chacko };
130629263acSSony Chacko 
131629263acSSony Chacko static int
qlcnic_83xx_idc_check_driver_presence_reg(struct qlcnic_adapter * adapter)132629263acSSony Chacko qlcnic_83xx_idc_check_driver_presence_reg(struct qlcnic_adapter *adapter)
133629263acSSony Chacko {
134629263acSSony Chacko 	u32 val;
135629263acSSony Chacko 
136629263acSSony Chacko 	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
137629263acSSony Chacko 	if ((val & 0xFFFF))
138629263acSSony Chacko 		return 1;
139629263acSSony Chacko 	else
140629263acSSony Chacko 		return 0;
141629263acSSony Chacko }
142629263acSSony Chacko 
qlcnic_83xx_idc_log_state_history(struct qlcnic_adapter * adapter)143629263acSSony Chacko static void qlcnic_83xx_idc_log_state_history(struct qlcnic_adapter *adapter)
144629263acSSony Chacko {
145629263acSSony Chacko 	u32 cur, prev;
146629263acSSony Chacko 	cur = adapter->ahw->idc.curr_state;
147629263acSSony Chacko 	prev = adapter->ahw->idc.prev_state;
148629263acSSony Chacko 
149629263acSSony Chacko 	dev_info(&adapter->pdev->dev,
150629263acSSony Chacko 		 "current state  = %s,  prev state = %s\n",
151629263acSSony Chacko 		 adapter->ahw->idc.name[cur],
152629263acSSony Chacko 		 adapter->ahw->idc.name[prev]);
153629263acSSony Chacko }
154629263acSSony Chacko 
qlcnic_83xx_idc_update_audit_reg(struct qlcnic_adapter * adapter,u8 mode,int lock)155629263acSSony Chacko static int qlcnic_83xx_idc_update_audit_reg(struct qlcnic_adapter *adapter,
156629263acSSony Chacko 					    u8 mode, int lock)
157629263acSSony Chacko {
158629263acSSony Chacko 	u32 val;
159629263acSSony Chacko 	int seconds;
160629263acSSony Chacko 
161629263acSSony Chacko 	if (lock) {
162629263acSSony Chacko 		if (qlcnic_83xx_lock_driver(adapter))
163629263acSSony Chacko 			return -EBUSY;
164629263acSSony Chacko 	}
165629263acSSony Chacko 
166f036e4f4SRajesh Borundia 	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_AUDIT);
167f036e4f4SRajesh Borundia 	val |= (adapter->portnum & 0xf);
168629263acSSony Chacko 	val |= mode << 7;
169629263acSSony Chacko 	if (mode)
170629263acSSony Chacko 		seconds = jiffies / HZ - adapter->ahw->idc.sec_counter;
171629263acSSony Chacko 	else
172629263acSSony Chacko 		seconds = jiffies / HZ;
173629263acSSony Chacko 
174629263acSSony Chacko 	val |= seconds << 8;
175629263acSSony Chacko 	QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_AUDIT, val);
176629263acSSony Chacko 	adapter->ahw->idc.sec_counter = jiffies / HZ;
177629263acSSony Chacko 
178629263acSSony Chacko 	if (lock)
179629263acSSony Chacko 		qlcnic_83xx_unlock_driver(adapter);
180629263acSSony Chacko 
181629263acSSony Chacko 	return 0;
182629263acSSony Chacko }
183629263acSSony Chacko 
qlcnic_83xx_idc_update_minor_version(struct qlcnic_adapter * adapter)184629263acSSony Chacko static void qlcnic_83xx_idc_update_minor_version(struct qlcnic_adapter *adapter)
185629263acSSony Chacko {
186629263acSSony Chacko 	u32 val;
187629263acSSony Chacko 
188629263acSSony Chacko 	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_MIN_VERSION);
189629263acSSony Chacko 	val = val & ~(0x3 << (adapter->portnum * 2));
190629263acSSony Chacko 	val = val | (QLC_83XX_IDC_MINOR_VERSION << (adapter->portnum * 2));
191629263acSSony Chacko 	QLCWRX(adapter->ahw, QLC_83XX_IDC_MIN_VERSION, val);
192629263acSSony Chacko }
193629263acSSony Chacko 
qlcnic_83xx_idc_update_major_version(struct qlcnic_adapter * adapter,int lock)194629263acSSony Chacko static int qlcnic_83xx_idc_update_major_version(struct qlcnic_adapter *adapter,
195629263acSSony Chacko 						int lock)
196629263acSSony Chacko {
197629263acSSony Chacko 	u32 val;
198629263acSSony Chacko 
199629263acSSony Chacko 	if (lock) {
200629263acSSony Chacko 		if (qlcnic_83xx_lock_driver(adapter))
201629263acSSony Chacko 			return -EBUSY;
202629263acSSony Chacko 	}
203629263acSSony Chacko 
204629263acSSony Chacko 	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_MAJ_VERSION);
205629263acSSony Chacko 	val = val & ~0xFF;
206629263acSSony Chacko 	val = val | QLC_83XX_IDC_MAJOR_VERSION;
207629263acSSony Chacko 	QLCWRX(adapter->ahw, QLC_83XX_IDC_MAJ_VERSION, val);
208629263acSSony Chacko 
209629263acSSony Chacko 	if (lock)
210629263acSSony Chacko 		qlcnic_83xx_unlock_driver(adapter);
211629263acSSony Chacko 
212629263acSSony Chacko 	return 0;
213629263acSSony Chacko }
214629263acSSony Chacko 
215629263acSSony Chacko static int
qlcnic_83xx_idc_update_drv_presence_reg(struct qlcnic_adapter * adapter,int status,int lock)216629263acSSony Chacko qlcnic_83xx_idc_update_drv_presence_reg(struct qlcnic_adapter *adapter,
217629263acSSony Chacko 					int status, int lock)
218629263acSSony Chacko {
219629263acSSony Chacko 	u32 val;
220629263acSSony Chacko 
221629263acSSony Chacko 	if (lock) {
222629263acSSony Chacko 		if (qlcnic_83xx_lock_driver(adapter))
223629263acSSony Chacko 			return -EBUSY;
224629263acSSony Chacko 	}
225629263acSSony Chacko 
226629263acSSony Chacko 	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
227629263acSSony Chacko 
228629263acSSony Chacko 	if (status)
229629263acSSony Chacko 		val = val | (1 << adapter->portnum);
230629263acSSony Chacko 	else
231629263acSSony Chacko 		val = val & ~(1 << adapter->portnum);
232629263acSSony Chacko 
233629263acSSony Chacko 	QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE, val);
234629263acSSony Chacko 	qlcnic_83xx_idc_update_minor_version(adapter);
235629263acSSony Chacko 
236629263acSSony Chacko 	if (lock)
237629263acSSony Chacko 		qlcnic_83xx_unlock_driver(adapter);
238629263acSSony Chacko 
239629263acSSony Chacko 	return 0;
240629263acSSony Chacko }
241629263acSSony Chacko 
qlcnic_83xx_idc_check_major_version(struct qlcnic_adapter * adapter)242629263acSSony Chacko static int qlcnic_83xx_idc_check_major_version(struct qlcnic_adapter *adapter)
243629263acSSony Chacko {
244629263acSSony Chacko 	u32 val;
245629263acSSony Chacko 	u8 version;
246629263acSSony Chacko 
247629263acSSony Chacko 	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_MAJ_VERSION);
248629263acSSony Chacko 	version = val & 0xFF;
249629263acSSony Chacko 
250629263acSSony Chacko 	if (version != QLC_83XX_IDC_MAJOR_VERSION) {
251629263acSSony Chacko 		dev_info(&adapter->pdev->dev,
252629263acSSony Chacko 			 "%s:mismatch. version 0x%x, expected version 0x%x\n",
253629263acSSony Chacko 			 __func__, version, QLC_83XX_IDC_MAJOR_VERSION);
254629263acSSony Chacko 		return -EIO;
255629263acSSony Chacko 	}
256629263acSSony Chacko 
257629263acSSony Chacko 	return 0;
258629263acSSony Chacko }
259629263acSSony Chacko 
qlcnic_83xx_idc_clear_registers(struct qlcnic_adapter * adapter,int lock)260629263acSSony Chacko static int qlcnic_83xx_idc_clear_registers(struct qlcnic_adapter *adapter,
261629263acSSony Chacko 					   int lock)
262629263acSSony Chacko {
263629263acSSony Chacko 	u32 val;
264629263acSSony Chacko 
265629263acSSony Chacko 	if (lock) {
266629263acSSony Chacko 		if (qlcnic_83xx_lock_driver(adapter))
267629263acSSony Chacko 			return -EBUSY;
268629263acSSony Chacko 	}
269629263acSSony Chacko 
270629263acSSony Chacko 	QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_ACK, 0);
271dbedd44eSJoe Perches 	/* Clear graceful reset bit */
272629263acSSony Chacko 	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
273629263acSSony Chacko 	val &= ~QLC_83XX_IDC_GRACEFULL_RESET;
274629263acSSony Chacko 	QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
275629263acSSony Chacko 
276629263acSSony Chacko 	if (lock)
277629263acSSony Chacko 		qlcnic_83xx_unlock_driver(adapter);
278629263acSSony Chacko 
279629263acSSony Chacko 	return 0;
280629263acSSony Chacko }
281629263acSSony Chacko 
qlcnic_83xx_idc_update_drv_ack_reg(struct qlcnic_adapter * adapter,int flag,int lock)282629263acSSony Chacko static int qlcnic_83xx_idc_update_drv_ack_reg(struct qlcnic_adapter *adapter,
283629263acSSony Chacko 					      int flag, int lock)
284629263acSSony Chacko {
285629263acSSony Chacko 	u32 val;
286629263acSSony Chacko 
287629263acSSony Chacko 	if (lock) {
288629263acSSony Chacko 		if (qlcnic_83xx_lock_driver(adapter))
289629263acSSony Chacko 			return -EBUSY;
290629263acSSony Chacko 	}
291629263acSSony Chacko 
292629263acSSony Chacko 	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_ACK);
293629263acSSony Chacko 	if (flag)
294629263acSSony Chacko 		val = val | (1 << adapter->portnum);
295629263acSSony Chacko 	else
296629263acSSony Chacko 		val = val & ~(1 << adapter->portnum);
297629263acSSony Chacko 	QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_ACK, val);
298629263acSSony Chacko 
299629263acSSony Chacko 	if (lock)
300629263acSSony Chacko 		qlcnic_83xx_unlock_driver(adapter);
301629263acSSony Chacko 
302629263acSSony Chacko 	return 0;
303629263acSSony Chacko }
304629263acSSony Chacko 
qlcnic_83xx_idc_check_timeout(struct qlcnic_adapter * adapter,int time_limit)305629263acSSony Chacko static int qlcnic_83xx_idc_check_timeout(struct qlcnic_adapter *adapter,
306629263acSSony Chacko 					 int time_limit)
307629263acSSony Chacko {
308629263acSSony Chacko 	u64 seconds;
309629263acSSony Chacko 
310629263acSSony Chacko 	seconds = jiffies / HZ - adapter->ahw->idc.sec_counter;
311629263acSSony Chacko 	if (seconds <= time_limit)
312629263acSSony Chacko 		return 0;
313629263acSSony Chacko 	else
314629263acSSony Chacko 		return -EBUSY;
315629263acSSony Chacko }
316629263acSSony Chacko 
317629263acSSony Chacko /**
318629263acSSony Chacko  * qlcnic_83xx_idc_check_reset_ack_reg
319629263acSSony Chacko  *
320629263acSSony Chacko  * @adapter: adapter structure
321629263acSSony Chacko  *
322629263acSSony Chacko  * Check ACK wait limit and clear the functions which failed to ACK
323629263acSSony Chacko  *
324629263acSSony Chacko  * Return 0 if all functions have acknowledged the reset request.
325629263acSSony Chacko  **/
qlcnic_83xx_idc_check_reset_ack_reg(struct qlcnic_adapter * adapter)326629263acSSony Chacko static int qlcnic_83xx_idc_check_reset_ack_reg(struct qlcnic_adapter *adapter)
327629263acSSony Chacko {
328629263acSSony Chacko 	int timeout;
329629263acSSony Chacko 	u32 ack, presence, val;
330629263acSSony Chacko 
331629263acSSony Chacko 	timeout = QLC_83XX_IDC_RESET_TIMEOUT_SECS;
332629263acSSony Chacko 	ack = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_ACK);
333629263acSSony Chacko 	presence = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
334629263acSSony Chacko 	dev_info(&adapter->pdev->dev,
335629263acSSony Chacko 		 "%s: ack = 0x%x, presence = 0x%x\n", __func__, ack, presence);
336629263acSSony Chacko 	if (!((ack & presence) == presence)) {
337629263acSSony Chacko 		if (qlcnic_83xx_idc_check_timeout(adapter, timeout)) {
338629263acSSony Chacko 			/* Clear functions which failed to ACK */
339629263acSSony Chacko 			dev_info(&adapter->pdev->dev,
340629263acSSony Chacko 				 "%s: ACK wait exceeds time limit\n", __func__);
341629263acSSony Chacko 			val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
342629263acSSony Chacko 			val = val & ~(ack ^ presence);
343629263acSSony Chacko 			if (qlcnic_83xx_lock_driver(adapter))
344629263acSSony Chacko 				return -EBUSY;
345629263acSSony Chacko 			QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE, val);
346629263acSSony Chacko 			dev_info(&adapter->pdev->dev,
347629263acSSony Chacko 				 "%s: updated drv presence reg = 0x%x\n",
348629263acSSony Chacko 				 __func__, val);
349629263acSSony Chacko 			qlcnic_83xx_unlock_driver(adapter);
350629263acSSony Chacko 			return 0;
351629263acSSony Chacko 
352629263acSSony Chacko 		} else {
353629263acSSony Chacko 			return 1;
354629263acSSony Chacko 		}
355629263acSSony Chacko 	} else {
356629263acSSony Chacko 		dev_info(&adapter->pdev->dev,
357629263acSSony Chacko 			 "%s: Reset ACK received from all functions\n",
358629263acSSony Chacko 			 __func__);
359629263acSSony Chacko 		return 0;
360629263acSSony Chacko 	}
361629263acSSony Chacko }
362629263acSSony Chacko 
363629263acSSony Chacko /**
364629263acSSony Chacko  * qlcnic_83xx_idc_tx_soft_reset
365629263acSSony Chacko  *
366629263acSSony Chacko  * @adapter: adapter structure
367629263acSSony Chacko  *
368629263acSSony Chacko  * Handle context deletion and recreation request from transmit routine
369629263acSSony Chacko  *
370629263acSSony Chacko  * Returns -EBUSY  or Success (0)
371629263acSSony Chacko  *
372629263acSSony Chacko  **/
qlcnic_83xx_idc_tx_soft_reset(struct qlcnic_adapter * adapter)373629263acSSony Chacko static int qlcnic_83xx_idc_tx_soft_reset(struct qlcnic_adapter *adapter)
374629263acSSony Chacko {
375629263acSSony Chacko 	struct net_device *netdev = adapter->netdev;
376629263acSSony Chacko 
377629263acSSony Chacko 	if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
378629263acSSony Chacko 		return -EBUSY;
379629263acSSony Chacko 
380629263acSSony Chacko 	netif_device_detach(netdev);
381629263acSSony Chacko 	qlcnic_down(adapter, netdev);
382629263acSSony Chacko 	qlcnic_up(adapter, netdev);
383629263acSSony Chacko 	netif_device_attach(netdev);
384629263acSSony Chacko 	clear_bit(__QLCNIC_RESETTING, &adapter->state);
38595b3890aSHimanshu Madhani 	netdev_info(adapter->netdev, "%s: soft reset complete.\n", __func__);
386629263acSSony Chacko 
387629263acSSony Chacko 	return 0;
388629263acSSony Chacko }
389629263acSSony Chacko 
390629263acSSony Chacko /**
391629263acSSony Chacko  * qlcnic_83xx_idc_detach_driver
392629263acSSony Chacko  *
393629263acSSony Chacko  * @adapter: adapter structure
394629263acSSony Chacko  * Detach net interface, stop TX and cleanup resources before the HW reset.
395629263acSSony Chacko  * Returns: None
396629263acSSony Chacko  *
397629263acSSony Chacko  **/
qlcnic_83xx_idc_detach_driver(struct qlcnic_adapter * adapter)398629263acSSony Chacko static void qlcnic_83xx_idc_detach_driver(struct qlcnic_adapter *adapter)
399629263acSSony Chacko {
400629263acSSony Chacko 	int i;
401629263acSSony Chacko 	struct net_device *netdev = adapter->netdev;
402629263acSSony Chacko 
403629263acSSony Chacko 	netif_device_detach(netdev);
404068a8d19SManish Chopra 	qlcnic_83xx_detach_mailbox_work(adapter);
405f036e4f4SRajesh Borundia 
406629263acSSony Chacko 	/* Disable mailbox interrupt */
407f036e4f4SRajesh Borundia 	qlcnic_83xx_disable_mbx_intr(adapter);
408629263acSSony Chacko 	qlcnic_down(adapter, netdev);
409629263acSSony Chacko 	for (i = 0; i < adapter->ahw->num_msix; i++) {
410629263acSSony Chacko 		adapter->ahw->intr_tbl[i].id = i;
411629263acSSony Chacko 		adapter->ahw->intr_tbl[i].enabled = 0;
412629263acSSony Chacko 		adapter->ahw->intr_tbl[i].src = 0;
413629263acSSony Chacko 	}
414f036e4f4SRajesh Borundia 
415f036e4f4SRajesh Borundia 	if (qlcnic_sriov_pf_check(adapter))
416f036e4f4SRajesh Borundia 		qlcnic_sriov_pf_reset(adapter);
417629263acSSony Chacko }
418629263acSSony Chacko 
419629263acSSony Chacko /**
420629263acSSony Chacko  * qlcnic_83xx_idc_attach_driver
421629263acSSony Chacko  *
422629263acSSony Chacko  * @adapter: adapter structure
423629263acSSony Chacko  *
424629263acSSony Chacko  * Re-attach and re-enable net interface
425629263acSSony Chacko  * Returns: None
426629263acSSony Chacko  *
427629263acSSony Chacko  **/
qlcnic_83xx_idc_attach_driver(struct qlcnic_adapter * adapter)428629263acSSony Chacko static void qlcnic_83xx_idc_attach_driver(struct qlcnic_adapter *adapter)
429629263acSSony Chacko {
430629263acSSony Chacko 	struct net_device *netdev = adapter->netdev;
431629263acSSony Chacko 
432629263acSSony Chacko 	if (netif_running(netdev)) {
433629263acSSony Chacko 		if (qlcnic_up(adapter, netdev))
434629263acSSony Chacko 			goto done;
435629263acSSony Chacko 		qlcnic_restore_indev_addr(netdev, NETDEV_UP);
436629263acSSony Chacko 	}
437629263acSSony Chacko done:
438629263acSSony Chacko 	netif_device_attach(netdev);
439629263acSSony Chacko }
440629263acSSony Chacko 
qlcnic_83xx_idc_enter_failed_state(struct qlcnic_adapter * adapter,int lock)441629263acSSony Chacko static int qlcnic_83xx_idc_enter_failed_state(struct qlcnic_adapter *adapter,
442629263acSSony Chacko 					      int lock)
443629263acSSony Chacko {
444629263acSSony Chacko 	if (lock) {
445629263acSSony Chacko 		if (qlcnic_83xx_lock_driver(adapter))
446629263acSSony Chacko 			return -EBUSY;
447629263acSSony Chacko 	}
448629263acSSony Chacko 
449629263acSSony Chacko 	qlcnic_83xx_idc_clear_registers(adapter, 0);
450629263acSSony Chacko 	QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE, QLC_83XX_IDC_DEV_FAILED);
451629263acSSony Chacko 	if (lock)
452629263acSSony Chacko 		qlcnic_83xx_unlock_driver(adapter);
453629263acSSony Chacko 
454629263acSSony Chacko 	qlcnic_83xx_idc_log_state_history(adapter);
455629263acSSony Chacko 	dev_info(&adapter->pdev->dev, "Device will enter failed state\n");
456629263acSSony Chacko 
457629263acSSony Chacko 	return 0;
458629263acSSony Chacko }
459629263acSSony Chacko 
qlcnic_83xx_idc_enter_init_state(struct qlcnic_adapter * adapter,int lock)460629263acSSony Chacko static int qlcnic_83xx_idc_enter_init_state(struct qlcnic_adapter *adapter,
461629263acSSony Chacko 					    int lock)
462629263acSSony Chacko {
463629263acSSony Chacko 	if (lock) {
464629263acSSony Chacko 		if (qlcnic_83xx_lock_driver(adapter))
465629263acSSony Chacko 			return -EBUSY;
466629263acSSony Chacko 	}
467629263acSSony Chacko 
468629263acSSony Chacko 	QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE, QLC_83XX_IDC_DEV_INIT);
469629263acSSony Chacko 
470629263acSSony Chacko 	if (lock)
471629263acSSony Chacko 		qlcnic_83xx_unlock_driver(adapter);
472629263acSSony Chacko 
473629263acSSony Chacko 	return 0;
474629263acSSony Chacko }
475629263acSSony Chacko 
qlcnic_83xx_idc_enter_need_quiesce(struct qlcnic_adapter * adapter,int lock)476629263acSSony Chacko static int qlcnic_83xx_idc_enter_need_quiesce(struct qlcnic_adapter *adapter,
477629263acSSony Chacko 					      int lock)
478629263acSSony Chacko {
479629263acSSony Chacko 	if (lock) {
480629263acSSony Chacko 		if (qlcnic_83xx_lock_driver(adapter))
481629263acSSony Chacko 			return -EBUSY;
482629263acSSony Chacko 	}
483629263acSSony Chacko 
484629263acSSony Chacko 	QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
485629263acSSony Chacko 	       QLC_83XX_IDC_DEV_NEED_QUISCENT);
486629263acSSony Chacko 
487629263acSSony Chacko 	if (lock)
488629263acSSony Chacko 		qlcnic_83xx_unlock_driver(adapter);
489629263acSSony Chacko 
490629263acSSony Chacko 	return 0;
491629263acSSony Chacko }
492629263acSSony Chacko 
493629263acSSony Chacko static int
qlcnic_83xx_idc_enter_need_reset_state(struct qlcnic_adapter * adapter,int lock)494629263acSSony Chacko qlcnic_83xx_idc_enter_need_reset_state(struct qlcnic_adapter *adapter, int lock)
495629263acSSony Chacko {
496629263acSSony Chacko 	if (lock) {
497629263acSSony Chacko 		if (qlcnic_83xx_lock_driver(adapter))
498629263acSSony Chacko 			return -EBUSY;
499629263acSSony Chacko 	}
500629263acSSony Chacko 
501629263acSSony Chacko 	QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
502629263acSSony Chacko 	       QLC_83XX_IDC_DEV_NEED_RESET);
503629263acSSony Chacko 
504629263acSSony Chacko 	if (lock)
505629263acSSony Chacko 		qlcnic_83xx_unlock_driver(adapter);
506629263acSSony Chacko 
507629263acSSony Chacko 	return 0;
508629263acSSony Chacko }
509629263acSSony Chacko 
qlcnic_83xx_idc_enter_ready_state(struct qlcnic_adapter * adapter,int lock)510629263acSSony Chacko static int qlcnic_83xx_idc_enter_ready_state(struct qlcnic_adapter *adapter,
511629263acSSony Chacko 					     int lock)
512629263acSSony Chacko {
513629263acSSony Chacko 	if (lock) {
514629263acSSony Chacko 		if (qlcnic_83xx_lock_driver(adapter))
515629263acSSony Chacko 			return -EBUSY;
516629263acSSony Chacko 	}
517629263acSSony Chacko 
518629263acSSony Chacko 	QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE, QLC_83XX_IDC_DEV_READY);
519629263acSSony Chacko 	if (lock)
520629263acSSony Chacko 		qlcnic_83xx_unlock_driver(adapter);
521629263acSSony Chacko 
522629263acSSony Chacko 	return 0;
523629263acSSony Chacko }
524629263acSSony Chacko 
525629263acSSony Chacko /**
526629263acSSony Chacko  * qlcnic_83xx_idc_find_reset_owner_id
527629263acSSony Chacko  *
528629263acSSony Chacko  * @adapter: adapter structure
529629263acSSony Chacko  *
530629263acSSony Chacko  * NIC gets precedence over ISCSI and ISCSI has precedence over FCOE.
531629263acSSony Chacko  * Within the same class, function with lowest PCI ID assumes ownership
532629263acSSony Chacko  *
533629263acSSony Chacko  * Returns: reset owner id or failure indication (-EIO)
534629263acSSony Chacko  *
535629263acSSony Chacko  **/
qlcnic_83xx_idc_find_reset_owner_id(struct qlcnic_adapter * adapter)536629263acSSony Chacko static int qlcnic_83xx_idc_find_reset_owner_id(struct qlcnic_adapter *adapter)
537629263acSSony Chacko {
538629263acSSony Chacko 	u32 reg, reg1, reg2, i, j, owner, class;
539629263acSSony Chacko 
540629263acSSony Chacko 	reg1 = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_PARTITION_INFO_1);
541629263acSSony Chacko 	reg2 = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_PARTITION_INFO_2);
542629263acSSony Chacko 	owner = QLCNIC_TYPE_NIC;
543629263acSSony Chacko 	i = 0;
544629263acSSony Chacko 	j = 0;
545629263acSSony Chacko 	reg = reg1;
546629263acSSony Chacko 
547629263acSSony Chacko 	do {
548629263acSSony Chacko 		class = (((reg & (0xF << j * 4)) >> j * 4) & 0x3);
549629263acSSony Chacko 		if (class == owner)
550629263acSSony Chacko 			break;
551629263acSSony Chacko 		if (i == (QLC_83XX_IDC_MAX_FUNC_PER_PARTITION_INFO - 1)) {
552629263acSSony Chacko 			reg = reg2;
553629263acSSony Chacko 			j = 0;
554629263acSSony Chacko 		} else {
555629263acSSony Chacko 			j++;
556629263acSSony Chacko 		}
557629263acSSony Chacko 
558629263acSSony Chacko 		if (i == (QLC_83XX_IDC_MAX_CNA_FUNCTIONS - 1)) {
559629263acSSony Chacko 			if (owner == QLCNIC_TYPE_NIC)
560629263acSSony Chacko 				owner = QLCNIC_TYPE_ISCSI;
561629263acSSony Chacko 			else if (owner == QLCNIC_TYPE_ISCSI)
562629263acSSony Chacko 				owner = QLCNIC_TYPE_FCOE;
563629263acSSony Chacko 			else if (owner == QLCNIC_TYPE_FCOE)
564629263acSSony Chacko 				return -EIO;
565629263acSSony Chacko 			reg = reg1;
566629263acSSony Chacko 			j = 0;
567629263acSSony Chacko 			i = 0;
568629263acSSony Chacko 		}
569629263acSSony Chacko 	} while (i++ < QLC_83XX_IDC_MAX_CNA_FUNCTIONS);
570629263acSSony Chacko 
571629263acSSony Chacko 	return i;
572629263acSSony Chacko }
573629263acSSony Chacko 
qlcnic_83xx_idc_restart_hw(struct qlcnic_adapter * adapter,int lock)574629263acSSony Chacko static int qlcnic_83xx_idc_restart_hw(struct qlcnic_adapter *adapter, int lock)
575629263acSSony Chacko {
576629263acSSony Chacko 	int ret = 0;
577629263acSSony Chacko 
578629263acSSony Chacko 	ret = qlcnic_83xx_restart_hw(adapter);
579629263acSSony Chacko 
580629263acSSony Chacko 	if (ret) {
581629263acSSony Chacko 		qlcnic_83xx_idc_enter_failed_state(adapter, lock);
582629263acSSony Chacko 	} else {
583629263acSSony Chacko 		qlcnic_83xx_idc_clear_registers(adapter, lock);
584629263acSSony Chacko 		ret = qlcnic_83xx_idc_enter_ready_state(adapter, lock);
585629263acSSony Chacko 	}
586629263acSSony Chacko 
587629263acSSony Chacko 	return ret;
588629263acSSony Chacko }
589629263acSSony Chacko 
qlcnic_83xx_idc_check_fan_failure(struct qlcnic_adapter * adapter)590629263acSSony Chacko static int qlcnic_83xx_idc_check_fan_failure(struct qlcnic_adapter *adapter)
591629263acSSony Chacko {
592629263acSSony Chacko 	u32 status;
593629263acSSony Chacko 
594629263acSSony Chacko 	status = QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS1);
595629263acSSony Chacko 
596629263acSSony Chacko 	if (status & QLCNIC_RCODE_FATAL_ERROR) {
597629263acSSony Chacko 		dev_err(&adapter->pdev->dev,
598629263acSSony Chacko 			"peg halt status1=0x%x\n", status);
599629263acSSony Chacko 		if (QLCNIC_FWERROR_CODE(status) == QLCNIC_FWERROR_FAN_FAILURE) {
600629263acSSony Chacko 			dev_err(&adapter->pdev->dev,
601629263acSSony Chacko 				"On board active cooling fan failed. "
602629263acSSony Chacko 				"Device has been halted.\n");
603629263acSSony Chacko 			dev_err(&adapter->pdev->dev,
604629263acSSony Chacko 				"Replace the adapter.\n");
605629263acSSony Chacko 			return -EIO;
606629263acSSony Chacko 		}
607629263acSSony Chacko 	}
608629263acSSony Chacko 
609629263acSSony Chacko 	return 0;
610629263acSSony Chacko }
611629263acSSony Chacko 
qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter * adapter)612486a5bc7SRajesh Borundia int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)
613629263acSSony Chacko {
614f036e4f4SRajesh Borundia 	int err;
615f036e4f4SRajesh Borundia 
616068a8d19SManish Chopra 	qlcnic_83xx_reinit_mbx_work(adapter->ahw->mailbox);
617068a8d19SManish Chopra 	qlcnic_83xx_enable_mbx_interrupt(adapter);
618068a8d19SManish Chopra 
6199b0fff2aSSucheta Chakraborty 	qlcnic_83xx_initialize_nic(adapter, 1);
620d5fcff04SHimanshu Madhani 
621f036e4f4SRajesh Borundia 	err = qlcnic_sriov_pf_reinit(adapter);
622f036e4f4SRajesh Borundia 	if (err)
623f036e4f4SRajesh Borundia 		return err;
624f036e4f4SRajesh Borundia 
625e5c4e6c6SManish Chopra 	qlcnic_83xx_enable_mbx_interrupt(adapter);
626629263acSSony Chacko 
627629263acSSony Chacko 	if (qlcnic_83xx_configure_opmode(adapter)) {
628629263acSSony Chacko 		qlcnic_83xx_idc_enter_failed_state(adapter, 1);
629629263acSSony Chacko 		return -EIO;
630629263acSSony Chacko 	}
631629263acSSony Chacko 
632629263acSSony Chacko 	if (adapter->nic_ops->init_driver(adapter)) {
633629263acSSony Chacko 		qlcnic_83xx_idc_enter_failed_state(adapter, 1);
634629263acSSony Chacko 		return -EIO;
635629263acSSony Chacko 	}
636629263acSSony Chacko 
63724866d15SHimanshu Madhani 	if (adapter->portnum == 0)
6388af3f33dSPratik Pujar 		qlcnic_set_drv_version(adapter);
63914d385b9SSucheta Chakraborty 
6401de899d3SSucheta Chakraborty 	qlcnic_dcb_get_info(adapter->dcb);
641629263acSSony Chacko 	qlcnic_83xx_idc_attach_driver(adapter);
642629263acSSony Chacko 
643629263acSSony Chacko 	return 0;
644629263acSSony Chacko }
645629263acSSony Chacko 
qlcnic_83xx_idc_update_idc_params(struct qlcnic_adapter * adapter)646629263acSSony Chacko static void qlcnic_83xx_idc_update_idc_params(struct qlcnic_adapter *adapter)
647629263acSSony Chacko {
648536faa61SSony Chacko 	struct qlcnic_hardware_context *ahw = adapter->ahw;
649536faa61SSony Chacko 
650629263acSSony Chacko 	qlcnic_83xx_idc_update_drv_presence_reg(adapter, 1, 1);
651629263acSSony Chacko 	qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
652629263acSSony Chacko 	set_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
653536faa61SSony Chacko 
654536faa61SSony Chacko 	ahw->idc.quiesce_req = 0;
655536faa61SSony Chacko 	ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY;
656536faa61SSony Chacko 	ahw->idc.err_code = 0;
657536faa61SSony Chacko 	ahw->idc.collect_dump = 0;
658536faa61SSony Chacko 	ahw->reset_context = 0;
659536faa61SSony Chacko 	adapter->tx_timeo_cnt = 0;
660099907faSSony Chacko 	ahw->idc.delay_reset = 0;
661536faa61SSony Chacko 
662536faa61SSony Chacko 	clear_bit(__QLCNIC_RESETTING, &adapter->state);
663629263acSSony Chacko }
664629263acSSony Chacko 
665629263acSSony Chacko /**
666629263acSSony Chacko  * qlcnic_83xx_idc_ready_state_entry
667629263acSSony Chacko  *
668629263acSSony Chacko  * @adapter: adapter structure
669629263acSSony Chacko  *
670629263acSSony Chacko  * Perform ready state initialization, this routine will get invoked only
671629263acSSony Chacko  * once from READY state.
672629263acSSony Chacko  *
673629263acSSony Chacko  * Returns: Error code or Success(0)
674629263acSSony Chacko  *
675629263acSSony Chacko  **/
qlcnic_83xx_idc_ready_state_entry(struct qlcnic_adapter * adapter)676629263acSSony Chacko int qlcnic_83xx_idc_ready_state_entry(struct qlcnic_adapter *adapter)
677629263acSSony Chacko {
678629263acSSony Chacko 	struct qlcnic_hardware_context *ahw = adapter->ahw;
679629263acSSony Chacko 
680629263acSSony Chacko 	if (ahw->idc.prev_state != QLC_83XX_IDC_DEV_READY) {
681629263acSSony Chacko 		qlcnic_83xx_idc_update_idc_params(adapter);
682629263acSSony Chacko 		/* Re-attach the device if required */
683629263acSSony Chacko 		if ((ahw->idc.prev_state == QLC_83XX_IDC_DEV_NEED_RESET) ||
684629263acSSony Chacko 		    (ahw->idc.prev_state == QLC_83XX_IDC_DEV_INIT)) {
685629263acSSony Chacko 			if (qlcnic_83xx_idc_reattach_driver(adapter))
686629263acSSony Chacko 				return -EIO;
687629263acSSony Chacko 		}
688629263acSSony Chacko 	}
689629263acSSony Chacko 
690629263acSSony Chacko 	return 0;
691629263acSSony Chacko }
692629263acSSony Chacko 
693d71170fbSSony Chacko /**
694d71170fbSSony Chacko  * qlcnic_83xx_idc_vnic_pf_entry
695d71170fbSSony Chacko  *
696d71170fbSSony Chacko  * @adapter: adapter structure
697d71170fbSSony Chacko  *
698d71170fbSSony Chacko  * Ensure vNIC mode privileged function starts only after vNIC mode is
699d71170fbSSony Chacko  * enabled by management function.
700d71170fbSSony Chacko  * If vNIC mode is ready, start initialization.
701d71170fbSSony Chacko  *
702d71170fbSSony Chacko  * Returns: -EIO or 0
703d71170fbSSony Chacko  *
704d71170fbSSony Chacko  **/
qlcnic_83xx_idc_vnic_pf_entry(struct qlcnic_adapter * adapter)705d71170fbSSony Chacko int qlcnic_83xx_idc_vnic_pf_entry(struct qlcnic_adapter *adapter)
706d71170fbSSony Chacko {
707d71170fbSSony Chacko 	u32 state;
708d71170fbSSony Chacko 	struct qlcnic_hardware_context *ahw = adapter->ahw;
709d71170fbSSony Chacko 
710d71170fbSSony Chacko 	/* Privileged function waits till mgmt function enables VNIC mode */
711d71170fbSSony Chacko 	state = QLCRDX(adapter->ahw, QLC_83XX_VNIC_STATE);
712d71170fbSSony Chacko 	if (state != QLCNIC_DEV_NPAR_OPER) {
713d71170fbSSony Chacko 		if (!ahw->idc.vnic_wait_limit--) {
714d71170fbSSony Chacko 			qlcnic_83xx_idc_enter_failed_state(adapter, 1);
715d71170fbSSony Chacko 			return -EIO;
716d71170fbSSony Chacko 		}
717d71170fbSSony Chacko 		dev_info(&adapter->pdev->dev, "vNIC mode disabled\n");
718d71170fbSSony Chacko 		return -EIO;
719d71170fbSSony Chacko 
720d71170fbSSony Chacko 	} else {
721d71170fbSSony Chacko 		/* Perform one time initialization from ready state */
722d71170fbSSony Chacko 		if (ahw->idc.vnic_state != QLCNIC_DEV_NPAR_OPER) {
723d71170fbSSony Chacko 			qlcnic_83xx_idc_update_idc_params(adapter);
724d71170fbSSony Chacko 
725d71170fbSSony Chacko 			/* If the previous state is UNKNOWN, device will be
726d71170fbSSony Chacko 			   already attached properly by Init routine*/
727d71170fbSSony Chacko 			if (ahw->idc.prev_state != QLC_83XX_IDC_DEV_UNKNOWN) {
728d71170fbSSony Chacko 				if (qlcnic_83xx_idc_reattach_driver(adapter))
729d71170fbSSony Chacko 					return -EIO;
730d71170fbSSony Chacko 			}
731d71170fbSSony Chacko 			adapter->ahw->idc.vnic_state =  QLCNIC_DEV_NPAR_OPER;
732d71170fbSSony Chacko 			dev_info(&adapter->pdev->dev, "vNIC mode enabled\n");
733d71170fbSSony Chacko 		}
734d71170fbSSony Chacko 	}
735d71170fbSSony Chacko 
736d71170fbSSony Chacko 	return 0;
737d71170fbSSony Chacko }
738d71170fbSSony Chacko 
qlcnic_83xx_idc_unknown_state(struct qlcnic_adapter * adapter)739629263acSSony Chacko static int qlcnic_83xx_idc_unknown_state(struct qlcnic_adapter *adapter)
740629263acSSony Chacko {
741629263acSSony Chacko 	adapter->ahw->idc.err_code = -EIO;
742629263acSSony Chacko 	dev_err(&adapter->pdev->dev,
743629263acSSony Chacko 		"%s: Device in unknown state\n", __func__);
74430fa15f6SManish Chopra 	clear_bit(__QLCNIC_RESETTING, &adapter->state);
745629263acSSony Chacko 	return 0;
746629263acSSony Chacko }
747629263acSSony Chacko 
748629263acSSony Chacko /**
7499f2e6fb6SYang Shen  * qlcnic_83xx_idc_cold_state_handler
750629263acSSony Chacko  *
751629263acSSony Chacko  * @adapter: adapter structure
752629263acSSony Chacko  *
753629263acSSony Chacko  * If HW is up and running device will enter READY state.
754629263acSSony Chacko  * If firmware image from host needs to be loaded, device is
755629263acSSony Chacko  * forced to start with the file firmware image.
756629263acSSony Chacko  *
757629263acSSony Chacko  * Returns: Error code or Success(0)
758629263acSSony Chacko  *
759629263acSSony Chacko  **/
qlcnic_83xx_idc_cold_state_handler(struct qlcnic_adapter * adapter)760629263acSSony Chacko static int qlcnic_83xx_idc_cold_state_handler(struct qlcnic_adapter *adapter)
761629263acSSony Chacko {
762629263acSSony Chacko 	qlcnic_83xx_idc_update_drv_presence_reg(adapter, 1, 0);
763629263acSSony Chacko 	qlcnic_83xx_idc_update_audit_reg(adapter, 1, 0);
764629263acSSony Chacko 
765629263acSSony Chacko 	if (qlcnic_load_fw_file) {
766629263acSSony Chacko 		qlcnic_83xx_idc_restart_hw(adapter, 0);
767629263acSSony Chacko 	} else {
768629263acSSony Chacko 		if (qlcnic_83xx_check_hw_status(adapter)) {
769629263acSSony Chacko 			qlcnic_83xx_idc_enter_failed_state(adapter, 0);
770629263acSSony Chacko 			return -EIO;
771629263acSSony Chacko 		} else {
772629263acSSony Chacko 			qlcnic_83xx_idc_enter_ready_state(adapter, 0);
773629263acSSony Chacko 		}
774629263acSSony Chacko 	}
775629263acSSony Chacko 	return 0;
776629263acSSony Chacko }
777629263acSSony Chacko 
778629263acSSony Chacko /**
779629263acSSony Chacko  * qlcnic_83xx_idc_init_state
780629263acSSony Chacko  *
781629263acSSony Chacko  * @adapter: adapter structure
782629263acSSony Chacko  *
783629263acSSony Chacko  * Reset owner will restart the device from this state.
784629263acSSony Chacko  * Device will enter failed state if it remains
785629263acSSony Chacko  * in this state for more than DEV_INIT time limit.
786629263acSSony Chacko  *
787629263acSSony Chacko  * Returns: Error code or Success(0)
788629263acSSony Chacko  *
789629263acSSony Chacko  **/
qlcnic_83xx_idc_init_state(struct qlcnic_adapter * adapter)790629263acSSony Chacko static int qlcnic_83xx_idc_init_state(struct qlcnic_adapter *adapter)
791629263acSSony Chacko {
792629263acSSony Chacko 	int timeout, ret = 0;
793629263acSSony Chacko 	u32 owner;
794629263acSSony Chacko 
795629263acSSony Chacko 	timeout = QLC_83XX_IDC_INIT_TIMEOUT_SECS;
796629263acSSony Chacko 	if (adapter->ahw->idc.prev_state == QLC_83XX_IDC_DEV_NEED_RESET) {
797629263acSSony Chacko 		owner = qlcnic_83xx_idc_find_reset_owner_id(adapter);
798629263acSSony Chacko 		if (adapter->ahw->pci_func == owner)
799629263acSSony Chacko 			ret = qlcnic_83xx_idc_restart_hw(adapter, 1);
800629263acSSony Chacko 	} else {
801629263acSSony Chacko 		ret = qlcnic_83xx_idc_check_timeout(adapter, timeout);
802629263acSSony Chacko 	}
803629263acSSony Chacko 
804629263acSSony Chacko 	return ret;
805629263acSSony Chacko }
806629263acSSony Chacko 
807629263acSSony Chacko /**
808629263acSSony Chacko  * qlcnic_83xx_idc_ready_state
809629263acSSony Chacko  *
810629263acSSony Chacko  * @adapter: adapter structure
811629263acSSony Chacko  *
812629263acSSony Chacko  * Perform IDC protocol specicifed actions after monitoring device state and
813629263acSSony Chacko  * events.
814629263acSSony Chacko  *
815629263acSSony Chacko  * Returns: Error code or Success(0)
816629263acSSony Chacko  *
817629263acSSony Chacko  **/
qlcnic_83xx_idc_ready_state(struct qlcnic_adapter * adapter)818629263acSSony Chacko static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter)
819629263acSSony Chacko {
820629263acSSony Chacko 	struct qlcnic_hardware_context *ahw = adapter->ahw;
821068a8d19SManish Chopra 	struct qlcnic_mailbox *mbx = ahw->mailbox;
822629263acSSony Chacko 	int ret = 0;
823068a8d19SManish Chopra 	u32 val;
824629263acSSony Chacko 
825629263acSSony Chacko 	/* Perform NIC configuration based ready state entry actions */
826629263acSSony Chacko 	if (ahw->idc.state_entry(adapter))
827629263acSSony Chacko 		return -EIO;
828629263acSSony Chacko 
829629263acSSony Chacko 	if (qlcnic_check_temp(adapter)) {
830629263acSSony Chacko 		if (ahw->temp == QLCNIC_TEMP_PANIC) {
831629263acSSony Chacko 			qlcnic_83xx_idc_check_fan_failure(adapter);
832629263acSSony Chacko 			dev_err(&adapter->pdev->dev,
833629263acSSony Chacko 				"Error: device temperature %d above limits\n",
834629263acSSony Chacko 				adapter->ahw->temp);
835068a8d19SManish Chopra 			clear_bit(QLC_83XX_MBX_READY, &mbx->status);
836629263acSSony Chacko 			set_bit(__QLCNIC_RESETTING, &adapter->state);
837629263acSSony Chacko 			qlcnic_83xx_idc_detach_driver(adapter);
838629263acSSony Chacko 			qlcnic_83xx_idc_enter_failed_state(adapter, 1);
839629263acSSony Chacko 			return -EIO;
840629263acSSony Chacko 		}
841629263acSSony Chacko 	}
842629263acSSony Chacko 
843629263acSSony Chacko 	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
844629263acSSony Chacko 	ret = qlcnic_83xx_check_heartbeat(adapter);
845629263acSSony Chacko 	if (ret) {
846629263acSSony Chacko 		adapter->flags |= QLCNIC_FW_HANG;
847629263acSSony Chacko 		if (!(val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY)) {
848068a8d19SManish Chopra 			clear_bit(QLC_83XX_MBX_READY, &mbx->status);
849629263acSSony Chacko 			set_bit(__QLCNIC_RESETTING, &adapter->state);
850629263acSSony Chacko 			qlcnic_83xx_idc_enter_need_reset_state(adapter, 1);
851891e71b1SPratik Pujar 		}  else {
85230fa15f6SManish Chopra 			netdev_info(adapter->netdev, "%s: Auto firmware recovery is disabled\n",
85330fa15f6SManish Chopra 				    __func__);
85430fa15f6SManish Chopra 			qlcnic_83xx_idc_enter_failed_state(adapter, 1);
855629263acSSony Chacko 		}
856629263acSSony Chacko 		return -EIO;
857629263acSSony Chacko 	}
858629263acSSony Chacko 
859629263acSSony Chacko 	if ((val & QLC_83XX_IDC_GRACEFULL_RESET) || ahw->idc.collect_dump) {
860068a8d19SManish Chopra 		clear_bit(QLC_83XX_MBX_READY, &mbx->status);
861068a8d19SManish Chopra 
862629263acSSony Chacko 		/* Move to need reset state and prepare for reset */
863629263acSSony Chacko 		qlcnic_83xx_idc_enter_need_reset_state(adapter, 1);
864629263acSSony Chacko 		return ret;
865629263acSSony Chacko 	}
866629263acSSony Chacko 
867629263acSSony Chacko 	/* Check for soft reset request */
868629263acSSony Chacko 	if (ahw->reset_context &&
869629263acSSony Chacko 	    !(val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY)) {
870536faa61SSony Chacko 		adapter->ahw->reset_context = 0;
871629263acSSony Chacko 		qlcnic_83xx_idc_tx_soft_reset(adapter);
872629263acSSony Chacko 		return ret;
873629263acSSony Chacko 	}
874629263acSSony Chacko 
875629263acSSony Chacko 	/* Move to need quiesce state if requested */
876629263acSSony Chacko 	if (adapter->ahw->idc.quiesce_req) {
877629263acSSony Chacko 		qlcnic_83xx_idc_enter_need_quiesce(adapter, 1);
878629263acSSony Chacko 		qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
879629263acSSony Chacko 		return ret;
880629263acSSony Chacko 	}
881629263acSSony Chacko 
882629263acSSony Chacko 	return ret;
883629263acSSony Chacko }
884629263acSSony Chacko 
885629263acSSony Chacko /**
886629263acSSony Chacko  * qlcnic_83xx_idc_need_reset_state
887629263acSSony Chacko  *
888629263acSSony Chacko  * @adapter: adapter structure
889629263acSSony Chacko  *
890629263acSSony Chacko  * Device will remain in this state until:
891dbedd44eSJoe Perches  *	Reset request ACK's are received from all the functions
892629263acSSony Chacko  *	Wait time exceeds max time limit
893629263acSSony Chacko  *
894629263acSSony Chacko  * Returns: Error code or Success(0)
895629263acSSony Chacko  *
896629263acSSony Chacko  **/
qlcnic_83xx_idc_need_reset_state(struct qlcnic_adapter * adapter)897629263acSSony Chacko static int qlcnic_83xx_idc_need_reset_state(struct qlcnic_adapter *adapter)
898629263acSSony Chacko {
899068a8d19SManish Chopra 	struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
900629263acSSony Chacko 	int ret = 0;
901629263acSSony Chacko 
902629263acSSony Chacko 	if (adapter->ahw->idc.prev_state != QLC_83XX_IDC_DEV_NEED_RESET) {
903629263acSSony Chacko 		qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
904629263acSSony Chacko 		set_bit(__QLCNIC_RESETTING, &adapter->state);
905068a8d19SManish Chopra 		clear_bit(QLC_83XX_MBX_READY, &mbx->status);
90634e8c406SHimanshu Madhani 		if (adapter->ahw->nic_mode == QLCNIC_VNIC_MODE)
907d71170fbSSony Chacko 			qlcnic_83xx_disable_vnic_mode(adapter, 1);
908099907faSSony Chacko 
909099907faSSony Chacko 		if (qlcnic_check_diag_status(adapter)) {
910099907faSSony Chacko 			dev_info(&adapter->pdev->dev,
911099907faSSony Chacko 				 "%s: Wait for diag completion\n", __func__);
912099907faSSony Chacko 			adapter->ahw->idc.delay_reset = 1;
913099907faSSony Chacko 			return 0;
914099907faSSony Chacko 		} else {
915099907faSSony Chacko 			qlcnic_83xx_idc_update_drv_ack_reg(adapter, 1, 1);
916629263acSSony Chacko 			qlcnic_83xx_idc_detach_driver(adapter);
917629263acSSony Chacko 		}
918099907faSSony Chacko 	}
919629263acSSony Chacko 
920099907faSSony Chacko 	if (qlcnic_check_diag_status(adapter)) {
921099907faSSony Chacko 		dev_info(&adapter->pdev->dev,
922099907faSSony Chacko 			 "%s: Wait for diag completion\n", __func__);
923099907faSSony Chacko 		return  -1;
924099907faSSony Chacko 	} else {
925099907faSSony Chacko 		if (adapter->ahw->idc.delay_reset) {
926099907faSSony Chacko 			qlcnic_83xx_idc_update_drv_ack_reg(adapter, 1, 1);
927099907faSSony Chacko 			qlcnic_83xx_idc_detach_driver(adapter);
928099907faSSony Chacko 			adapter->ahw->idc.delay_reset = 0;
929099907faSSony Chacko 		}
930099907faSSony Chacko 
931099907faSSony Chacko 		/* Check for ACK from other functions */
932629263acSSony Chacko 		ret = qlcnic_83xx_idc_check_reset_ack_reg(adapter);
933629263acSSony Chacko 		if (ret) {
934629263acSSony Chacko 			dev_info(&adapter->pdev->dev,
935629263acSSony Chacko 				 "%s: Waiting for reset ACK\n", __func__);
936099907faSSony Chacko 			return -1;
937099907faSSony Chacko 		}
938629263acSSony Chacko 	}
939629263acSSony Chacko 
940629263acSSony Chacko 	/* Transit to INIT state and restart the HW */
941629263acSSony Chacko 	qlcnic_83xx_idc_enter_init_state(adapter, 1);
942629263acSSony Chacko 
943629263acSSony Chacko 	return ret;
944629263acSSony Chacko }
945629263acSSony Chacko 
qlcnic_83xx_idc_need_quiesce_state(struct qlcnic_adapter * adapter)946629263acSSony Chacko static int qlcnic_83xx_idc_need_quiesce_state(struct qlcnic_adapter *adapter)
947629263acSSony Chacko {
948629263acSSony Chacko 	dev_err(&adapter->pdev->dev, "%s: TBD\n", __func__);
949629263acSSony Chacko 	return 0;
950629263acSSony Chacko }
951629263acSSony Chacko 
qlcnic_83xx_idc_failed_state(struct qlcnic_adapter * adapter)95230fa15f6SManish Chopra static void qlcnic_83xx_idc_failed_state(struct qlcnic_adapter *adapter)
953629263acSSony Chacko {
95430fa15f6SManish Chopra 	struct qlcnic_hardware_context *ahw = adapter->ahw;
95530fa15f6SManish Chopra 	u32 val, owner;
956629263acSSony Chacko 
95730fa15f6SManish Chopra 	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
95830fa15f6SManish Chopra 	if (val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) {
95930fa15f6SManish Chopra 		owner = qlcnic_83xx_idc_find_reset_owner_id(adapter);
96030fa15f6SManish Chopra 		if (ahw->pci_func == owner) {
96130fa15f6SManish Chopra 			qlcnic_83xx_stop_hw(adapter);
96230fa15f6SManish Chopra 			qlcnic_dump_fw(adapter);
96330fa15f6SManish Chopra 		}
96430fa15f6SManish Chopra 	}
96530fa15f6SManish Chopra 
96630fa15f6SManish Chopra 	netdev_warn(adapter->netdev, "%s: Reboot will be required to recover the adapter!!\n",
96730fa15f6SManish Chopra 		    __func__);
96830fa15f6SManish Chopra 	clear_bit(__QLCNIC_RESETTING, &adapter->state);
96930fa15f6SManish Chopra 	ahw->idc.err_code = -EIO;
97030fa15f6SManish Chopra 
97130fa15f6SManish Chopra 	return;
972629263acSSony Chacko }
973629263acSSony Chacko 
qlcnic_83xx_idc_quiesce_state(struct qlcnic_adapter * adapter)974629263acSSony Chacko static int qlcnic_83xx_idc_quiesce_state(struct qlcnic_adapter *adapter)
975629263acSSony Chacko {
976629263acSSony Chacko 	dev_info(&adapter->pdev->dev, "%s: TBD\n", __func__);
977629263acSSony Chacko 	return 0;
978629263acSSony Chacko }
979629263acSSony Chacko 
qlcnic_83xx_idc_check_state_validity(struct qlcnic_adapter * adapter,u32 state)980629263acSSony Chacko static int qlcnic_83xx_idc_check_state_validity(struct qlcnic_adapter *adapter,
981629263acSSony Chacko 						u32 state)
982629263acSSony Chacko {
983629263acSSony Chacko 	u32 cur, prev, next;
984629263acSSony Chacko 
985629263acSSony Chacko 	cur = adapter->ahw->idc.curr_state;
986629263acSSony Chacko 	prev = adapter->ahw->idc.prev_state;
987629263acSSony Chacko 	next = state;
988629263acSSony Chacko 
989629263acSSony Chacko 	if ((next < QLC_83XX_IDC_DEV_COLD) ||
990629263acSSony Chacko 	    (next > QLC_83XX_IDC_DEV_QUISCENT)) {
991629263acSSony Chacko 		dev_err(&adapter->pdev->dev,
992629263acSSony Chacko 			"%s: curr %d, prev %d, next state %d is  invalid\n",
993629263acSSony Chacko 			__func__, cur, prev, state);
994629263acSSony Chacko 		return 1;
995629263acSSony Chacko 	}
996629263acSSony Chacko 
997629263acSSony Chacko 	if ((cur == QLC_83XX_IDC_DEV_UNKNOWN) &&
998629263acSSony Chacko 	    (prev == QLC_83XX_IDC_DEV_UNKNOWN)) {
999629263acSSony Chacko 		if ((next != QLC_83XX_IDC_DEV_COLD) &&
1000629263acSSony Chacko 		    (next != QLC_83XX_IDC_DEV_READY)) {
1001629263acSSony Chacko 			dev_err(&adapter->pdev->dev,
1002629263acSSony Chacko 				"%s: failed, cur %d prev %d next %d\n",
1003629263acSSony Chacko 				__func__, cur, prev, next);
1004629263acSSony Chacko 			return 1;
1005629263acSSony Chacko 		}
1006629263acSSony Chacko 	}
1007629263acSSony Chacko 
1008629263acSSony Chacko 	if (next == QLC_83XX_IDC_DEV_INIT) {
1009629263acSSony Chacko 		if ((prev != QLC_83XX_IDC_DEV_INIT) &&
1010629263acSSony Chacko 		    (prev != QLC_83XX_IDC_DEV_COLD) &&
1011629263acSSony Chacko 		    (prev != QLC_83XX_IDC_DEV_NEED_RESET)) {
1012629263acSSony Chacko 			dev_err(&adapter->pdev->dev,
1013629263acSSony Chacko 				"%s: failed, cur %d prev %d next %d\n",
1014629263acSSony Chacko 				__func__, cur, prev, next);
1015629263acSSony Chacko 			return 1;
1016629263acSSony Chacko 		}
1017629263acSSony Chacko 	}
1018629263acSSony Chacko 
1019629263acSSony Chacko 	return 0;
1020629263acSSony Chacko }
1021629263acSSony Chacko 
10222b3d7b75SShahed Shaikh #define QLC_83XX_ENCAP_TYPE_VXLAN	BIT_1
10232b3d7b75SShahed Shaikh #define QLC_83XX_MATCH_ENCAP_ID		BIT_2
10242b3d7b75SShahed Shaikh #define QLC_83XX_SET_VXLAN_UDP_DPORT	BIT_3
10252b3d7b75SShahed Shaikh #define QLC_83XX_VXLAN_UDP_DPORT(PORT)	((PORT & 0xffff) << 16)
10262b3d7b75SShahed Shaikh 
10272b3d7b75SShahed Shaikh #define QLCNIC_ENABLE_INGRESS_ENCAP_PARSING 1
10282b3d7b75SShahed Shaikh #define QLCNIC_DISABLE_INGRESS_ENCAP_PARSING 0
10292b3d7b75SShahed Shaikh 
qlcnic_set_vxlan_port(struct qlcnic_adapter * adapter,u16 port)103078c6bc2bSJakub Kicinski int qlcnic_set_vxlan_port(struct qlcnic_adapter *adapter, u16 port)
10312b3d7b75SShahed Shaikh {
10322b3d7b75SShahed Shaikh 	struct qlcnic_cmd_args cmd;
10332b3d7b75SShahed Shaikh 	int ret = 0;
10342b3d7b75SShahed Shaikh 
10352b3d7b75SShahed Shaikh 	memset(&cmd, 0, sizeof(cmd));
10362b3d7b75SShahed Shaikh 
10372b3d7b75SShahed Shaikh 	ret = qlcnic_alloc_mbx_args(&cmd, adapter,
10382b3d7b75SShahed Shaikh 				    QLCNIC_CMD_INIT_NIC_FUNC);
10392b3d7b75SShahed Shaikh 	if (ret)
10402b3d7b75SShahed Shaikh 		return ret;
10412b3d7b75SShahed Shaikh 
10422b3d7b75SShahed Shaikh 	cmd.req.arg[1] = QLC_83XX_MULTI_TENANCY_INFO;
10432b3d7b75SShahed Shaikh 	cmd.req.arg[2] = QLC_83XX_ENCAP_TYPE_VXLAN |
10442b3d7b75SShahed Shaikh 			 QLC_83XX_SET_VXLAN_UDP_DPORT |
10452b3d7b75SShahed Shaikh 			 QLC_83XX_VXLAN_UDP_DPORT(port);
10462b3d7b75SShahed Shaikh 
10472b3d7b75SShahed Shaikh 	ret = qlcnic_issue_cmd(adapter, &cmd);
10482b3d7b75SShahed Shaikh 	if (ret)
10492b3d7b75SShahed Shaikh 		netdev_err(adapter->netdev,
10502b3d7b75SShahed Shaikh 			   "Failed to set VXLAN port %d in adapter\n",
10512b3d7b75SShahed Shaikh 			   port);
10522b3d7b75SShahed Shaikh 
10532b3d7b75SShahed Shaikh 	qlcnic_free_mbx_args(&cmd);
10542b3d7b75SShahed Shaikh 
10552b3d7b75SShahed Shaikh 	return ret;
10562b3d7b75SShahed Shaikh }
10572b3d7b75SShahed Shaikh 
qlcnic_set_vxlan_parsing(struct qlcnic_adapter * adapter,u16 port)105878c6bc2bSJakub Kicinski int qlcnic_set_vxlan_parsing(struct qlcnic_adapter *adapter, u16 port)
10592b3d7b75SShahed Shaikh {
10602b3d7b75SShahed Shaikh 	struct qlcnic_cmd_args cmd;
10612b3d7b75SShahed Shaikh 	int ret = 0;
10622b3d7b75SShahed Shaikh 
10632b3d7b75SShahed Shaikh 	memset(&cmd, 0, sizeof(cmd));
10642b3d7b75SShahed Shaikh 
10652b3d7b75SShahed Shaikh 	ret = qlcnic_alloc_mbx_args(&cmd, adapter,
10662b3d7b75SShahed Shaikh 				    QLCNIC_CMD_SET_INGRESS_ENCAP);
10672b3d7b75SShahed Shaikh 	if (ret)
10682b3d7b75SShahed Shaikh 		return ret;
10692b3d7b75SShahed Shaikh 
107078c6bc2bSJakub Kicinski 	cmd.req.arg[1] = port ? QLCNIC_ENABLE_INGRESS_ENCAP_PARSING :
10712b3d7b75SShahed Shaikh 				QLCNIC_DISABLE_INGRESS_ENCAP_PARSING;
10722b3d7b75SShahed Shaikh 
10732b3d7b75SShahed Shaikh 	ret = qlcnic_issue_cmd(adapter, &cmd);
10742b3d7b75SShahed Shaikh 	if (ret)
10752b3d7b75SShahed Shaikh 		netdev_err(adapter->netdev,
10762b3d7b75SShahed Shaikh 			   "Failed to %s VXLAN parsing for port %d\n",
107778c6bc2bSJakub Kicinski 			   port ? "enable" : "disable", port);
10782b3d7b75SShahed Shaikh 	else
10792b3d7b75SShahed Shaikh 		netdev_info(adapter->netdev,
10802b3d7b75SShahed Shaikh 			    "%s VXLAN parsing for port %d\n",
108178c6bc2bSJakub Kicinski 			    port ? "Enabled" : "Disabled", port);
10822b3d7b75SShahed Shaikh 
10832b3d7b75SShahed Shaikh 	qlcnic_free_mbx_args(&cmd);
10842b3d7b75SShahed Shaikh 
10852b3d7b75SShahed Shaikh 	return ret;
10862b3d7b75SShahed Shaikh }
10872b3d7b75SShahed Shaikh 
qlcnic_83xx_periodic_tasks(struct qlcnic_adapter * adapter)1088629263acSSony Chacko static void qlcnic_83xx_periodic_tasks(struct qlcnic_adapter *adapter)
1089629263acSSony Chacko {
1090629263acSSony Chacko 	if (adapter->fhash.fnum)
1091629263acSSony Chacko 		qlcnic_prune_lb_filters(adapter);
1092629263acSSony Chacko }
1093629263acSSony Chacko 
1094629263acSSony Chacko /**
1095629263acSSony Chacko  * qlcnic_83xx_idc_poll_dev_state
1096629263acSSony Chacko  *
1097629263acSSony Chacko  * @work: kernel work queue structure used to schedule the function
1098629263acSSony Chacko  *
1099629263acSSony Chacko  * Poll device state periodically and perform state specific
1100629263acSSony Chacko  * actions defined by Inter Driver Communication (IDC) protocol.
1101629263acSSony Chacko  *
1102629263acSSony Chacko  * Returns: None
1103629263acSSony Chacko  *
1104629263acSSony Chacko  **/
qlcnic_83xx_idc_poll_dev_state(struct work_struct * work)1105629263acSSony Chacko void qlcnic_83xx_idc_poll_dev_state(struct work_struct *work)
1106629263acSSony Chacko {
1107629263acSSony Chacko 	struct qlcnic_adapter *adapter;
1108629263acSSony Chacko 	u32 state;
1109629263acSSony Chacko 
1110629263acSSony Chacko 	adapter = container_of(work, struct qlcnic_adapter, fw_work.work);
1111629263acSSony Chacko 	state =	QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE);
1112629263acSSony Chacko 
1113629263acSSony Chacko 	if (qlcnic_83xx_idc_check_state_validity(adapter, state)) {
1114629263acSSony Chacko 		qlcnic_83xx_idc_log_state_history(adapter);
1115629263acSSony Chacko 		adapter->ahw->idc.curr_state = QLC_83XX_IDC_DEV_UNKNOWN;
1116629263acSSony Chacko 	} else {
1117629263acSSony Chacko 		adapter->ahw->idc.curr_state = state;
1118629263acSSony Chacko 	}
1119629263acSSony Chacko 
1120629263acSSony Chacko 	switch (adapter->ahw->idc.curr_state) {
1121629263acSSony Chacko 	case QLC_83XX_IDC_DEV_READY:
1122629263acSSony Chacko 		qlcnic_83xx_idc_ready_state(adapter);
1123629263acSSony Chacko 		break;
1124629263acSSony Chacko 	case QLC_83XX_IDC_DEV_NEED_RESET:
1125629263acSSony Chacko 		qlcnic_83xx_idc_need_reset_state(adapter);
1126629263acSSony Chacko 		break;
1127629263acSSony Chacko 	case QLC_83XX_IDC_DEV_NEED_QUISCENT:
1128629263acSSony Chacko 		qlcnic_83xx_idc_need_quiesce_state(adapter);
1129629263acSSony Chacko 		break;
1130629263acSSony Chacko 	case QLC_83XX_IDC_DEV_FAILED:
1131629263acSSony Chacko 		qlcnic_83xx_idc_failed_state(adapter);
1132629263acSSony Chacko 		return;
1133629263acSSony Chacko 	case QLC_83XX_IDC_DEV_INIT:
1134629263acSSony Chacko 		qlcnic_83xx_idc_init_state(adapter);
1135629263acSSony Chacko 		break;
1136629263acSSony Chacko 	case QLC_83XX_IDC_DEV_QUISCENT:
1137629263acSSony Chacko 		qlcnic_83xx_idc_quiesce_state(adapter);
1138629263acSSony Chacko 		break;
1139629263acSSony Chacko 	default:
1140629263acSSony Chacko 		qlcnic_83xx_idc_unknown_state(adapter);
1141629263acSSony Chacko 		return;
1142629263acSSony Chacko 	}
1143629263acSSony Chacko 	adapter->ahw->idc.prev_state = adapter->ahw->idc.curr_state;
1144629263acSSony Chacko 	qlcnic_83xx_periodic_tasks(adapter);
1145629263acSSony Chacko 
1146629263acSSony Chacko 	/* Re-schedule the function */
1147629263acSSony Chacko 	if (test_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status))
1148629263acSSony Chacko 		qlcnic_schedule_work(adapter, qlcnic_83xx_idc_poll_dev_state,
1149629263acSSony Chacko 				     adapter->ahw->idc.delay);
1150629263acSSony Chacko }
1151629263acSSony Chacko 
qlcnic_83xx_setup_idc_parameters(struct qlcnic_adapter * adapter)1152629263acSSony Chacko static void qlcnic_83xx_setup_idc_parameters(struct qlcnic_adapter *adapter)
1153629263acSSony Chacko {
1154629263acSSony Chacko 	u32 idc_params, val;
1155629263acSSony Chacko 
11564324414fSSony Chacko 	if (qlcnic_83xx_flash_read32(adapter, QLC_83XX_IDC_FLASH_PARAM_ADDR,
1157629263acSSony Chacko 				     (u8 *)&idc_params, 1)) {
1158629263acSSony Chacko 		dev_info(&adapter->pdev->dev,
1159629263acSSony Chacko 			 "%s:failed to get IDC params from flash\n", __func__);
1160629263acSSony Chacko 		adapter->dev_init_timeo = QLC_83XX_IDC_INIT_TIMEOUT_SECS;
1161629263acSSony Chacko 		adapter->reset_ack_timeo = QLC_83XX_IDC_RESET_TIMEOUT_SECS;
1162629263acSSony Chacko 	} else {
1163629263acSSony Chacko 		adapter->dev_init_timeo = idc_params & 0xFFFF;
1164629263acSSony Chacko 		adapter->reset_ack_timeo = ((idc_params >> 16) & 0xFFFF);
1165629263acSSony Chacko 	}
1166629263acSSony Chacko 
1167629263acSSony Chacko 	adapter->ahw->idc.curr_state = QLC_83XX_IDC_DEV_UNKNOWN;
1168629263acSSony Chacko 	adapter->ahw->idc.prev_state = QLC_83XX_IDC_DEV_UNKNOWN;
1169629263acSSony Chacko 	adapter->ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY;
1170629263acSSony Chacko 	adapter->ahw->idc.err_code = 0;
1171629263acSSony Chacko 	adapter->ahw->idc.collect_dump = 0;
1172629263acSSony Chacko 	adapter->ahw->idc.name = (char **)qlc_83xx_idc_states;
1173629263acSSony Chacko 
1174629263acSSony Chacko 	clear_bit(__QLCNIC_RESETTING, &adapter->state);
1175629263acSSony Chacko 	set_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
1176629263acSSony Chacko 
1177629263acSSony Chacko 	/* Check if reset recovery is disabled */
1178629263acSSony Chacko 	if (!qlcnic_auto_fw_reset) {
1179629263acSSony Chacko 		/* Propagate do not reset request to other functions */
1180629263acSSony Chacko 		val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
1181629263acSSony Chacko 		val = val | QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY;
1182629263acSSony Chacko 		QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
1183629263acSSony Chacko 	}
1184629263acSSony Chacko }
1185629263acSSony Chacko 
1186629263acSSony Chacko static int
qlcnic_83xx_idc_first_to_load_function_handler(struct qlcnic_adapter * adapter)1187629263acSSony Chacko qlcnic_83xx_idc_first_to_load_function_handler(struct qlcnic_adapter *adapter)
1188629263acSSony Chacko {
1189629263acSSony Chacko 	u32 state, val;
1190629263acSSony Chacko 
1191629263acSSony Chacko 	if (qlcnic_83xx_lock_driver(adapter))
1192629263acSSony Chacko 		return -EIO;
1193629263acSSony Chacko 
1194629263acSSony Chacko 	/* Clear driver lock register */
1195629263acSSony Chacko 	QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, 0);
1196629263acSSony Chacko 	if (qlcnic_83xx_idc_update_major_version(adapter, 0)) {
1197629263acSSony Chacko 		qlcnic_83xx_unlock_driver(adapter);
1198629263acSSony Chacko 		return -EIO;
1199629263acSSony Chacko 	}
1200629263acSSony Chacko 
1201629263acSSony Chacko 	state =	QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE);
1202629263acSSony Chacko 	if (qlcnic_83xx_idc_check_state_validity(adapter, state)) {
1203629263acSSony Chacko 		qlcnic_83xx_unlock_driver(adapter);
1204629263acSSony Chacko 		return -EIO;
1205629263acSSony Chacko 	}
1206629263acSSony Chacko 
1207629263acSSony Chacko 	if (state != QLC_83XX_IDC_DEV_COLD && qlcnic_load_fw_file) {
1208629263acSSony Chacko 		QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
1209629263acSSony Chacko 		       QLC_83XX_IDC_DEV_COLD);
1210629263acSSony Chacko 		state = QLC_83XX_IDC_DEV_COLD;
1211629263acSSony Chacko 	}
1212629263acSSony Chacko 
1213629263acSSony Chacko 	adapter->ahw->idc.curr_state = state;
1214629263acSSony Chacko 	/* First to load function should cold boot the device */
1215629263acSSony Chacko 	if (state == QLC_83XX_IDC_DEV_COLD)
1216629263acSSony Chacko 		qlcnic_83xx_idc_cold_state_handler(adapter);
1217629263acSSony Chacko 
1218629263acSSony Chacko 	/* Check if reset recovery is enabled */
1219629263acSSony Chacko 	if (qlcnic_auto_fw_reset) {
1220629263acSSony Chacko 		val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
1221629263acSSony Chacko 		val = val & ~QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY;
1222629263acSSony Chacko 		QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
1223629263acSSony Chacko 	}
1224629263acSSony Chacko 
1225629263acSSony Chacko 	qlcnic_83xx_unlock_driver(adapter);
1226629263acSSony Chacko 
1227629263acSSony Chacko 	return 0;
1228629263acSSony Chacko }
1229629263acSSony Chacko 
qlcnic_83xx_idc_init(struct qlcnic_adapter * adapter)1230486a5bc7SRajesh Borundia int qlcnic_83xx_idc_init(struct qlcnic_adapter *adapter)
1231629263acSSony Chacko {
123281d0aeb0SSony Chacko 	int ret = -EIO;
123381d0aeb0SSony Chacko 
1234629263acSSony Chacko 	qlcnic_83xx_setup_idc_parameters(adapter);
1235629263acSSony Chacko 
123681d0aeb0SSony Chacko 	if (qlcnic_83xx_get_reset_instruction_template(adapter))
123781d0aeb0SSony Chacko 		return ret;
123881d0aeb0SSony Chacko 
1239629263acSSony Chacko 	if (!qlcnic_83xx_idc_check_driver_presence_reg(adapter)) {
1240629263acSSony Chacko 		if (qlcnic_83xx_idc_first_to_load_function_handler(adapter))
1241629263acSSony Chacko 			return -EIO;
1242629263acSSony Chacko 	} else {
1243629263acSSony Chacko 		if (qlcnic_83xx_idc_check_major_version(adapter))
1244629263acSSony Chacko 			return -EIO;
1245629263acSSony Chacko 	}
1246629263acSSony Chacko 
1247629263acSSony Chacko 	qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
1248629263acSSony Chacko 
1249629263acSSony Chacko 	return 0;
1250629263acSSony Chacko }
1251629263acSSony Chacko 
qlcnic_83xx_idc_exit(struct qlcnic_adapter * adapter)1252629263acSSony Chacko void qlcnic_83xx_idc_exit(struct qlcnic_adapter *adapter)
1253629263acSSony Chacko {
1254629263acSSony Chacko 	int id;
1255629263acSSony Chacko 	u32 val;
1256629263acSSony Chacko 
1257629263acSSony Chacko 	while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
1258629263acSSony Chacko 		usleep_range(10000, 11000);
1259629263acSSony Chacko 
1260629263acSSony Chacko 	id = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
1261629263acSSony Chacko 	id = id & 0xFF;
1262629263acSSony Chacko 
1263629263acSSony Chacko 	if (id == adapter->portnum) {
1264629263acSSony Chacko 		dev_err(&adapter->pdev->dev,
1265629263acSSony Chacko 			"%s: wait for lock recovery.. %d\n", __func__, id);
1266629263acSSony Chacko 		msleep(20);
1267629263acSSony Chacko 		id = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
1268629263acSSony Chacko 		id = id & 0xFF;
1269629263acSSony Chacko 	}
1270629263acSSony Chacko 
1271629263acSSony Chacko 	/* Clear driver presence bit */
1272629263acSSony Chacko 	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
1273629263acSSony Chacko 	val = val & ~(1 << adapter->portnum);
1274629263acSSony Chacko 	QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE, val);
1275629263acSSony Chacko 	clear_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
1276629263acSSony Chacko 	clear_bit(__QLCNIC_RESETTING, &adapter->state);
1277629263acSSony Chacko 
1278629263acSSony Chacko 	cancel_delayed_work_sync(&adapter->fw_work);
1279629263acSSony Chacko }
1280629263acSSony Chacko 
qlcnic_83xx_idc_request_reset(struct qlcnic_adapter * adapter,u32 key)1281629263acSSony Chacko void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *adapter, u32 key)
1282629263acSSony Chacko {
1283629263acSSony Chacko 	u32 val;
1284629263acSSony Chacko 
1285068a8d19SManish Chopra 	if (qlcnic_sriov_vf_check(adapter))
1286068a8d19SManish Chopra 		return;
1287068a8d19SManish Chopra 
1288629263acSSony Chacko 	if (qlcnic_83xx_lock_driver(adapter)) {
1289629263acSSony Chacko 		dev_err(&adapter->pdev->dev,
1290629263acSSony Chacko 			"%s:failed, please retry\n", __func__);
1291629263acSSony Chacko 		return;
1292629263acSSony Chacko 	}
1293629263acSSony Chacko 
1294629263acSSony Chacko 	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
129530fa15f6SManish Chopra 	if (val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) {
129630fa15f6SManish Chopra 		netdev_info(adapter->netdev, "%s: Auto firmware recovery is disabled\n",
129730fa15f6SManish Chopra 			    __func__);
129830fa15f6SManish Chopra 		qlcnic_83xx_idc_enter_failed_state(adapter, 0);
1299629263acSSony Chacko 		qlcnic_83xx_unlock_driver(adapter);
1300629263acSSony Chacko 		return;
1301629263acSSony Chacko 	}
1302629263acSSony Chacko 
1303629263acSSony Chacko 	if (key == QLCNIC_FORCE_FW_RESET) {
1304629263acSSony Chacko 		val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
1305629263acSSony Chacko 		val = val | QLC_83XX_IDC_GRACEFULL_RESET;
1306629263acSSony Chacko 		QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
1307629263acSSony Chacko 	} else if (key == QLCNIC_FORCE_FW_DUMP_KEY) {
1308629263acSSony Chacko 		adapter->ahw->idc.collect_dump = 1;
1309629263acSSony Chacko 	}
1310629263acSSony Chacko 
1311629263acSSony Chacko 	qlcnic_83xx_unlock_driver(adapter);
1312629263acSSony Chacko 	return;
1313629263acSSony Chacko }
1314629263acSSony Chacko 
qlcnic_83xx_copy_bootloader(struct qlcnic_adapter * adapter)1315629263acSSony Chacko static int qlcnic_83xx_copy_bootloader(struct qlcnic_adapter *adapter)
1316629263acSSony Chacko {
1317629263acSSony Chacko 	u8 *p_cache;
1318629263acSSony Chacko 	u32 src, size;
1319629263acSSony Chacko 	u64 dest;
1320629263acSSony Chacko 	int ret = -EIO;
1321629263acSSony Chacko 
1322629263acSSony Chacko 	src = QLC_83XX_BOOTLOADER_FLASH_ADDR;
1323629263acSSony Chacko 	dest = QLCRDX(adapter->ahw, QLCNIC_BOOTLOADER_ADDR);
1324629263acSSony Chacko 	size = QLCRDX(adapter->ahw, QLCNIC_BOOTLOADER_SIZE);
1325629263acSSony Chacko 
1326629263acSSony Chacko 	/* alignment check */
1327629263acSSony Chacko 	if (size & 0xF)
1328629263acSSony Chacko 		size = (size + 16) & ~0xF;
1329629263acSSony Chacko 
13303fc38e26SManish Chopra 	p_cache = vzalloc(size);
1331b2adaca9SJoe Perches 	if (p_cache == NULL)
1332629263acSSony Chacko 		return -ENOMEM;
1333b2adaca9SJoe Perches 
1334629263acSSony Chacko 	ret = qlcnic_83xx_lockless_flash_read32(adapter, src, p_cache,
1335629263acSSony Chacko 						size / sizeof(u32));
1336629263acSSony Chacko 	if (ret) {
13373fc38e26SManish Chopra 		vfree(p_cache);
1338629263acSSony Chacko 		return ret;
1339629263acSSony Chacko 	}
1340629263acSSony Chacko 	/* 16 byte write to MS memory */
13418d37ba02SShahed Shaikh 	ret = qlcnic_ms_mem_write128(adapter, dest, (u32 *)p_cache,
1342629263acSSony Chacko 				     size / 16);
1343629263acSSony Chacko 	if (ret) {
13443fc38e26SManish Chopra 		vfree(p_cache);
1345629263acSSony Chacko 		return ret;
1346629263acSSony Chacko 	}
13473fc38e26SManish Chopra 	vfree(p_cache);
1348629263acSSony Chacko 
1349629263acSSony Chacko 	return ret;
1350629263acSSony Chacko }
1351629263acSSony Chacko 
qlcnic_83xx_copy_fw_file(struct qlcnic_adapter * adapter)1352629263acSSony Chacko static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
1353629263acSSony Chacko {
13547000078aSPratik Pujar 	struct qlc_83xx_fw_info *fw_info = adapter->ahw->fw_info;
13557000078aSPratik Pujar 	const struct firmware *fw = fw_info->fw;
13563d8623e6SShahed Shaikh 	u32 dest, *p_cache, *temp;
13573d8623e6SShahed Shaikh 	__le32 *temp_le;
1358629263acSSony Chacko 	u8 data[16];
1359629263acSSony Chacko 	size_t size;
1360666eb96dSColin Ian King 	int i, ret;
13617000078aSPratik Pujar 	u64 addr;
1362629263acSSony Chacko 
13630e90ad9bSShahed Shaikh 	temp = vzalloc(fw->size);
13643d8623e6SShahed Shaikh 	if (!temp) {
13653d8623e6SShahed Shaikh 		release_firmware(fw);
13663d8623e6SShahed Shaikh 		fw_info->fw = NULL;
13673d8623e6SShahed Shaikh 		return -ENOMEM;
13683d8623e6SShahed Shaikh 	}
13693d8623e6SShahed Shaikh 
13703d8623e6SShahed Shaikh 	temp_le = (__le32 *)fw->data;
13713d8623e6SShahed Shaikh 
13723d8623e6SShahed Shaikh 	/* FW image in file is in little endian, swap the data to nullify
13733d8623e6SShahed Shaikh 	 * the effect of writel() operation on big endian platform.
13743d8623e6SShahed Shaikh 	 */
13753d8623e6SShahed Shaikh 	for (i = 0; i < fw->size / sizeof(u32); i++)
13763d8623e6SShahed Shaikh 		temp[i] = __le32_to_cpu(temp_le[i]);
13773d8623e6SShahed Shaikh 
1378629263acSSony Chacko 	dest = QLCRDX(adapter->ahw, QLCNIC_FW_IMAGE_ADDR);
13797000078aSPratik Pujar 	size = (fw->size & ~0xF);
13803d8623e6SShahed Shaikh 	p_cache = temp;
1381629263acSSony Chacko 	addr = (u64)dest;
1382629263acSSony Chacko 
13838d37ba02SShahed Shaikh 	ret = qlcnic_ms_mem_write128(adapter, addr,
13844e2e865dSJoe Perches 				     p_cache, size / 16);
1385629263acSSony Chacko 	if (ret) {
1386629263acSSony Chacko 		dev_err(&adapter->pdev->dev, "MS memory write failed\n");
13873d8623e6SShahed Shaikh 		goto exit;
1388629263acSSony Chacko 	}
1389629263acSSony Chacko 
1390629263acSSony Chacko 	/* alignment check */
13917000078aSPratik Pujar 	if (fw->size & 0xF) {
1392629263acSSony Chacko 		addr = dest + size;
13937000078aSPratik Pujar 		for (i = 0; i < (fw->size & 0xF); i++)
139415f1bb1fSShahed Shaikh 			data[i] = ((u8 *)temp)[size + i];
1395629263acSSony Chacko 		for (; i < 16; i++)
1396629263acSSony Chacko 			data[i] = 0;
13978d37ba02SShahed Shaikh 		ret = qlcnic_ms_mem_write128(adapter, addr,
1398629263acSSony Chacko 					     (u32 *)data, 1);
1399629263acSSony Chacko 		if (ret) {
1400629263acSSony Chacko 			dev_err(&adapter->pdev->dev,
1401629263acSSony Chacko 				"MS memory write failed\n");
14023d8623e6SShahed Shaikh 			goto exit;
1403629263acSSony Chacko 		}
1404629263acSSony Chacko 	}
1405629263acSSony Chacko 
14063d8623e6SShahed Shaikh exit:
14073d8623e6SShahed Shaikh 	release_firmware(fw);
14083d8623e6SShahed Shaikh 	fw_info->fw = NULL;
14090e90ad9bSShahed Shaikh 	vfree(temp);
14103d8623e6SShahed Shaikh 
14113d8623e6SShahed Shaikh 	return ret;
1412629263acSSony Chacko }
1413629263acSSony Chacko 
qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter * adapter)1414629263acSSony Chacko static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
1415629263acSSony Chacko {
1416629263acSSony Chacko 	int i, j;
1417629263acSSony Chacko 	u32 val = 0, val1 = 0, reg = 0;
14184bd8e738SHimanshu Madhani 	int err = 0;
1419629263acSSony Chacko 
14204bd8e738SHimanshu Madhani 	val = QLCRD32(adapter, QLC_83XX_SRE_SHIM_REG, &err);
14214bd8e738SHimanshu Madhani 	if (err == -EIO)
14224bd8e738SHimanshu Madhani 		return;
1423629263acSSony Chacko 	dev_info(&adapter->pdev->dev, "SRE-Shim Ctrl:0x%x\n", val);
1424629263acSSony Chacko 
1425629263acSSony Chacko 	for (j = 0; j < 2; j++) {
1426629263acSSony Chacko 		if (j == 0) {
1427629263acSSony Chacko 			dev_info(&adapter->pdev->dev,
1428629263acSSony Chacko 				 "Port 0 RxB Pause Threshold Regs[TC7..TC0]:");
1429629263acSSony Chacko 			reg = QLC_83XX_PORT0_THRESHOLD;
1430629263acSSony Chacko 		} else if (j == 1) {
1431629263acSSony Chacko 			dev_info(&adapter->pdev->dev,
1432629263acSSony Chacko 				 "Port 1 RxB Pause Threshold Regs[TC7..TC0]:");
1433629263acSSony Chacko 			reg = QLC_83XX_PORT1_THRESHOLD;
1434629263acSSony Chacko 		}
1435629263acSSony Chacko 		for (i = 0; i < 8; i++) {
14364bd8e738SHimanshu Madhani 			val = QLCRD32(adapter, reg + (i * 0x4), &err);
14374bd8e738SHimanshu Madhani 			if (err == -EIO)
14384bd8e738SHimanshu Madhani 				return;
1439629263acSSony Chacko 			dev_info(&adapter->pdev->dev, "0x%x  ", val);
1440629263acSSony Chacko 		}
1441629263acSSony Chacko 		dev_info(&adapter->pdev->dev, "\n");
1442629263acSSony Chacko 	}
1443629263acSSony Chacko 
1444629263acSSony Chacko 	for (j = 0; j < 2; j++) {
1445629263acSSony Chacko 		if (j == 0) {
1446629263acSSony Chacko 			dev_info(&adapter->pdev->dev,
1447629263acSSony Chacko 				 "Port 0 RxB TC Max Cell Registers[4..1]:");
1448629263acSSony Chacko 			reg = QLC_83XX_PORT0_TC_MC_REG;
1449629263acSSony Chacko 		} else if (j == 1) {
1450629263acSSony Chacko 			dev_info(&adapter->pdev->dev,
1451629263acSSony Chacko 				 "Port 1 RxB TC Max Cell Registers[4..1]:");
1452629263acSSony Chacko 			reg = QLC_83XX_PORT1_TC_MC_REG;
1453629263acSSony Chacko 		}
1454629263acSSony Chacko 		for (i = 0; i < 4; i++) {
14554bd8e738SHimanshu Madhani 			val = QLCRD32(adapter, reg + (i * 0x4), &err);
14564bd8e738SHimanshu Madhani 			if (err == -EIO)
14574bd8e738SHimanshu Madhani 				return;
1458629263acSSony Chacko 			dev_info(&adapter->pdev->dev, "0x%x  ", val);
1459629263acSSony Chacko 		}
1460629263acSSony Chacko 		dev_info(&adapter->pdev->dev, "\n");
1461629263acSSony Chacko 	}
1462629263acSSony Chacko 
1463629263acSSony Chacko 	for (j = 0; j < 2; j++) {
1464629263acSSony Chacko 		if (j == 0) {
1465629263acSSony Chacko 			dev_info(&adapter->pdev->dev,
1466629263acSSony Chacko 				 "Port 0 RxB Rx TC Stats[TC7..TC0]:");
1467629263acSSony Chacko 			reg = QLC_83XX_PORT0_TC_STATS;
1468629263acSSony Chacko 		} else if (j == 1) {
1469629263acSSony Chacko 			dev_info(&adapter->pdev->dev,
1470629263acSSony Chacko 				 "Port 1 RxB Rx TC Stats[TC7..TC0]:");
1471629263acSSony Chacko 			reg = QLC_83XX_PORT1_TC_STATS;
1472629263acSSony Chacko 		}
1473629263acSSony Chacko 		for (i = 7; i >= 0; i--) {
14744bd8e738SHimanshu Madhani 			val = QLCRD32(adapter, reg, &err);
14754bd8e738SHimanshu Madhani 			if (err == -EIO)
14764bd8e738SHimanshu Madhani 				return;
1477629263acSSony Chacko 			val &= ~(0x7 << 29);    /* Reset bits 29 to 31 */
1478629263acSSony Chacko 			QLCWR32(adapter, reg, (val | (i << 29)));
14794bd8e738SHimanshu Madhani 			val = QLCRD32(adapter, reg, &err);
14804bd8e738SHimanshu Madhani 			if (err == -EIO)
14814bd8e738SHimanshu Madhani 				return;
1482629263acSSony Chacko 			dev_info(&adapter->pdev->dev, "0x%x  ", val);
1483629263acSSony Chacko 		}
1484629263acSSony Chacko 		dev_info(&adapter->pdev->dev, "\n");
1485629263acSSony Chacko 	}
1486629263acSSony Chacko 
14874bd8e738SHimanshu Madhani 	val = QLCRD32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD, &err);
14884bd8e738SHimanshu Madhani 	if (err == -EIO)
14894bd8e738SHimanshu Madhani 		return;
14904bd8e738SHimanshu Madhani 	val1 = QLCRD32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD, &err);
14914bd8e738SHimanshu Madhani 	if (err == -EIO)
14924bd8e738SHimanshu Madhani 		return;
1493629263acSSony Chacko 	dev_info(&adapter->pdev->dev,
1494629263acSSony Chacko 		 "IFB-Pause Thresholds: Port 2:0x%x, Port 3:0x%x\n",
1495629263acSSony Chacko 		 val, val1);
1496629263acSSony Chacko }
1497629263acSSony Chacko 
149881d0aeb0SSony Chacko 
qlcnic_83xx_disable_pause_frames(struct qlcnic_adapter * adapter)1499629263acSSony Chacko static void qlcnic_83xx_disable_pause_frames(struct qlcnic_adapter *adapter)
1500629263acSSony Chacko {
1501629263acSSony Chacko 	u32 reg = 0, i, j;
1502629263acSSony Chacko 
1503629263acSSony Chacko 	if (qlcnic_83xx_lock_driver(adapter)) {
1504629263acSSony Chacko 		dev_err(&adapter->pdev->dev,
1505629263acSSony Chacko 			"%s:failed to acquire driver lock\n", __func__);
1506629263acSSony Chacko 		return;
1507629263acSSony Chacko 	}
1508629263acSSony Chacko 
1509629263acSSony Chacko 	qlcnic_83xx_dump_pause_control_regs(adapter);
1510629263acSSony Chacko 	QLCWR32(adapter, QLC_83XX_SRE_SHIM_REG, 0x0);
1511629263acSSony Chacko 
1512629263acSSony Chacko 	for (j = 0; j < 2; j++) {
1513629263acSSony Chacko 		if (j == 0)
1514629263acSSony Chacko 			reg = QLC_83XX_PORT0_THRESHOLD;
1515629263acSSony Chacko 		else if (j == 1)
1516629263acSSony Chacko 			reg = QLC_83XX_PORT1_THRESHOLD;
1517629263acSSony Chacko 
1518629263acSSony Chacko 		for (i = 0; i < 8; i++)
1519629263acSSony Chacko 			QLCWR32(adapter, reg + (i * 0x4), 0x0);
1520629263acSSony Chacko 	}
1521629263acSSony Chacko 
1522629263acSSony Chacko 	for (j = 0; j < 2; j++) {
1523629263acSSony Chacko 		if (j == 0)
1524629263acSSony Chacko 			reg = QLC_83XX_PORT0_TC_MC_REG;
1525629263acSSony Chacko 		else if (j == 1)
1526629263acSSony Chacko 			reg = QLC_83XX_PORT1_TC_MC_REG;
1527629263acSSony Chacko 
1528629263acSSony Chacko 		for (i = 0; i < 4; i++)
1529629263acSSony Chacko 			QLCWR32(adapter, reg + (i * 0x4), 0x03FF03FF);
1530629263acSSony Chacko 	}
1531629263acSSony Chacko 
1532629263acSSony Chacko 	QLCWR32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD, 0);
1533629263acSSony Chacko 	QLCWR32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD, 0);
1534629263acSSony Chacko 	dev_info(&adapter->pdev->dev,
1535629263acSSony Chacko 		 "Disabled pause frames successfully on all ports\n");
1536629263acSSony Chacko 	qlcnic_83xx_unlock_driver(adapter);
1537629263acSSony Chacko }
1538629263acSSony Chacko 
qlcnic_83xx_take_eport_out_of_reset(struct qlcnic_adapter * adapter)1539c0d79cd0SManish Chopra static void qlcnic_83xx_take_eport_out_of_reset(struct qlcnic_adapter *adapter)
1540c0d79cd0SManish Chopra {
1541c0d79cd0SManish Chopra 	QLCWR32(adapter, QLC_83XX_RESET_REG, 0);
1542c0d79cd0SManish Chopra 	QLCWR32(adapter, QLC_83XX_RESET_PORT0, 0);
1543c0d79cd0SManish Chopra 	QLCWR32(adapter, QLC_83XX_RESET_PORT1, 0);
1544c0d79cd0SManish Chopra 	QLCWR32(adapter, QLC_83XX_RESET_PORT2, 0);
1545c0d79cd0SManish Chopra 	QLCWR32(adapter, QLC_83XX_RESET_PORT3, 0);
1546c0d79cd0SManish Chopra 	QLCWR32(adapter, QLC_83XX_RESET_SRESHIM, 0);
1547c0d79cd0SManish Chopra 	QLCWR32(adapter, QLC_83XX_RESET_EPGSHIM, 0);
1548c0d79cd0SManish Chopra 	QLCWR32(adapter, QLC_83XX_RESET_ETHERPCS, 0);
1549c0d79cd0SManish Chopra 	QLCWR32(adapter, QLC_83XX_RESET_CONTROL, 1);
1550c0d79cd0SManish Chopra }
1551c0d79cd0SManish Chopra 
qlcnic_83xx_check_heartbeat(struct qlcnic_adapter * p_dev)1552629263acSSony Chacko static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev)
1553629263acSSony Chacko {
1554629263acSSony Chacko 	u32 heartbeat, peg_status;
15554bd8e738SHimanshu Madhani 	int retries, ret = -EIO, err = 0;
1556629263acSSony Chacko 
1557629263acSSony Chacko 	retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT;
1558629263acSSony Chacko 	p_dev->heartbeat = QLC_SHARED_REG_RD32(p_dev,
1559629263acSSony Chacko 					       QLCNIC_PEG_ALIVE_COUNTER);
1560629263acSSony Chacko 
1561629263acSSony Chacko 	do {
1562629263acSSony Chacko 		msleep(QLCNIC_HEARTBEAT_PERIOD_MSECS);
1563629263acSSony Chacko 		heartbeat = QLC_SHARED_REG_RD32(p_dev,
1564629263acSSony Chacko 						QLCNIC_PEG_ALIVE_COUNTER);
1565629263acSSony Chacko 		if (heartbeat != p_dev->heartbeat) {
1566629263acSSony Chacko 			ret = QLCNIC_RCODE_SUCCESS;
1567629263acSSony Chacko 			break;
1568629263acSSony Chacko 		}
1569629263acSSony Chacko 	} while (--retries);
1570629263acSSony Chacko 
1571629263acSSony Chacko 	if (ret) {
1572629263acSSony Chacko 		dev_err(&p_dev->pdev->dev, "firmware hang detected\n");
1573c0d79cd0SManish Chopra 		qlcnic_83xx_take_eport_out_of_reset(p_dev);
1574629263acSSony Chacko 		qlcnic_83xx_disable_pause_frames(p_dev);
1575629263acSSony Chacko 		peg_status = QLC_SHARED_REG_RD32(p_dev,
1576629263acSSony Chacko 						 QLCNIC_PEG_HALT_STATUS1);
1577629263acSSony Chacko 		dev_info(&p_dev->pdev->dev, "Dumping HW/FW registers\n"
1578629263acSSony Chacko 			 "PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
1579629263acSSony Chacko 			 "PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
1580629263acSSony Chacko 			 "PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
1581629263acSSony Chacko 			 "PEG_NET_4_PC: 0x%x\n", peg_status,
1582629263acSSony Chacko 			 QLC_SHARED_REG_RD32(p_dev, QLCNIC_PEG_HALT_STATUS2),
15834bd8e738SHimanshu Madhani 			 QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_0, &err),
15844bd8e738SHimanshu Madhani 			 QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_1, &err),
15854bd8e738SHimanshu Madhani 			 QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_2, &err),
15864bd8e738SHimanshu Madhani 			 QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_3, &err),
15874bd8e738SHimanshu Madhani 			 QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_4, &err));
1588629263acSSony Chacko 
1589629263acSSony Chacko 		if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
1590629263acSSony Chacko 			dev_err(&p_dev->pdev->dev,
1591629263acSSony Chacko 				"Device is being reset err code 0x00006700.\n");
1592629263acSSony Chacko 	}
1593629263acSSony Chacko 
1594629263acSSony Chacko 	return ret;
1595629263acSSony Chacko }
1596629263acSSony Chacko 
qlcnic_83xx_check_cmd_peg_status(struct qlcnic_adapter * p_dev)1597629263acSSony Chacko static int qlcnic_83xx_check_cmd_peg_status(struct qlcnic_adapter *p_dev)
1598629263acSSony Chacko {
1599629263acSSony Chacko 	int retries = QLCNIC_CMDPEG_CHECK_RETRY_COUNT;
1600629263acSSony Chacko 	u32 val;
1601629263acSSony Chacko 
1602629263acSSony Chacko 	do {
1603629263acSSony Chacko 		val = QLC_SHARED_REG_RD32(p_dev, QLCNIC_CMDPEG_STATE);
1604629263acSSony Chacko 		if (val == QLC_83XX_CMDPEG_COMPLETE)
1605629263acSSony Chacko 			return 0;
1606629263acSSony Chacko 		msleep(QLCNIC_CMDPEG_CHECK_DELAY);
1607629263acSSony Chacko 	} while (--retries);
1608629263acSSony Chacko 
1609629263acSSony Chacko 	dev_err(&p_dev->pdev->dev, "%s: failed, state = 0x%x\n", __func__, val);
1610629263acSSony Chacko 	return -EIO;
1611629263acSSony Chacko }
1612629263acSSony Chacko 
qlcnic_83xx_check_hw_status(struct qlcnic_adapter * p_dev)161321041400Sstephen hemminger static int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev)
1614629263acSSony Chacko {
1615629263acSSony Chacko 	int err;
1616629263acSSony Chacko 
1617629263acSSony Chacko 	err = qlcnic_83xx_check_cmd_peg_status(p_dev);
1618629263acSSony Chacko 	if (err)
1619629263acSSony Chacko 		return err;
1620629263acSSony Chacko 
1621629263acSSony Chacko 	err = qlcnic_83xx_check_heartbeat(p_dev);
1622629263acSSony Chacko 	if (err)
1623629263acSSony Chacko 		return err;
1624629263acSSony Chacko 
1625629263acSSony Chacko 	return err;
1626629263acSSony Chacko }
1627629263acSSony Chacko 
qlcnic_83xx_poll_reg(struct qlcnic_adapter * p_dev,u32 addr,int duration,u32 mask,u32 status)162881d0aeb0SSony Chacko static int qlcnic_83xx_poll_reg(struct qlcnic_adapter *p_dev, u32 addr,
162981d0aeb0SSony Chacko 				int duration, u32 mask, u32 status)
163081d0aeb0SSony Chacko {
16314bd8e738SHimanshu Madhani 	int timeout_error, err = 0;
163281d0aeb0SSony Chacko 	u32 value;
163381d0aeb0SSony Chacko 	u8 retries;
163481d0aeb0SSony Chacko 
16354bd8e738SHimanshu Madhani 	value = QLCRD32(p_dev, addr, &err);
16364bd8e738SHimanshu Madhani 	if (err == -EIO)
16374bd8e738SHimanshu Madhani 		return err;
163881d0aeb0SSony Chacko 	retries = duration / 10;
163981d0aeb0SSony Chacko 
164081d0aeb0SSony Chacko 	do {
164181d0aeb0SSony Chacko 		if ((value & mask) != status) {
164281d0aeb0SSony Chacko 			timeout_error = 1;
164381d0aeb0SSony Chacko 			msleep(duration / 10);
16444bd8e738SHimanshu Madhani 			value = QLCRD32(p_dev, addr, &err);
16454bd8e738SHimanshu Madhani 			if (err == -EIO)
16464bd8e738SHimanshu Madhani 				return err;
164781d0aeb0SSony Chacko 		} else {
164881d0aeb0SSony Chacko 			timeout_error = 0;
164981d0aeb0SSony Chacko 			break;
165081d0aeb0SSony Chacko 		}
165181d0aeb0SSony Chacko 	} while (retries--);
165281d0aeb0SSony Chacko 
165381d0aeb0SSony Chacko 	if (timeout_error) {
165481d0aeb0SSony Chacko 		p_dev->ahw->reset.seq_error++;
165581d0aeb0SSony Chacko 		dev_err(&p_dev->pdev->dev,
165681d0aeb0SSony Chacko 			"%s: Timeout Err, entry_num = %d\n",
165781d0aeb0SSony Chacko 			__func__, p_dev->ahw->reset.seq_index);
165881d0aeb0SSony Chacko 		dev_err(&p_dev->pdev->dev,
165981d0aeb0SSony Chacko 			"0x%08x 0x%08x 0x%08x\n",
166081d0aeb0SSony Chacko 			value, mask, status);
166181d0aeb0SSony Chacko 	}
166281d0aeb0SSony Chacko 
166381d0aeb0SSony Chacko 	return timeout_error;
166481d0aeb0SSony Chacko }
166581d0aeb0SSony Chacko 
qlcnic_83xx_reset_template_checksum(struct qlcnic_adapter * p_dev)166681d0aeb0SSony Chacko static int qlcnic_83xx_reset_template_checksum(struct qlcnic_adapter *p_dev)
166781d0aeb0SSony Chacko {
166881d0aeb0SSony Chacko 	u32 sum = 0;
166981d0aeb0SSony Chacko 	u16 *buff = (u16 *)p_dev->ahw->reset.buff;
167081d0aeb0SSony Chacko 	int count = p_dev->ahw->reset.hdr->size / sizeof(u16);
167181d0aeb0SSony Chacko 
167281d0aeb0SSony Chacko 	while (count-- > 0)
167381d0aeb0SSony Chacko 		sum += *buff++;
167481d0aeb0SSony Chacko 
167581d0aeb0SSony Chacko 	while (sum >> 16)
167681d0aeb0SSony Chacko 		sum = (sum & 0xFFFF) + (sum >> 16);
167781d0aeb0SSony Chacko 
167881d0aeb0SSony Chacko 	if (~sum) {
167981d0aeb0SSony Chacko 		return 0;
168081d0aeb0SSony Chacko 	} else {
168181d0aeb0SSony Chacko 		dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
168281d0aeb0SSony Chacko 		return -1;
168381d0aeb0SSony Chacko 	}
168481d0aeb0SSony Chacko }
168581d0aeb0SSony Chacko 
qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter * p_dev)168621041400Sstephen hemminger static int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev)
168781d0aeb0SSony Chacko {
168881d0aeb0SSony Chacko 	struct qlcnic_hardware_context *ahw = p_dev->ahw;
1689486a5bc7SRajesh Borundia 	u32 addr, count, prev_ver, curr_ver;
1690486a5bc7SRajesh Borundia 	u8 *p_buff;
1691486a5bc7SRajesh Borundia 
1692486a5bc7SRajesh Borundia 	if (ahw->reset.buff != NULL) {
1693486a5bc7SRajesh Borundia 		prev_ver = p_dev->fw_version;
1694486a5bc7SRajesh Borundia 		curr_ver = qlcnic_83xx_get_fw_version(p_dev);
1695486a5bc7SRajesh Borundia 		if (curr_ver > prev_ver)
1696486a5bc7SRajesh Borundia 			kfree(ahw->reset.buff);
1697486a5bc7SRajesh Borundia 		else
1698486a5bc7SRajesh Borundia 			return 0;
1699486a5bc7SRajesh Borundia 	}
170081d0aeb0SSony Chacko 
170181d0aeb0SSony Chacko 	ahw->reset.seq_error = 0;
170281d0aeb0SSony Chacko 	ahw->reset.buff = kzalloc(QLC_83XX_RESTART_TEMPLATE_SIZE, GFP_KERNEL);
1703bcaeb886SXu Wang 	if (ahw->reset.buff == NULL)
170481d0aeb0SSony Chacko 		return -ENOMEM;
1705b2adaca9SJoe Perches 
170681d0aeb0SSony Chacko 	p_buff = p_dev->ahw->reset.buff;
170781d0aeb0SSony Chacko 	addr = QLC_83XX_RESET_TEMPLATE_ADDR;
170881d0aeb0SSony Chacko 	count = sizeof(struct qlc_83xx_reset_hdr) / sizeof(u32);
170981d0aeb0SSony Chacko 
171081d0aeb0SSony Chacko 	/* Copy template header from flash */
171181d0aeb0SSony Chacko 	if (qlcnic_83xx_flash_read32(p_dev, addr, p_buff, count)) {
171281d0aeb0SSony Chacko 		dev_err(&p_dev->pdev->dev, "%s: flash read failed\n", __func__);
171381d0aeb0SSony Chacko 		return -EIO;
171481d0aeb0SSony Chacko 	}
171581d0aeb0SSony Chacko 	ahw->reset.hdr = (struct qlc_83xx_reset_hdr *)ahw->reset.buff;
171681d0aeb0SSony Chacko 	addr = QLC_83XX_RESET_TEMPLATE_ADDR + ahw->reset.hdr->hdr_size;
171781d0aeb0SSony Chacko 	p_buff = ahw->reset.buff + ahw->reset.hdr->hdr_size;
171881d0aeb0SSony Chacko 	count = (ahw->reset.hdr->size - ahw->reset.hdr->hdr_size) / sizeof(u32);
171981d0aeb0SSony Chacko 
172081d0aeb0SSony Chacko 	/* Copy rest of the template */
172181d0aeb0SSony Chacko 	if (qlcnic_83xx_flash_read32(p_dev, addr, p_buff, count)) {
172281d0aeb0SSony Chacko 		dev_err(&p_dev->pdev->dev, "%s: flash read failed\n", __func__);
172381d0aeb0SSony Chacko 		return -EIO;
172481d0aeb0SSony Chacko 	}
172581d0aeb0SSony Chacko 
172681d0aeb0SSony Chacko 	if (qlcnic_83xx_reset_template_checksum(p_dev))
172781d0aeb0SSony Chacko 		return -EIO;
172881d0aeb0SSony Chacko 	/* Get Stop, Start and Init command offsets */
172981d0aeb0SSony Chacko 	ahw->reset.init_offset = ahw->reset.buff + ahw->reset.hdr->init_offset;
173081d0aeb0SSony Chacko 	ahw->reset.start_offset = ahw->reset.buff +
173181d0aeb0SSony Chacko 				  ahw->reset.hdr->start_offset;
173281d0aeb0SSony Chacko 	ahw->reset.stop_offset = ahw->reset.buff + ahw->reset.hdr->hdr_size;
173381d0aeb0SSony Chacko 	return 0;
173481d0aeb0SSony Chacko }
173581d0aeb0SSony Chacko 
173681d0aeb0SSony Chacko /* Read Write HW register command */
qlcnic_83xx_read_write_crb_reg(struct qlcnic_adapter * p_dev,u32 raddr,u32 waddr)173781d0aeb0SSony Chacko static void qlcnic_83xx_read_write_crb_reg(struct qlcnic_adapter *p_dev,
173881d0aeb0SSony Chacko 					   u32 raddr, u32 waddr)
173981d0aeb0SSony Chacko {
17404bd8e738SHimanshu Madhani 	int err = 0;
17414bd8e738SHimanshu Madhani 	u32 value;
174281d0aeb0SSony Chacko 
17434bd8e738SHimanshu Madhani 	value = QLCRD32(p_dev, raddr, &err);
17444bd8e738SHimanshu Madhani 	if (err == -EIO)
17454bd8e738SHimanshu Madhani 		return;
174681d0aeb0SSony Chacko 	qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
174781d0aeb0SSony Chacko }
174881d0aeb0SSony Chacko 
174981d0aeb0SSony Chacko /* Read Modify Write HW register command */
qlcnic_83xx_rmw_crb_reg(struct qlcnic_adapter * p_dev,u32 raddr,u32 waddr,struct qlc_83xx_rmw * p_rmw_hdr)175081d0aeb0SSony Chacko static void qlcnic_83xx_rmw_crb_reg(struct qlcnic_adapter *p_dev,
175181d0aeb0SSony Chacko 				    u32 raddr, u32 waddr,
175281d0aeb0SSony Chacko 				    struct qlc_83xx_rmw *p_rmw_hdr)
175381d0aeb0SSony Chacko {
17544bd8e738SHimanshu Madhani 	int err = 0;
17554bd8e738SHimanshu Madhani 	u32 value;
175681d0aeb0SSony Chacko 
17574bd8e738SHimanshu Madhani 	if (p_rmw_hdr->index_a) {
175881d0aeb0SSony Chacko 		value = p_dev->ahw->reset.array[p_rmw_hdr->index_a];
17594bd8e738SHimanshu Madhani 	} else {
17604bd8e738SHimanshu Madhani 		value = QLCRD32(p_dev, raddr, &err);
17614bd8e738SHimanshu Madhani 		if (err == -EIO)
17624bd8e738SHimanshu Madhani 			return;
17634bd8e738SHimanshu Madhani 	}
176481d0aeb0SSony Chacko 
176581d0aeb0SSony Chacko 	value &= p_rmw_hdr->mask;
176681d0aeb0SSony Chacko 	value <<= p_rmw_hdr->shl;
176781d0aeb0SSony Chacko 	value >>= p_rmw_hdr->shr;
176881d0aeb0SSony Chacko 	value |= p_rmw_hdr->or_value;
176981d0aeb0SSony Chacko 	value ^= p_rmw_hdr->xor_value;
177081d0aeb0SSony Chacko 	qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
177181d0aeb0SSony Chacko }
177281d0aeb0SSony Chacko 
177381d0aeb0SSony Chacko /* Write HW register command */
qlcnic_83xx_write_list(struct qlcnic_adapter * p_dev,struct qlc_83xx_entry_hdr * p_hdr)177481d0aeb0SSony Chacko static void qlcnic_83xx_write_list(struct qlcnic_adapter *p_dev,
177581d0aeb0SSony Chacko 				   struct qlc_83xx_entry_hdr *p_hdr)
177681d0aeb0SSony Chacko {
177781d0aeb0SSony Chacko 	int i;
177881d0aeb0SSony Chacko 	struct qlc_83xx_entry *entry;
177981d0aeb0SSony Chacko 
178081d0aeb0SSony Chacko 	entry = (struct qlc_83xx_entry *)((char *)p_hdr +
178181d0aeb0SSony Chacko 					  sizeof(struct qlc_83xx_entry_hdr));
178281d0aeb0SSony Chacko 
178381d0aeb0SSony Chacko 	for (i = 0; i < p_hdr->count; i++, entry++) {
178481d0aeb0SSony Chacko 		qlcnic_83xx_wrt_reg_indirect(p_dev, entry->arg1,
178581d0aeb0SSony Chacko 					     entry->arg2);
178681d0aeb0SSony Chacko 		if (p_hdr->delay)
178781d0aeb0SSony Chacko 			udelay((u32)(p_hdr->delay));
178881d0aeb0SSony Chacko 	}
178981d0aeb0SSony Chacko }
179081d0aeb0SSony Chacko 
179181d0aeb0SSony Chacko /* Read and Write instruction */
qlcnic_83xx_read_write_list(struct qlcnic_adapter * p_dev,struct qlc_83xx_entry_hdr * p_hdr)179281d0aeb0SSony Chacko static void qlcnic_83xx_read_write_list(struct qlcnic_adapter *p_dev,
179381d0aeb0SSony Chacko 					struct qlc_83xx_entry_hdr *p_hdr)
179481d0aeb0SSony Chacko {
179581d0aeb0SSony Chacko 	int i;
179681d0aeb0SSony Chacko 	struct qlc_83xx_entry *entry;
179781d0aeb0SSony Chacko 
179881d0aeb0SSony Chacko 	entry = (struct qlc_83xx_entry *)((char *)p_hdr +
179981d0aeb0SSony Chacko 					  sizeof(struct qlc_83xx_entry_hdr));
180081d0aeb0SSony Chacko 
180181d0aeb0SSony Chacko 	for (i = 0; i < p_hdr->count; i++, entry++) {
180281d0aeb0SSony Chacko 		qlcnic_83xx_read_write_crb_reg(p_dev, entry->arg1,
180381d0aeb0SSony Chacko 					       entry->arg2);
180481d0aeb0SSony Chacko 		if (p_hdr->delay)
180581d0aeb0SSony Chacko 			udelay((u32)(p_hdr->delay));
180681d0aeb0SSony Chacko 	}
180781d0aeb0SSony Chacko }
180881d0aeb0SSony Chacko 
180981d0aeb0SSony Chacko /* Poll HW register command */
qlcnic_83xx_poll_list(struct qlcnic_adapter * p_dev,struct qlc_83xx_entry_hdr * p_hdr)181081d0aeb0SSony Chacko static void qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev,
181181d0aeb0SSony Chacko 				  struct qlc_83xx_entry_hdr *p_hdr)
181281d0aeb0SSony Chacko {
181381d0aeb0SSony Chacko 	long delay;
181481d0aeb0SSony Chacko 	struct qlc_83xx_entry *entry;
181581d0aeb0SSony Chacko 	struct qlc_83xx_poll *poll;
18164bd8e738SHimanshu Madhani 	int i, err = 0;
181781d0aeb0SSony Chacko 	unsigned long arg1, arg2;
181881d0aeb0SSony Chacko 
181981d0aeb0SSony Chacko 	poll = (struct qlc_83xx_poll *)((char *)p_hdr +
182081d0aeb0SSony Chacko 					sizeof(struct qlc_83xx_entry_hdr));
182181d0aeb0SSony Chacko 
182281d0aeb0SSony Chacko 	entry = (struct qlc_83xx_entry *)((char *)poll +
182381d0aeb0SSony Chacko 					  sizeof(struct qlc_83xx_poll));
182481d0aeb0SSony Chacko 	delay = (long)p_hdr->delay;
182581d0aeb0SSony Chacko 
182681d0aeb0SSony Chacko 	if (!delay) {
182781d0aeb0SSony Chacko 		for (i = 0; i < p_hdr->count; i++, entry++)
182881d0aeb0SSony Chacko 			qlcnic_83xx_poll_reg(p_dev, entry->arg1,
182981d0aeb0SSony Chacko 					     delay, poll->mask,
183081d0aeb0SSony Chacko 					     poll->status);
183181d0aeb0SSony Chacko 	} else {
183281d0aeb0SSony Chacko 		for (i = 0; i < p_hdr->count; i++, entry++) {
183381d0aeb0SSony Chacko 			arg1 = entry->arg1;
183481d0aeb0SSony Chacko 			arg2 = entry->arg2;
183581d0aeb0SSony Chacko 			if (delay) {
183681d0aeb0SSony Chacko 				if (qlcnic_83xx_poll_reg(p_dev,
183781d0aeb0SSony Chacko 							 arg1, delay,
183881d0aeb0SSony Chacko 							 poll->mask,
183981d0aeb0SSony Chacko 							 poll->status)){
18404bd8e738SHimanshu Madhani 					QLCRD32(p_dev, arg1, &err);
18414bd8e738SHimanshu Madhani 					if (err == -EIO)
18424bd8e738SHimanshu Madhani 						return;
18434bd8e738SHimanshu Madhani 					QLCRD32(p_dev, arg2, &err);
18444bd8e738SHimanshu Madhani 					if (err == -EIO)
18454bd8e738SHimanshu Madhani 						return;
184681d0aeb0SSony Chacko 				}
184781d0aeb0SSony Chacko 			}
184881d0aeb0SSony Chacko 		}
184981d0aeb0SSony Chacko 	}
185081d0aeb0SSony Chacko }
185181d0aeb0SSony Chacko 
185281d0aeb0SSony Chacko /* Poll and write HW register command */
qlcnic_83xx_poll_write_list(struct qlcnic_adapter * p_dev,struct qlc_83xx_entry_hdr * p_hdr)185381d0aeb0SSony Chacko static void qlcnic_83xx_poll_write_list(struct qlcnic_adapter *p_dev,
185481d0aeb0SSony Chacko 					struct qlc_83xx_entry_hdr *p_hdr)
185581d0aeb0SSony Chacko {
185681d0aeb0SSony Chacko 	int i;
185781d0aeb0SSony Chacko 	long delay;
185881d0aeb0SSony Chacko 	struct qlc_83xx_quad_entry *entry;
185981d0aeb0SSony Chacko 	struct qlc_83xx_poll *poll;
186081d0aeb0SSony Chacko 
186181d0aeb0SSony Chacko 	poll = (struct qlc_83xx_poll *)((char *)p_hdr +
186281d0aeb0SSony Chacko 					sizeof(struct qlc_83xx_entry_hdr));
186381d0aeb0SSony Chacko 	entry = (struct qlc_83xx_quad_entry *)((char *)poll +
186481d0aeb0SSony Chacko 					       sizeof(struct qlc_83xx_poll));
186581d0aeb0SSony Chacko 	delay = (long)p_hdr->delay;
186681d0aeb0SSony Chacko 
186781d0aeb0SSony Chacko 	for (i = 0; i < p_hdr->count; i++, entry++) {
186881d0aeb0SSony Chacko 		qlcnic_83xx_wrt_reg_indirect(p_dev, entry->dr_addr,
186981d0aeb0SSony Chacko 					     entry->dr_value);
187081d0aeb0SSony Chacko 		qlcnic_83xx_wrt_reg_indirect(p_dev, entry->ar_addr,
187181d0aeb0SSony Chacko 					     entry->ar_value);
187281d0aeb0SSony Chacko 		if (delay)
187381d0aeb0SSony Chacko 			qlcnic_83xx_poll_reg(p_dev, entry->ar_addr, delay,
187481d0aeb0SSony Chacko 					     poll->mask, poll->status);
187581d0aeb0SSony Chacko 	}
187681d0aeb0SSony Chacko }
187781d0aeb0SSony Chacko 
187881d0aeb0SSony Chacko /* Read Modify Write register command */
qlcnic_83xx_read_modify_write(struct qlcnic_adapter * p_dev,struct qlc_83xx_entry_hdr * p_hdr)187981d0aeb0SSony Chacko static void qlcnic_83xx_read_modify_write(struct qlcnic_adapter *p_dev,
188081d0aeb0SSony Chacko 					  struct qlc_83xx_entry_hdr *p_hdr)
188181d0aeb0SSony Chacko {
188281d0aeb0SSony Chacko 	int i;
188381d0aeb0SSony Chacko 	struct qlc_83xx_entry *entry;
188481d0aeb0SSony Chacko 	struct qlc_83xx_rmw *rmw_hdr;
188581d0aeb0SSony Chacko 
188681d0aeb0SSony Chacko 	rmw_hdr = (struct qlc_83xx_rmw *)((char *)p_hdr +
188781d0aeb0SSony Chacko 					  sizeof(struct qlc_83xx_entry_hdr));
188881d0aeb0SSony Chacko 
188981d0aeb0SSony Chacko 	entry = (struct qlc_83xx_entry *)((char *)rmw_hdr +
189081d0aeb0SSony Chacko 					  sizeof(struct qlc_83xx_rmw));
189181d0aeb0SSony Chacko 
189281d0aeb0SSony Chacko 	for (i = 0; i < p_hdr->count; i++, entry++) {
189381d0aeb0SSony Chacko 		qlcnic_83xx_rmw_crb_reg(p_dev, entry->arg1,
189481d0aeb0SSony Chacko 					entry->arg2, rmw_hdr);
189581d0aeb0SSony Chacko 		if (p_hdr->delay)
189681d0aeb0SSony Chacko 			udelay((u32)(p_hdr->delay));
189781d0aeb0SSony Chacko 	}
189881d0aeb0SSony Chacko }
189981d0aeb0SSony Chacko 
qlcnic_83xx_pause(struct qlc_83xx_entry_hdr * p_hdr)190081d0aeb0SSony Chacko static void qlcnic_83xx_pause(struct qlc_83xx_entry_hdr *p_hdr)
190181d0aeb0SSony Chacko {
190281d0aeb0SSony Chacko 	if (p_hdr->delay)
190381d0aeb0SSony Chacko 		mdelay((u32)((long)p_hdr->delay));
190481d0aeb0SSony Chacko }
190581d0aeb0SSony Chacko 
190681d0aeb0SSony Chacko /* Read and poll register command */
qlcnic_83xx_poll_read_list(struct qlcnic_adapter * p_dev,struct qlc_83xx_entry_hdr * p_hdr)190781d0aeb0SSony Chacko static void qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev,
190881d0aeb0SSony Chacko 				       struct qlc_83xx_entry_hdr *p_hdr)
190981d0aeb0SSony Chacko {
191081d0aeb0SSony Chacko 	long delay;
19114bd8e738SHimanshu Madhani 	int index, i, j, err;
191281d0aeb0SSony Chacko 	struct qlc_83xx_quad_entry *entry;
191381d0aeb0SSony Chacko 	struct qlc_83xx_poll *poll;
191481d0aeb0SSony Chacko 	unsigned long addr;
191581d0aeb0SSony Chacko 
191681d0aeb0SSony Chacko 	poll = (struct qlc_83xx_poll *)((char *)p_hdr +
191781d0aeb0SSony Chacko 					sizeof(struct qlc_83xx_entry_hdr));
191881d0aeb0SSony Chacko 
191981d0aeb0SSony Chacko 	entry = (struct qlc_83xx_quad_entry *)((char *)poll +
192081d0aeb0SSony Chacko 					       sizeof(struct qlc_83xx_poll));
192181d0aeb0SSony Chacko 	delay = (long)p_hdr->delay;
192281d0aeb0SSony Chacko 
192381d0aeb0SSony Chacko 	for (i = 0; i < p_hdr->count; i++, entry++) {
192481d0aeb0SSony Chacko 		qlcnic_83xx_wrt_reg_indirect(p_dev, entry->ar_addr,
192581d0aeb0SSony Chacko 					     entry->ar_value);
192681d0aeb0SSony Chacko 		if (delay) {
192781d0aeb0SSony Chacko 			if (!qlcnic_83xx_poll_reg(p_dev, entry->ar_addr, delay,
192881d0aeb0SSony Chacko 						  poll->mask, poll->status)){
192981d0aeb0SSony Chacko 				index = p_dev->ahw->reset.array_index;
193081d0aeb0SSony Chacko 				addr = entry->dr_addr;
19314bd8e738SHimanshu Madhani 				j = QLCRD32(p_dev, addr, &err);
19324bd8e738SHimanshu Madhani 				if (err == -EIO)
19334bd8e738SHimanshu Madhani 					return;
19344bd8e738SHimanshu Madhani 
193581d0aeb0SSony Chacko 				p_dev->ahw->reset.array[index++] = j;
193681d0aeb0SSony Chacko 
193781d0aeb0SSony Chacko 				if (index == QLC_83XX_MAX_RESET_SEQ_ENTRIES)
193881d0aeb0SSony Chacko 					p_dev->ahw->reset.array_index = 1;
193981d0aeb0SSony Chacko 			}
194081d0aeb0SSony Chacko 		}
194181d0aeb0SSony Chacko 	}
194281d0aeb0SSony Chacko }
194381d0aeb0SSony Chacko 
qlcnic_83xx_seq_end(struct qlcnic_adapter * p_dev)194481d0aeb0SSony Chacko static inline void qlcnic_83xx_seq_end(struct qlcnic_adapter *p_dev)
194581d0aeb0SSony Chacko {
194681d0aeb0SSony Chacko 	p_dev->ahw->reset.seq_end = 1;
194781d0aeb0SSony Chacko }
194881d0aeb0SSony Chacko 
qlcnic_83xx_template_end(struct qlcnic_adapter * p_dev)194981d0aeb0SSony Chacko static void qlcnic_83xx_template_end(struct qlcnic_adapter *p_dev)
195081d0aeb0SSony Chacko {
195181d0aeb0SSony Chacko 	p_dev->ahw->reset.template_end = 1;
195281d0aeb0SSony Chacko 	if (p_dev->ahw->reset.seq_error == 0)
195381d0aeb0SSony Chacko 		dev_err(&p_dev->pdev->dev,
195481d0aeb0SSony Chacko 			"HW restart process completed successfully.\n");
195581d0aeb0SSony Chacko 	else
195681d0aeb0SSony Chacko 		dev_err(&p_dev->pdev->dev,
195781d0aeb0SSony Chacko 			"HW restart completed with timeout errors.\n");
195881d0aeb0SSony Chacko }
195981d0aeb0SSony Chacko 
196081d0aeb0SSony Chacko /**
196181d0aeb0SSony Chacko * qlcnic_83xx_exec_template_cmd
196281d0aeb0SSony Chacko *
196381d0aeb0SSony Chacko * @p_dev: adapter structure
196481d0aeb0SSony Chacko * @p_buff: Poiter to instruction template
196581d0aeb0SSony Chacko *
196681d0aeb0SSony Chacko * Template provides instructions to stop, restart and initalize firmware.
196781d0aeb0SSony Chacko * These instructions are abstracted as a series of read, write and
196881d0aeb0SSony Chacko * poll operations on hardware registers. Register information and operation
196981d0aeb0SSony Chacko * specifics are not exposed to the driver. Driver reads the template from
197081d0aeb0SSony Chacko * flash and executes the instructions located at pre-defined offsets.
197181d0aeb0SSony Chacko *
197281d0aeb0SSony Chacko * Returns: None
197381d0aeb0SSony Chacko * */
qlcnic_83xx_exec_template_cmd(struct qlcnic_adapter * p_dev,char * p_buff)197481d0aeb0SSony Chacko static void qlcnic_83xx_exec_template_cmd(struct qlcnic_adapter *p_dev,
197581d0aeb0SSony Chacko 					  char *p_buff)
197681d0aeb0SSony Chacko {
197781d0aeb0SSony Chacko 	int index, entries;
197881d0aeb0SSony Chacko 	struct qlc_83xx_entry_hdr *p_hdr;
197981d0aeb0SSony Chacko 	char *entry = p_buff;
198081d0aeb0SSony Chacko 
198181d0aeb0SSony Chacko 	p_dev->ahw->reset.seq_end = 0;
198281d0aeb0SSony Chacko 	p_dev->ahw->reset.template_end = 0;
198381d0aeb0SSony Chacko 	entries = p_dev->ahw->reset.hdr->entries;
198481d0aeb0SSony Chacko 	index = p_dev->ahw->reset.seq_index;
198581d0aeb0SSony Chacko 
198681d0aeb0SSony Chacko 	for (; (!p_dev->ahw->reset.seq_end) && (index < entries); index++) {
198781d0aeb0SSony Chacko 		p_hdr = (struct qlc_83xx_entry_hdr *)entry;
198881d0aeb0SSony Chacko 
198981d0aeb0SSony Chacko 		switch (p_hdr->cmd) {
199081d0aeb0SSony Chacko 		case QLC_83XX_OPCODE_NOP:
199181d0aeb0SSony Chacko 			break;
199281d0aeb0SSony Chacko 		case QLC_83XX_OPCODE_WRITE_LIST:
199381d0aeb0SSony Chacko 			qlcnic_83xx_write_list(p_dev, p_hdr);
199481d0aeb0SSony Chacko 			break;
199581d0aeb0SSony Chacko 		case QLC_83XX_OPCODE_READ_WRITE_LIST:
199681d0aeb0SSony Chacko 			qlcnic_83xx_read_write_list(p_dev, p_hdr);
199781d0aeb0SSony Chacko 			break;
199881d0aeb0SSony Chacko 		case QLC_83XX_OPCODE_POLL_LIST:
199981d0aeb0SSony Chacko 			qlcnic_83xx_poll_list(p_dev, p_hdr);
200081d0aeb0SSony Chacko 			break;
200181d0aeb0SSony Chacko 		case QLC_83XX_OPCODE_POLL_WRITE_LIST:
200281d0aeb0SSony Chacko 			qlcnic_83xx_poll_write_list(p_dev, p_hdr);
200381d0aeb0SSony Chacko 			break;
200481d0aeb0SSony Chacko 		case QLC_83XX_OPCODE_READ_MODIFY_WRITE:
200581d0aeb0SSony Chacko 			qlcnic_83xx_read_modify_write(p_dev, p_hdr);
200681d0aeb0SSony Chacko 			break;
200781d0aeb0SSony Chacko 		case QLC_83XX_OPCODE_SEQ_PAUSE:
200881d0aeb0SSony Chacko 			qlcnic_83xx_pause(p_hdr);
200981d0aeb0SSony Chacko 			break;
201081d0aeb0SSony Chacko 		case QLC_83XX_OPCODE_SEQ_END:
201181d0aeb0SSony Chacko 			qlcnic_83xx_seq_end(p_dev);
201281d0aeb0SSony Chacko 			break;
201381d0aeb0SSony Chacko 		case QLC_83XX_OPCODE_TMPL_END:
201481d0aeb0SSony Chacko 			qlcnic_83xx_template_end(p_dev);
201581d0aeb0SSony Chacko 			break;
201681d0aeb0SSony Chacko 		case QLC_83XX_OPCODE_POLL_READ_LIST:
201781d0aeb0SSony Chacko 			qlcnic_83xx_poll_read_list(p_dev, p_hdr);
201881d0aeb0SSony Chacko 			break;
201981d0aeb0SSony Chacko 		default:
202081d0aeb0SSony Chacko 			dev_err(&p_dev->pdev->dev,
202181d0aeb0SSony Chacko 				"%s: Unknown opcode 0x%04x in template %d\n",
202281d0aeb0SSony Chacko 				__func__, p_hdr->cmd, index);
202381d0aeb0SSony Chacko 			break;
202481d0aeb0SSony Chacko 		}
202581d0aeb0SSony Chacko 		entry += p_hdr->size;
202622e98449SManish Chopra 		cond_resched();
202781d0aeb0SSony Chacko 	}
202881d0aeb0SSony Chacko 	p_dev->ahw->reset.seq_index = index;
202981d0aeb0SSony Chacko }
203081d0aeb0SSony Chacko 
qlcnic_83xx_stop_hw(struct qlcnic_adapter * p_dev)203121041400Sstephen hemminger static void qlcnic_83xx_stop_hw(struct qlcnic_adapter *p_dev)
203281d0aeb0SSony Chacko {
203381d0aeb0SSony Chacko 	p_dev->ahw->reset.seq_index = 0;
203481d0aeb0SSony Chacko 
203581d0aeb0SSony Chacko 	qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.stop_offset);
203681d0aeb0SSony Chacko 	if (p_dev->ahw->reset.seq_end != 1)
203781d0aeb0SSony Chacko 		dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
203881d0aeb0SSony Chacko }
203981d0aeb0SSony Chacko 
qlcnic_83xx_start_hw(struct qlcnic_adapter * p_dev)204081d0aeb0SSony Chacko static void qlcnic_83xx_start_hw(struct qlcnic_adapter *p_dev)
204181d0aeb0SSony Chacko {
204281d0aeb0SSony Chacko 	qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.start_offset);
204381d0aeb0SSony Chacko 	if (p_dev->ahw->reset.template_end != 1)
204481d0aeb0SSony Chacko 		dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
204581d0aeb0SSony Chacko }
204681d0aeb0SSony Chacko 
qlcnic_83xx_init_hw(struct qlcnic_adapter * p_dev)204781d0aeb0SSony Chacko static void qlcnic_83xx_init_hw(struct qlcnic_adapter *p_dev)
204881d0aeb0SSony Chacko {
204981d0aeb0SSony Chacko 	qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.init_offset);
205081d0aeb0SSony Chacko 	if (p_dev->ahw->reset.seq_end != 1)
205181d0aeb0SSony Chacko 		dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
205281d0aeb0SSony Chacko }
205381d0aeb0SSony Chacko 
20543ced0a88SShahed Shaikh /* POST FW related definations*/
20553ced0a88SShahed Shaikh #define QLC_83XX_POST_SIGNATURE_REG	0x41602014
20563ced0a88SShahed Shaikh #define QLC_83XX_POST_MODE_REG		0x41602018
20573ced0a88SShahed Shaikh #define QLC_83XX_POST_FAST_MODE		0
20583ced0a88SShahed Shaikh #define QLC_83XX_POST_MEDIUM_MODE	1
20593ced0a88SShahed Shaikh #define QLC_83XX_POST_SLOW_MODE		2
20603ced0a88SShahed Shaikh 
20613ced0a88SShahed Shaikh /* POST Timeout values in milliseconds */
20623ced0a88SShahed Shaikh #define QLC_83XX_POST_FAST_MODE_TIMEOUT	690
20633ced0a88SShahed Shaikh #define QLC_83XX_POST_MED_MODE_TIMEOUT	2930
20643ced0a88SShahed Shaikh #define QLC_83XX_POST_SLOW_MODE_TIMEOUT	7500
20653ced0a88SShahed Shaikh 
20663ced0a88SShahed Shaikh /* POST result values */
20673ced0a88SShahed Shaikh #define QLC_83XX_POST_PASS			0xfffffff0
20683ced0a88SShahed Shaikh #define QLC_83XX_POST_ASIC_STRESS_TEST_FAIL	0xffffffff
20693ced0a88SShahed Shaikh #define QLC_83XX_POST_DDR_TEST_FAIL		0xfffffffe
20703ced0a88SShahed Shaikh #define QLC_83XX_POST_ASIC_MEMORY_TEST_FAIL	0xfffffffc
20713ced0a88SShahed Shaikh #define QLC_83XX_POST_FLASH_TEST_FAIL		0xfffffff8
20723ced0a88SShahed Shaikh 
qlcnic_83xx_run_post(struct qlcnic_adapter * adapter)20733ced0a88SShahed Shaikh static int qlcnic_83xx_run_post(struct qlcnic_adapter *adapter)
20743ced0a88SShahed Shaikh {
20753ced0a88SShahed Shaikh 	struct qlc_83xx_fw_info *fw_info = adapter->ahw->fw_info;
20763ced0a88SShahed Shaikh 	struct device *dev = &adapter->pdev->dev;
20773ced0a88SShahed Shaikh 	int timeout, count, ret = 0;
20783ced0a88SShahed Shaikh 	u32 signature;
20793ced0a88SShahed Shaikh 
20803ced0a88SShahed Shaikh 	/* Set timeout values with extra 2 seconds of buffer */
20813ced0a88SShahed Shaikh 	switch (adapter->ahw->post_mode) {
20823ced0a88SShahed Shaikh 	case QLC_83XX_POST_FAST_MODE:
20833ced0a88SShahed Shaikh 		timeout = QLC_83XX_POST_FAST_MODE_TIMEOUT + 2000;
20843ced0a88SShahed Shaikh 		break;
20853ced0a88SShahed Shaikh 	case QLC_83XX_POST_MEDIUM_MODE:
20863ced0a88SShahed Shaikh 		timeout = QLC_83XX_POST_MED_MODE_TIMEOUT + 2000;
20873ced0a88SShahed Shaikh 		break;
20883ced0a88SShahed Shaikh 	case QLC_83XX_POST_SLOW_MODE:
20893ced0a88SShahed Shaikh 		timeout = QLC_83XX_POST_SLOW_MODE_TIMEOUT + 2000;
20903ced0a88SShahed Shaikh 		break;
20913ced0a88SShahed Shaikh 	default:
20923ced0a88SShahed Shaikh 		return -EINVAL;
20933ced0a88SShahed Shaikh 	}
20943ced0a88SShahed Shaikh 
20953ced0a88SShahed Shaikh 	strncpy(fw_info->fw_file_name, QLC_83XX_POST_FW_FILE_NAME,
20963ced0a88SShahed Shaikh 		QLC_FW_FILE_NAME_LEN);
20973ced0a88SShahed Shaikh 
20983ced0a88SShahed Shaikh 	ret = request_firmware(&fw_info->fw, fw_info->fw_file_name, dev);
20993ced0a88SShahed Shaikh 	if (ret) {
21003ced0a88SShahed Shaikh 		dev_err(dev, "POST firmware can not be loaded, skipping POST\n");
21013ced0a88SShahed Shaikh 		return 0;
21023ced0a88SShahed Shaikh 	}
21033ced0a88SShahed Shaikh 
21043ced0a88SShahed Shaikh 	ret = qlcnic_83xx_copy_fw_file(adapter);
21053ced0a88SShahed Shaikh 	if (ret)
21063ced0a88SShahed Shaikh 		return ret;
21073ced0a88SShahed Shaikh 
21083ced0a88SShahed Shaikh 	/* clear QLC_83XX_POST_SIGNATURE_REG register */
21093ced0a88SShahed Shaikh 	qlcnic_ind_wr(adapter, QLC_83XX_POST_SIGNATURE_REG, 0);
21103ced0a88SShahed Shaikh 
21113ced0a88SShahed Shaikh 	/* Set POST mode */
21123ced0a88SShahed Shaikh 	qlcnic_ind_wr(adapter, QLC_83XX_POST_MODE_REG,
21133ced0a88SShahed Shaikh 		      adapter->ahw->post_mode);
21143ced0a88SShahed Shaikh 
21153ced0a88SShahed Shaikh 	QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID,
21163ced0a88SShahed Shaikh 			    QLC_83XX_BOOT_FROM_FILE);
21173ced0a88SShahed Shaikh 
21183ced0a88SShahed Shaikh 	qlcnic_83xx_start_hw(adapter);
21193ced0a88SShahed Shaikh 
21203ced0a88SShahed Shaikh 	count = 0;
21213ced0a88SShahed Shaikh 	do {
21223ced0a88SShahed Shaikh 		msleep(100);
21233ced0a88SShahed Shaikh 		count += 100;
21243ced0a88SShahed Shaikh 
21253ced0a88SShahed Shaikh 		signature = qlcnic_ind_rd(adapter, QLC_83XX_POST_SIGNATURE_REG);
21263ced0a88SShahed Shaikh 		if (signature == QLC_83XX_POST_PASS)
21273ced0a88SShahed Shaikh 			break;
21283ced0a88SShahed Shaikh 	} while (timeout > count);
21293ced0a88SShahed Shaikh 
21303ced0a88SShahed Shaikh 	if (timeout <= count) {
21313ced0a88SShahed Shaikh 		dev_err(dev, "POST timed out, signature = 0x%08x\n", signature);
21323ced0a88SShahed Shaikh 		return -EIO;
21333ced0a88SShahed Shaikh 	}
21343ced0a88SShahed Shaikh 
21353ced0a88SShahed Shaikh 	switch (signature) {
21363ced0a88SShahed Shaikh 	case QLC_83XX_POST_PASS:
21373ced0a88SShahed Shaikh 		dev_info(dev, "POST passed, Signature = 0x%08x\n", signature);
21383ced0a88SShahed Shaikh 		break;
21393ced0a88SShahed Shaikh 	case QLC_83XX_POST_ASIC_STRESS_TEST_FAIL:
21403ced0a88SShahed Shaikh 		dev_err(dev, "POST failed, Test case : ASIC STRESS TEST, Signature = 0x%08x\n",
21413ced0a88SShahed Shaikh 			signature);
21423ced0a88SShahed Shaikh 		ret = -EIO;
21433ced0a88SShahed Shaikh 		break;
21443ced0a88SShahed Shaikh 	case QLC_83XX_POST_DDR_TEST_FAIL:
21453ced0a88SShahed Shaikh 		dev_err(dev, "POST failed, Test case : DDT TEST, Signature = 0x%08x\n",
21463ced0a88SShahed Shaikh 			signature);
21473ced0a88SShahed Shaikh 		ret = -EIO;
21483ced0a88SShahed Shaikh 		break;
21493ced0a88SShahed Shaikh 	case QLC_83XX_POST_ASIC_MEMORY_TEST_FAIL:
21503ced0a88SShahed Shaikh 		dev_err(dev, "POST failed, Test case : ASIC MEMORY TEST, Signature = 0x%08x\n",
21513ced0a88SShahed Shaikh 			signature);
21523ced0a88SShahed Shaikh 		ret = -EIO;
21533ced0a88SShahed Shaikh 		break;
21543ced0a88SShahed Shaikh 	case QLC_83XX_POST_FLASH_TEST_FAIL:
21553ced0a88SShahed Shaikh 		dev_err(dev, "POST failed, Test case : FLASH TEST, Signature = 0x%08x\n",
21563ced0a88SShahed Shaikh 			signature);
21573ced0a88SShahed Shaikh 		ret = -EIO;
21583ced0a88SShahed Shaikh 		break;
21593ced0a88SShahed Shaikh 	default:
21603ced0a88SShahed Shaikh 		dev_err(dev, "POST failed, Test case : INVALID, Signature = 0x%08x\n",
21613ced0a88SShahed Shaikh 			signature);
21623ced0a88SShahed Shaikh 		ret = -EIO;
21633ced0a88SShahed Shaikh 		break;
21643ced0a88SShahed Shaikh 	}
21653ced0a88SShahed Shaikh 
21663ced0a88SShahed Shaikh 	return ret;
21673ced0a88SShahed Shaikh }
21683ced0a88SShahed Shaikh 
qlcnic_83xx_load_fw_image_from_host(struct qlcnic_adapter * adapter)2169629263acSSony Chacko static int qlcnic_83xx_load_fw_image_from_host(struct qlcnic_adapter *adapter)
2170629263acSSony Chacko {
21717000078aSPratik Pujar 	struct qlc_83xx_fw_info *fw_info = adapter->ahw->fw_info;
2172629263acSSony Chacko 	int err = -EIO;
2173629263acSSony Chacko 
21747000078aSPratik Pujar 	if (request_firmware(&fw_info->fw, fw_info->fw_file_name,
2175fef349ceSPratik Pujar 			     &(adapter->pdev->dev))) {
2176629263acSSony Chacko 		dev_err(&adapter->pdev->dev,
2177629263acSSony Chacko 			"No file FW image, loading flash FW image.\n");
2178629263acSSony Chacko 		QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID,
2179629263acSSony Chacko 				    QLC_83XX_BOOT_FROM_FLASH);
2180629263acSSony Chacko 	} else {
2181629263acSSony Chacko 		if (qlcnic_83xx_copy_fw_file(adapter))
2182629263acSSony Chacko 			return err;
2183629263acSSony Chacko 		QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID,
2184629263acSSony Chacko 				    QLC_83XX_BOOT_FROM_FILE);
2185629263acSSony Chacko 	}
2186629263acSSony Chacko 
2187629263acSSony Chacko 	return 0;
2188629263acSSony Chacko }
2189629263acSSony Chacko 
qlcnic_83xx_restart_hw(struct qlcnic_adapter * adapter)2190629263acSSony Chacko static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter)
2191629263acSSony Chacko {
21924e60ac46SSony Chacko 	u32 val;
2193629263acSSony Chacko 	int err = -EIO;
2194629263acSSony Chacko 
219581d0aeb0SSony Chacko 	qlcnic_83xx_stop_hw(adapter);
21964e60ac46SSony Chacko 
21974e60ac46SSony Chacko 	/* Collect FW register dump if required */
21984e60ac46SSony Chacko 	val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
21994e60ac46SSony Chacko 	if (!(val & QLC_83XX_IDC_GRACEFULL_RESET))
22004e60ac46SSony Chacko 		qlcnic_dump_fw(adapter);
220130fa15f6SManish Chopra 
220230fa15f6SManish Chopra 	if (val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) {
220330fa15f6SManish Chopra 		netdev_info(adapter->netdev, "%s: Auto firmware recovery is disabled\n",
220430fa15f6SManish Chopra 			    __func__);
220530fa15f6SManish Chopra 		qlcnic_83xx_idc_enter_failed_state(adapter, 1);
220630fa15f6SManish Chopra 		return err;
220730fa15f6SManish Chopra 	}
220830fa15f6SManish Chopra 
220981d0aeb0SSony Chacko 	qlcnic_83xx_init_hw(adapter);
221081d0aeb0SSony Chacko 
2211629263acSSony Chacko 	if (qlcnic_83xx_copy_bootloader(adapter))
2212629263acSSony Chacko 		return err;
22133ced0a88SShahed Shaikh 
22143ced0a88SShahed Shaikh 	/* Check if POST needs to be run */
22153ced0a88SShahed Shaikh 	if (adapter->ahw->run_post) {
22163ced0a88SShahed Shaikh 		err = qlcnic_83xx_run_post(adapter);
22173ced0a88SShahed Shaikh 		if (err)
22183ced0a88SShahed Shaikh 			return err;
22193ced0a88SShahed Shaikh 
22203ced0a88SShahed Shaikh 		/* No need to run POST in next reset sequence */
22213ced0a88SShahed Shaikh 		adapter->ahw->run_post = false;
22223ced0a88SShahed Shaikh 
22233ced0a88SShahed Shaikh 		/* Again reset the adapter to load regular firmware  */
22243ced0a88SShahed Shaikh 		qlcnic_83xx_stop_hw(adapter);
22253ced0a88SShahed Shaikh 		qlcnic_83xx_init_hw(adapter);
22263ced0a88SShahed Shaikh 
22273ced0a88SShahed Shaikh 		err = qlcnic_83xx_copy_bootloader(adapter);
22283ced0a88SShahed Shaikh 		if (err)
22293ced0a88SShahed Shaikh 			return err;
22303ced0a88SShahed Shaikh 	}
22313ced0a88SShahed Shaikh 
2232629263acSSony Chacko 	/* Boot either flash image or firmware image from host file system */
22333ced0a88SShahed Shaikh 	if (qlcnic_load_fw_file == 1) {
22343beb9be1SZhang Changzhong 		err = qlcnic_83xx_load_fw_image_from_host(adapter);
22353beb9be1SZhang Changzhong 		if (err)
2236629263acSSony Chacko 			return err;
2237629263acSSony Chacko 	} else {
2238629263acSSony Chacko 		QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID,
2239629263acSSony Chacko 				    QLC_83XX_BOOT_FROM_FLASH);
2240629263acSSony Chacko 	}
2241629263acSSony Chacko 
224281d0aeb0SSony Chacko 	qlcnic_83xx_start_hw(adapter);
2243629263acSSony Chacko 	if (qlcnic_83xx_check_hw_status(adapter))
2244629263acSSony Chacko 		return -EIO;
2245629263acSSony Chacko 
2246629263acSSony Chacko 	return 0;
2247629263acSSony Chacko }
2248629263acSSony Chacko 
qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter * adapter)224921041400Sstephen hemminger static int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter)
2250629263acSSony Chacko {
2251629263acSSony Chacko 	int err;
2252629263acSSony Chacko 	struct qlcnic_info nic_info;
2253629263acSSony Chacko 	struct qlcnic_hardware_context *ahw = adapter->ahw;
2254629263acSSony Chacko 
2255629263acSSony Chacko 	memset(&nic_info, 0, sizeof(struct qlcnic_info));
2256629263acSSony Chacko 	err = qlcnic_get_nic_info(adapter, &nic_info, ahw->pci_func);
2257629263acSSony Chacko 	if (err)
2258629263acSSony Chacko 		return -EIO;
2259629263acSSony Chacko 
2260629263acSSony Chacko 	ahw->physical_port = (u8) nic_info.phys_port;
2261629263acSSony Chacko 	ahw->switch_mode = nic_info.switch_mode;
2262629263acSSony Chacko 	ahw->max_tx_ques = nic_info.max_tx_ques;
2263629263acSSony Chacko 	ahw->max_rx_ques = nic_info.max_rx_ques;
2264629263acSSony Chacko 	ahw->capabilities = nic_info.capabilities;
2265629263acSSony Chacko 	ahw->max_mac_filters = nic_info.max_mac_filters;
2266629263acSSony Chacko 	ahw->max_mtu = nic_info.max_mtu;
2267629263acSSony Chacko 
226835dafcb0SSony Chacko 	/* eSwitch capability indicates vNIC mode.
226935dafcb0SSony Chacko 	 * vNIC and SRIOV are mutually exclusive operational modes.
227035dafcb0SSony Chacko 	 * If SR-IOV capability is detected, SR-IOV physical function
227135dafcb0SSony Chacko 	 * will get initialized in default mode.
227235dafcb0SSony Chacko 	 * SR-IOV virtual function initialization follows a
227335dafcb0SSony Chacko 	 * different code path and opmode.
227435dafcb0SSony Chacko 	 * SRIOV mode has precedence over vNIC mode.
227502feda17SRajesh Borundia 	 */
227635dafcb0SSony Chacko 	if (test_bit(__QLCNIC_SRIOV_CAPABLE, &adapter->state))
227735dafcb0SSony Chacko 		return QLC_83XX_DEFAULT_OPMODE;
227802feda17SRajesh Borundia 
227935dafcb0SSony Chacko 	if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY)
228034e8c406SHimanshu Madhani 		return QLCNIC_VNIC_MODE;
2281629263acSSony Chacko 
228235dafcb0SSony Chacko 	return QLC_83XX_DEFAULT_OPMODE;
2283629263acSSony Chacko }
2284629263acSSony Chacko 
qlcnic_83xx_configure_opmode(struct qlcnic_adapter * adapter)228502feda17SRajesh Borundia int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter)
2286629263acSSony Chacko {
228735dafcb0SSony Chacko 	struct qlcnic_hardware_context *ahw = adapter->ahw;
22887b546842SShahed Shaikh 	u16 max_sds_rings, max_tx_rings;
2289629263acSSony Chacko 	int ret;
2290629263acSSony Chacko 
2291629263acSSony Chacko 	ret = qlcnic_83xx_get_nic_configuration(adapter);
2292629263acSSony Chacko 	if (ret == -EIO)
2293629263acSSony Chacko 		return -EIO;
2294629263acSSony Chacko 
229534e8c406SHimanshu Madhani 	if (ret == QLCNIC_VNIC_MODE) {
229634e8c406SHimanshu Madhani 		ahw->nic_mode = QLCNIC_VNIC_MODE;
229734e8c406SHimanshu Madhani 
2298d71170fbSSony Chacko 		if (qlcnic_83xx_config_vnic_opmode(adapter))
2299d71170fbSSony Chacko 			return -EIO;
230035dafcb0SSony Chacko 
23017b546842SShahed Shaikh 		max_sds_rings = QLCNIC_MAX_VNIC_SDS_RINGS;
23027b546842SShahed Shaikh 		max_tx_rings = QLCNIC_MAX_VNIC_TX_RINGS;
230335dafcb0SSony Chacko 	} else if (ret == QLC_83XX_DEFAULT_OPMODE) {
230434e8c406SHimanshu Madhani 		ahw->nic_mode = QLCNIC_DEFAULT_MODE;
230535dafcb0SSony Chacko 		adapter->nic_ops->init_driver = qlcnic_83xx_init_default_driver;
230635dafcb0SSony Chacko 		ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
23077b546842SShahed Shaikh 		max_sds_rings = QLCNIC_MAX_SDS_RINGS;
23087b546842SShahed Shaikh 		max_tx_rings = QLCNIC_MAX_TX_RINGS;
230935dafcb0SSony Chacko 	} else {
2310c65762fcSSucheta Chakraborty 		dev_err(&adapter->pdev->dev, "%s: Invalid opmode %d\n",
2311c65762fcSSucheta Chakraborty 			__func__, ret);
2312629263acSSony Chacko 		return -EIO;
2313629263acSSony Chacko 	}
2314629263acSSony Chacko 
23157b546842SShahed Shaikh 	adapter->max_sds_rings = min(ahw->max_rx_ques, max_sds_rings);
23167b546842SShahed Shaikh 	adapter->max_tx_rings = min(ahw->max_tx_ques, max_tx_rings);
23177b546842SShahed Shaikh 
2318629263acSSony Chacko 	return 0;
2319629263acSSony Chacko }
2320629263acSSony Chacko 
qlcnic_83xx_config_buff_descriptors(struct qlcnic_adapter * adapter)2321629263acSSony Chacko static void qlcnic_83xx_config_buff_descriptors(struct qlcnic_adapter *adapter)
2322629263acSSony Chacko {
2323629263acSSony Chacko 	struct qlcnic_hardware_context *ahw = adapter->ahw;
2324629263acSSony Chacko 
2325629263acSSony Chacko 	if (ahw->port_type == QLCNIC_XGBE) {
2326629263acSSony Chacko 		adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
2327629263acSSony Chacko 		adapter->max_rxd = MAX_RCV_DESCRIPTORS_10G;
2328629263acSSony Chacko 		adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
2329629263acSSony Chacko 		adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
2330629263acSSony Chacko 
2331629263acSSony Chacko 	} else if (ahw->port_type == QLCNIC_GBE) {
2332629263acSSony Chacko 		adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
2333629263acSSony Chacko 		adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
2334629263acSSony Chacko 		adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
2335629263acSSony Chacko 		adapter->max_rxd = MAX_RCV_DESCRIPTORS_1G;
2336629263acSSony Chacko 	}
2337629263acSSony Chacko 	adapter->num_txd = MAX_CMD_DESCRIPTORS;
2338629263acSSony Chacko 	adapter->max_rds_rings = MAX_RDS_RINGS;
2339629263acSSony Chacko }
2340629263acSSony Chacko 
qlcnic_83xx_init_default_driver(struct qlcnic_adapter * adapter)2341629263acSSony Chacko static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter)
2342629263acSSony Chacko {
2343629263acSSony Chacko 	int err = -EIO;
2344629263acSSony Chacko 
23454e60ac46SSony Chacko 	qlcnic_83xx_get_minidump_template(adapter);
2346629263acSSony Chacko 	if (qlcnic_83xx_get_port_info(adapter))
2347629263acSSony Chacko 		return err;
2348629263acSSony Chacko 
2349629263acSSony Chacko 	qlcnic_83xx_config_buff_descriptors(adapter);
2350629263acSSony Chacko 	adapter->ahw->msix_supported = !!qlcnic_use_msi_x;
2351629263acSSony Chacko 	adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
2352629263acSSony Chacko 
2353629263acSSony Chacko 	dev_info(&adapter->pdev->dev, "HAL Version: %d\n",
2354629263acSSony Chacko 		 adapter->ahw->fw_hal_version);
2355629263acSSony Chacko 
2356629263acSSony Chacko 	return 0;
2357629263acSSony Chacko }
2358629263acSSony Chacko 
2359629263acSSony Chacko #define IS_QLC_83XX_USED(a, b, c) (((1 << a->portnum) & b) || ((c >> 6) & 0x1))
qlcnic_83xx_clear_function_resources(struct qlcnic_adapter * adapter)2360629263acSSony Chacko static void qlcnic_83xx_clear_function_resources(struct qlcnic_adapter *adapter)
2361629263acSSony Chacko {
2362629263acSSony Chacko 	struct qlcnic_cmd_args cmd;
2363629263acSSony Chacko 	u32 presence_mask, audit_mask;
2364629263acSSony Chacko 	int status;
2365629263acSSony Chacko 
2366629263acSSony Chacko 	presence_mask = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
2367629263acSSony Chacko 	audit_mask = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_AUDIT);
2368629263acSSony Chacko 
2369629263acSSony Chacko 	if (IS_QLC_83XX_USED(adapter, presence_mask, audit_mask)) {
2370b6b4316cSShahed Shaikh 		status = qlcnic_alloc_mbx_args(&cmd, adapter,
2371b6b4316cSShahed Shaikh 					       QLCNIC_CMD_STOP_NIC_FUNC);
2372b6b4316cSShahed Shaikh 		if (status)
2373b6b4316cSShahed Shaikh 			return;
2374b6b4316cSShahed Shaikh 
2375629263acSSony Chacko 		cmd.req.arg[1] = BIT_31;
2376629263acSSony Chacko 		status = qlcnic_issue_cmd(adapter, &cmd);
2377629263acSSony Chacko 		if (status)
2378629263acSSony Chacko 			dev_err(&adapter->pdev->dev,
2379629263acSSony Chacko 				"Failed to clean up the function resources\n");
2380629263acSSony Chacko 		qlcnic_free_mbx_args(&cmd);
2381629263acSSony Chacko 	}
2382629263acSSony Chacko }
2383629263acSSony Chacko 
qlcnic_83xx_get_fw_info(struct qlcnic_adapter * adapter)23847000078aSPratik Pujar static int qlcnic_83xx_get_fw_info(struct qlcnic_adapter *adapter)
23857000078aSPratik Pujar {
23867000078aSPratik Pujar 	struct qlcnic_hardware_context *ahw = adapter->ahw;
23877000078aSPratik Pujar 	struct pci_dev *pdev = adapter->pdev;
23887000078aSPratik Pujar 	struct qlc_83xx_fw_info *fw_info;
23897000078aSPratik Pujar 	int err = 0;
23907000078aSPratik Pujar 
23917000078aSPratik Pujar 	ahw->fw_info = kzalloc(sizeof(*fw_info), GFP_KERNEL);
23927000078aSPratik Pujar 	if (!ahw->fw_info) {
23937000078aSPratik Pujar 		err = -ENOMEM;
23947000078aSPratik Pujar 	} else {
23957000078aSPratik Pujar 		fw_info = ahw->fw_info;
23967000078aSPratik Pujar 		switch (pdev->device) {
23977000078aSPratik Pujar 		case PCI_DEVICE_ID_QLOGIC_QLE834X:
239840e2b8edSShahed Shaikh 		case PCI_DEVICE_ID_QLOGIC_QLE8830:
23997000078aSPratik Pujar 			strncpy(fw_info->fw_file_name, QLC_83XX_FW_FILE_NAME,
24007000078aSPratik Pujar 				QLC_FW_FILE_NAME_LEN);
24017000078aSPratik Pujar 			break;
24027000078aSPratik Pujar 		case PCI_DEVICE_ID_QLOGIC_QLE844X:
24037000078aSPratik Pujar 			strncpy(fw_info->fw_file_name, QLC_84XX_FW_FILE_NAME,
24047000078aSPratik Pujar 				QLC_FW_FILE_NAME_LEN);
24057000078aSPratik Pujar 			break;
24067000078aSPratik Pujar 		default:
24077000078aSPratik Pujar 			dev_err(&pdev->dev, "%s: Invalid device id\n",
24087000078aSPratik Pujar 				__func__);
24097000078aSPratik Pujar 			err = -EINVAL;
24107000078aSPratik Pujar 			break;
24117000078aSPratik Pujar 		}
24127000078aSPratik Pujar 	}
24137000078aSPratik Pujar 
24147000078aSPratik Pujar 	return err;
24157000078aSPratik Pujar }
24167000078aSPratik Pujar 
qlcnic_83xx_init_rings(struct qlcnic_adapter * adapter)241734e8c406SHimanshu Madhani static void qlcnic_83xx_init_rings(struct qlcnic_adapter *adapter)
241834e8c406SHimanshu Madhani {
241918afc102SHimanshu Madhani 	u8 rx_cnt = QLCNIC_DEF_SDS_RINGS;
242018afc102SHimanshu Madhani 	u8 tx_cnt = QLCNIC_DEF_TX_RINGS;
242118afc102SHimanshu Madhani 
242234e8c406SHimanshu Madhani 	adapter->max_tx_rings = QLCNIC_MAX_TX_RINGS;
242334e8c406SHimanshu Madhani 	adapter->max_sds_rings = QLCNIC_MAX_SDS_RINGS;
242434e8c406SHimanshu Madhani 
242518afc102SHimanshu Madhani 	if (!adapter->ahw->msix_supported) {
242618afc102SHimanshu Madhani 		rx_cnt = QLCNIC_SINGLE_RING;
242718afc102SHimanshu Madhani 		tx_cnt = QLCNIC_SINGLE_RING;
242818afc102SHimanshu Madhani 	}
242934e8c406SHimanshu Madhani 
243034e8c406SHimanshu Madhani 	/* compute and set drv sds rings */
243118afc102SHimanshu Madhani 	qlcnic_set_tx_ring_count(adapter, tx_cnt);
243218afc102SHimanshu Madhani 	qlcnic_set_sds_ring_count(adapter, rx_cnt);
243334e8c406SHimanshu Madhani }
24347000078aSPratik Pujar 
qlcnic_83xx_init(struct qlcnic_adapter * adapter)2435a72dc199SChristophe JAILLET int qlcnic_83xx_init(struct qlcnic_adapter *adapter)
2436629263acSSony Chacko {
2437629263acSSony Chacko 	struct qlcnic_hardware_context *ahw = adapter->ahw;
2438068a8d19SManish Chopra 	int err = 0;
2439629263acSSony Chacko 
244072ebe349SSucheta Chakraborty 	adapter->rx_mac_learn = false;
2441068a8d19SManish Chopra 	ahw->msix_supported = !!qlcnic_use_msi_x;
244234e8c406SHimanshu Madhani 
24433ced0a88SShahed Shaikh 	/* Check if POST needs to be run */
24443ced0a88SShahed Shaikh 	switch (qlcnic_load_fw_file) {
24453ced0a88SShahed Shaikh 	case 2:
24463ced0a88SShahed Shaikh 		ahw->post_mode = QLC_83XX_POST_FAST_MODE;
24473ced0a88SShahed Shaikh 		ahw->run_post = true;
24483ced0a88SShahed Shaikh 		break;
24493ced0a88SShahed Shaikh 	case 3:
24503ced0a88SShahed Shaikh 		ahw->post_mode = QLC_83XX_POST_MEDIUM_MODE;
24513ced0a88SShahed Shaikh 		ahw->run_post = true;
24523ced0a88SShahed Shaikh 		break;
24533ced0a88SShahed Shaikh 	case 4:
24543ced0a88SShahed Shaikh 		ahw->post_mode = QLC_83XX_POST_SLOW_MODE;
24553ced0a88SShahed Shaikh 		ahw->run_post = true;
24563ced0a88SShahed Shaikh 		break;
24573ced0a88SShahed Shaikh 	default:
24583ced0a88SShahed Shaikh 		ahw->run_post = false;
24593ced0a88SShahed Shaikh 		break;
24603ced0a88SShahed Shaikh 	}
24613ced0a88SShahed Shaikh 
246234e8c406SHimanshu Madhani 	qlcnic_83xx_init_rings(adapter);
246334e8c406SHimanshu Madhani 
2464068a8d19SManish Chopra 	err = qlcnic_83xx_init_mailbox_work(adapter);
2465068a8d19SManish Chopra 	if (err)
2466068a8d19SManish Chopra 		goto exit;
2467f8468331SRajesh Borundia 
2468068a8d19SManish Chopra 	if (qlcnic_sriov_vf_check(adapter)) {
2469a72dc199SChristophe JAILLET 		err = qlcnic_sriov_vf_init(adapter);
2470068a8d19SManish Chopra 		if (err)
2471068a8d19SManish Chopra 			goto detach_mbx;
2472068a8d19SManish Chopra 		else
2473068a8d19SManish Chopra 			return err;
2474068a8d19SManish Chopra 	}
2475629263acSSony Chacko 
247678ea2d97SSucheta Chakraborty 	if (qlcnic_83xx_read_flash_descriptor_table(adapter) ||
247778ea2d97SSucheta Chakraborty 	    qlcnic_83xx_read_flash_mfg_id(adapter)) {
247878ea2d97SSucheta Chakraborty 		dev_err(&adapter->pdev->dev, "Failed reading flash mfg id\n");
247978ea2d97SSucheta Chakraborty 		err = -ENOTRECOVERABLE;
248078ea2d97SSucheta Chakraborty 		goto detach_mbx;
248178ea2d97SSucheta Chakraborty 	}
248278ea2d97SSucheta Chakraborty 
2483068a8d19SManish Chopra 	err = qlcnic_83xx_check_hw_status(adapter);
2484068a8d19SManish Chopra 	if (err)
2485068a8d19SManish Chopra 		goto detach_mbx;
2486629263acSSony Chacko 
24877000078aSPratik Pujar 	err = qlcnic_83xx_get_fw_info(adapter);
2488b5acb255SManish Chopra 	if (err)
2489b5acb255SManish Chopra 		goto detach_mbx;
2490b5acb255SManish Chopra 
24917000078aSPratik Pujar 	err = qlcnic_83xx_idc_init(adapter);
24927000078aSPratik Pujar 	if (err)
249378ea2d97SSucheta Chakraborty 		goto detach_mbx;
24947000078aSPratik Pujar 
249534e8c406SHimanshu Madhani 	err = qlcnic_setup_intr(adapter);
2496068a8d19SManish Chopra 	if (err) {
2497068a8d19SManish Chopra 		dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n");
2498068a8d19SManish Chopra 		goto disable_intr;
2499068a8d19SManish Chopra 	}
2500068a8d19SManish Chopra 
2501463518a0SSucheta Chakraborty 	INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
2502463518a0SSucheta Chakraborty 
2503068a8d19SManish Chopra 	err = qlcnic_83xx_setup_mbx_intr(adapter);
2504068a8d19SManish Chopra 	if (err)
2505068a8d19SManish Chopra 		goto disable_mbx_intr;
2506068a8d19SManish Chopra 
2507629263acSSony Chacko 	qlcnic_83xx_clear_function_resources(adapter);
2508*13a7c896SDaniil Tatianin 
2509*13a7c896SDaniil Tatianin 	err = qlcnic_dcb_enable(adapter->dcb);
2510*13a7c896SDaniil Tatianin 	if (err) {
2511*13a7c896SDaniil Tatianin 		qlcnic_dcb_free(adapter->dcb);
2512*13a7c896SDaniil Tatianin 		goto disable_mbx_intr;
2513*13a7c896SDaniil Tatianin 	}
2514*13a7c896SDaniil Tatianin 
25159b0fff2aSSucheta Chakraborty 	qlcnic_83xx_initialize_nic(adapter, 1);
25164d52e1e8SSucheta Chakraborty 	qlcnic_dcb_get_info(adapter->dcb);
2517d5fcff04SHimanshu Madhani 
2518629263acSSony Chacko 	/* Configure default, SR-IOV or Virtual NIC mode of operation */
2519068a8d19SManish Chopra 	err = qlcnic_83xx_configure_opmode(adapter);
2520068a8d19SManish Chopra 	if (err)
2521068a8d19SManish Chopra 		goto disable_mbx_intr;
2522629263acSSony Chacko 
252334e8c406SHimanshu Madhani 
2524629263acSSony Chacko 	/* Perform operating mode specific initialization */
2525068a8d19SManish Chopra 	err = adapter->nic_ops->init_driver(adapter);
2526068a8d19SManish Chopra 	if (err)
2527068a8d19SManish Chopra 		goto disable_mbx_intr;
2528629263acSSony Chacko 
2529629263acSSony Chacko 	/* Periodically monitor device status */
2530629263acSSony Chacko 	qlcnic_83xx_idc_poll_dev_state(&adapter->fw_work.work);
2531068a8d19SManish Chopra 	return 0;
2532629263acSSony Chacko 
2533068a8d19SManish Chopra disable_mbx_intr:
2534068a8d19SManish Chopra 	qlcnic_83xx_free_mbx_intr(adapter);
2535068a8d19SManish Chopra 
2536068a8d19SManish Chopra disable_intr:
2537068a8d19SManish Chopra 	qlcnic_teardown_intr(adapter);
2538068a8d19SManish Chopra 
2539068a8d19SManish Chopra detach_mbx:
2540068a8d19SManish Chopra 	qlcnic_83xx_detach_mailbox_work(adapter);
2541068a8d19SManish Chopra 	qlcnic_83xx_free_mailbox(ahw->mailbox);
254278ea2d97SSucheta Chakraborty 	ahw->mailbox = NULL;
2543068a8d19SManish Chopra exit:
2544068a8d19SManish Chopra 	return err;
2545629263acSSony Chacko }
25469ce226faSPratik Pujar 
qlcnic_83xx_aer_stop_poll_work(struct qlcnic_adapter * adapter)25479ce226faSPratik Pujar void qlcnic_83xx_aer_stop_poll_work(struct qlcnic_adapter *adapter)
25489ce226faSPratik Pujar {
25499ce226faSPratik Pujar 	struct qlcnic_hardware_context *ahw = adapter->ahw;
25509ce226faSPratik Pujar 	struct qlc_83xx_idc *idc = &ahw->idc;
25519ce226faSPratik Pujar 
25529ce226faSPratik Pujar 	clear_bit(QLC_83XX_MBX_READY, &idc->status);
25539ce226faSPratik Pujar 	cancel_delayed_work_sync(&adapter->fw_work);
25549ce226faSPratik Pujar 
255534e8c406SHimanshu Madhani 	if (ahw->nic_mode == QLCNIC_VNIC_MODE)
25569ce226faSPratik Pujar 		qlcnic_83xx_disable_vnic_mode(adapter, 1);
25579ce226faSPratik Pujar 
25589ce226faSPratik Pujar 	qlcnic_83xx_idc_detach_driver(adapter);
25599b0fff2aSSucheta Chakraborty 	qlcnic_83xx_initialize_nic(adapter, 0);
25609ce226faSPratik Pujar 
25619ce226faSPratik Pujar 	cancel_delayed_work_sync(&adapter->idc_aen_work);
25629ce226faSPratik Pujar }
25639ce226faSPratik Pujar 
qlcnic_83xx_aer_reset(struct qlcnic_adapter * adapter)25649ce226faSPratik Pujar int qlcnic_83xx_aer_reset(struct qlcnic_adapter *adapter)
25659ce226faSPratik Pujar {
25669ce226faSPratik Pujar 	struct qlcnic_hardware_context *ahw = adapter->ahw;
25679ce226faSPratik Pujar 	struct qlc_83xx_idc *idc = &ahw->idc;
25689ce226faSPratik Pujar 	int ret = 0;
25699ce226faSPratik Pujar 	u32 owner;
25709ce226faSPratik Pujar 
25719ce226faSPratik Pujar 	/* Mark the previous IDC state as NEED_RESET so
25729ce226faSPratik Pujar 	 * that state_entry() will perform the reattachment
25739ce226faSPratik Pujar 	 * and bringup the device
25749ce226faSPratik Pujar 	 */
25759ce226faSPratik Pujar 	idc->prev_state = QLC_83XX_IDC_DEV_NEED_RESET;
25769ce226faSPratik Pujar 	owner = qlcnic_83xx_idc_find_reset_owner_id(adapter);
25779ce226faSPratik Pujar 	if (ahw->pci_func == owner) {
25789ce226faSPratik Pujar 		ret = qlcnic_83xx_restart_hw(adapter);
25799ce226faSPratik Pujar 		if (ret < 0)
25809ce226faSPratik Pujar 			return ret;
25819ce226faSPratik Pujar 		qlcnic_83xx_idc_clear_registers(adapter, 0);
25829ce226faSPratik Pujar 	}
25839ce226faSPratik Pujar 
25849ce226faSPratik Pujar 	ret = idc->state_entry(adapter);
25859ce226faSPratik Pujar 	return ret;
25869ce226faSPratik Pujar }
25879ce226faSPratik Pujar 
qlcnic_83xx_aer_start_poll_work(struct qlcnic_adapter * adapter)25889ce226faSPratik Pujar void qlcnic_83xx_aer_start_poll_work(struct qlcnic_adapter *adapter)
25899ce226faSPratik Pujar {
25909ce226faSPratik Pujar 	struct qlcnic_hardware_context *ahw = adapter->ahw;
25919ce226faSPratik Pujar 	struct qlc_83xx_idc *idc = &ahw->idc;
25929ce226faSPratik Pujar 	u32 owner;
25939ce226faSPratik Pujar 
25949ce226faSPratik Pujar 	idc->prev_state = QLC_83XX_IDC_DEV_READY;
25959ce226faSPratik Pujar 	owner = qlcnic_83xx_idc_find_reset_owner_id(adapter);
25969ce226faSPratik Pujar 	if (ahw->pci_func == owner)
25979ce226faSPratik Pujar 		qlcnic_83xx_idc_enter_ready_state(adapter, 0);
25989ce226faSPratik Pujar 
25999ce226faSPratik Pujar 	qlcnic_schedule_work(adapter, qlcnic_83xx_idc_poll_dev_state, 0);
26009ce226faSPratik Pujar }
2601