1fe56b9e6SYuval Mintz /* QLogic qed NIC Driver
2fe56b9e6SYuval Mintz  * Copyright (c) 2015 QLogic Corporation
3fe56b9e6SYuval Mintz  *
4fe56b9e6SYuval Mintz  * This software is available under the terms of the GNU General Public License
5fe56b9e6SYuval Mintz  * (GPL) Version 2, available from the file COPYING in the main directory of
6fe56b9e6SYuval Mintz  * this source tree.
7fe56b9e6SYuval Mintz  */
8fe56b9e6SYuval Mintz 
9fe56b9e6SYuval Mintz #include <linux/types.h>
10fe56b9e6SYuval Mintz #include <asm/byteorder.h>
11fe56b9e6SYuval Mintz #include <linux/io.h>
12fe56b9e6SYuval Mintz #include <linux/bitops.h>
13fe56b9e6SYuval Mintz #include <linux/delay.h>
14fe56b9e6SYuval Mintz #include <linux/dma-mapping.h>
15fe56b9e6SYuval Mintz #include <linux/errno.h>
16fe56b9e6SYuval Mintz #include <linux/interrupt.h>
17fe56b9e6SYuval Mintz #include <linux/kernel.h>
18fe56b9e6SYuval Mintz #include <linux/pci.h>
19fe56b9e6SYuval Mintz #include <linux/slab.h>
20fe56b9e6SYuval Mintz #include <linux/string.h>
21fe56b9e6SYuval Mintz #include "qed.h"
22fe56b9e6SYuval Mintz #include "qed_hsi.h"
23fe56b9e6SYuval Mintz #include "qed_hw.h"
24fe56b9e6SYuval Mintz #include "qed_init_ops.h"
25fe56b9e6SYuval Mintz #include "qed_int.h"
26fe56b9e6SYuval Mintz #include "qed_mcp.h"
27fe56b9e6SYuval Mintz #include "qed_reg_addr.h"
28fe56b9e6SYuval Mintz #include "qed_sp.h"
29fe56b9e6SYuval Mintz 
30fe56b9e6SYuval Mintz struct qed_pi_info {
31fe56b9e6SYuval Mintz 	qed_int_comp_cb_t	comp_cb;
32fe56b9e6SYuval Mintz 	void			*cookie;
33fe56b9e6SYuval Mintz };
34fe56b9e6SYuval Mintz 
35fe56b9e6SYuval Mintz struct qed_sb_sp_info {
36fe56b9e6SYuval Mintz 	struct qed_sb_info	sb_info;
37fe56b9e6SYuval Mintz 
38fe56b9e6SYuval Mintz 	/* per protocol index data */
39fe56b9e6SYuval Mintz 	struct qed_pi_info	pi_info_arr[PIS_PER_SB];
40fe56b9e6SYuval Mintz };
41fe56b9e6SYuval Mintz 
42fe56b9e6SYuval Mintz void qed_int_sp_dpc(unsigned long hwfn_cookie)
43fe56b9e6SYuval Mintz {
44fe56b9e6SYuval Mintz 	struct qed_hwfn *p_hwfn = (struct qed_hwfn *)hwfn_cookie;
45fe56b9e6SYuval Mintz 	struct qed_pi_info *pi_info = NULL;
46fe56b9e6SYuval Mintz 	struct qed_sb_info *sb_info;
47fe56b9e6SYuval Mintz 	int arr_size;
48fe56b9e6SYuval Mintz 	u16 rc = 0;
49fe56b9e6SYuval Mintz 
50fe56b9e6SYuval Mintz 	if (!p_hwfn) {
51fe56b9e6SYuval Mintz 		DP_ERR(p_hwfn->cdev, "DPC called - no hwfn!\n");
52fe56b9e6SYuval Mintz 		return;
53fe56b9e6SYuval Mintz 	}
54fe56b9e6SYuval Mintz 
55fe56b9e6SYuval Mintz 	if (!p_hwfn->p_sp_sb) {
56fe56b9e6SYuval Mintz 		DP_ERR(p_hwfn->cdev, "DPC called - no p_sp_sb\n");
57fe56b9e6SYuval Mintz 		return;
58fe56b9e6SYuval Mintz 	}
59fe56b9e6SYuval Mintz 
60fe56b9e6SYuval Mintz 	sb_info = &p_hwfn->p_sp_sb->sb_info;
61fe56b9e6SYuval Mintz 	arr_size = ARRAY_SIZE(p_hwfn->p_sp_sb->pi_info_arr);
62fe56b9e6SYuval Mintz 	if (!sb_info) {
63fe56b9e6SYuval Mintz 		DP_ERR(p_hwfn->cdev,
64fe56b9e6SYuval Mintz 		       "Status block is NULL - cannot ack interrupts\n");
65fe56b9e6SYuval Mintz 		return;
66fe56b9e6SYuval Mintz 	}
67fe56b9e6SYuval Mintz 
68fe56b9e6SYuval Mintz 	DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, "DPC Called! (hwfn %p %d)\n",
69fe56b9e6SYuval Mintz 		   p_hwfn, p_hwfn->my_id);
70fe56b9e6SYuval Mintz 
71fe56b9e6SYuval Mintz 	/* Disable ack for def status block. Required both for msix +
72fe56b9e6SYuval Mintz 	 * inta in non-mask mode, in inta does no harm.
73fe56b9e6SYuval Mintz 	 */
74fe56b9e6SYuval Mintz 	qed_sb_ack(sb_info, IGU_INT_DISABLE, 0);
75fe56b9e6SYuval Mintz 
76fe56b9e6SYuval Mintz 	/* Gather Interrupts/Attentions information */
77fe56b9e6SYuval Mintz 	if (!sb_info->sb_virt) {
78fe56b9e6SYuval Mintz 		DP_ERR(
79fe56b9e6SYuval Mintz 			p_hwfn->cdev,
80fe56b9e6SYuval Mintz 			"Interrupt Status block is NULL - cannot check for new interrupts!\n");
81fe56b9e6SYuval Mintz 	} else {
82fe56b9e6SYuval Mintz 		u32 tmp_index = sb_info->sb_ack;
83fe56b9e6SYuval Mintz 
84fe56b9e6SYuval Mintz 		rc = qed_sb_update_sb_idx(sb_info);
85fe56b9e6SYuval Mintz 		DP_VERBOSE(p_hwfn->cdev, NETIF_MSG_INTR,
86fe56b9e6SYuval Mintz 			   "Interrupt indices: 0x%08x --> 0x%08x\n",
87fe56b9e6SYuval Mintz 			   tmp_index, sb_info->sb_ack);
88fe56b9e6SYuval Mintz 	}
89fe56b9e6SYuval Mintz 
90fe56b9e6SYuval Mintz 	/* Check if we expect interrupts at this time. if not just ack them */
91fe56b9e6SYuval Mintz 	if (!(rc & QED_SB_EVENT_MASK)) {
92fe56b9e6SYuval Mintz 		qed_sb_ack(sb_info, IGU_INT_ENABLE, 1);
93fe56b9e6SYuval Mintz 		return;
94fe56b9e6SYuval Mintz 	}
95fe56b9e6SYuval Mintz 
96fe56b9e6SYuval Mintz 	/* Check the validity of the DPC ptt. If not ack interrupts and fail */
97fe56b9e6SYuval Mintz 	if (!p_hwfn->p_dpc_ptt) {
98fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn->cdev, "Failed to allocate PTT\n");
99fe56b9e6SYuval Mintz 		qed_sb_ack(sb_info, IGU_INT_ENABLE, 1);
100fe56b9e6SYuval Mintz 		return;
101fe56b9e6SYuval Mintz 	}
102fe56b9e6SYuval Mintz 
103fe56b9e6SYuval Mintz 	if (rc & QED_SB_IDX) {
104fe56b9e6SYuval Mintz 		int pi;
105fe56b9e6SYuval Mintz 
106fe56b9e6SYuval Mintz 		/* Look for a free index */
107fe56b9e6SYuval Mintz 		for (pi = 0; pi < arr_size; pi++) {
108fe56b9e6SYuval Mintz 			pi_info = &p_hwfn->p_sp_sb->pi_info_arr[pi];
109fe56b9e6SYuval Mintz 			if (pi_info->comp_cb)
110fe56b9e6SYuval Mintz 				pi_info->comp_cb(p_hwfn, pi_info->cookie);
111fe56b9e6SYuval Mintz 		}
112fe56b9e6SYuval Mintz 	}
113fe56b9e6SYuval Mintz 
114fe56b9e6SYuval Mintz 	qed_sb_ack(sb_info, IGU_INT_ENABLE, 1);
115fe56b9e6SYuval Mintz }
116fe56b9e6SYuval Mintz 
117fe56b9e6SYuval Mintz /* coalescing timeout = timeset << (timer_res + 1) */
118fe56b9e6SYuval Mintz #define QED_CAU_DEF_RX_USECS 24
119fe56b9e6SYuval Mintz #define QED_CAU_DEF_TX_USECS 48
120fe56b9e6SYuval Mintz 
121fe56b9e6SYuval Mintz void qed_init_cau_sb_entry(struct qed_hwfn *p_hwfn,
122fe56b9e6SYuval Mintz 			   struct cau_sb_entry *p_sb_entry,
123fe56b9e6SYuval Mintz 			   u8 pf_id,
124fe56b9e6SYuval Mintz 			   u16 vf_number,
125fe56b9e6SYuval Mintz 			   u8 vf_valid)
126fe56b9e6SYuval Mintz {
127fe56b9e6SYuval Mintz 	u32 cau_state;
128fe56b9e6SYuval Mintz 
129fe56b9e6SYuval Mintz 	memset(p_sb_entry, 0, sizeof(*p_sb_entry));
130fe56b9e6SYuval Mintz 
131fe56b9e6SYuval Mintz 	SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_PF_NUMBER, pf_id);
132fe56b9e6SYuval Mintz 	SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_VF_NUMBER, vf_number);
133fe56b9e6SYuval Mintz 	SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_VF_VALID, vf_valid);
134fe56b9e6SYuval Mintz 	SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_SB_TIMESET0, 0x7F);
135fe56b9e6SYuval Mintz 	SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_SB_TIMESET1, 0x7F);
136fe56b9e6SYuval Mintz 
137fe56b9e6SYuval Mintz 	/* setting the time resultion to a fixed value ( = 1) */
138fe56b9e6SYuval Mintz 	SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_TIMER_RES0,
139fe56b9e6SYuval Mintz 		  QED_CAU_DEF_RX_TIMER_RES);
140fe56b9e6SYuval Mintz 	SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_TIMER_RES1,
141fe56b9e6SYuval Mintz 		  QED_CAU_DEF_TX_TIMER_RES);
142fe56b9e6SYuval Mintz 
143fe56b9e6SYuval Mintz 	cau_state = CAU_HC_DISABLE_STATE;
144fe56b9e6SYuval Mintz 
145fe56b9e6SYuval Mintz 	if (p_hwfn->cdev->int_coalescing_mode == QED_COAL_MODE_ENABLE) {
146fe56b9e6SYuval Mintz 		cau_state = CAU_HC_ENABLE_STATE;
147fe56b9e6SYuval Mintz 		if (!p_hwfn->cdev->rx_coalesce_usecs)
148fe56b9e6SYuval Mintz 			p_hwfn->cdev->rx_coalesce_usecs =
149fe56b9e6SYuval Mintz 				QED_CAU_DEF_RX_USECS;
150fe56b9e6SYuval Mintz 		if (!p_hwfn->cdev->tx_coalesce_usecs)
151fe56b9e6SYuval Mintz 			p_hwfn->cdev->tx_coalesce_usecs =
152fe56b9e6SYuval Mintz 				QED_CAU_DEF_TX_USECS;
153fe56b9e6SYuval Mintz 	}
154fe56b9e6SYuval Mintz 
155fe56b9e6SYuval Mintz 	SET_FIELD(p_sb_entry->data, CAU_SB_ENTRY_STATE0, cau_state);
156fe56b9e6SYuval Mintz 	SET_FIELD(p_sb_entry->data, CAU_SB_ENTRY_STATE1, cau_state);
157fe56b9e6SYuval Mintz }
158fe56b9e6SYuval Mintz 
159fe56b9e6SYuval Mintz void qed_int_cau_conf_sb(struct qed_hwfn *p_hwfn,
160fe56b9e6SYuval Mintz 			 struct qed_ptt *p_ptt,
161fe56b9e6SYuval Mintz 			 dma_addr_t sb_phys,
162fe56b9e6SYuval Mintz 			 u16 igu_sb_id,
163fe56b9e6SYuval Mintz 			 u16 vf_number,
164fe56b9e6SYuval Mintz 			 u8 vf_valid)
165fe56b9e6SYuval Mintz {
166fe56b9e6SYuval Mintz 	struct cau_sb_entry sb_entry;
167fe56b9e6SYuval Mintz 	u32 val;
168fe56b9e6SYuval Mintz 
169fe56b9e6SYuval Mintz 	qed_init_cau_sb_entry(p_hwfn, &sb_entry, p_hwfn->rel_pf_id,
170fe56b9e6SYuval Mintz 			      vf_number, vf_valid);
171fe56b9e6SYuval Mintz 
172fe56b9e6SYuval Mintz 	if (p_hwfn->hw_init_done) {
173fe56b9e6SYuval Mintz 		val = CAU_REG_SB_ADDR_MEMORY + igu_sb_id * sizeof(u64);
174fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, val, lower_32_bits(sb_phys));
175fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, val + sizeof(u32),
176fe56b9e6SYuval Mintz 		       upper_32_bits(sb_phys));
177fe56b9e6SYuval Mintz 
178fe56b9e6SYuval Mintz 		val = CAU_REG_SB_VAR_MEMORY + igu_sb_id * sizeof(u64);
179fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, val, sb_entry.data);
180fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt, val + sizeof(u32), sb_entry.params);
181fe56b9e6SYuval Mintz 	} else {
182fe56b9e6SYuval Mintz 		/* Initialize Status Block Address */
183fe56b9e6SYuval Mintz 		STORE_RT_REG_AGG(p_hwfn,
184fe56b9e6SYuval Mintz 				 CAU_REG_SB_ADDR_MEMORY_RT_OFFSET +
185fe56b9e6SYuval Mintz 				 igu_sb_id * 2,
186fe56b9e6SYuval Mintz 				 sb_phys);
187fe56b9e6SYuval Mintz 
188fe56b9e6SYuval Mintz 		STORE_RT_REG_AGG(p_hwfn,
189fe56b9e6SYuval Mintz 				 CAU_REG_SB_VAR_MEMORY_RT_OFFSET +
190fe56b9e6SYuval Mintz 				 igu_sb_id * 2,
191fe56b9e6SYuval Mintz 				 sb_entry);
192fe56b9e6SYuval Mintz 	}
193fe56b9e6SYuval Mintz 
194fe56b9e6SYuval Mintz 	/* Configure pi coalescing if set */
195fe56b9e6SYuval Mintz 	if (p_hwfn->cdev->int_coalescing_mode == QED_COAL_MODE_ENABLE) {
196fe56b9e6SYuval Mintz 		u8 timeset = p_hwfn->cdev->rx_coalesce_usecs >>
197fe56b9e6SYuval Mintz 			     (QED_CAU_DEF_RX_TIMER_RES + 1);
198fe56b9e6SYuval Mintz 		u8 num_tc = 1, i;
199fe56b9e6SYuval Mintz 
200fe56b9e6SYuval Mintz 		qed_int_cau_conf_pi(p_hwfn, p_ptt, igu_sb_id, RX_PI,
201fe56b9e6SYuval Mintz 				    QED_COAL_RX_STATE_MACHINE,
202fe56b9e6SYuval Mintz 				    timeset);
203fe56b9e6SYuval Mintz 
204fe56b9e6SYuval Mintz 		timeset = p_hwfn->cdev->tx_coalesce_usecs >>
205fe56b9e6SYuval Mintz 			  (QED_CAU_DEF_TX_TIMER_RES + 1);
206fe56b9e6SYuval Mintz 
207fe56b9e6SYuval Mintz 		for (i = 0; i < num_tc; i++) {
208fe56b9e6SYuval Mintz 			qed_int_cau_conf_pi(p_hwfn, p_ptt,
209fe56b9e6SYuval Mintz 					    igu_sb_id, TX_PI(i),
210fe56b9e6SYuval Mintz 					    QED_COAL_TX_STATE_MACHINE,
211fe56b9e6SYuval Mintz 					    timeset);
212fe56b9e6SYuval Mintz 		}
213fe56b9e6SYuval Mintz 	}
214fe56b9e6SYuval Mintz }
215fe56b9e6SYuval Mintz 
216fe56b9e6SYuval Mintz void qed_int_cau_conf_pi(struct qed_hwfn *p_hwfn,
217fe56b9e6SYuval Mintz 			 struct qed_ptt *p_ptt,
218fe56b9e6SYuval Mintz 			 u16 igu_sb_id,
219fe56b9e6SYuval Mintz 			 u32 pi_index,
220fe56b9e6SYuval Mintz 			 enum qed_coalescing_fsm coalescing_fsm,
221fe56b9e6SYuval Mintz 			 u8 timeset)
222fe56b9e6SYuval Mintz {
223fe56b9e6SYuval Mintz 	struct cau_pi_entry pi_entry;
224fe56b9e6SYuval Mintz 	u32 sb_offset;
225fe56b9e6SYuval Mintz 	u32 pi_offset;
226fe56b9e6SYuval Mintz 
227fe56b9e6SYuval Mintz 	sb_offset = igu_sb_id * PIS_PER_SB;
228fe56b9e6SYuval Mintz 	memset(&pi_entry, 0, sizeof(struct cau_pi_entry));
229fe56b9e6SYuval Mintz 
230fe56b9e6SYuval Mintz 	SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_PI_TIMESET, timeset);
231fe56b9e6SYuval Mintz 	if (coalescing_fsm == QED_COAL_RX_STATE_MACHINE)
232fe56b9e6SYuval Mintz 		SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_FSM_SEL, 0);
233fe56b9e6SYuval Mintz 	else
234fe56b9e6SYuval Mintz 		SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_FSM_SEL, 1);
235fe56b9e6SYuval Mintz 
236fe56b9e6SYuval Mintz 	pi_offset = sb_offset + pi_index;
237fe56b9e6SYuval Mintz 	if (p_hwfn->hw_init_done) {
238fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt,
239fe56b9e6SYuval Mintz 		       CAU_REG_PI_MEMORY + pi_offset * sizeof(u32),
240fe56b9e6SYuval Mintz 		       *((u32 *)&(pi_entry)));
241fe56b9e6SYuval Mintz 	} else {
242fe56b9e6SYuval Mintz 		STORE_RT_REG(p_hwfn,
243fe56b9e6SYuval Mintz 			     CAU_REG_PI_MEMORY_RT_OFFSET + pi_offset,
244fe56b9e6SYuval Mintz 			     *((u32 *)&(pi_entry)));
245fe56b9e6SYuval Mintz 	}
246fe56b9e6SYuval Mintz }
247fe56b9e6SYuval Mintz 
248fe56b9e6SYuval Mintz void qed_int_sb_setup(struct qed_hwfn *p_hwfn,
249fe56b9e6SYuval Mintz 		      struct qed_ptt *p_ptt,
250fe56b9e6SYuval Mintz 		      struct qed_sb_info *sb_info)
251fe56b9e6SYuval Mintz {
252fe56b9e6SYuval Mintz 	/* zero status block and ack counter */
253fe56b9e6SYuval Mintz 	sb_info->sb_ack = 0;
254fe56b9e6SYuval Mintz 	memset(sb_info->sb_virt, 0, sizeof(*sb_info->sb_virt));
255fe56b9e6SYuval Mintz 
256fe56b9e6SYuval Mintz 	qed_int_cau_conf_sb(p_hwfn, p_ptt, sb_info->sb_phys,
257fe56b9e6SYuval Mintz 			    sb_info->igu_sb_id, 0, 0);
258fe56b9e6SYuval Mintz }
259fe56b9e6SYuval Mintz 
260fe56b9e6SYuval Mintz /**
261fe56b9e6SYuval Mintz  * @brief qed_get_igu_sb_id - given a sw sb_id return the
262fe56b9e6SYuval Mintz  *        igu_sb_id
263fe56b9e6SYuval Mintz  *
264fe56b9e6SYuval Mintz  * @param p_hwfn
265fe56b9e6SYuval Mintz  * @param sb_id
266fe56b9e6SYuval Mintz  *
267fe56b9e6SYuval Mintz  * @return u16
268fe56b9e6SYuval Mintz  */
269fe56b9e6SYuval Mintz static u16 qed_get_igu_sb_id(struct qed_hwfn *p_hwfn,
270fe56b9e6SYuval Mintz 			     u16 sb_id)
271fe56b9e6SYuval Mintz {
272fe56b9e6SYuval Mintz 	u16 igu_sb_id;
273fe56b9e6SYuval Mintz 
274fe56b9e6SYuval Mintz 	/* Assuming continuous set of IGU SBs dedicated for given PF */
275fe56b9e6SYuval Mintz 	if (sb_id == QED_SP_SB_ID)
276fe56b9e6SYuval Mintz 		igu_sb_id = p_hwfn->hw_info.p_igu_info->igu_dsb_id;
277fe56b9e6SYuval Mintz 	else
278fe56b9e6SYuval Mintz 		igu_sb_id = sb_id + p_hwfn->hw_info.p_igu_info->igu_base_sb;
279fe56b9e6SYuval Mintz 
280fe56b9e6SYuval Mintz 	DP_VERBOSE(p_hwfn, NETIF_MSG_INTR, "SB [%s] index is 0x%04x\n",
281fe56b9e6SYuval Mintz 		   (sb_id == QED_SP_SB_ID) ? "DSB" : "non-DSB", igu_sb_id);
282fe56b9e6SYuval Mintz 
283fe56b9e6SYuval Mintz 	return igu_sb_id;
284fe56b9e6SYuval Mintz }
285fe56b9e6SYuval Mintz 
286fe56b9e6SYuval Mintz int qed_int_sb_init(struct qed_hwfn *p_hwfn,
287fe56b9e6SYuval Mintz 		    struct qed_ptt *p_ptt,
288fe56b9e6SYuval Mintz 		    struct qed_sb_info *sb_info,
289fe56b9e6SYuval Mintz 		    void *sb_virt_addr,
290fe56b9e6SYuval Mintz 		    dma_addr_t sb_phy_addr,
291fe56b9e6SYuval Mintz 		    u16 sb_id)
292fe56b9e6SYuval Mintz {
293fe56b9e6SYuval Mintz 	sb_info->sb_virt = sb_virt_addr;
294fe56b9e6SYuval Mintz 	sb_info->sb_phys = sb_phy_addr;
295fe56b9e6SYuval Mintz 
296fe56b9e6SYuval Mintz 	sb_info->igu_sb_id = qed_get_igu_sb_id(p_hwfn, sb_id);
297fe56b9e6SYuval Mintz 
298fe56b9e6SYuval Mintz 	if (sb_id != QED_SP_SB_ID) {
299fe56b9e6SYuval Mintz 		p_hwfn->sbs_info[sb_id] = sb_info;
300fe56b9e6SYuval Mintz 		p_hwfn->num_sbs++;
301fe56b9e6SYuval Mintz 	}
302fe56b9e6SYuval Mintz 
303fe56b9e6SYuval Mintz 	sb_info->cdev = p_hwfn->cdev;
304fe56b9e6SYuval Mintz 
305fe56b9e6SYuval Mintz 	/* The igu address will hold the absolute address that needs to be
306fe56b9e6SYuval Mintz 	 * written to for a specific status block
307fe56b9e6SYuval Mintz 	 */
308fe56b9e6SYuval Mintz 	sb_info->igu_addr = (u8 __iomem *)p_hwfn->regview +
309fe56b9e6SYuval Mintz 					  GTT_BAR0_MAP_REG_IGU_CMD +
310fe56b9e6SYuval Mintz 					  (sb_info->igu_sb_id << 3);
311fe56b9e6SYuval Mintz 
312fe56b9e6SYuval Mintz 	sb_info->flags |= QED_SB_INFO_INIT;
313fe56b9e6SYuval Mintz 
314fe56b9e6SYuval Mintz 	qed_int_sb_setup(p_hwfn, p_ptt, sb_info);
315fe56b9e6SYuval Mintz 
316fe56b9e6SYuval Mintz 	return 0;
317fe56b9e6SYuval Mintz }
318fe56b9e6SYuval Mintz 
319fe56b9e6SYuval Mintz int qed_int_sb_release(struct qed_hwfn *p_hwfn,
320fe56b9e6SYuval Mintz 		       struct qed_sb_info *sb_info,
321fe56b9e6SYuval Mintz 		       u16 sb_id)
322fe56b9e6SYuval Mintz {
323fe56b9e6SYuval Mintz 	if (sb_id == QED_SP_SB_ID) {
324fe56b9e6SYuval Mintz 		DP_ERR(p_hwfn, "Do Not free sp sb using this function");
325fe56b9e6SYuval Mintz 		return -EINVAL;
326fe56b9e6SYuval Mintz 	}
327fe56b9e6SYuval Mintz 
328fe56b9e6SYuval Mintz 	/* zero status block and ack counter */
329fe56b9e6SYuval Mintz 	sb_info->sb_ack = 0;
330fe56b9e6SYuval Mintz 	memset(sb_info->sb_virt, 0, sizeof(*sb_info->sb_virt));
331fe56b9e6SYuval Mintz 
332fe56b9e6SYuval Mintz 	p_hwfn->sbs_info[sb_id] = NULL;
333fe56b9e6SYuval Mintz 	p_hwfn->num_sbs--;
334fe56b9e6SYuval Mintz 
335fe56b9e6SYuval Mintz 	return 0;
336fe56b9e6SYuval Mintz }
337fe56b9e6SYuval Mintz 
338fe56b9e6SYuval Mintz static void qed_int_sp_sb_free(struct qed_hwfn *p_hwfn)
339fe56b9e6SYuval Mintz {
340fe56b9e6SYuval Mintz 	struct qed_sb_sp_info *p_sb = p_hwfn->p_sp_sb;
341fe56b9e6SYuval Mintz 
342fe56b9e6SYuval Mintz 	if (p_sb) {
343fe56b9e6SYuval Mintz 		if (p_sb->sb_info.sb_virt)
344fe56b9e6SYuval Mintz 			dma_free_coherent(&p_hwfn->cdev->pdev->dev,
345fe56b9e6SYuval Mintz 					  SB_ALIGNED_SIZE(p_hwfn),
346fe56b9e6SYuval Mintz 					  p_sb->sb_info.sb_virt,
347fe56b9e6SYuval Mintz 					  p_sb->sb_info.sb_phys);
348fe56b9e6SYuval Mintz 		kfree(p_sb);
349fe56b9e6SYuval Mintz 	}
350fe56b9e6SYuval Mintz }
351fe56b9e6SYuval Mintz 
352fe56b9e6SYuval Mintz static int qed_int_sp_sb_alloc(struct qed_hwfn *p_hwfn,
353fe56b9e6SYuval Mintz 			       struct qed_ptt *p_ptt)
354fe56b9e6SYuval Mintz {
355fe56b9e6SYuval Mintz 	struct qed_sb_sp_info *p_sb;
356fe56b9e6SYuval Mintz 	dma_addr_t p_phys = 0;
357fe56b9e6SYuval Mintz 	void *p_virt;
358fe56b9e6SYuval Mintz 
359fe56b9e6SYuval Mintz 	/* SB struct */
360fe56b9e6SYuval Mintz 	p_sb = kmalloc(sizeof(*p_sb), GFP_ATOMIC);
361fe56b9e6SYuval Mintz 	if (!p_sb) {
362fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_sb_info'\n");
363fe56b9e6SYuval Mintz 		return -ENOMEM;
364fe56b9e6SYuval Mintz 	}
365fe56b9e6SYuval Mintz 
366fe56b9e6SYuval Mintz 	/* SB ring  */
367fe56b9e6SYuval Mintz 	p_virt = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
368fe56b9e6SYuval Mintz 				    SB_ALIGNED_SIZE(p_hwfn),
369fe56b9e6SYuval Mintz 				    &p_phys, GFP_KERNEL);
370fe56b9e6SYuval Mintz 	if (!p_virt) {
371fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn, "Failed to allocate status block\n");
372fe56b9e6SYuval Mintz 		kfree(p_sb);
373fe56b9e6SYuval Mintz 		return -ENOMEM;
374fe56b9e6SYuval Mintz 	}
375fe56b9e6SYuval Mintz 
376fe56b9e6SYuval Mintz 	/* Status Block setup */
377fe56b9e6SYuval Mintz 	p_hwfn->p_sp_sb = p_sb;
378fe56b9e6SYuval Mintz 	qed_int_sb_init(p_hwfn, p_ptt, &p_sb->sb_info, p_virt,
379fe56b9e6SYuval Mintz 			p_phys, QED_SP_SB_ID);
380fe56b9e6SYuval Mintz 
381fe56b9e6SYuval Mintz 	memset(p_sb->pi_info_arr, 0, sizeof(p_sb->pi_info_arr));
382fe56b9e6SYuval Mintz 
383fe56b9e6SYuval Mintz 	return 0;
384fe56b9e6SYuval Mintz }
385fe56b9e6SYuval Mintz 
386fe56b9e6SYuval Mintz static void qed_int_sp_sb_setup(struct qed_hwfn *p_hwfn,
387fe56b9e6SYuval Mintz 				struct qed_ptt *p_ptt)
388fe56b9e6SYuval Mintz {
389fe56b9e6SYuval Mintz 	if (!p_hwfn)
390fe56b9e6SYuval Mintz 		return;
391fe56b9e6SYuval Mintz 
392fe56b9e6SYuval Mintz 	if (p_hwfn->p_sp_sb)
393fe56b9e6SYuval Mintz 		qed_int_sb_setup(p_hwfn, p_ptt, &p_hwfn->p_sp_sb->sb_info);
394fe56b9e6SYuval Mintz 	else
395fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn->cdev,
396fe56b9e6SYuval Mintz 			  "Failed to setup Slow path status block - NULL pointer\n");
397fe56b9e6SYuval Mintz }
398fe56b9e6SYuval Mintz 
399fe56b9e6SYuval Mintz int qed_int_register_cb(struct qed_hwfn *p_hwfn,
400fe56b9e6SYuval Mintz 			qed_int_comp_cb_t comp_cb,
401fe56b9e6SYuval Mintz 			void *cookie,
402fe56b9e6SYuval Mintz 			u8 *sb_idx,
403fe56b9e6SYuval Mintz 			__le16 **p_fw_cons)
404fe56b9e6SYuval Mintz {
405fe56b9e6SYuval Mintz 	struct qed_sb_sp_info *p_sp_sb = p_hwfn->p_sp_sb;
406fe56b9e6SYuval Mintz 	int qed_status = -ENOMEM;
407fe56b9e6SYuval Mintz 	u8 pi;
408fe56b9e6SYuval Mintz 
409fe56b9e6SYuval Mintz 	/* Look for a free index */
410fe56b9e6SYuval Mintz 	for (pi = 0; pi < ARRAY_SIZE(p_sp_sb->pi_info_arr); pi++) {
411fe56b9e6SYuval Mintz 		if (!p_sp_sb->pi_info_arr[pi].comp_cb) {
412fe56b9e6SYuval Mintz 			p_sp_sb->pi_info_arr[pi].comp_cb = comp_cb;
413fe56b9e6SYuval Mintz 			p_sp_sb->pi_info_arr[pi].cookie = cookie;
414fe56b9e6SYuval Mintz 			*sb_idx = pi;
415fe56b9e6SYuval Mintz 			*p_fw_cons = &p_sp_sb->sb_info.sb_virt->pi_array[pi];
416fe56b9e6SYuval Mintz 			qed_status = 0;
417fe56b9e6SYuval Mintz 			break;
418fe56b9e6SYuval Mintz 		}
419fe56b9e6SYuval Mintz 	}
420fe56b9e6SYuval Mintz 
421fe56b9e6SYuval Mintz 	return qed_status;
422fe56b9e6SYuval Mintz }
423fe56b9e6SYuval Mintz 
424fe56b9e6SYuval Mintz int qed_int_unregister_cb(struct qed_hwfn *p_hwfn, u8 pi)
425fe56b9e6SYuval Mintz {
426fe56b9e6SYuval Mintz 	struct qed_sb_sp_info *p_sp_sb = p_hwfn->p_sp_sb;
427fe56b9e6SYuval Mintz 	int qed_status = -ENOMEM;
428fe56b9e6SYuval Mintz 
429fe56b9e6SYuval Mintz 	if (p_sp_sb->pi_info_arr[pi].comp_cb) {
430fe56b9e6SYuval Mintz 		p_sp_sb->pi_info_arr[pi].comp_cb = NULL;
431fe56b9e6SYuval Mintz 		p_sp_sb->pi_info_arr[pi].cookie = NULL;
432fe56b9e6SYuval Mintz 		qed_status = 0;
433fe56b9e6SYuval Mintz 	}
434fe56b9e6SYuval Mintz 
435fe56b9e6SYuval Mintz 	return qed_status;
436fe56b9e6SYuval Mintz }
437fe56b9e6SYuval Mintz 
438fe56b9e6SYuval Mintz u16 qed_int_get_sp_sb_id(struct qed_hwfn *p_hwfn)
439fe56b9e6SYuval Mintz {
440fe56b9e6SYuval Mintz 	return p_hwfn->p_sp_sb->sb_info.igu_sb_id;
441fe56b9e6SYuval Mintz }
442fe56b9e6SYuval Mintz 
443fe56b9e6SYuval Mintz void qed_int_igu_enable_int(struct qed_hwfn *p_hwfn,
444fe56b9e6SYuval Mintz 			    struct qed_ptt *p_ptt,
445fe56b9e6SYuval Mintz 			    enum qed_int_mode int_mode)
446fe56b9e6SYuval Mintz {
447fe56b9e6SYuval Mintz 	u32 igu_pf_conf = IGU_PF_CONF_FUNC_EN;
448fe56b9e6SYuval Mintz 
449fe56b9e6SYuval Mintz 	p_hwfn->cdev->int_mode = int_mode;
450fe56b9e6SYuval Mintz 	switch (p_hwfn->cdev->int_mode) {
451fe56b9e6SYuval Mintz 	case QED_INT_MODE_INTA:
452fe56b9e6SYuval Mintz 		igu_pf_conf |= IGU_PF_CONF_INT_LINE_EN;
453fe56b9e6SYuval Mintz 		igu_pf_conf |= IGU_PF_CONF_SINGLE_ISR_EN;
454fe56b9e6SYuval Mintz 		break;
455fe56b9e6SYuval Mintz 
456fe56b9e6SYuval Mintz 	case QED_INT_MODE_MSI:
457fe56b9e6SYuval Mintz 		igu_pf_conf |= IGU_PF_CONF_MSI_MSIX_EN;
458fe56b9e6SYuval Mintz 		igu_pf_conf |= IGU_PF_CONF_SINGLE_ISR_EN;
459fe56b9e6SYuval Mintz 		break;
460fe56b9e6SYuval Mintz 
461fe56b9e6SYuval Mintz 	case QED_INT_MODE_MSIX:
462fe56b9e6SYuval Mintz 		igu_pf_conf |= IGU_PF_CONF_MSI_MSIX_EN;
463fe56b9e6SYuval Mintz 		break;
464fe56b9e6SYuval Mintz 	case QED_INT_MODE_POLL:
465fe56b9e6SYuval Mintz 		break;
466fe56b9e6SYuval Mintz 	}
467fe56b9e6SYuval Mintz 
468fe56b9e6SYuval Mintz 	qed_wr(p_hwfn, p_ptt, IGU_REG_PF_CONFIGURATION, igu_pf_conf);
469fe56b9e6SYuval Mintz }
470fe56b9e6SYuval Mintz 
471fe56b9e6SYuval Mintz void qed_int_igu_enable(struct qed_hwfn *p_hwfn,
472fe56b9e6SYuval Mintz 			struct qed_ptt *p_ptt,
473fe56b9e6SYuval Mintz 			enum qed_int_mode int_mode)
474fe56b9e6SYuval Mintz {
475fe56b9e6SYuval Mintz 	int i;
476fe56b9e6SYuval Mintz 
477fe56b9e6SYuval Mintz 	p_hwfn->b_int_enabled = 1;
478fe56b9e6SYuval Mintz 
479fe56b9e6SYuval Mintz 	/* Mask non-link attentions */
480fe56b9e6SYuval Mintz 	for (i = 0; i < 9; i++)
481fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt,
482fe56b9e6SYuval Mintz 		       MISC_REG_AEU_ENABLE1_IGU_OUT_0 + (i << 2), 0);
483fe56b9e6SYuval Mintz 
484fe56b9e6SYuval Mintz 	/* Enable interrupt Generation */
485fe56b9e6SYuval Mintz 	qed_int_igu_enable_int(p_hwfn, p_ptt, int_mode);
486fe56b9e6SYuval Mintz 
487fe56b9e6SYuval Mintz 	/* Flush the writes to IGU */
488fe56b9e6SYuval Mintz 	mmiowb();
489fe56b9e6SYuval Mintz }
490fe56b9e6SYuval Mintz 
491fe56b9e6SYuval Mintz void qed_int_igu_disable_int(struct qed_hwfn *p_hwfn,
492fe56b9e6SYuval Mintz 			     struct qed_ptt *p_ptt)
493fe56b9e6SYuval Mintz {
494fe56b9e6SYuval Mintz 	p_hwfn->b_int_enabled = 0;
495fe56b9e6SYuval Mintz 
496fe56b9e6SYuval Mintz 	qed_wr(p_hwfn, p_ptt, IGU_REG_PF_CONFIGURATION, 0);
497fe56b9e6SYuval Mintz }
498fe56b9e6SYuval Mintz 
499fe56b9e6SYuval Mintz #define IGU_CLEANUP_SLEEP_LENGTH                (1000)
500fe56b9e6SYuval Mintz void qed_int_igu_cleanup_sb(struct qed_hwfn *p_hwfn,
501fe56b9e6SYuval Mintz 			    struct qed_ptt *p_ptt,
502fe56b9e6SYuval Mintz 			    u32 sb_id,
503fe56b9e6SYuval Mintz 			    bool cleanup_set,
504fe56b9e6SYuval Mintz 			    u16 opaque_fid
505fe56b9e6SYuval Mintz 			    )
506fe56b9e6SYuval Mintz {
507fe56b9e6SYuval Mintz 	u32 pxp_addr = IGU_CMD_INT_ACK_BASE + sb_id;
508fe56b9e6SYuval Mintz 	u32 sleep_cnt = IGU_CLEANUP_SLEEP_LENGTH;
509fe56b9e6SYuval Mintz 	u32 data = 0;
510fe56b9e6SYuval Mintz 	u32 cmd_ctrl = 0;
511fe56b9e6SYuval Mintz 	u32 val = 0;
512fe56b9e6SYuval Mintz 	u32 sb_bit = 0;
513fe56b9e6SYuval Mintz 	u32 sb_bit_addr = 0;
514fe56b9e6SYuval Mintz 
515fe56b9e6SYuval Mintz 	/* Set the data field */
516fe56b9e6SYuval Mintz 	SET_FIELD(data, IGU_CLEANUP_CLEANUP_SET, cleanup_set ? 1 : 0);
517fe56b9e6SYuval Mintz 	SET_FIELD(data, IGU_CLEANUP_CLEANUP_TYPE, 0);
518fe56b9e6SYuval Mintz 	SET_FIELD(data, IGU_CLEANUP_COMMAND_TYPE, IGU_COMMAND_TYPE_SET);
519fe56b9e6SYuval Mintz 
520fe56b9e6SYuval Mintz 	/* Set the control register */
521fe56b9e6SYuval Mintz 	SET_FIELD(cmd_ctrl, IGU_CTRL_REG_PXP_ADDR, pxp_addr);
522fe56b9e6SYuval Mintz 	SET_FIELD(cmd_ctrl, IGU_CTRL_REG_FID, opaque_fid);
523fe56b9e6SYuval Mintz 	SET_FIELD(cmd_ctrl, IGU_CTRL_REG_TYPE, IGU_CTRL_CMD_TYPE_WR);
524fe56b9e6SYuval Mintz 
525fe56b9e6SYuval Mintz 	qed_wr(p_hwfn, p_ptt, IGU_REG_COMMAND_REG_32LSB_DATA, data);
526fe56b9e6SYuval Mintz 
527fe56b9e6SYuval Mintz 	barrier();
528fe56b9e6SYuval Mintz 
529fe56b9e6SYuval Mintz 	qed_wr(p_hwfn, p_ptt, IGU_REG_COMMAND_REG_CTRL, cmd_ctrl);
530fe56b9e6SYuval Mintz 
531fe56b9e6SYuval Mintz 	/* Flush the write to IGU */
532fe56b9e6SYuval Mintz 	mmiowb();
533fe56b9e6SYuval Mintz 
534fe56b9e6SYuval Mintz 	/* calculate where to read the status bit from */
535fe56b9e6SYuval Mintz 	sb_bit = 1 << (sb_id % 32);
536fe56b9e6SYuval Mintz 	sb_bit_addr = sb_id / 32 * sizeof(u32);
537fe56b9e6SYuval Mintz 
538fe56b9e6SYuval Mintz 	sb_bit_addr += IGU_REG_CLEANUP_STATUS_0;
539fe56b9e6SYuval Mintz 
540fe56b9e6SYuval Mintz 	/* Now wait for the command to complete */
541fe56b9e6SYuval Mintz 	do {
542fe56b9e6SYuval Mintz 		val = qed_rd(p_hwfn, p_ptt, sb_bit_addr);
543fe56b9e6SYuval Mintz 
544fe56b9e6SYuval Mintz 		if ((val & sb_bit) == (cleanup_set ? sb_bit : 0))
545fe56b9e6SYuval Mintz 			break;
546fe56b9e6SYuval Mintz 
547fe56b9e6SYuval Mintz 		usleep_range(5000, 10000);
548fe56b9e6SYuval Mintz 	} while (--sleep_cnt);
549fe56b9e6SYuval Mintz 
550fe56b9e6SYuval Mintz 	if (!sleep_cnt)
551fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn,
552fe56b9e6SYuval Mintz 			  "Timeout waiting for clear status 0x%08x [for sb %d]\n",
553fe56b9e6SYuval Mintz 			  val, sb_id);
554fe56b9e6SYuval Mintz }
555fe56b9e6SYuval Mintz 
556fe56b9e6SYuval Mintz void qed_int_igu_init_pure_rt_single(struct qed_hwfn *p_hwfn,
557fe56b9e6SYuval Mintz 				     struct qed_ptt *p_ptt,
558fe56b9e6SYuval Mintz 				     u32 sb_id,
559fe56b9e6SYuval Mintz 				     u16 opaque,
560fe56b9e6SYuval Mintz 				     bool b_set)
561fe56b9e6SYuval Mintz {
562fe56b9e6SYuval Mintz 	int pi;
563fe56b9e6SYuval Mintz 
564fe56b9e6SYuval Mintz 	/* Set */
565fe56b9e6SYuval Mintz 	if (b_set)
566fe56b9e6SYuval Mintz 		qed_int_igu_cleanup_sb(p_hwfn, p_ptt, sb_id, 1, opaque);
567fe56b9e6SYuval Mintz 
568fe56b9e6SYuval Mintz 	/* Clear */
569fe56b9e6SYuval Mintz 	qed_int_igu_cleanup_sb(p_hwfn, p_ptt, sb_id, 0, opaque);
570fe56b9e6SYuval Mintz 
571fe56b9e6SYuval Mintz 	/* Clear the CAU for the SB */
572fe56b9e6SYuval Mintz 	for (pi = 0; pi < 12; pi++)
573fe56b9e6SYuval Mintz 		qed_wr(p_hwfn, p_ptt,
574fe56b9e6SYuval Mintz 		       CAU_REG_PI_MEMORY + (sb_id * 12 + pi) * 4, 0);
575fe56b9e6SYuval Mintz }
576fe56b9e6SYuval Mintz 
577fe56b9e6SYuval Mintz void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn,
578fe56b9e6SYuval Mintz 			      struct qed_ptt *p_ptt,
579fe56b9e6SYuval Mintz 			      bool b_set,
580fe56b9e6SYuval Mintz 			      bool b_slowpath)
581fe56b9e6SYuval Mintz {
582fe56b9e6SYuval Mintz 	u32 igu_base_sb = p_hwfn->hw_info.p_igu_info->igu_base_sb;
583fe56b9e6SYuval Mintz 	u32 igu_sb_cnt = p_hwfn->hw_info.p_igu_info->igu_sb_cnt;
584fe56b9e6SYuval Mintz 	u32 sb_id = 0;
585fe56b9e6SYuval Mintz 	u32 val = 0;
586fe56b9e6SYuval Mintz 
587fe56b9e6SYuval Mintz 	val = qed_rd(p_hwfn, p_ptt, IGU_REG_BLOCK_CONFIGURATION);
588fe56b9e6SYuval Mintz 	val |= IGU_REG_BLOCK_CONFIGURATION_VF_CLEANUP_EN;
589fe56b9e6SYuval Mintz 	val &= ~IGU_REG_BLOCK_CONFIGURATION_PXP_TPH_INTERFACE_EN;
590fe56b9e6SYuval Mintz 	qed_wr(p_hwfn, p_ptt, IGU_REG_BLOCK_CONFIGURATION, val);
591fe56b9e6SYuval Mintz 
592fe56b9e6SYuval Mintz 	DP_VERBOSE(p_hwfn, NETIF_MSG_INTR,
593fe56b9e6SYuval Mintz 		   "IGU cleaning SBs [%d,...,%d]\n",
594fe56b9e6SYuval Mintz 		   igu_base_sb, igu_base_sb + igu_sb_cnt - 1);
595fe56b9e6SYuval Mintz 
596fe56b9e6SYuval Mintz 	for (sb_id = igu_base_sb; sb_id < igu_base_sb + igu_sb_cnt; sb_id++)
597fe56b9e6SYuval Mintz 		qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, sb_id,
598fe56b9e6SYuval Mintz 						p_hwfn->hw_info.opaque_fid,
599fe56b9e6SYuval Mintz 						b_set);
600fe56b9e6SYuval Mintz 
601fe56b9e6SYuval Mintz 	if (b_slowpath) {
602fe56b9e6SYuval Mintz 		sb_id = p_hwfn->hw_info.p_igu_info->igu_dsb_id;
603fe56b9e6SYuval Mintz 		DP_VERBOSE(p_hwfn, NETIF_MSG_INTR,
604fe56b9e6SYuval Mintz 			   "IGU cleaning slowpath SB [%d]\n", sb_id);
605fe56b9e6SYuval Mintz 		qed_int_igu_init_pure_rt_single(p_hwfn, p_ptt, sb_id,
606fe56b9e6SYuval Mintz 						p_hwfn->hw_info.opaque_fid,
607fe56b9e6SYuval Mintz 						b_set);
608fe56b9e6SYuval Mintz 	}
609fe56b9e6SYuval Mintz }
610fe56b9e6SYuval Mintz 
611fe56b9e6SYuval Mintz int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn,
612fe56b9e6SYuval Mintz 			 struct qed_ptt *p_ptt)
613fe56b9e6SYuval Mintz {
614fe56b9e6SYuval Mintz 	struct qed_igu_info *p_igu_info;
615fe56b9e6SYuval Mintz 	struct qed_igu_block *blk;
616fe56b9e6SYuval Mintz 	u32 val;
617fe56b9e6SYuval Mintz 	u16 sb_id;
618fe56b9e6SYuval Mintz 	u16 prev_sb_id = 0xFF;
619fe56b9e6SYuval Mintz 
620fe56b9e6SYuval Mintz 	p_hwfn->hw_info.p_igu_info = kzalloc(sizeof(*p_igu_info), GFP_ATOMIC);
621fe56b9e6SYuval Mintz 
622fe56b9e6SYuval Mintz 	if (!p_hwfn->hw_info.p_igu_info)
623fe56b9e6SYuval Mintz 		return -ENOMEM;
624fe56b9e6SYuval Mintz 
625fe56b9e6SYuval Mintz 	p_igu_info = p_hwfn->hw_info.p_igu_info;
626fe56b9e6SYuval Mintz 
627fe56b9e6SYuval Mintz 	/* Initialize base sb / sb cnt for PFs */
628fe56b9e6SYuval Mintz 	p_igu_info->igu_base_sb		= 0xffff;
629fe56b9e6SYuval Mintz 	p_igu_info->igu_sb_cnt		= 0;
630fe56b9e6SYuval Mintz 	p_igu_info->igu_dsb_id		= 0xffff;
631fe56b9e6SYuval Mintz 	p_igu_info->igu_base_sb_iov	= 0xffff;
632fe56b9e6SYuval Mintz 
633fe56b9e6SYuval Mintz 	for (sb_id = 0; sb_id < QED_MAPPING_MEMORY_SIZE(p_hwfn->cdev);
634fe56b9e6SYuval Mintz 	     sb_id++) {
635fe56b9e6SYuval Mintz 		blk = &p_igu_info->igu_map.igu_blocks[sb_id];
636fe56b9e6SYuval Mintz 
637fe56b9e6SYuval Mintz 		val = qed_rd(p_hwfn, p_ptt,
638fe56b9e6SYuval Mintz 			     IGU_REG_MAPPING_MEMORY + sizeof(u32) * sb_id);
639fe56b9e6SYuval Mintz 
640fe56b9e6SYuval Mintz 		/* stop scanning when hit first invalid PF entry */
641fe56b9e6SYuval Mintz 		if (!GET_FIELD(val, IGU_MAPPING_LINE_VALID) &&
642fe56b9e6SYuval Mintz 		    GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID))
643fe56b9e6SYuval Mintz 			break;
644fe56b9e6SYuval Mintz 
645fe56b9e6SYuval Mintz 		blk->status = QED_IGU_STATUS_VALID;
646fe56b9e6SYuval Mintz 		blk->function_id = GET_FIELD(val,
647fe56b9e6SYuval Mintz 					     IGU_MAPPING_LINE_FUNCTION_NUMBER);
648fe56b9e6SYuval Mintz 		blk->is_pf = GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID);
649fe56b9e6SYuval Mintz 		blk->vector_number = GET_FIELD(val,
650fe56b9e6SYuval Mintz 					       IGU_MAPPING_LINE_VECTOR_NUMBER);
651fe56b9e6SYuval Mintz 
652fe56b9e6SYuval Mintz 		DP_VERBOSE(p_hwfn, NETIF_MSG_INTR,
653fe56b9e6SYuval Mintz 			   "IGU_BLOCK[sb_id]:%x:func_id = %d is_pf = %d vector_num = 0x%x\n",
654fe56b9e6SYuval Mintz 			   val, blk->function_id, blk->is_pf,
655fe56b9e6SYuval Mintz 			   blk->vector_number);
656fe56b9e6SYuval Mintz 
657fe56b9e6SYuval Mintz 		if (blk->is_pf) {
658fe56b9e6SYuval Mintz 			if (blk->function_id == p_hwfn->rel_pf_id) {
659fe56b9e6SYuval Mintz 				blk->status |= QED_IGU_STATUS_PF;
660fe56b9e6SYuval Mintz 
661fe56b9e6SYuval Mintz 				if (blk->vector_number == 0) {
662fe56b9e6SYuval Mintz 					if (p_igu_info->igu_dsb_id == 0xffff)
663fe56b9e6SYuval Mintz 						p_igu_info->igu_dsb_id = sb_id;
664fe56b9e6SYuval Mintz 				} else {
665fe56b9e6SYuval Mintz 					if (p_igu_info->igu_base_sb ==
666fe56b9e6SYuval Mintz 					    0xffff) {
667fe56b9e6SYuval Mintz 						p_igu_info->igu_base_sb = sb_id;
668fe56b9e6SYuval Mintz 					} else if (prev_sb_id != sb_id - 1) {
669fe56b9e6SYuval Mintz 						DP_NOTICE(p_hwfn->cdev,
670fe56b9e6SYuval Mintz 							  "consecutive igu vectors for HWFN %x broken",
671fe56b9e6SYuval Mintz 							  p_hwfn->rel_pf_id);
672fe56b9e6SYuval Mintz 						break;
673fe56b9e6SYuval Mintz 					}
674fe56b9e6SYuval Mintz 					prev_sb_id = sb_id;
675fe56b9e6SYuval Mintz 					/* we don't count the default */
676fe56b9e6SYuval Mintz 					(p_igu_info->igu_sb_cnt)++;
677fe56b9e6SYuval Mintz 				}
678fe56b9e6SYuval Mintz 			}
679fe56b9e6SYuval Mintz 		}
680fe56b9e6SYuval Mintz 	}
681fe56b9e6SYuval Mintz 
682fe56b9e6SYuval Mintz 	DP_VERBOSE(p_hwfn, NETIF_MSG_INTR,
683fe56b9e6SYuval Mintz 		   "IGU igu_base_sb=0x%x igu_sb_cnt=%d igu_dsb_id=0x%x\n",
684fe56b9e6SYuval Mintz 		   p_igu_info->igu_base_sb,
685fe56b9e6SYuval Mintz 		   p_igu_info->igu_sb_cnt,
686fe56b9e6SYuval Mintz 		   p_igu_info->igu_dsb_id);
687fe56b9e6SYuval Mintz 
688fe56b9e6SYuval Mintz 	if (p_igu_info->igu_base_sb == 0xffff ||
689fe56b9e6SYuval Mintz 	    p_igu_info->igu_dsb_id == 0xffff ||
690fe56b9e6SYuval Mintz 	    p_igu_info->igu_sb_cnt == 0) {
691fe56b9e6SYuval Mintz 		DP_NOTICE(p_hwfn,
692fe56b9e6SYuval Mintz 			  "IGU CAM returned invalid values igu_base_sb=0x%x igu_sb_cnt=%d igu_dsb_id=0x%x\n",
693fe56b9e6SYuval Mintz 			   p_igu_info->igu_base_sb,
694fe56b9e6SYuval Mintz 			   p_igu_info->igu_sb_cnt,
695fe56b9e6SYuval Mintz 			   p_igu_info->igu_dsb_id);
696fe56b9e6SYuval Mintz 		return -EINVAL;
697fe56b9e6SYuval Mintz 	}
698fe56b9e6SYuval Mintz 
699fe56b9e6SYuval Mintz 	return 0;
700fe56b9e6SYuval Mintz }
701fe56b9e6SYuval Mintz 
702fe56b9e6SYuval Mintz /**
703fe56b9e6SYuval Mintz  * @brief Initialize igu runtime registers
704fe56b9e6SYuval Mintz  *
705fe56b9e6SYuval Mintz  * @param p_hwfn
706fe56b9e6SYuval Mintz  */
707fe56b9e6SYuval Mintz void qed_int_igu_init_rt(struct qed_hwfn *p_hwfn)
708fe56b9e6SYuval Mintz {
709fe56b9e6SYuval Mintz 	u32 igu_pf_conf = 0;
710fe56b9e6SYuval Mintz 
711fe56b9e6SYuval Mintz 	igu_pf_conf |= IGU_PF_CONF_FUNC_EN;
712fe56b9e6SYuval Mintz 
713fe56b9e6SYuval Mintz 	STORE_RT_REG(p_hwfn, IGU_REG_PF_CONFIGURATION_RT_OFFSET, igu_pf_conf);
714fe56b9e6SYuval Mintz }
715fe56b9e6SYuval Mintz 
716fe56b9e6SYuval Mintz u64 qed_int_igu_read_sisr_reg(struct qed_hwfn *p_hwfn)
717fe56b9e6SYuval Mintz {
718fe56b9e6SYuval Mintz 	u64 intr_status = 0;
719fe56b9e6SYuval Mintz 	u32 intr_status_lo = 0;
720fe56b9e6SYuval Mintz 	u32 intr_status_hi = 0;
721fe56b9e6SYuval Mintz 	u32 lsb_igu_cmd_addr = IGU_REG_SISR_MDPC_WMASK_LSB_UPPER -
722fe56b9e6SYuval Mintz 			       IGU_CMD_INT_ACK_BASE;
723fe56b9e6SYuval Mintz 	u32 msb_igu_cmd_addr = IGU_REG_SISR_MDPC_WMASK_MSB_UPPER -
724fe56b9e6SYuval Mintz 			       IGU_CMD_INT_ACK_BASE;
725fe56b9e6SYuval Mintz 
726fe56b9e6SYuval Mintz 	intr_status_lo = REG_RD(p_hwfn,
727fe56b9e6SYuval Mintz 				GTT_BAR0_MAP_REG_IGU_CMD +
728fe56b9e6SYuval Mintz 				lsb_igu_cmd_addr * 8);
729fe56b9e6SYuval Mintz 	intr_status_hi = REG_RD(p_hwfn,
730fe56b9e6SYuval Mintz 				GTT_BAR0_MAP_REG_IGU_CMD +
731fe56b9e6SYuval Mintz 				msb_igu_cmd_addr * 8);
732fe56b9e6SYuval Mintz 	intr_status = ((u64)intr_status_hi << 32) + (u64)intr_status_lo;
733fe56b9e6SYuval Mintz 
734fe56b9e6SYuval Mintz 	return intr_status;
735fe56b9e6SYuval Mintz }
736fe56b9e6SYuval Mintz 
737fe56b9e6SYuval Mintz static void qed_int_sp_dpc_setup(struct qed_hwfn *p_hwfn)
738fe56b9e6SYuval Mintz {
739fe56b9e6SYuval Mintz 	tasklet_init(p_hwfn->sp_dpc,
740fe56b9e6SYuval Mintz 		     qed_int_sp_dpc, (unsigned long)p_hwfn);
741fe56b9e6SYuval Mintz 	p_hwfn->b_sp_dpc_enabled = true;
742fe56b9e6SYuval Mintz }
743fe56b9e6SYuval Mintz 
744fe56b9e6SYuval Mintz static int qed_int_sp_dpc_alloc(struct qed_hwfn *p_hwfn)
745fe56b9e6SYuval Mintz {
746fe56b9e6SYuval Mintz 	p_hwfn->sp_dpc = kmalloc(sizeof(*p_hwfn->sp_dpc), GFP_ATOMIC);
747fe56b9e6SYuval Mintz 	if (!p_hwfn->sp_dpc)
748fe56b9e6SYuval Mintz 		return -ENOMEM;
749fe56b9e6SYuval Mintz 
750fe56b9e6SYuval Mintz 	return 0;
751fe56b9e6SYuval Mintz }
752fe56b9e6SYuval Mintz 
753fe56b9e6SYuval Mintz static void qed_int_sp_dpc_free(struct qed_hwfn *p_hwfn)
754fe56b9e6SYuval Mintz {
755fe56b9e6SYuval Mintz 	kfree(p_hwfn->sp_dpc);
756fe56b9e6SYuval Mintz }
757fe56b9e6SYuval Mintz 
758fe56b9e6SYuval Mintz int qed_int_alloc(struct qed_hwfn *p_hwfn,
759fe56b9e6SYuval Mintz 		  struct qed_ptt *p_ptt)
760fe56b9e6SYuval Mintz {
761fe56b9e6SYuval Mintz 	int rc = 0;
762fe56b9e6SYuval Mintz 
763fe56b9e6SYuval Mintz 	rc = qed_int_sp_dpc_alloc(p_hwfn);
764fe56b9e6SYuval Mintz 	if (rc) {
765fe56b9e6SYuval Mintz 		DP_ERR(p_hwfn->cdev, "Failed to allocate sp dpc mem\n");
766fe56b9e6SYuval Mintz 		return rc;
767fe56b9e6SYuval Mintz 	}
768fe56b9e6SYuval Mintz 	rc = qed_int_sp_sb_alloc(p_hwfn, p_ptt);
769fe56b9e6SYuval Mintz 	if (rc) {
770fe56b9e6SYuval Mintz 		DP_ERR(p_hwfn->cdev, "Failed to allocate sp sb mem\n");
771fe56b9e6SYuval Mintz 		return rc;
772fe56b9e6SYuval Mintz 	}
773fe56b9e6SYuval Mintz 
774fe56b9e6SYuval Mintz 	return rc;
775fe56b9e6SYuval Mintz }
776fe56b9e6SYuval Mintz 
777fe56b9e6SYuval Mintz void qed_int_free(struct qed_hwfn *p_hwfn)
778fe56b9e6SYuval Mintz {
779fe56b9e6SYuval Mintz 	qed_int_sp_sb_free(p_hwfn);
780fe56b9e6SYuval Mintz 	qed_int_sp_dpc_free(p_hwfn);
781fe56b9e6SYuval Mintz }
782fe56b9e6SYuval Mintz 
783fe56b9e6SYuval Mintz void qed_int_setup(struct qed_hwfn *p_hwfn,
784fe56b9e6SYuval Mintz 		   struct qed_ptt *p_ptt)
785fe56b9e6SYuval Mintz {
786fe56b9e6SYuval Mintz 	qed_int_sp_sb_setup(p_hwfn, p_ptt);
787fe56b9e6SYuval Mintz 	qed_int_sp_dpc_setup(p_hwfn);
788fe56b9e6SYuval Mintz }
789fe56b9e6SYuval Mintz 
790fe56b9e6SYuval Mintz int qed_int_get_num_sbs(struct qed_hwfn *p_hwfn,
791fe56b9e6SYuval Mintz 			int *p_iov_blks)
792fe56b9e6SYuval Mintz {
793fe56b9e6SYuval Mintz 	struct qed_igu_info *info = p_hwfn->hw_info.p_igu_info;
794fe56b9e6SYuval Mintz 
795fe56b9e6SYuval Mintz 	if (!info)
796fe56b9e6SYuval Mintz 		return 0;
797fe56b9e6SYuval Mintz 
798fe56b9e6SYuval Mintz 	if (p_iov_blks)
799fe56b9e6SYuval Mintz 		*p_iov_blks = info->free_blks;
800fe56b9e6SYuval Mintz 
801fe56b9e6SYuval Mintz 	return info->igu_sb_cnt;
802fe56b9e6SYuval Mintz }
803