1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2014 QLogic Corporation
24 * The contents of this file are subject to the terms of the
25 * QLogic End User License (the "License").
26 * You may not use this file except in compliance with the License.
27 *
28 * You can obtain a copy of the License at
29 * http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/
30 * QLogic_End_User_Software_License.txt
31 * See the License for the specific language governing permissions
32 * and limitations under the License.
33 */
34
35 #include "bnxe.h"
36
37
38 typedef struct _BnxeWorkItem
39 {
40 s_list_entry_t link;
41 void * pWorkData;
42 u32_t workDataLen;
43 u32_t delayMs;
44 void (*pWorkCbkCopy)(um_device_t *, void *, u32_t);
45 void (*pWorkCbkNoCopy)(um_device_t *, void *);
46 void (*pWorkCbkGeneric)(um_device_t *);
47 } BnxeWorkItem;
48
49
BnxeWorkQueueInstanceWaitAndDestroy(BnxeWorkQueueInstance * pWorkq)50 static void BnxeWorkQueueInstanceWaitAndDestroy(BnxeWorkQueueInstance * pWorkq)
51 {
52 if (pWorkq->pTaskq)
53 {
54 ddi_taskq_wait(pWorkq->pTaskq);
55 ddi_taskq_destroy(pWorkq->pTaskq);
56 mutex_destroy(&pWorkq->workQueueMutex);
57 }
58
59 memset(pWorkq, 0, sizeof(BnxeWorkQueueInstance));
60 }
61
62
BnxeWorkQueueInit(um_device_t * pUM)63 boolean_t BnxeWorkQueueInit(um_device_t * pUM)
64 {
65 pUM->workqs.instq.pUM = pUM;
66
67 strcpy(pUM->workqs.instq.taskqName, pUM->devName);
68 strcat(pUM->workqs.instq.taskqName, "_inst_q");
69
70 mutex_init(&pUM->workqs.instq.workQueueMutex, NULL,
71 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority));
72
73 if ((pUM->workqs.instq.pTaskq =
74 ddi_taskq_create(pUM->pDev,
75 pUM->workqs.instq.taskqName,
76 1,
77 TASKQ_DEFAULTPRI,
78 0)) == NULL)
79 {
80 BnxeLogWarn(pUM, "Failed to create the workqs instq");
81 return B_FALSE;
82 }
83
84 pUM->workqs.instq.pUM = pUM;
85
86 strcpy(pUM->workqs.delayq.taskqName, pUM->devName);
87 strcat(pUM->workqs.delayq.taskqName, "_delay_q");
88
89 mutex_init(&pUM->workqs.delayq.workQueueMutex, NULL,
90 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority));
91
92 if ((pUM->workqs.delayq.pTaskq =
93 ddi_taskq_create(pUM->pDev,
94 pUM->workqs.delayq.taskqName,
95 16, /* XXX Is this enough? */
96 TASKQ_DEFAULTPRI,
97 0)) == NULL)
98 {
99 BnxeLogWarn(pUM, "Failed to create the workqs delayq");
100 BnxeWorkQueueInstanceWaitAndDestroy(&pUM->workqs.instq);
101 return B_FALSE;
102 }
103
104 pUM->workqs.delayq.pUM = pUM;
105
106 return B_TRUE;
107 }
108
109
BnxeWorkQueueWaitAndDestroy(um_device_t * pUM)110 void BnxeWorkQueueWaitAndDestroy(um_device_t * pUM)
111 {
112 BnxeWorkQueueInstanceWaitAndDestroy(&pUM->workqs.instq);
113 BnxeWorkQueueInstanceWaitAndDestroy(&pUM->workqs.delayq);
114 }
115
116
BnxeWorkQueueDispatch(void * pArg)117 static void BnxeWorkQueueDispatch(void * pArg)
118 {
119 BnxeWorkQueueInstance * pWorkq = (BnxeWorkQueueInstance *)pArg;
120 um_device_t * pUM = (um_device_t *)pWorkq->pUM;
121 BnxeWorkItem * pWorkItem;
122
123 mutex_enter(&pWorkq->workQueueMutex);
124 pWorkItem = (BnxeWorkItem *)s_list_pop_head(&pWorkq->workQueue);
125 mutex_exit(&pWorkq->workQueueMutex);
126
127 if (pWorkItem == NULL)
128 {
129 BnxeLogWarn(pUM, "Work item is NULL!");
130 pWorkq->workItemError++;
131 return;
132 }
133
134 if ((pWorkItem->pWorkCbkCopy == NULL) &&
135 (pWorkItem->pWorkCbkNoCopy == NULL) &&
136 (pWorkItem->pWorkCbkGeneric == NULL))
137 {
138 BnxeLogWarn(pUM, "Work item callback is NULL!");
139 pWorkq->workItemError++;
140 goto BnxeWorkQueueDispatch_done;
141 }
142
143 if (pWorkItem->delayMs > 0)
144 {
145 /* this only occurs when processing the delayq */
146 drv_usecwait(pWorkItem->delayMs * 1000);
147 }
148
149 if (pWorkItem->pWorkCbkCopy)
150 {
151 pWorkItem->pWorkCbkCopy(pUM,
152 pWorkItem->pWorkData,
153 pWorkItem->workDataLen);
154 }
155 else if (pWorkItem->pWorkCbkNoCopy)
156 {
157 pWorkItem->pWorkCbkNoCopy(pUM,
158 pWorkItem->pWorkData);
159 }
160 else /* (pWorkItem->pWorkCbkGeneric) */
161 {
162 pWorkItem->pWorkCbkGeneric(pUM);
163 }
164
165 pWorkq->workItemComplete++;
166
167 BnxeWorkQueueDispatch_done:
168
169 kmem_free(pWorkItem, (sizeof(BnxeWorkItem) + pWorkItem->workDataLen));
170 }
171
172
BnxeWorkQueueTrigger(um_device_t * pUM,BnxeWorkQueueInstance * pWorkq)173 static void BnxeWorkQueueTrigger(um_device_t * pUM,
174 BnxeWorkQueueInstance * pWorkq)
175 {
176 if (pUM->chipStarted)
177 {
178 ddi_taskq_dispatch(pWorkq->pTaskq,
179 BnxeWorkQueueDispatch,
180 (void *)pWorkq,
181 DDI_NOSLEEP);
182 }
183 else
184 {
185 BnxeLogInfo(pUM, "Delaying WorkQ item since chip not yet started.");
186 }
187 }
188
189
BnxeWorkQueueStartPending(um_device_t * pUM)190 void BnxeWorkQueueStartPending(um_device_t * pUM)
191 {
192 u32_t cnt;
193
194 if (!pUM->chipStarted)
195 {
196 BnxeLogWarn(pUM, "Triggering WorkQs and chip not started!");
197 return;
198 }
199
200 mutex_enter(&pUM->workqs.instq.workQueueMutex);
201 cnt = s_list_entry_cnt(&pUM->workqs.instq.workQueue);
202 mutex_exit(&pUM->workqs.instq.workQueueMutex);
203
204 if (cnt)
205 {
206 BnxeWorkQueueTrigger(pUM, &pUM->workqs.instq);
207 }
208
209 mutex_enter(&pUM->workqs.delayq.workQueueMutex);
210 cnt = s_list_entry_cnt(&pUM->workqs.delayq.workQueue);
211 mutex_exit(&pUM->workqs.delayq.workQueueMutex);
212
213 if (cnt)
214 {
215 BnxeWorkQueueTrigger(pUM, &pUM->workqs.delayq);
216 }
217 }
218
219
BnxeWorkQueueAdd(um_device_t * pUM,void (* pWorkCbkCopy)(um_device_t *,void *,u32_t),void * pWorkData,u32_t workDataLen)220 boolean_t BnxeWorkQueueAdd(um_device_t * pUM,
221 void (*pWorkCbkCopy)(um_device_t *, void *, u32_t),
222 void * pWorkData,
223 u32_t workDataLen)
224 {
225 BnxeWorkItem * pWorkItem;
226
227 if ((pWorkItem = kmem_zalloc((sizeof(BnxeWorkItem) + workDataLen),
228 KM_NOSLEEP)) == NULL)
229 {
230 BnxeLogWarn(pUM, "Failed to allocate memory for work item!");
231 return B_FALSE;
232 }
233
234 pWorkItem->pWorkData = (pWorkItem + 1);
235 pWorkItem->workDataLen = workDataLen;
236 pWorkItem->pWorkCbkCopy = pWorkCbkCopy;
237 pWorkItem->pWorkCbkNoCopy = NULL;
238 pWorkItem->pWorkCbkGeneric = NULL;
239 pWorkItem->delayMs = 0;
240
241 memcpy(pWorkItem->pWorkData, pWorkData, workDataLen);
242
243 mutex_enter(&pUM->workqs.instq.workQueueMutex);
244
245 s_list_push_tail(&pUM->workqs.instq.workQueue, &pWorkItem->link);
246 pUM->workqs.instq.workItemQueued++;
247 if (s_list_entry_cnt(&pUM->workqs.instq.workQueue) >
248 pUM->workqs.instq.highWater)
249 {
250 pUM->workqs.instq.highWater =
251 s_list_entry_cnt(&pUM->workqs.instq.workQueue);
252 }
253
254 mutex_exit(&pUM->workqs.instq.workQueueMutex);
255
256 BnxeWorkQueueTrigger(pUM, &pUM->workqs.instq);
257
258 return B_TRUE;
259 }
260
261
BnxeWorkQueueAddNoCopy(um_device_t * pUM,void (* pWorkCbkNoCopy)(um_device_t *,void *),void * pWorkData)262 boolean_t BnxeWorkQueueAddNoCopy(um_device_t * pUM,
263 void (*pWorkCbkNoCopy)(um_device_t *, void *),
264 void * pWorkData)
265 {
266 BnxeWorkItem * pWorkItem;
267
268 if ((pWorkItem = kmem_zalloc(sizeof(BnxeWorkItem), KM_NOSLEEP)) == NULL)
269 {
270 BnxeLogWarn(pUM, "Failed to allocate memory for work item!");
271 return B_FALSE;
272 }
273
274 pWorkItem->pWorkData = pWorkData;
275 pWorkItem->workDataLen = 0;
276 pWorkItem->pWorkCbkCopy = NULL;
277 pWorkItem->pWorkCbkNoCopy = pWorkCbkNoCopy;
278 pWorkItem->pWorkCbkGeneric = NULL;
279 pWorkItem->delayMs = 0;
280
281 mutex_enter(&pUM->workqs.instq.workQueueMutex);
282
283 s_list_push_tail(&pUM->workqs.instq.workQueue, &pWorkItem->link);
284 pUM->workqs.instq.workItemQueued++;
285 if (s_list_entry_cnt(&pUM->workqs.instq.workQueue) >
286 pUM->workqs.instq.highWater)
287 {
288 pUM->workqs.instq.highWater =
289 s_list_entry_cnt(&pUM->workqs.instq.workQueue);
290 }
291
292 mutex_exit(&pUM->workqs.instq.workQueueMutex);
293
294 BnxeWorkQueueTrigger(pUM, &pUM->workqs.instq);
295
296 return B_TRUE;
297 }
298
299
BnxeWorkQueueAddGeneric(um_device_t * pUM,void (* pWorkCbkGeneric)(um_device_t *))300 boolean_t BnxeWorkQueueAddGeneric(um_device_t * pUM,
301 void (*pWorkCbkGeneric)(um_device_t *))
302 {
303 BnxeWorkItem * pWorkItem;
304
305 if ((pWorkItem = kmem_zalloc(sizeof(BnxeWorkItem), KM_NOSLEEP)) == NULL)
306 {
307 BnxeLogWarn(pUM, "Failed to allocate memory for work item!");
308 return B_FALSE;
309 }
310
311 pWorkItem->pWorkData = NULL;
312 pWorkItem->workDataLen = 0;
313 pWorkItem->pWorkCbkCopy = NULL;
314 pWorkItem->pWorkCbkNoCopy = NULL;
315 pWorkItem->pWorkCbkGeneric = pWorkCbkGeneric;
316 pWorkItem->delayMs = 0;
317
318 mutex_enter(&pUM->workqs.instq.workQueueMutex);
319
320 s_list_push_tail(&pUM->workqs.instq.workQueue, &pWorkItem->link);
321 pUM->workqs.instq.workItemQueued++;
322 if (s_list_entry_cnt(&pUM->workqs.instq.workQueue) >
323 pUM->workqs.instq.highWater)
324 {
325 pUM->workqs.instq.highWater =
326 s_list_entry_cnt(&pUM->workqs.instq.workQueue);
327 }
328
329 mutex_exit(&pUM->workqs.instq.workQueueMutex);
330
331 BnxeWorkQueueTrigger(pUM, &pUM->workqs.instq);
332
333 return B_TRUE;
334 }
335
336
BnxeWorkQueueAddDelay(um_device_t * pUM,void (* pWorkCbkCopy)(um_device_t *,void *,u32_t),void * pWorkData,u32_t workDataLen,u32_t delayMs)337 boolean_t BnxeWorkQueueAddDelay(um_device_t * pUM,
338 void (*pWorkCbkCopy)(um_device_t *, void *, u32_t),
339 void * pWorkData,
340 u32_t workDataLen,
341 u32_t delayMs)
342 {
343 BnxeWorkItem * pWorkItem;
344
345 if ((pWorkItem = kmem_zalloc((sizeof(BnxeWorkItem) + workDataLen),
346 KM_NOSLEEP)) == NULL)
347 {
348 BnxeLogWarn(pUM, "Failed to allocate memory for work item!");
349 return B_FALSE;
350 }
351
352 pWorkItem->pWorkData = (pWorkItem + 1);
353 pWorkItem->workDataLen = workDataLen;
354 pWorkItem->pWorkCbkCopy = pWorkCbkCopy;
355 pWorkItem->pWorkCbkNoCopy = NULL;
356 pWorkItem->pWorkCbkGeneric = NULL;
357 pWorkItem->delayMs = delayMs;
358
359 memcpy(pWorkItem->pWorkData, pWorkData, workDataLen);
360
361 mutex_enter(&pUM->workqs.delayq.workQueueMutex);
362
363 s_list_push_tail(&pUM->workqs.delayq.workQueue, &pWorkItem->link);
364 pUM->workqs.delayq.workItemQueued++;
365 if (s_list_entry_cnt(&pUM->workqs.delayq.workQueue) >
366 pUM->workqs.delayq.highWater)
367 {
368 pUM->workqs.delayq.highWater =
369 s_list_entry_cnt(&pUM->workqs.delayq.workQueue);
370 }
371
372 mutex_exit(&pUM->workqs.delayq.workQueueMutex);
373
374 BnxeWorkQueueTrigger(pUM, &pUM->workqs.delayq);
375
376 return B_TRUE;
377 }
378
379
BnxeWorkQueueAddDelayNoCopy(um_device_t * pUM,void (* pWorkCbkNoCopy)(um_device_t *,void *),void * pWorkData,u32_t delayMs)380 boolean_t BnxeWorkQueueAddDelayNoCopy(um_device_t * pUM,
381 void (*pWorkCbkNoCopy)(um_device_t *, void *),
382 void * pWorkData,
383 u32_t delayMs)
384 {
385 BnxeWorkItem * pWorkItem;
386
387 if ((pWorkItem = kmem_zalloc(sizeof(BnxeWorkItem), KM_NOSLEEP)) == NULL)
388 {
389 BnxeLogWarn(pUM, "Failed to allocate memory for work item!");
390 return B_FALSE;
391 }
392
393 pWorkItem->pWorkData = pWorkData;
394 pWorkItem->workDataLen = 0;
395 pWorkItem->pWorkCbkCopy = NULL;
396 pWorkItem->pWorkCbkNoCopy = pWorkCbkNoCopy;
397 pWorkItem->pWorkCbkGeneric = NULL;
398 pWorkItem->delayMs = delayMs;
399
400 mutex_enter(&pUM->workqs.delayq.workQueueMutex);
401
402 s_list_push_tail(&pUM->workqs.delayq.workQueue, &pWorkItem->link);
403 pUM->workqs.delayq.workItemQueued++;
404 if (s_list_entry_cnt(&pUM->workqs.delayq.workQueue) >
405 pUM->workqs.delayq.highWater)
406 {
407 pUM->workqs.delayq.highWater =
408 s_list_entry_cnt(&pUM->workqs.delayq.workQueue);
409 }
410
411 mutex_exit(&pUM->workqs.delayq.workQueueMutex);
412
413 BnxeWorkQueueTrigger(pUM, &pUM->workqs.delayq);
414
415 return B_TRUE;
416 }
417
418
BnxeWorkQueueAddDelayGeneric(um_device_t * pUM,void (* pWorkCbkGeneric)(um_device_t *),u32_t delayMs)419 boolean_t BnxeWorkQueueAddDelayGeneric(um_device_t * pUM,
420 void (*pWorkCbkGeneric)(um_device_t *),
421 u32_t delayMs)
422 {
423 BnxeWorkItem * pWorkItem;
424
425 if ((pWorkItem = kmem_zalloc(sizeof(BnxeWorkItem), KM_NOSLEEP)) == NULL)
426 {
427 BnxeLogWarn(pUM, "Failed to allocate memory for work item!");
428 return B_FALSE;
429 }
430
431 pWorkItem->pWorkData = NULL;
432 pWorkItem->workDataLen = 0;
433 pWorkItem->pWorkCbkCopy = NULL;
434 pWorkItem->pWorkCbkNoCopy = NULL;
435 pWorkItem->pWorkCbkGeneric = pWorkCbkGeneric;
436 pWorkItem->delayMs = delayMs;
437
438 mutex_enter(&pUM->workqs.delayq.workQueueMutex);
439
440 s_list_push_tail(&pUM->workqs.delayq.workQueue, &pWorkItem->link);
441 pUM->workqs.delayq.workItemQueued++;
442 if (s_list_entry_cnt(&pUM->workqs.delayq.workQueue) >
443 pUM->workqs.delayq.highWater)
444 {
445 pUM->workqs.delayq.highWater =
446 s_list_entry_cnt(&pUM->workqs.delayq.workQueue);
447 }
448
449 mutex_exit(&pUM->workqs.delayq.workQueueMutex);
450
451 BnxeWorkQueueTrigger(pUM, &pUM->workqs.delayq);
452
453 return B_TRUE;
454 }
455
456