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 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 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 110 void BnxeWorkQueueWaitAndDestroy(um_device_t * pUM) 111 { 112 BnxeWorkQueueInstanceWaitAndDestroy(&pUM->workqs.instq); 113 BnxeWorkQueueInstanceWaitAndDestroy(&pUM->workqs.delayq); 114 } 115 116 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 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 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 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 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 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 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 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 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