xref: /freebsd/sys/dev/ixl/ixl_iw.c (revision 7d4dceec103039e2b2fa90793ceeb71a8d6684aa)
1cb6b8299SEric Joyner /******************************************************************************
2cb6b8299SEric Joyner 
3f4cc2d17SEric Joyner   Copyright (c) 2013-2018, Intel Corporation
4cb6b8299SEric Joyner   All rights reserved.
5cb6b8299SEric Joyner 
6cb6b8299SEric Joyner   Redistribution and use in source and binary forms, with or without
7cb6b8299SEric Joyner   modification, are permitted provided that the following conditions are met:
8cb6b8299SEric Joyner 
9cb6b8299SEric Joyner    1. Redistributions of source code must retain the above copyright notice,
10cb6b8299SEric Joyner       this list of conditions and the following disclaimer.
11cb6b8299SEric Joyner 
12cb6b8299SEric Joyner    2. Redistributions in binary form must reproduce the above copyright
13cb6b8299SEric Joyner       notice, this list of conditions and the following disclaimer in the
14cb6b8299SEric Joyner       documentation and/or other materials provided with the distribution.
15cb6b8299SEric Joyner 
16cb6b8299SEric Joyner    3. Neither the name of the Intel Corporation nor the names of its
17cb6b8299SEric Joyner       contributors may be used to endorse or promote products derived from
18cb6b8299SEric Joyner       this software without specific prior written permission.
19cb6b8299SEric Joyner 
20cb6b8299SEric Joyner   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21cb6b8299SEric Joyner   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22cb6b8299SEric Joyner   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23cb6b8299SEric Joyner   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24cb6b8299SEric Joyner   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25cb6b8299SEric Joyner   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26cb6b8299SEric Joyner   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27cb6b8299SEric Joyner   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28cb6b8299SEric Joyner   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29cb6b8299SEric Joyner   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30cb6b8299SEric Joyner   POSSIBILITY OF SUCH DAMAGE.
31cb6b8299SEric Joyner 
32cb6b8299SEric Joyner ******************************************************************************/
33cb6b8299SEric Joyner /*$FreeBSD$*/
34cb6b8299SEric Joyner 
35cb6b8299SEric Joyner #include "ixl.h"
36cb6b8299SEric Joyner #include "ixl_pf.h"
37cb6b8299SEric Joyner #include "ixl_iw.h"
38cb6b8299SEric Joyner #include "ixl_iw_int.h"
39cb6b8299SEric Joyner 
40cb6b8299SEric Joyner #ifdef	IXL_IW
41cb6b8299SEric Joyner 
42cb6b8299SEric Joyner #define IXL_IW_VEC_BASE(pf)	((pf)->msix - (pf)->iw_msix)
43cb6b8299SEric Joyner #define IXL_IW_VEC_COUNT(pf)	((pf)->iw_msix)
44cb6b8299SEric Joyner #define IXL_IW_VEC_LIMIT(pf)	((pf)->msix)
45cb6b8299SEric Joyner 
46cb6b8299SEric Joyner extern int ixl_enable_iwarp;
47cb6b8299SEric Joyner 
48cb6b8299SEric Joyner static struct ixl_iw_state ixl_iw;
49cb6b8299SEric Joyner static int ixl_iw_ref_cnt;
50cb6b8299SEric Joyner 
51cb6b8299SEric Joyner static void
52cb6b8299SEric Joyner ixl_iw_pf_msix_reset(struct ixl_pf *pf)
53cb6b8299SEric Joyner {
54cb6b8299SEric Joyner 	struct i40e_hw *hw = &pf->hw;
55cb6b8299SEric Joyner 	u32 reg;
56cb6b8299SEric Joyner 	int vec;
57cb6b8299SEric Joyner 
58cb6b8299SEric Joyner 	for (vec = IXL_IW_VEC_BASE(pf); vec < IXL_IW_VEC_LIMIT(pf); vec++) {
59cb6b8299SEric Joyner 		reg = I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK;
60cb6b8299SEric Joyner 		wr32(hw, I40E_PFINT_LNKLSTN(vec - 1), reg);
61cb6b8299SEric Joyner 	}
62cb6b8299SEric Joyner 
63cb6b8299SEric Joyner 	return;
64cb6b8299SEric Joyner }
65cb6b8299SEric Joyner 
66cb6b8299SEric Joyner static void
67cb6b8299SEric Joyner ixl_iw_invoke_op(void *context, int pending)
68cb6b8299SEric Joyner {
69cb6b8299SEric Joyner 	struct ixl_iw_pf_entry *pf_entry = (struct ixl_iw_pf_entry *)context;
70cb6b8299SEric Joyner 	struct ixl_iw_pf info;
71cb6b8299SEric Joyner 	bool initialize;
72cb6b8299SEric Joyner 	int err;
73cb6b8299SEric Joyner 
74cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
75cb6b8299SEric Joyner 
76cb6b8299SEric Joyner 	mtx_lock(&ixl_iw.mtx);
77cb6b8299SEric Joyner 	if ((pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_ON) &&
78cb6b8299SEric Joyner 	    (pf_entry->state.iw_current == IXL_IW_PF_STATE_OFF))
79cb6b8299SEric Joyner 		initialize = true;
80cb6b8299SEric Joyner 	else if ((pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_OFF) &&
81cb6b8299SEric Joyner 	         (pf_entry->state.iw_current == IXL_IW_PF_STATE_ON))
82cb6b8299SEric Joyner 		initialize = false;
83cb6b8299SEric Joyner 	else {
84cb6b8299SEric Joyner 		/* nothing to be done, so finish here */
85cb6b8299SEric Joyner 		mtx_unlock(&ixl_iw.mtx);
86cb6b8299SEric Joyner 		return;
87cb6b8299SEric Joyner 	}
88cb6b8299SEric Joyner 	info = pf_entry->pf_info;
89cb6b8299SEric Joyner 	mtx_unlock(&ixl_iw.mtx);
90cb6b8299SEric Joyner 
91cb6b8299SEric Joyner 	if (initialize) {
92cb6b8299SEric Joyner 		err = ixl_iw.ops->init(&info);
93cb6b8299SEric Joyner 		if (err)
94cb6b8299SEric Joyner 			device_printf(pf_entry->pf->dev,
95cb6b8299SEric Joyner 				"%s: failed to initialize iwarp (err %d)\n",
96cb6b8299SEric Joyner 				__func__, err);
97cb6b8299SEric Joyner 		else
98cb6b8299SEric Joyner 			pf_entry->state.iw_current = IXL_IW_PF_STATE_ON;
99cb6b8299SEric Joyner 	} else {
100cb6b8299SEric Joyner 		err = ixl_iw.ops->stop(&info);
101cb6b8299SEric Joyner 		if (err)
102cb6b8299SEric Joyner 			device_printf(pf_entry->pf->dev,
103cb6b8299SEric Joyner 				"%s: failed to stop iwarp (err %d)\n",
104cb6b8299SEric Joyner 				__func__, err);
105cb6b8299SEric Joyner 		else {
106cb6b8299SEric Joyner 			ixl_iw_pf_msix_reset(pf_entry->pf);
107cb6b8299SEric Joyner 			pf_entry->state.iw_current = IXL_IW_PF_STATE_OFF;
108cb6b8299SEric Joyner 		}
109cb6b8299SEric Joyner 	}
110cb6b8299SEric Joyner 	return;
111cb6b8299SEric Joyner }
112cb6b8299SEric Joyner 
113cb6b8299SEric Joyner static void
114cb6b8299SEric Joyner ixl_iw_uninit(void)
115cb6b8299SEric Joyner {
116cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
117cb6b8299SEric Joyner 
118cb6b8299SEric Joyner 	mtx_destroy(&ixl_iw.mtx);
119cb6b8299SEric Joyner 
120cb6b8299SEric Joyner 	return;
121cb6b8299SEric Joyner }
122cb6b8299SEric Joyner 
123cb6b8299SEric Joyner static void
124cb6b8299SEric Joyner ixl_iw_init(void)
125cb6b8299SEric Joyner {
126cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
127cb6b8299SEric Joyner 
128cb6b8299SEric Joyner 	LIST_INIT(&ixl_iw.pfs);
129cb6b8299SEric Joyner 	mtx_init(&ixl_iw.mtx, "ixl_iw_pfs", NULL, MTX_DEF);
130cb6b8299SEric Joyner 	ixl_iw.registered = false;
131cb6b8299SEric Joyner 
132cb6b8299SEric Joyner 	return;
133cb6b8299SEric Joyner }
134cb6b8299SEric Joyner 
135cb6b8299SEric Joyner /******************************************************************************
136cb6b8299SEric Joyner  * if_ixl internal API
137cb6b8299SEric Joyner  *****************************************************************************/
138cb6b8299SEric Joyner 
139cb6b8299SEric Joyner int
140cb6b8299SEric Joyner ixl_iw_pf_init(struct ixl_pf *pf)
141cb6b8299SEric Joyner {
142cb6b8299SEric Joyner 	struct ixl_iw_pf_entry *pf_entry;
143cb6b8299SEric Joyner 	struct ixl_iw_pf *pf_info;
144cb6b8299SEric Joyner 	int err = 0;
145cb6b8299SEric Joyner 
146cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
147cb6b8299SEric Joyner 
148cb6b8299SEric Joyner 	mtx_lock(&ixl_iw.mtx);
149cb6b8299SEric Joyner 
150cb6b8299SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
151cb6b8299SEric Joyner 		if (pf_entry->pf == pf)
152cb6b8299SEric Joyner 			break;
153cb6b8299SEric Joyner 	if (pf_entry == NULL) {
154cb6b8299SEric Joyner 		/* attempt to initialize PF not yet attached - sth is wrong */
155cb6b8299SEric Joyner 		device_printf(pf->dev, "%s: PF not found\n", __func__);
156cb6b8299SEric Joyner 		err = ENOENT;
157cb6b8299SEric Joyner 		goto out;
158cb6b8299SEric Joyner 	}
159cb6b8299SEric Joyner 
160cb6b8299SEric Joyner 	pf_info = &pf_entry->pf_info;
161cb6b8299SEric Joyner 
162cb6b8299SEric Joyner 	pf_info->handle	= (void *)pf;
163cb6b8299SEric Joyner 
164cb6b8299SEric Joyner 	pf_info->ifp		= pf->vsi.ifp;
165cb6b8299SEric Joyner 	pf_info->dev		= pf->dev;
166cb6b8299SEric Joyner 	pf_info->pci_mem	= pf->pci_mem;
167cb6b8299SEric Joyner 	pf_info->pf_id		= pf->hw.pf_id;
168cb6b8299SEric Joyner 	pf_info->mtu		= pf->vsi.ifp->if_mtu;
169cb6b8299SEric Joyner 
170cb6b8299SEric Joyner 	pf_info->iw_msix.count	= IXL_IW_VEC_COUNT(pf);
171cb6b8299SEric Joyner 	pf_info->iw_msix.base	= IXL_IW_VEC_BASE(pf);
172cb6b8299SEric Joyner 
173cb6b8299SEric Joyner 	for (int i = 0; i < IXL_IW_MAX_USER_PRIORITY; i++)
174cb6b8299SEric Joyner 		pf_info->qs_handle[i] = le16_to_cpu(pf->vsi.info.qs_handle[0]);
175cb6b8299SEric Joyner 
176cb6b8299SEric Joyner 	pf_entry->state.pf = IXL_IW_PF_STATE_ON;
177cb6b8299SEric Joyner 	if (ixl_iw.registered) {
178cb6b8299SEric Joyner 		pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_ON;
179cb6b8299SEric Joyner 		taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task);
180cb6b8299SEric Joyner 	}
181cb6b8299SEric Joyner 
182cb6b8299SEric Joyner out:
183cb6b8299SEric Joyner 	mtx_unlock(&ixl_iw.mtx);
184cb6b8299SEric Joyner 
185cb6b8299SEric Joyner 	return (err);
186cb6b8299SEric Joyner }
187cb6b8299SEric Joyner 
188cb6b8299SEric Joyner void
189cb6b8299SEric Joyner ixl_iw_pf_stop(struct ixl_pf *pf)
190cb6b8299SEric Joyner {
191cb6b8299SEric Joyner 	struct ixl_iw_pf_entry *pf_entry;
192cb6b8299SEric Joyner 
193cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
194cb6b8299SEric Joyner 
195cb6b8299SEric Joyner 	mtx_lock(&ixl_iw.mtx);
196cb6b8299SEric Joyner 
197cb6b8299SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
198cb6b8299SEric Joyner 		if (pf_entry->pf == pf)
199cb6b8299SEric Joyner 			break;
200cb6b8299SEric Joyner 	if (pf_entry == NULL) {
201cb6b8299SEric Joyner 		/* attempt to stop PF which has not been attached - sth is wrong */
202cb6b8299SEric Joyner 		device_printf(pf->dev, "%s: PF not found\n", __func__);
203cb6b8299SEric Joyner 		goto out;
204cb6b8299SEric Joyner 	}
205cb6b8299SEric Joyner 
206cb6b8299SEric Joyner 	pf_entry->state.pf = IXL_IW_PF_STATE_OFF;
207cb6b8299SEric Joyner 	if (pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_ON) {
208cb6b8299SEric Joyner 		pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_OFF;
209cb6b8299SEric Joyner 		if (ixl_iw.registered)
210cb6b8299SEric Joyner 			taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task);
211cb6b8299SEric Joyner 	}
212cb6b8299SEric Joyner 
213cb6b8299SEric Joyner out:
214cb6b8299SEric Joyner 	mtx_unlock(&ixl_iw.mtx);
215cb6b8299SEric Joyner 
216cb6b8299SEric Joyner 	return;
217cb6b8299SEric Joyner }
218cb6b8299SEric Joyner 
219cb6b8299SEric Joyner int
220cb6b8299SEric Joyner ixl_iw_pf_attach(struct ixl_pf *pf)
221cb6b8299SEric Joyner {
222cb6b8299SEric Joyner 	struct ixl_iw_pf_entry *pf_entry;
223cb6b8299SEric Joyner 	int err = 0;
224cb6b8299SEric Joyner 
225cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
226cb6b8299SEric Joyner 
227cb6b8299SEric Joyner 	if (ixl_iw_ref_cnt == 0)
228cb6b8299SEric Joyner 		ixl_iw_init();
229cb6b8299SEric Joyner 
230cb6b8299SEric Joyner 	mtx_lock(&ixl_iw.mtx);
231cb6b8299SEric Joyner 
232cb6b8299SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
233cb6b8299SEric Joyner 		if (pf_entry->pf == pf) {
234cb6b8299SEric Joyner 			device_printf(pf->dev, "%s: PF already exists\n",
235cb6b8299SEric Joyner 			    __func__);
236cb6b8299SEric Joyner 			err = EEXIST;
237cb6b8299SEric Joyner 			goto out;
238cb6b8299SEric Joyner 		}
239cb6b8299SEric Joyner 
240cb6b8299SEric Joyner 	pf_entry = malloc(sizeof(struct ixl_iw_pf_entry),
241*7d4dceecSKrzysztof Galazka 			M_IXL, M_NOWAIT | M_ZERO);
242cb6b8299SEric Joyner 	if (pf_entry == NULL) {
243cb6b8299SEric Joyner 		device_printf(pf->dev,
244cb6b8299SEric Joyner 		    "%s: failed to allocate memory to attach new PF\n",
245cb6b8299SEric Joyner 		    __func__);
246cb6b8299SEric Joyner 		err = ENOMEM;
247cb6b8299SEric Joyner 		goto out;
248cb6b8299SEric Joyner 	}
249cb6b8299SEric Joyner 	pf_entry->pf = pf;
250cb6b8299SEric Joyner 	pf_entry->state.pf		= IXL_IW_PF_STATE_OFF;
251cb6b8299SEric Joyner 	pf_entry->state.iw_scheduled	= IXL_IW_PF_STATE_OFF;
252cb6b8299SEric Joyner 	pf_entry->state.iw_current	= IXL_IW_PF_STATE_OFF;
253cb6b8299SEric Joyner 
254cb6b8299SEric Joyner 	LIST_INSERT_HEAD(&ixl_iw.pfs, pf_entry, node);
255cb6b8299SEric Joyner 	ixl_iw_ref_cnt++;
256cb6b8299SEric Joyner 
257cb6b8299SEric Joyner 	TASK_INIT(&pf_entry->iw_task, 0, ixl_iw_invoke_op, pf_entry);
258cb6b8299SEric Joyner out:
259cb6b8299SEric Joyner 	mtx_unlock(&ixl_iw.mtx);
260cb6b8299SEric Joyner 
261cb6b8299SEric Joyner 	return (err);
262cb6b8299SEric Joyner }
263cb6b8299SEric Joyner 
264cb6b8299SEric Joyner int
265cb6b8299SEric Joyner ixl_iw_pf_detach(struct ixl_pf *pf)
266cb6b8299SEric Joyner {
267cb6b8299SEric Joyner 	struct ixl_iw_pf_entry *pf_entry;
268cb6b8299SEric Joyner 	int err = 0;
269cb6b8299SEric Joyner 
270cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
271cb6b8299SEric Joyner 
272cb6b8299SEric Joyner 	mtx_lock(&ixl_iw.mtx);
273cb6b8299SEric Joyner 
274cb6b8299SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
275cb6b8299SEric Joyner 		if (pf_entry->pf == pf)
276cb6b8299SEric Joyner 			break;
277cb6b8299SEric Joyner 	if (pf_entry == NULL) {
278cb6b8299SEric Joyner 		/* attempt to stop PF which has not been attached - sth is wrong */
279cb6b8299SEric Joyner 		device_printf(pf->dev, "%s: PF not found\n", __func__);
280cb6b8299SEric Joyner 		err = ENOENT;
281cb6b8299SEric Joyner 		goto out;
282cb6b8299SEric Joyner 	}
283cb6b8299SEric Joyner 
284cb6b8299SEric Joyner 	if (pf_entry->state.pf != IXL_IW_PF_STATE_OFF) {
285cb6b8299SEric Joyner 		/* attempt to detach PF which has not yet been stopped - sth is wrong */
286cb6b8299SEric Joyner 		device_printf(pf->dev, "%s: failed - PF is still active\n",
287cb6b8299SEric Joyner 		    __func__);
288cb6b8299SEric Joyner 		err = EBUSY;
289cb6b8299SEric Joyner 		goto out;
290cb6b8299SEric Joyner 	}
291cb6b8299SEric Joyner 	LIST_REMOVE(pf_entry, node);
292*7d4dceecSKrzysztof Galazka 	free(pf_entry, M_IXL);
293cb6b8299SEric Joyner 	ixl_iw_ref_cnt--;
294cb6b8299SEric Joyner 
295cb6b8299SEric Joyner out:
296cb6b8299SEric Joyner 	mtx_unlock(&ixl_iw.mtx);
297cb6b8299SEric Joyner 
298cb6b8299SEric Joyner 	if (ixl_iw_ref_cnt == 0)
299cb6b8299SEric Joyner 		ixl_iw_uninit();
300cb6b8299SEric Joyner 
301cb6b8299SEric Joyner 	return (err);
302cb6b8299SEric Joyner }
303cb6b8299SEric Joyner 
304cb6b8299SEric Joyner 
305cb6b8299SEric Joyner /******************************************************************************
306cb6b8299SEric Joyner  * API exposed to iw_ixl module
307cb6b8299SEric Joyner  *****************************************************************************/
308cb6b8299SEric Joyner 
309cb6b8299SEric Joyner int
310cb6b8299SEric Joyner ixl_iw_pf_reset(void *pf_handle)
311cb6b8299SEric Joyner {
312cb6b8299SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)pf_handle;
313cb6b8299SEric Joyner 
314cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
315cb6b8299SEric Joyner 
316cb6b8299SEric Joyner 	IXL_PF_LOCK(pf);
317cb6b8299SEric Joyner 	ixl_init_locked(pf);
318cb6b8299SEric Joyner 	IXL_PF_UNLOCK(pf);
319cb6b8299SEric Joyner 
320cb6b8299SEric Joyner 	return (0);
321cb6b8299SEric Joyner }
322cb6b8299SEric Joyner 
323cb6b8299SEric Joyner int
324cb6b8299SEric Joyner ixl_iw_pf_msix_init(void *pf_handle,
325cb6b8299SEric Joyner 	struct ixl_iw_msix_mapping *msix_info)
326cb6b8299SEric Joyner {
327cb6b8299SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)pf_handle;
328cb6b8299SEric Joyner 	struct i40e_hw *hw = &pf->hw;
329cb6b8299SEric Joyner 	u32 reg;
330cb6b8299SEric Joyner 	int vec, i;
331cb6b8299SEric Joyner 
332cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
333cb6b8299SEric Joyner 
334cb6b8299SEric Joyner 	if ((msix_info->aeq_vector < IXL_IW_VEC_BASE(pf)) ||
335cb6b8299SEric Joyner 	    (msix_info->aeq_vector >= IXL_IW_VEC_LIMIT(pf))) {
336b97de13aSMarius Strobl 		printf("%s: invalid MSI-X vector (%i) for AEQ\n",
337cb6b8299SEric Joyner 		    __func__, msix_info->aeq_vector);
338cb6b8299SEric Joyner 		return (EINVAL);
339cb6b8299SEric Joyner 	}
340cb6b8299SEric Joyner 	reg = I40E_PFINT_AEQCTL_CAUSE_ENA_MASK |
341cb6b8299SEric Joyner 		(msix_info->aeq_vector << I40E_PFINT_AEQCTL_MSIX_INDX_SHIFT) |
342cb6b8299SEric Joyner 		(msix_info->itr_indx << I40E_PFINT_AEQCTL_ITR_INDX_SHIFT);
343cb6b8299SEric Joyner 	wr32(hw, I40E_PFINT_AEQCTL, reg);
344cb6b8299SEric Joyner 
345cb6b8299SEric Joyner 	for (vec = IXL_IW_VEC_BASE(pf); vec < IXL_IW_VEC_LIMIT(pf); vec++) {
346cb6b8299SEric Joyner 		for (i = 0; i < msix_info->ceq_cnt; i++)
347cb6b8299SEric Joyner 			if (msix_info->ceq_vector[i] == vec)
348cb6b8299SEric Joyner 				break;
349cb6b8299SEric Joyner 		if (i == msix_info->ceq_cnt) {
350cb6b8299SEric Joyner 			/* this vector has no CEQ mapped */
351cb6b8299SEric Joyner 			reg = I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK;
352cb6b8299SEric Joyner 			wr32(hw, I40E_PFINT_LNKLSTN(vec - 1), reg);
353cb6b8299SEric Joyner 		} else {
354cb6b8299SEric Joyner 			reg = (i & I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK) |
355cb6b8299SEric Joyner 			    (I40E_QUEUE_TYPE_PE_CEQ <<
356cb6b8299SEric Joyner 			    I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT);
357cb6b8299SEric Joyner 			wr32(hw, I40E_PFINT_LNKLSTN(vec - 1), reg);
358cb6b8299SEric Joyner 
359cb6b8299SEric Joyner 			reg = I40E_PFINT_CEQCTL_CAUSE_ENA_MASK |
360cb6b8299SEric Joyner 			    (vec << I40E_PFINT_CEQCTL_MSIX_INDX_SHIFT) |
361cb6b8299SEric Joyner 			    (msix_info->itr_indx <<
362cb6b8299SEric Joyner 			    I40E_PFINT_CEQCTL_ITR_INDX_SHIFT) |
363cb6b8299SEric Joyner 			    (IXL_QUEUE_EOL <<
364cb6b8299SEric Joyner 			    I40E_PFINT_CEQCTL_NEXTQ_INDX_SHIFT);
365cb6b8299SEric Joyner 			wr32(hw, I40E_PFINT_CEQCTL(i), reg);
366cb6b8299SEric Joyner 		}
367cb6b8299SEric Joyner 	}
368cb6b8299SEric Joyner 
369cb6b8299SEric Joyner 	return (0);
370cb6b8299SEric Joyner }
371cb6b8299SEric Joyner 
372cb6b8299SEric Joyner int
373cb6b8299SEric Joyner ixl_iw_register(struct ixl_iw_ops *ops)
374cb6b8299SEric Joyner {
375cb6b8299SEric Joyner 	struct ixl_iw_pf_entry *pf_entry;
376cb6b8299SEric Joyner 	int err = 0;
377ceebc2f3SEric Joyner 	int iwarp_cap_on_pfs = 0;
378cb6b8299SEric Joyner 
379cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
380ceebc2f3SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
381ceebc2f3SEric Joyner 		iwarp_cap_on_pfs += pf_entry->pf->hw.func_caps.iwarp;
382ceebc2f3SEric Joyner 	if (!iwarp_cap_on_pfs && ixl_enable_iwarp) {
383ceebc2f3SEric Joyner 		printf("%s: the device is not iwarp-capable, registering dropped\n",
384ceebc2f3SEric Joyner 		    __func__);
385ceebc2f3SEric Joyner 		return (ENODEV);
386ceebc2f3SEric Joyner 	}
387cb6b8299SEric Joyner 	if (ixl_enable_iwarp == 0) {
388cb6b8299SEric Joyner 		printf("%s: enable_iwarp is off, registering dropped\n",
389cb6b8299SEric Joyner 		    __func__);
390cb6b8299SEric Joyner 		return (EACCES);
391cb6b8299SEric Joyner 	}
392cb6b8299SEric Joyner 
393cb6b8299SEric Joyner 	if ((ops->init == NULL) || (ops->stop == NULL)) {
394cb6b8299SEric Joyner 		printf("%s: invalid iwarp driver ops\n", __func__);
395cb6b8299SEric Joyner 		return (EINVAL);
396cb6b8299SEric Joyner 	}
397cb6b8299SEric Joyner 
398cb6b8299SEric Joyner 	mtx_lock(&ixl_iw.mtx);
399cb6b8299SEric Joyner 	if (ixl_iw.registered) {
400cb6b8299SEric Joyner 		printf("%s: iwarp driver already registered\n", __func__);
401ceebc2f3SEric Joyner 		err = (EBUSY);
402cb6b8299SEric Joyner 		goto out;
403cb6b8299SEric Joyner 	}
404ceebc2f3SEric Joyner 	ixl_iw.registered = true;
405ceebc2f3SEric Joyner 	mtx_unlock(&ixl_iw.mtx);
406cb6b8299SEric Joyner 
407cb6b8299SEric Joyner 	ixl_iw.tq = taskqueue_create("ixl_iw", M_NOWAIT,
408cb6b8299SEric Joyner 		taskqueue_thread_enqueue, &ixl_iw.tq);
409cb6b8299SEric Joyner 	if (ixl_iw.tq == NULL) {
410cb6b8299SEric Joyner 		printf("%s: failed to create queue\n", __func__);
411ceebc2f3SEric Joyner 		ixl_iw.registered = false;
412ceebc2f3SEric Joyner 		return (ENOMEM);
413cb6b8299SEric Joyner 	}
414cb6b8299SEric Joyner 	taskqueue_start_threads(&ixl_iw.tq, 1, PI_NET, "ixl iw");
415cb6b8299SEric Joyner 
416cb6b8299SEric Joyner 	ixl_iw.ops = malloc(sizeof(struct ixl_iw_ops),
417*7d4dceecSKrzysztof Galazka 			M_IXL, M_NOWAIT | M_ZERO);
418cb6b8299SEric Joyner 	if (ixl_iw.ops == NULL) {
419cb6b8299SEric Joyner 		printf("%s: failed to allocate memory\n", __func__);
420cb6b8299SEric Joyner 		taskqueue_free(ixl_iw.tq);
421ceebc2f3SEric Joyner 		ixl_iw.registered = false;
422ceebc2f3SEric Joyner 		return (ENOMEM);
423cb6b8299SEric Joyner 	}
424cb6b8299SEric Joyner 
425cb6b8299SEric Joyner 	ixl_iw.ops->init = ops->init;
426cb6b8299SEric Joyner 	ixl_iw.ops->stop = ops->stop;
427cb6b8299SEric Joyner 
428ceebc2f3SEric Joyner 	mtx_lock(&ixl_iw.mtx);
429cb6b8299SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
430cb6b8299SEric Joyner 		if (pf_entry->state.pf == IXL_IW_PF_STATE_ON) {
431cb6b8299SEric Joyner 			pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_ON;
432cb6b8299SEric Joyner 			taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task);
433cb6b8299SEric Joyner 		}
434cb6b8299SEric Joyner out:
435cb6b8299SEric Joyner 	mtx_unlock(&ixl_iw.mtx);
436cb6b8299SEric Joyner 
437cb6b8299SEric Joyner 	return (err);
438cb6b8299SEric Joyner }
439cb6b8299SEric Joyner 
440cb6b8299SEric Joyner int
441cb6b8299SEric Joyner ixl_iw_unregister(void)
442cb6b8299SEric Joyner {
443cb6b8299SEric Joyner 	struct ixl_iw_pf_entry *pf_entry;
444ceebc2f3SEric Joyner 	int iwarp_cap_on_pfs = 0;
445cb6b8299SEric Joyner 
446cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
447cb6b8299SEric Joyner 
448ceebc2f3SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
449ceebc2f3SEric Joyner 		iwarp_cap_on_pfs += pf_entry->pf->hw.func_caps.iwarp;
450ceebc2f3SEric Joyner 	if (!iwarp_cap_on_pfs && ixl_enable_iwarp) {
451ceebc2f3SEric Joyner 		printf("%s: attempt to unregister driver when no iwarp-capable device present\n",
452ceebc2f3SEric Joyner 		    __func__);
453ceebc2f3SEric Joyner 		return (ENODEV);
454ceebc2f3SEric Joyner 	}
455ceebc2f3SEric Joyner 
456ceebc2f3SEric Joyner 	if (ixl_enable_iwarp == 0) {
457ceebc2f3SEric Joyner 		printf("%s: attempt to unregister driver when enable_iwarp is off\n",
458ceebc2f3SEric Joyner 		    __func__);
459ceebc2f3SEric Joyner 		return (ENODEV);
460ceebc2f3SEric Joyner 	}
461cb6b8299SEric Joyner 	mtx_lock(&ixl_iw.mtx);
462cb6b8299SEric Joyner 
463cb6b8299SEric Joyner 	if (!ixl_iw.registered) {
464cb6b8299SEric Joyner 		printf("%s: failed - iwarp driver has not been registered\n",
465cb6b8299SEric Joyner 		    __func__);
466cb6b8299SEric Joyner 		mtx_unlock(&ixl_iw.mtx);
467cb6b8299SEric Joyner 		return (ENOENT);
468cb6b8299SEric Joyner 	}
469cb6b8299SEric Joyner 
470cb6b8299SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
471cb6b8299SEric Joyner 		if (pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_ON) {
472cb6b8299SEric Joyner 			pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_OFF;
473cb6b8299SEric Joyner 			taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task);
474cb6b8299SEric Joyner 		}
475cb6b8299SEric Joyner 
476cb6b8299SEric Joyner 	ixl_iw.registered = false;
477cb6b8299SEric Joyner 
478cb6b8299SEric Joyner 	mtx_unlock(&ixl_iw.mtx);
479cb6b8299SEric Joyner 
480cb6b8299SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
481cb6b8299SEric Joyner 		taskqueue_drain(ixl_iw.tq, &pf_entry->iw_task);
482cb6b8299SEric Joyner 	taskqueue_free(ixl_iw.tq);
483cb6b8299SEric Joyner 	ixl_iw.tq = NULL;
484*7d4dceecSKrzysztof Galazka 	free(ixl_iw.ops, M_IXL);
485cb6b8299SEric Joyner 	ixl_iw.ops = NULL;
486cb6b8299SEric Joyner 
487cb6b8299SEric Joyner 	return (0);
488cb6b8299SEric Joyner }
489cb6b8299SEric Joyner 
490cb6b8299SEric Joyner #endif /* IXL_IW */
491