xref: /freebsd/sys/dev/ixl/ixl_iw.c (revision 71625ec9ad2a9bc8c09784fbd23b759830e0ee5f)
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 
34cb6b8299SEric Joyner #include "ixl.h"
35cb6b8299SEric Joyner #include "ixl_pf.h"
36cb6b8299SEric Joyner #include "ixl_iw.h"
37cb6b8299SEric Joyner #include "ixl_iw_int.h"
38cb6b8299SEric Joyner 
39cb6b8299SEric Joyner #ifdef	IXL_IW
40cb6b8299SEric Joyner 
41cb6b8299SEric Joyner #define IXL_IW_VEC_BASE(pf)	((pf)->msix - (pf)->iw_msix)
42cb6b8299SEric Joyner #define IXL_IW_VEC_COUNT(pf)	((pf)->iw_msix)
43cb6b8299SEric Joyner #define IXL_IW_VEC_LIMIT(pf)	((pf)->msix)
44cb6b8299SEric Joyner 
45cb6b8299SEric Joyner extern int ixl_enable_iwarp;
46cb6b8299SEric Joyner 
47cb6b8299SEric Joyner static struct ixl_iw_state ixl_iw;
48cb6b8299SEric Joyner static int ixl_iw_ref_cnt;
49cb6b8299SEric Joyner 
50cb6b8299SEric Joyner static void
ixl_iw_pf_msix_reset(struct ixl_pf * pf)51cb6b8299SEric Joyner ixl_iw_pf_msix_reset(struct ixl_pf *pf)
52cb6b8299SEric Joyner {
53cb6b8299SEric Joyner 	struct i40e_hw *hw = &pf->hw;
54cb6b8299SEric Joyner 	u32 reg;
55cb6b8299SEric Joyner 	int vec;
56cb6b8299SEric Joyner 
57cb6b8299SEric Joyner 	for (vec = IXL_IW_VEC_BASE(pf); vec < IXL_IW_VEC_LIMIT(pf); vec++) {
58cb6b8299SEric Joyner 		reg = I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK;
59cb6b8299SEric Joyner 		wr32(hw, I40E_PFINT_LNKLSTN(vec - 1), reg);
60cb6b8299SEric Joyner 	}
61cb6b8299SEric Joyner 
62cb6b8299SEric Joyner 	return;
63cb6b8299SEric Joyner }
64cb6b8299SEric Joyner 
65cb6b8299SEric Joyner static void
ixl_iw_invoke_op(void * context,int pending)66cb6b8299SEric Joyner ixl_iw_invoke_op(void *context, int pending)
67cb6b8299SEric Joyner {
68cb6b8299SEric Joyner 	struct ixl_iw_pf_entry *pf_entry = (struct ixl_iw_pf_entry *)context;
69cb6b8299SEric Joyner 	struct ixl_iw_pf info;
70cb6b8299SEric Joyner 	bool initialize;
71cb6b8299SEric Joyner 	int err;
72cb6b8299SEric Joyner 
73cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
74cb6b8299SEric Joyner 
75cb6b8299SEric Joyner 	mtx_lock(&ixl_iw.mtx);
76cb6b8299SEric Joyner 	if ((pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_ON) &&
77cb6b8299SEric Joyner 	    (pf_entry->state.iw_current == IXL_IW_PF_STATE_OFF))
78cb6b8299SEric Joyner 		initialize = true;
79cb6b8299SEric Joyner 	else if ((pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_OFF) &&
80cb6b8299SEric Joyner 	         (pf_entry->state.iw_current == IXL_IW_PF_STATE_ON))
81cb6b8299SEric Joyner 		initialize = false;
82cb6b8299SEric Joyner 	else {
83cb6b8299SEric Joyner 		/* nothing to be done, so finish here */
84cb6b8299SEric Joyner 		mtx_unlock(&ixl_iw.mtx);
85cb6b8299SEric Joyner 		return;
86cb6b8299SEric Joyner 	}
87cb6b8299SEric Joyner 	info = pf_entry->pf_info;
88cb6b8299SEric Joyner 	mtx_unlock(&ixl_iw.mtx);
89cb6b8299SEric Joyner 
90cb6b8299SEric Joyner 	if (initialize) {
91cb6b8299SEric Joyner 		err = ixl_iw.ops->init(&info);
92cb6b8299SEric Joyner 		if (err)
93cb6b8299SEric Joyner 			device_printf(pf_entry->pf->dev,
94cb6b8299SEric Joyner 				"%s: failed to initialize iwarp (err %d)\n",
95cb6b8299SEric Joyner 				__func__, err);
96cb6b8299SEric Joyner 		else
97cb6b8299SEric Joyner 			pf_entry->state.iw_current = IXL_IW_PF_STATE_ON;
98cb6b8299SEric Joyner 	} else {
99cb6b8299SEric Joyner 		err = ixl_iw.ops->stop(&info);
100cb6b8299SEric Joyner 		if (err)
101cb6b8299SEric Joyner 			device_printf(pf_entry->pf->dev,
102cb6b8299SEric Joyner 				"%s: failed to stop iwarp (err %d)\n",
103cb6b8299SEric Joyner 				__func__, err);
104cb6b8299SEric Joyner 		else {
105cb6b8299SEric Joyner 			ixl_iw_pf_msix_reset(pf_entry->pf);
106cb6b8299SEric Joyner 			pf_entry->state.iw_current = IXL_IW_PF_STATE_OFF;
107cb6b8299SEric Joyner 		}
108cb6b8299SEric Joyner 	}
109cb6b8299SEric Joyner 	return;
110cb6b8299SEric Joyner }
111cb6b8299SEric Joyner 
112cb6b8299SEric Joyner static void
ixl_iw_uninit(void)113cb6b8299SEric Joyner ixl_iw_uninit(void)
114cb6b8299SEric Joyner {
115cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
116cb6b8299SEric Joyner 
117cb6b8299SEric Joyner 	mtx_destroy(&ixl_iw.mtx);
118cb6b8299SEric Joyner 
119cb6b8299SEric Joyner 	return;
120cb6b8299SEric Joyner }
121cb6b8299SEric Joyner 
122cb6b8299SEric Joyner static void
ixl_iw_init(void)123cb6b8299SEric Joyner ixl_iw_init(void)
124cb6b8299SEric Joyner {
125cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
126cb6b8299SEric Joyner 
127cb6b8299SEric Joyner 	LIST_INIT(&ixl_iw.pfs);
128cb6b8299SEric Joyner 	mtx_init(&ixl_iw.mtx, "ixl_iw_pfs", NULL, MTX_DEF);
129cb6b8299SEric Joyner 	ixl_iw.registered = false;
130cb6b8299SEric Joyner 
131cb6b8299SEric Joyner 	return;
132cb6b8299SEric Joyner }
133cb6b8299SEric Joyner 
134cb6b8299SEric Joyner /******************************************************************************
135cb6b8299SEric Joyner  * if_ixl internal API
136cb6b8299SEric Joyner  *****************************************************************************/
137cb6b8299SEric Joyner 
138cb6b8299SEric Joyner int
ixl_iw_pf_init(struct ixl_pf * pf)139cb6b8299SEric Joyner ixl_iw_pf_init(struct ixl_pf *pf)
140cb6b8299SEric Joyner {
141cb6b8299SEric Joyner 	struct ixl_iw_pf_entry *pf_entry;
142cb6b8299SEric Joyner 	struct ixl_iw_pf *pf_info;
143cb6b8299SEric Joyner 	int err = 0;
144cb6b8299SEric Joyner 
145cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
146cb6b8299SEric Joyner 
147cb6b8299SEric Joyner 	mtx_lock(&ixl_iw.mtx);
148cb6b8299SEric Joyner 
149cb6b8299SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
150cb6b8299SEric Joyner 		if (pf_entry->pf == pf)
151cb6b8299SEric Joyner 			break;
152cb6b8299SEric Joyner 	if (pf_entry == NULL) {
153cb6b8299SEric Joyner 		/* attempt to initialize PF not yet attached - sth is wrong */
154cb6b8299SEric Joyner 		device_printf(pf->dev, "%s: PF not found\n", __func__);
155cb6b8299SEric Joyner 		err = ENOENT;
156cb6b8299SEric Joyner 		goto out;
157cb6b8299SEric Joyner 	}
158cb6b8299SEric Joyner 
159cb6b8299SEric Joyner 	pf_info = &pf_entry->pf_info;
160cb6b8299SEric Joyner 
161cb6b8299SEric Joyner 	pf_info->handle	= (void *)pf;
162cb6b8299SEric Joyner 
163cb6b8299SEric Joyner 	pf_info->ifp		= pf->vsi.ifp;
164cb6b8299SEric Joyner 	pf_info->dev		= pf->dev;
165cb6b8299SEric Joyner 	pf_info->pci_mem	= pf->pci_mem;
166cb6b8299SEric Joyner 	pf_info->pf_id		= pf->hw.pf_id;
167*79422a71SJustin Hibbits 	pf_info->mtu		= if_getmtu(pf->vsi.ifp);
168cb6b8299SEric Joyner 
169cb6b8299SEric Joyner 	pf_info->iw_msix.count	= IXL_IW_VEC_COUNT(pf);
170cb6b8299SEric Joyner 	pf_info->iw_msix.base	= IXL_IW_VEC_BASE(pf);
171cb6b8299SEric Joyner 
172cb6b8299SEric Joyner 	for (int i = 0; i < IXL_IW_MAX_USER_PRIORITY; i++)
173cb6b8299SEric Joyner 		pf_info->qs_handle[i] = le16_to_cpu(pf->vsi.info.qs_handle[0]);
174cb6b8299SEric Joyner 
175cb6b8299SEric Joyner 	pf_entry->state.pf = IXL_IW_PF_STATE_ON;
176cb6b8299SEric Joyner 	if (ixl_iw.registered) {
177cb6b8299SEric Joyner 		pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_ON;
178cb6b8299SEric Joyner 		taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task);
179cb6b8299SEric Joyner 	}
180cb6b8299SEric Joyner 
181cb6b8299SEric Joyner out:
182cb6b8299SEric Joyner 	mtx_unlock(&ixl_iw.mtx);
183cb6b8299SEric Joyner 
184cb6b8299SEric Joyner 	return (err);
185cb6b8299SEric Joyner }
186cb6b8299SEric Joyner 
187cb6b8299SEric Joyner void
ixl_iw_pf_stop(struct ixl_pf * pf)188cb6b8299SEric Joyner ixl_iw_pf_stop(struct ixl_pf *pf)
189cb6b8299SEric Joyner {
190cb6b8299SEric Joyner 	struct ixl_iw_pf_entry *pf_entry;
191cb6b8299SEric Joyner 
192cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
193cb6b8299SEric Joyner 
194cb6b8299SEric Joyner 	mtx_lock(&ixl_iw.mtx);
195cb6b8299SEric Joyner 
196cb6b8299SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
197cb6b8299SEric Joyner 		if (pf_entry->pf == pf)
198cb6b8299SEric Joyner 			break;
199cb6b8299SEric Joyner 	if (pf_entry == NULL) {
200cb6b8299SEric Joyner 		/* attempt to stop PF which has not been attached - sth is wrong */
201cb6b8299SEric Joyner 		device_printf(pf->dev, "%s: PF not found\n", __func__);
202cb6b8299SEric Joyner 		goto out;
203cb6b8299SEric Joyner 	}
204cb6b8299SEric Joyner 
205cb6b8299SEric Joyner 	pf_entry->state.pf = IXL_IW_PF_STATE_OFF;
206cb6b8299SEric Joyner 	if (pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_ON) {
207cb6b8299SEric Joyner 		pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_OFF;
208cb6b8299SEric Joyner 		if (ixl_iw.registered)
209cb6b8299SEric Joyner 			taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task);
210cb6b8299SEric Joyner 	}
211cb6b8299SEric Joyner 
212cb6b8299SEric Joyner out:
213cb6b8299SEric Joyner 	mtx_unlock(&ixl_iw.mtx);
214cb6b8299SEric Joyner 
215cb6b8299SEric Joyner 	return;
216cb6b8299SEric Joyner }
217cb6b8299SEric Joyner 
218cb6b8299SEric Joyner int
ixl_iw_pf_attach(struct ixl_pf * pf)219cb6b8299SEric Joyner ixl_iw_pf_attach(struct ixl_pf *pf)
220cb6b8299SEric Joyner {
221cb6b8299SEric Joyner 	struct ixl_iw_pf_entry *pf_entry;
222cb6b8299SEric Joyner 	int err = 0;
223cb6b8299SEric Joyner 
224cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
225cb6b8299SEric Joyner 
226cb6b8299SEric Joyner 	if (ixl_iw_ref_cnt == 0)
227cb6b8299SEric Joyner 		ixl_iw_init();
228cb6b8299SEric Joyner 
229cb6b8299SEric Joyner 	mtx_lock(&ixl_iw.mtx);
230cb6b8299SEric Joyner 
231cb6b8299SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
232cb6b8299SEric Joyner 		if (pf_entry->pf == pf) {
233cb6b8299SEric Joyner 			device_printf(pf->dev, "%s: PF already exists\n",
234cb6b8299SEric Joyner 			    __func__);
235cb6b8299SEric Joyner 			err = EEXIST;
236cb6b8299SEric Joyner 			goto out;
237cb6b8299SEric Joyner 		}
238cb6b8299SEric Joyner 
239cb6b8299SEric Joyner 	pf_entry = malloc(sizeof(struct ixl_iw_pf_entry),
2407d4dceecSKrzysztof Galazka 			M_IXL, M_NOWAIT | M_ZERO);
241cb6b8299SEric Joyner 	if (pf_entry == NULL) {
242cb6b8299SEric Joyner 		device_printf(pf->dev,
243cb6b8299SEric Joyner 		    "%s: failed to allocate memory to attach new PF\n",
244cb6b8299SEric Joyner 		    __func__);
245cb6b8299SEric Joyner 		err = ENOMEM;
246cb6b8299SEric Joyner 		goto out;
247cb6b8299SEric Joyner 	}
248cb6b8299SEric Joyner 	pf_entry->pf = pf;
249cb6b8299SEric Joyner 	pf_entry->state.pf		= IXL_IW_PF_STATE_OFF;
250cb6b8299SEric Joyner 	pf_entry->state.iw_scheduled	= IXL_IW_PF_STATE_OFF;
251cb6b8299SEric Joyner 	pf_entry->state.iw_current	= IXL_IW_PF_STATE_OFF;
252cb6b8299SEric Joyner 
253cb6b8299SEric Joyner 	LIST_INSERT_HEAD(&ixl_iw.pfs, pf_entry, node);
254cb6b8299SEric Joyner 	ixl_iw_ref_cnt++;
255cb6b8299SEric Joyner 
256cb6b8299SEric Joyner 	TASK_INIT(&pf_entry->iw_task, 0, ixl_iw_invoke_op, pf_entry);
257cb6b8299SEric Joyner out:
258cb6b8299SEric Joyner 	mtx_unlock(&ixl_iw.mtx);
259cb6b8299SEric Joyner 
260cb6b8299SEric Joyner 	return (err);
261cb6b8299SEric Joyner }
262cb6b8299SEric Joyner 
263cb6b8299SEric Joyner int
ixl_iw_pf_detach(struct ixl_pf * pf)264cb6b8299SEric Joyner ixl_iw_pf_detach(struct ixl_pf *pf)
265cb6b8299SEric Joyner {
266cb6b8299SEric Joyner 	struct ixl_iw_pf_entry *pf_entry;
267cb6b8299SEric Joyner 	int err = 0;
268cb6b8299SEric Joyner 
269cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
270cb6b8299SEric Joyner 
271cb6b8299SEric Joyner 	mtx_lock(&ixl_iw.mtx);
272cb6b8299SEric Joyner 
273cb6b8299SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
274cb6b8299SEric Joyner 		if (pf_entry->pf == pf)
275cb6b8299SEric Joyner 			break;
276cb6b8299SEric Joyner 	if (pf_entry == NULL) {
277cb6b8299SEric Joyner 		/* attempt to stop PF which has not been attached - sth is wrong */
278cb6b8299SEric Joyner 		device_printf(pf->dev, "%s: PF not found\n", __func__);
279cb6b8299SEric Joyner 		err = ENOENT;
280cb6b8299SEric Joyner 		goto out;
281cb6b8299SEric Joyner 	}
282cb6b8299SEric Joyner 
283cb6b8299SEric Joyner 	if (pf_entry->state.pf != IXL_IW_PF_STATE_OFF) {
284cb6b8299SEric Joyner 		/* attempt to detach PF which has not yet been stopped - sth is wrong */
285cb6b8299SEric Joyner 		device_printf(pf->dev, "%s: failed - PF is still active\n",
286cb6b8299SEric Joyner 		    __func__);
287cb6b8299SEric Joyner 		err = EBUSY;
288cb6b8299SEric Joyner 		goto out;
289cb6b8299SEric Joyner 	}
290cb6b8299SEric Joyner 	LIST_REMOVE(pf_entry, node);
2917d4dceecSKrzysztof Galazka 	free(pf_entry, M_IXL);
292cb6b8299SEric Joyner 	ixl_iw_ref_cnt--;
293cb6b8299SEric Joyner 
294cb6b8299SEric Joyner out:
295cb6b8299SEric Joyner 	mtx_unlock(&ixl_iw.mtx);
296cb6b8299SEric Joyner 
297cb6b8299SEric Joyner 	if (ixl_iw_ref_cnt == 0)
298cb6b8299SEric Joyner 		ixl_iw_uninit();
299cb6b8299SEric Joyner 
300cb6b8299SEric Joyner 	return (err);
301cb6b8299SEric Joyner }
302cb6b8299SEric Joyner 
303cb6b8299SEric Joyner 
304cb6b8299SEric Joyner /******************************************************************************
305cb6b8299SEric Joyner  * API exposed to iw_ixl module
306cb6b8299SEric Joyner  *****************************************************************************/
307cb6b8299SEric Joyner 
308cb6b8299SEric Joyner int
ixl_iw_pf_reset(void * pf_handle)309cb6b8299SEric Joyner ixl_iw_pf_reset(void *pf_handle)
310cb6b8299SEric Joyner {
311cb6b8299SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)pf_handle;
312cb6b8299SEric Joyner 
313cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
314cb6b8299SEric Joyner 
315cb6b8299SEric Joyner 	IXL_PF_LOCK(pf);
316cb6b8299SEric Joyner 	ixl_init_locked(pf);
317cb6b8299SEric Joyner 	IXL_PF_UNLOCK(pf);
318cb6b8299SEric Joyner 
319cb6b8299SEric Joyner 	return (0);
320cb6b8299SEric Joyner }
321cb6b8299SEric Joyner 
322cb6b8299SEric Joyner int
ixl_iw_pf_msix_init(void * pf_handle,struct ixl_iw_msix_mapping * msix_info)323cb6b8299SEric Joyner ixl_iw_pf_msix_init(void *pf_handle,
324cb6b8299SEric Joyner 	struct ixl_iw_msix_mapping *msix_info)
325cb6b8299SEric Joyner {
326cb6b8299SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)pf_handle;
327cb6b8299SEric Joyner 	struct i40e_hw *hw = &pf->hw;
328cb6b8299SEric Joyner 	u32 reg;
329cb6b8299SEric Joyner 	int vec, i;
330cb6b8299SEric Joyner 
331cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
332cb6b8299SEric Joyner 
333cb6b8299SEric Joyner 	if ((msix_info->aeq_vector < IXL_IW_VEC_BASE(pf)) ||
334cb6b8299SEric Joyner 	    (msix_info->aeq_vector >= IXL_IW_VEC_LIMIT(pf))) {
335b97de13aSMarius Strobl 		printf("%s: invalid MSI-X vector (%i) for AEQ\n",
336cb6b8299SEric Joyner 		    __func__, msix_info->aeq_vector);
337cb6b8299SEric Joyner 		return (EINVAL);
338cb6b8299SEric Joyner 	}
339cb6b8299SEric Joyner 	reg = I40E_PFINT_AEQCTL_CAUSE_ENA_MASK |
340cb6b8299SEric Joyner 		(msix_info->aeq_vector << I40E_PFINT_AEQCTL_MSIX_INDX_SHIFT) |
341cb6b8299SEric Joyner 		(msix_info->itr_indx << I40E_PFINT_AEQCTL_ITR_INDX_SHIFT);
342cb6b8299SEric Joyner 	wr32(hw, I40E_PFINT_AEQCTL, reg);
343cb6b8299SEric Joyner 
344cb6b8299SEric Joyner 	for (vec = IXL_IW_VEC_BASE(pf); vec < IXL_IW_VEC_LIMIT(pf); vec++) {
345cb6b8299SEric Joyner 		for (i = 0; i < msix_info->ceq_cnt; i++)
346cb6b8299SEric Joyner 			if (msix_info->ceq_vector[i] == vec)
347cb6b8299SEric Joyner 				break;
348cb6b8299SEric Joyner 		if (i == msix_info->ceq_cnt) {
349cb6b8299SEric Joyner 			/* this vector has no CEQ mapped */
350cb6b8299SEric Joyner 			reg = I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK;
351cb6b8299SEric Joyner 			wr32(hw, I40E_PFINT_LNKLSTN(vec - 1), reg);
352cb6b8299SEric Joyner 		} else {
353cb6b8299SEric Joyner 			reg = (i & I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK) |
354cb6b8299SEric Joyner 			    (I40E_QUEUE_TYPE_PE_CEQ <<
355cb6b8299SEric Joyner 			    I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT);
356cb6b8299SEric Joyner 			wr32(hw, I40E_PFINT_LNKLSTN(vec - 1), reg);
357cb6b8299SEric Joyner 
358cb6b8299SEric Joyner 			reg = I40E_PFINT_CEQCTL_CAUSE_ENA_MASK |
359cb6b8299SEric Joyner 			    (vec << I40E_PFINT_CEQCTL_MSIX_INDX_SHIFT) |
360cb6b8299SEric Joyner 			    (msix_info->itr_indx <<
361cb6b8299SEric Joyner 			    I40E_PFINT_CEQCTL_ITR_INDX_SHIFT) |
362cb6b8299SEric Joyner 			    (IXL_QUEUE_EOL <<
363cb6b8299SEric Joyner 			    I40E_PFINT_CEQCTL_NEXTQ_INDX_SHIFT);
364cb6b8299SEric Joyner 			wr32(hw, I40E_PFINT_CEQCTL(i), reg);
365cb6b8299SEric Joyner 		}
366cb6b8299SEric Joyner 	}
367cb6b8299SEric Joyner 
368cb6b8299SEric Joyner 	return (0);
369cb6b8299SEric Joyner }
370cb6b8299SEric Joyner 
371cb6b8299SEric Joyner int
ixl_iw_register(struct ixl_iw_ops * ops)372cb6b8299SEric Joyner ixl_iw_register(struct ixl_iw_ops *ops)
373cb6b8299SEric Joyner {
374cb6b8299SEric Joyner 	struct ixl_iw_pf_entry *pf_entry;
375cb6b8299SEric Joyner 	int err = 0;
376ceebc2f3SEric Joyner 	int iwarp_cap_on_pfs = 0;
377cb6b8299SEric Joyner 
378cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
379ceebc2f3SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
380ceebc2f3SEric Joyner 		iwarp_cap_on_pfs += pf_entry->pf->hw.func_caps.iwarp;
381ceebc2f3SEric Joyner 	if (!iwarp_cap_on_pfs && ixl_enable_iwarp) {
382ceebc2f3SEric Joyner 		printf("%s: the device is not iwarp-capable, registering dropped\n",
383ceebc2f3SEric Joyner 		    __func__);
384ceebc2f3SEric Joyner 		return (ENODEV);
385ceebc2f3SEric Joyner 	}
386cb6b8299SEric Joyner 	if (ixl_enable_iwarp == 0) {
387cb6b8299SEric Joyner 		printf("%s: enable_iwarp is off, registering dropped\n",
388cb6b8299SEric Joyner 		    __func__);
389cb6b8299SEric Joyner 		return (EACCES);
390cb6b8299SEric Joyner 	}
391cb6b8299SEric Joyner 
392cb6b8299SEric Joyner 	if ((ops->init == NULL) || (ops->stop == NULL)) {
393cb6b8299SEric Joyner 		printf("%s: invalid iwarp driver ops\n", __func__);
394cb6b8299SEric Joyner 		return (EINVAL);
395cb6b8299SEric Joyner 	}
396cb6b8299SEric Joyner 
397cb6b8299SEric Joyner 	mtx_lock(&ixl_iw.mtx);
398cb6b8299SEric Joyner 	if (ixl_iw.registered) {
399cb6b8299SEric Joyner 		printf("%s: iwarp driver already registered\n", __func__);
400ceebc2f3SEric Joyner 		err = (EBUSY);
401cb6b8299SEric Joyner 		goto out;
402cb6b8299SEric Joyner 	}
403ceebc2f3SEric Joyner 	ixl_iw.registered = true;
404ceebc2f3SEric Joyner 	mtx_unlock(&ixl_iw.mtx);
405cb6b8299SEric Joyner 
406cb6b8299SEric Joyner 	ixl_iw.tq = taskqueue_create("ixl_iw", M_NOWAIT,
407cb6b8299SEric Joyner 		taskqueue_thread_enqueue, &ixl_iw.tq);
408cb6b8299SEric Joyner 	if (ixl_iw.tq == NULL) {
409cb6b8299SEric Joyner 		printf("%s: failed to create queue\n", __func__);
410ceebc2f3SEric Joyner 		ixl_iw.registered = false;
411ceebc2f3SEric Joyner 		return (ENOMEM);
412cb6b8299SEric Joyner 	}
413cb6b8299SEric Joyner 	taskqueue_start_threads(&ixl_iw.tq, 1, PI_NET, "ixl iw");
414cb6b8299SEric Joyner 
415cb6b8299SEric Joyner 	ixl_iw.ops = malloc(sizeof(struct ixl_iw_ops),
4167d4dceecSKrzysztof Galazka 			M_IXL, M_NOWAIT | M_ZERO);
417cb6b8299SEric Joyner 	if (ixl_iw.ops == NULL) {
418cb6b8299SEric Joyner 		printf("%s: failed to allocate memory\n", __func__);
419cb6b8299SEric Joyner 		taskqueue_free(ixl_iw.tq);
420ceebc2f3SEric Joyner 		ixl_iw.registered = false;
421ceebc2f3SEric Joyner 		return (ENOMEM);
422cb6b8299SEric Joyner 	}
423cb6b8299SEric Joyner 
424cb6b8299SEric Joyner 	ixl_iw.ops->init = ops->init;
425cb6b8299SEric Joyner 	ixl_iw.ops->stop = ops->stop;
426cb6b8299SEric Joyner 
427ceebc2f3SEric Joyner 	mtx_lock(&ixl_iw.mtx);
428cb6b8299SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
429cb6b8299SEric Joyner 		if (pf_entry->state.pf == IXL_IW_PF_STATE_ON) {
430cb6b8299SEric Joyner 			pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_ON;
431cb6b8299SEric Joyner 			taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task);
432cb6b8299SEric Joyner 		}
433cb6b8299SEric Joyner out:
434cb6b8299SEric Joyner 	mtx_unlock(&ixl_iw.mtx);
435cb6b8299SEric Joyner 
436cb6b8299SEric Joyner 	return (err);
437cb6b8299SEric Joyner }
438cb6b8299SEric Joyner 
439cb6b8299SEric Joyner int
ixl_iw_unregister(void)440cb6b8299SEric Joyner ixl_iw_unregister(void)
441cb6b8299SEric Joyner {
442cb6b8299SEric Joyner 	struct ixl_iw_pf_entry *pf_entry;
443ceebc2f3SEric Joyner 	int iwarp_cap_on_pfs = 0;
444cb6b8299SEric Joyner 
445cb6b8299SEric Joyner 	INIT_DEBUGOUT("begin");
446cb6b8299SEric Joyner 
447ceebc2f3SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
448ceebc2f3SEric Joyner 		iwarp_cap_on_pfs += pf_entry->pf->hw.func_caps.iwarp;
449ceebc2f3SEric Joyner 	if (!iwarp_cap_on_pfs && ixl_enable_iwarp) {
450ceebc2f3SEric Joyner 		printf("%s: attempt to unregister driver when no iwarp-capable device present\n",
451ceebc2f3SEric Joyner 		    __func__);
452ceebc2f3SEric Joyner 		return (ENODEV);
453ceebc2f3SEric Joyner 	}
454ceebc2f3SEric Joyner 
455ceebc2f3SEric Joyner 	if (ixl_enable_iwarp == 0) {
456ceebc2f3SEric Joyner 		printf("%s: attempt to unregister driver when enable_iwarp is off\n",
457ceebc2f3SEric Joyner 		    __func__);
458ceebc2f3SEric Joyner 		return (ENODEV);
459ceebc2f3SEric Joyner 	}
460cb6b8299SEric Joyner 	mtx_lock(&ixl_iw.mtx);
461cb6b8299SEric Joyner 
462cb6b8299SEric Joyner 	if (!ixl_iw.registered) {
463cb6b8299SEric Joyner 		printf("%s: failed - iwarp driver has not been registered\n",
464cb6b8299SEric Joyner 		    __func__);
465cb6b8299SEric Joyner 		mtx_unlock(&ixl_iw.mtx);
466cb6b8299SEric Joyner 		return (ENOENT);
467cb6b8299SEric Joyner 	}
468cb6b8299SEric Joyner 
469cb6b8299SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
470cb6b8299SEric Joyner 		if (pf_entry->state.iw_scheduled == IXL_IW_PF_STATE_ON) {
471cb6b8299SEric Joyner 			pf_entry->state.iw_scheduled = IXL_IW_PF_STATE_OFF;
472cb6b8299SEric Joyner 			taskqueue_enqueue(ixl_iw.tq, &pf_entry->iw_task);
473cb6b8299SEric Joyner 		}
474cb6b8299SEric Joyner 
475cb6b8299SEric Joyner 	ixl_iw.registered = false;
476cb6b8299SEric Joyner 
477cb6b8299SEric Joyner 	mtx_unlock(&ixl_iw.mtx);
478cb6b8299SEric Joyner 
479cb6b8299SEric Joyner 	LIST_FOREACH(pf_entry, &ixl_iw.pfs, node)
480cb6b8299SEric Joyner 		taskqueue_drain(ixl_iw.tq, &pf_entry->iw_task);
481cb6b8299SEric Joyner 	taskqueue_free(ixl_iw.tq);
482cb6b8299SEric Joyner 	ixl_iw.tq = NULL;
4837d4dceecSKrzysztof Galazka 	free(ixl_iw.ops, M_IXL);
484cb6b8299SEric Joyner 	ixl_iw.ops = NULL;
485cb6b8299SEric Joyner 
486cb6b8299SEric Joyner 	return (0);
487cb6b8299SEric Joyner }
488cb6b8299SEric Joyner 
489cb6b8299SEric Joyner #endif /* IXL_IW */
490