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