Robert Mustacchi | d14abf1 | 2014-06-06 22:58:53 +0000 | [diff] [blame] | 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 | /* |
| 36 | * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. |
| 37 | */ |
| 38 | |
| 39 | #include "bnxe.h" |
| 40 | |
| 41 | |
| 42 | ddi_dma_attr_t bnxeRxDmaAttrib = |
| 43 | { |
| 44 | DMA_ATTR_V0, /* dma_attr_version */ |
| 45 | 0, /* dma_attr_addr_lo */ |
| 46 | 0xffffffffffffffff, /* dma_attr_addr_hi */ |
| 47 | 0xffffffffffffffff, /* dma_attr_count_max */ |
| 48 | BNXE_DMA_ALIGNMENT, /* dma_attr_align */ |
| 49 | 0xffffffff, /* dma_attr_burstsizes */ |
| 50 | 1, /* dma_attr_minxfer */ |
| 51 | 0xffffffffffffffff, /* dma_attr_maxxfer */ |
| 52 | 0xffffffffffffffff, /* dma_attr_seg */ |
| 53 | 1, /* dma_attr_sgllen */ |
| 54 | 1, /* dma_attr_granular */ |
| 55 | 0, /* dma_attr_flags */ |
| 56 | }; |
| 57 | |
| 58 | |
| 59 | static void BnxeRxPostBuffers(um_device_t * pUM, |
| 60 | int idx, |
| 61 | s_list_t * pReclaimList) |
| 62 | { |
| 63 | lm_rx_chain_t * pLmRxChain = &LM_RXQ(&pUM->lm_dev, idx); |
| 64 | u32_t returnedBytes = 0; |
| 65 | lm_packet_t * pLmPkt; |
| 66 | |
| 67 | /* return bytes from reclaimed list to LM */ |
| 68 | pLmPkt = (lm_packet_t *)s_list_peek_head(pReclaimList); |
| 69 | while (pLmPkt) |
| 70 | { |
| 71 | returnedBytes += pLmPkt->size; |
| 72 | pLmPkt = (lm_packet_t *)s_list_next_entry(&pLmPkt->link); |
| 73 | } |
| 74 | |
| 75 | BNXE_LOCK_ENTER_RX(pUM, idx); |
| 76 | |
| 77 | if (pUM->rxq[idx].rxLowWater > s_list_entry_cnt(&pLmRxChain->active_descq)) |
| 78 | { |
| 79 | pUM->rxq[idx].rxLowWater = s_list_entry_cnt(&pLmRxChain->active_descq); |
| 80 | } |
| 81 | |
| 82 | lm_return_packet_bytes(&pUM->lm_dev, idx, returnedBytes); |
| 83 | |
| 84 | s_list_add_tail(&pLmRxChain->common.free_descq, pReclaimList); |
| 85 | s_list_clear(pReclaimList); |
| 86 | |
| 87 | #if 0 |
| 88 | /* |
| 89 | * Don't post buffers if we don't have too many free buffers and there are a |
| 90 | * lot of buffers already posted. |
| 91 | */ |
| 92 | if (lm_bd_chain_avail_bds(&pLmRxChain->bd_chain) < 32) |
| 93 | { |
| 94 | BNXE_LOCK_EXIT_RX(pUM, idx); |
| 95 | return; |
| 96 | } |
| 97 | |
| 98 | /* |
| 99 | * Don't post buffers if there aren't really that many to post yet. |
| 100 | */ |
| 101 | if (s_list_entry_cnt(&pLmRxChain->common.free_descq) < 32) |
| 102 | { |
| 103 | BNXE_LOCK_EXIT_RX(pUM, idx); |
| 104 | return; |
| 105 | } |
| 106 | #endif |
| 107 | |
| 108 | lm_post_buffers(&pUM->lm_dev, idx, NULL, 0); |
| 109 | |
| 110 | BNXE_LOCK_EXIT_RX(pUM, idx); |
| 111 | } |
| 112 | |
| 113 | |
| 114 | static u32_t BnxeRxPktDescrSize(um_device_t * pUM) |
| 115 | { |
| 116 | u32_t descSize; |
| 117 | |
| 118 | (void)pUM; |
| 119 | |
| 120 | descSize = sizeof(um_rxpacket_t) + SIZEOF_SIG; |
| 121 | |
| 122 | return ALIGN_VALUE_TO_WORD_BOUNDARY(descSize); |
| 123 | } |
| 124 | |
| 125 | |
| 126 | static void BnxeRxPktDescrFree(um_device_t * pUM, |
| 127 | um_rxpacket_t * pRxPkt) |
| 128 | { |
| 129 | u32_t descSize; |
| 130 | caddr_t pMem; |
| 131 | |
| 132 | BnxeDbgBreakIfFastPath(pUM, SIG(pRxPkt) != L2PACKET_RX_SIG); |
| 133 | |
| 134 | descSize = BnxeRxPktDescrSize(pUM); |
| 135 | pMem = (caddr_t)pRxPkt - SIZEOF_SIG; |
| 136 | |
| 137 | kmem_free(pMem, descSize); |
| 138 | } |
| 139 | |
| 140 | |
| 141 | static void BnxeRxPktFree(char * free_arg) |
| 142 | { |
| 143 | um_rxpacket_t * pRxPkt = (um_rxpacket_t *)free_arg; |
| 144 | um_device_t * pUM = (um_device_t *)pRxPkt->pUM; |
| 145 | int idx = pRxPkt->idx; |
| 146 | s_list_t doneRxQ; |
| 147 | |
| 148 | if (pUM->magic != BNXE_MAGIC) |
| 149 | { |
| 150 | /* |
| 151 | * Oh my! The free_arg data got corrupted. Log a message and leak this |
| 152 | * packet. We don't decrement the 'up in the stack count' since we |
| 153 | * can't be sure this packet really was a packet we previously sent up. |
| 154 | */ |
| 155 | BnxeLogWarn(NULL, "ERROR freeing packet - UM is invalid! (%p)", pRxPkt); |
| 156 | return; |
| 157 | } |
| 158 | |
| 159 | if (pUM->rxBufSignature[LM_CHAIN_IDX_CLI(&pUM->lm_dev, idx)] != |
| 160 | pRxPkt->signature) |
| 161 | { |
| 162 | /* |
| 163 | * The stack is freeing a packet that was from a previous plumb of |
| 164 | * the interface. |
| 165 | */ |
| 166 | pRxPkt->lm_pkt.u1.rx.mem_phys[0].as_u64 = 0; |
| 167 | pRxPkt->rx_info.mem_virt = NULL; |
| 168 | pRxPkt->rx_info.mem_size = 0; |
| 169 | |
| 170 | ddi_dma_unbind_handle(pRxPkt->dmaHandle); |
| 171 | ddi_dma_mem_free(&pRxPkt->dmaAccHandle); |
| 172 | ddi_dma_free_handle(&pRxPkt->dmaHandle); |
| 173 | |
| 174 | BnxeRxPktDescrFree(pUM, pRxPkt); |
| 175 | } |
| 176 | else |
| 177 | { |
| 178 | s_list_clear(&doneRxQ); |
| 179 | |
| 180 | BNXE_LOCK_ENTER_DONERX(pUM, idx); |
| 181 | |
| 182 | s_list_push_tail(&pUM->rxq[idx].doneRxQ, |
| 183 | &((lm_packet_t *)pRxPkt)->link); |
| 184 | |
| 185 | /* post packets when a bunch are ready */ |
| 186 | if (s_list_entry_cnt(&pUM->rxq[idx].doneRxQ) >= pUM->devParams.maxRxFree) |
| 187 | { |
| 188 | doneRxQ = pUM->rxq[idx].doneRxQ; |
| 189 | s_list_clear(&pUM->rxq[idx].doneRxQ); |
| 190 | } |
| 191 | |
| 192 | BNXE_LOCK_EXIT_DONERX(pUM, idx); |
| 193 | |
| 194 | if (s_list_entry_cnt(&doneRxQ)) |
| 195 | { |
| 196 | BnxeRxPostBuffers(pUM, idx, &doneRxQ); |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | atomic_dec_32(&pUM->rxq[idx].rxBufUpInStack); |
| 201 | } |
| 202 | |
| 203 | |
| 204 | boolean_t BnxeWaitForPacketsFromClient(um_device_t * pUM, |
| 205 | int cliIdx) |
| 206 | { |
| 207 | int i, idx, cnt=0, tot=0; |
| 208 | |
| 209 | switch (cliIdx) |
| 210 | { |
| 211 | case LM_CLI_IDX_FCOE: |
| 212 | |
| 213 | for (i = 0; i < 5; i++) |
| 214 | { |
| 215 | if ((cnt = pUM->rxq[FCOE_CID(&pUM->lm_dev)].rxBufUpInStack) == 0) |
| 216 | { |
| 217 | break; |
| 218 | } |
| 219 | |
| 220 | /* twiddle our thumbs for one second */ |
| 221 | delay(drv_usectohz(1000000)); |
| 222 | } |
| 223 | |
| 224 | if (cnt) |
| 225 | { |
| 226 | BnxeLogWarn(pUM, "%d packets still held by FCoE (chain %d)!", |
| 227 | cnt, FCOE_CID(&pUM->lm_dev)); |
| 228 | return B_FALSE; |
| 229 | } |
| 230 | |
| 231 | break; |
| 232 | |
| 233 | case LM_CLI_IDX_NDIS: |
| 234 | |
| 235 | tot = 0; |
| 236 | |
| 237 | LM_FOREACH_RSS_IDX(&pUM->lm_dev, idx) |
| 238 | { |
| 239 | for (i = 0; i < 5; i++) |
| 240 | { |
| 241 | if ((cnt = pUM->rxq[idx].rxBufUpInStack) == 0) |
| 242 | { |
| 243 | break; |
| 244 | } |
| 245 | |
| 246 | /* twiddle our thumbs for one second */ |
| 247 | delay(drv_usectohz(1000000)); |
| 248 | } |
| 249 | |
| 250 | tot += cnt; |
| 251 | } |
| 252 | |
| 253 | if (tot) |
| 254 | { |
| 255 | BnxeLogWarn(pUM, "%d packets still held by the stack (chain %d)!", |
| 256 | tot, idx); |
| 257 | return B_FALSE; |
| 258 | } |
| 259 | |
| 260 | break; |
| 261 | |
| 262 | default: |
| 263 | |
| 264 | BnxeLogWarn(pUM, "ERROR: Invalid cliIdx for BnxeWaitForPacketsFromClient (%d)", cliIdx); |
| 265 | break; |
| 266 | } |
| 267 | |
| 268 | return B_TRUE; |
| 269 | } |
| 270 | |
| 271 | |
| 272 | /* numBytes is only valid when polling is TRUE */ |
| 273 | mblk_t * BnxeRxRingProcess(um_device_t * pUM, |
| 274 | int idx, |
| 275 | boolean_t polling, |
| 276 | int numBytes) |
| 277 | { |
| 278 | RxQueue * pRxQ; |
| 279 | lm_rx_chain_t * pLmRxChain; |
| 280 | u32_t activeDescqCount; |
| 281 | boolean_t forceCopy; |
| 282 | um_rxpacket_t * pRxPkt; |
| 283 | lm_packet_t * pLmPkt; |
| 284 | u32_t pktLen; |
| 285 | boolean_t dataCopied; |
| 286 | u32_t notCopiedCount; |
| 287 | mblk_t * pMblk; |
| 288 | int ofldFlags; |
| 289 | mblk_t * head = NULL; |
| 290 | mblk_t * tail = NULL; |
| 291 | s_list_t rxList; |
| 292 | s_list_t reclaimList; |
| 293 | int procBytes = 0; |
| 294 | s_list_t tmpList; |
| 295 | sp_cqes_info sp_cqes; |
| 296 | u32_t pktsRxed; |
| 297 | |
| 298 | pRxQ = &pUM->rxq[idx]; |
| 299 | |
| 300 | s_list_clear(&tmpList); |
| 301 | |
| 302 | /* get the list of packets received */ |
| 303 | BNXE_LOCK_ENTER_RX(pUM, idx); |
| 304 | |
| 305 | pktsRxed = lm_get_packets_rcvd(&pUM->lm_dev, idx, &tmpList, &sp_cqes); |
| 306 | |
| 307 | /* grab any waiting packets */ |
| 308 | rxList = pRxQ->waitRxQ; |
| 309 | s_list_clear(&pRxQ->waitRxQ); |
| 310 | |
| 311 | /* put any new packets at the end of the queue */ |
| 312 | s_list_add_tail(&rxList, &tmpList); |
| 313 | |
| 314 | BNXE_LOCK_EXIT_RX(pUM, idx); |
| 315 | |
| 316 | /* now complete the ramrods */ |
| 317 | lm_complete_ramrods(&pUM->lm_dev, &sp_cqes); |
| 318 | |
| 319 | if (s_list_entry_cnt(&rxList) == 0) |
| 320 | { |
| 321 | return NULL; |
| 322 | } |
| 323 | |
| 324 | s_list_clear(&reclaimList); |
| 325 | notCopiedCount = 0; |
| 326 | |
| 327 | pLmRxChain = &LM_RXQ(&pUM->lm_dev, idx); |
| 328 | |
| 329 | activeDescqCount = s_list_entry_cnt(&pLmRxChain->active_descq); |
| 330 | |
| 331 | forceCopy = (activeDescqCount < |
| 332 | (pUM->lm_dev.params.l2_rx_desc_cnt[LM_CHAIN_IDX_CLI(&pUM->lm_dev, idx)] >> 3)); |
| 333 | |
| 334 | /* send the packets up the stack */ |
| 335 | while (1) |
| 336 | { |
| 337 | pRxPkt = (um_rxpacket_t *)s_list_pop_head(&rxList); |
| 338 | if (pRxPkt == NULL) |
| 339 | { |
| 340 | break; |
| 341 | } |
| 342 | |
| 343 | pLmPkt = &(pRxPkt->lm_pkt); |
| 344 | |
| 345 | if (pLmPkt->status != LM_STATUS_SUCCESS) |
| 346 | { |
| 347 | /* XXX increment error stat? */ |
| 348 | s_list_push_tail(&reclaimList, &pLmPkt->link); |
| 349 | continue; |
| 350 | } |
| 351 | |
| 352 | pktLen = pLmPkt->size; |
| 353 | |
| 354 | if (polling == TRUE) |
| 355 | { |
| 356 | /* When polling an rx ring we can only process up to numBytes */ |
| 357 | if ((procBytes + pktLen) <= numBytes) |
| 358 | { |
| 359 | /* continue to process this packet */ |
| 360 | procBytes += pktLen; |
| 361 | } |
| 362 | else |
| 363 | { |
| 364 | /* put this packet not processed back on the list (front) */ |
| 365 | s_list_push_head(&rxList, &pRxPkt->lm_pkt.link); |
| 366 | break; |
| 367 | } |
| 368 | } |
| 369 | |
| 370 | (void)ddi_dma_sync(pRxPkt->dmaHandle, |
| 371 | 0, |
| 372 | pktLen, |
| 373 | DDI_DMA_SYNC_FORKERNEL); |
| 374 | |
| 375 | if (pUM->fmCapabilities && |
| 376 | BnxeCheckDmaHandle(pRxPkt->dmaHandle) != DDI_FM_OK) |
| 377 | { |
| 378 | ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_DEGRADED); |
| 379 | } |
| 380 | |
| 381 | dataCopied = B_FALSE; |
| 382 | |
| 383 | if (forceCopy || |
| 384 | (pUM->devParams.rxCopyThreshold && |
| 385 | (pktLen < pUM->devParams.rxCopyThreshold))) |
| 386 | { |
| 387 | if ((pMblk = allocb(pktLen, BPRI_MED)) == NULL) |
| 388 | { |
| 389 | pRxQ->rxDiscards++; |
| 390 | s_list_push_tail(&reclaimList, &pLmPkt->link); |
| 391 | continue; |
| 392 | } |
| 393 | |
| 394 | /* copy the packet into the new mblk */ |
| 395 | bcopy((pRxPkt->rx_info.mem_virt + BNXE_DMA_RX_OFFSET), |
| 396 | pMblk->b_rptr, pktLen); |
| 397 | pMblk->b_wptr = (pMblk->b_rptr + pktLen); |
| 398 | dataCopied = B_TRUE; |
| 399 | |
| 400 | pRxQ->rxCopied++; |
| 401 | |
| 402 | goto BnxeRxRingProcess_sendup; |
| 403 | } |
| 404 | |
| 405 | if ((activeDescqCount == 0) && (s_list_entry_cnt(&rxList) == 0)) |
| 406 | { |
| 407 | /* |
| 408 | * If the hardware is out of receive buffers and we are on the last |
| 409 | * receive packet then drop the packet. We do this because we might |
| 410 | * not be able to allocate any new receive buffers before the ISR |
| 411 | * completes. If this happens, the driver will enter an infinite |
| 412 | * interrupt loop where the hardware is requesting rx buffers the |
| 413 | * driver cannot allocate. To prevent a system livelock we leave |
| 414 | * one buffer perpetually available. Note that we do this after |
| 415 | * giving the double copy code a chance to claim the packet. |
| 416 | */ |
| 417 | |
| 418 | /* FIXME |
| 419 | * Make sure to add one more to the rx packet descriptor count |
| 420 | * before allocating them. |
| 421 | */ |
| 422 | |
| 423 | pRxQ->rxDiscards++; |
| 424 | s_list_push_tail(&reclaimList, &pLmPkt->link); |
| 425 | continue; |
| 426 | } |
| 427 | |
| 428 | /* |
| 429 | * If we got here then the packet wasn't copied so we need to create a |
| 430 | * new mblk_t which references the lm_packet_t buffer. |
| 431 | */ |
| 432 | |
| 433 | pRxPkt->freeRtn.free_func = BnxeRxPktFree; |
| 434 | pRxPkt->freeRtn.free_arg = (char *)pRxPkt; |
| 435 | pRxPkt->pUM = (void *)pUM; |
| 436 | pRxPkt->idx = idx; |
| 437 | |
| 438 | if ((pMblk = desballoc((pRxPkt->rx_info.mem_virt + BNXE_DMA_RX_OFFSET), |
| 439 | pktLen, |
| 440 | BPRI_MED, |
| 441 | &pRxPkt->freeRtn)) == NULL) |
| 442 | { |
| 443 | pRxQ->rxDiscards++; |
| 444 | s_list_push_tail(&reclaimList, &pLmPkt->link); |
| 445 | continue; |
| 446 | } |
| 447 | |
| 448 | pMblk->b_wptr = (pMblk->b_rptr + pktLen); |
| 449 | |
| 450 | BnxeRxRingProcess_sendup: |
| 451 | |
| 452 | /* |
| 453 | * Check if the checksum was offloaded so we can pass the result to |
| 454 | * the stack. |
| 455 | */ |
| 456 | ofldFlags = 0; |
| 457 | |
| 458 | if ((pUM->devParams.enabled_oflds & LM_OFFLOAD_RX_IP_CKSUM) && |
| 459 | (pRxPkt->rx_info.flags & LM_RX_FLAG_IP_CKSUM_IS_GOOD)) |
| 460 | { |
| 461 | ofldFlags |= HCK_IPV4_HDRCKSUM_OK; |
| 462 | } |
| 463 | |
| 464 | if (((pUM->devParams.enabled_oflds & LM_OFFLOAD_RX_TCP_CKSUM) && |
| 465 | (pRxPkt->rx_info.flags & LM_RX_FLAG_TCP_CKSUM_IS_GOOD)) || |
| 466 | ((pUM->devParams.enabled_oflds & LM_OFFLOAD_RX_UDP_CKSUM) && |
| 467 | (pRxPkt->rx_info.flags & LM_RX_FLAG_UDP_CKSUM_IS_GOOD))) |
| 468 | { |
| 469 | ofldFlags |= HCK_FULLCKSUM_OK; |
| 470 | } |
| 471 | |
| 472 | if (ofldFlags != 0) |
| 473 | { |
| 474 | mac_hcksum_set(pMblk, 0, 0, 0, 0, ofldFlags); |
| 475 | } |
| 476 | |
| 477 | /* |
| 478 | * If the packet data was copied into a new recieve buffer then put this |
| 479 | * descriptor in a list to be reclaimed later. If not, then increment a |
| 480 | * counter so we can track how many of our descriptors are held by the |
| 481 | * stack. |
| 482 | */ |
| 483 | if (dataCopied == B_TRUE) |
| 484 | { |
| 485 | s_list_push_tail(&reclaimList, &pLmPkt->link); |
| 486 | } |
| 487 | else |
| 488 | { |
| 489 | notCopiedCount++; |
| 490 | } |
| 491 | |
| 492 | if (head == NULL) |
| 493 | { |
| 494 | head = pMblk; |
| 495 | } |
| 496 | else |
| 497 | { |
| 498 | tail->b_next = pMblk; |
| 499 | } |
| 500 | |
| 501 | tail = pMblk; |
| 502 | tail->b_next = NULL; |
| 503 | |
| 504 | #if 0 |
| 505 | BnxeDumpPkt(pUM, |
| 506 | (BNXE_FCOE(pUM) && (idx == FCOE_CID(&pUM->lm_dev))) ? |
| 507 | "<- FCoE L2 RX <-" : "<- L2 RX <-", |
| 508 | pMblk, B_TRUE); |
| 509 | #endif |
| 510 | } |
| 511 | |
| 512 | if (head) |
| 513 | { |
| 514 | if (notCopiedCount) |
| 515 | { |
| 516 | /* track all non-copied packets that will be held by the stack */ |
| 517 | atomic_add_32(&pUM->rxq[idx].rxBufUpInStack, notCopiedCount); |
| 518 | } |
| 519 | |
| 520 | /* pass the mblk chain up the stack */ |
| 521 | if (polling == FALSE) |
| 522 | { |
| 523 | |
| 524 | /* XXX NEED TO ADD STATS FOR RX PATH UPCALLS */ |
| 525 | |
| 526 | if (BNXE_FCOE(pUM) && (idx == FCOE_CID(&pUM->lm_dev))) |
| 527 | { |
| 528 | /* XXX verify fcoe frees all packets on success or error */ |
| 529 | if (pUM->fcoe.pDev && pUM->fcoe.bind.cliIndicateRx) |
| 530 | { |
| 531 | pUM->fcoe.bind.cliIndicateRx(pUM->fcoe.pDev, head); |
| 532 | } |
| 533 | else |
| 534 | { |
| 535 | /* FCoE isn't bound? Reclaim the chain... */ |
| 536 | freemsgchain(head); |
| 537 | head = NULL; |
| 538 | } |
| 539 | } |
| 540 | else |
| 541 | { |
| 542 | #if defined(BNXE_RINGS) && (defined(__S11) || defined(__S12)) |
| 543 | mac_rx_ring(pUM->pMac, |
| 544 | pUM->rxq[idx].ringHandle, |
| 545 | head, |
| 546 | pUM->rxq[idx].genNumber); |
| 547 | #else |
| 548 | mac_rx(pUM->pMac, |
| 549 | pUM->macRxResourceHandles[idx], |
| 550 | head); |
| 551 | #endif |
| 552 | } |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | if ((polling == TRUE) && s_list_entry_cnt(&rxList)) |
| 557 | { |
| 558 | /* put the packets not processed back on the list (front) */ |
| 559 | BNXE_LOCK_ENTER_RX(pUM, idx); |
| 560 | s_list_add_head(&pRxQ->waitRxQ, &rxList); |
| 561 | BNXE_LOCK_EXIT_RX(pUM, idx); |
| 562 | } |
| 563 | |
| 564 | if (s_list_entry_cnt(&reclaimList)) |
| 565 | { |
| 566 | BnxeRxPostBuffers(pUM, idx, &reclaimList); |
| 567 | } |
| 568 | |
| 569 | return (polling == TRUE) ? head : NULL; |
| 570 | } |
| 571 | |
| 572 | |
| 573 | /* |
| 574 | * Dumping packets simply moves all packets from the waiting queue to the free |
| 575 | * queue. Note that the packets are not posted back to the LM. |
| 576 | */ |
| 577 | static void BnxeRxRingDump(um_device_t * pUM, |
| 578 | int idx) |
| 579 | { |
| 580 | s_list_t tmpList; |
| 581 | |
| 582 | BNXE_LOCK_ENTER_RX(pUM, idx); |
| 583 | |
| 584 | tmpList = pUM->rxq[idx].waitRxQ; |
| 585 | s_list_clear(&pUM->rxq[idx].waitRxQ); |
| 586 | |
| 587 | s_list_add_tail(&LM_RXQ(&pUM->lm_dev, idx).common.free_descq, &tmpList); |
| 588 | |
| 589 | BNXE_LOCK_EXIT_RX(pUM, idx); |
| 590 | } |
| 591 | |
| 592 | |
| 593 | /* |
| 594 | * Aborting packets stops all rx processing by dumping the currently waiting |
| 595 | * packets and aborting all the rx descriptors currently posted in the LM. |
| 596 | */ |
| 597 | static void BnxeRxPktsAbortIdx(um_device_t * pUM, |
| 598 | int idx) |
| 599 | { |
| 600 | BnxeRxRingDump(pUM, idx); |
| 601 | |
| 602 | BNXE_LOCK_ENTER_RX(pUM, idx); |
| 603 | lm_abort(&pUM->lm_dev, ABORT_OP_RX_CHAIN, idx); |
| 604 | BNXE_LOCK_EXIT_RX(pUM, idx); |
| 605 | } |
| 606 | |
| 607 | |
| 608 | void BnxeRxPktsAbort(um_device_t * pUM, |
| 609 | int cliIdx) |
| 610 | { |
| 611 | int idx; |
| 612 | |
| 613 | switch (cliIdx) |
| 614 | { |
| 615 | case LM_CLI_IDX_FCOE: |
| 616 | |
| 617 | BnxeRxPktsAbortIdx(pUM, FCOE_CID(&pUM->lm_dev)); |
| 618 | break; |
| 619 | |
| 620 | case LM_CLI_IDX_NDIS: |
| 621 | |
| 622 | LM_FOREACH_RSS_IDX(&pUM->lm_dev, idx) |
| 623 | { |
| 624 | BnxeRxPktsAbortIdx(pUM, idx); |
| 625 | } |
| 626 | |
| 627 | break; |
| 628 | |
| 629 | default: |
| 630 | |
| 631 | BnxeLogWarn(pUM, "ERROR: Invalid cliIdx for BnxeRxPktsAbort (%d)", cliIdx); |
| 632 | break; |
| 633 | } |
| 634 | } |
| 635 | |
| 636 | |
| 637 | static int BnxeRxBufAlloc(um_device_t * pUM, |
| 638 | int idx, |
| 639 | um_rxpacket_t * pRxPkt) |
| 640 | { |
| 641 | ddi_dma_cookie_t cookie; |
| 642 | u32_t count; |
| 643 | size_t length; |
| 644 | int rc; |
| 645 | |
| 646 | if ((rc = ddi_dma_alloc_handle(pUM->pDev, |
| 647 | &bnxeRxDmaAttrib, |
| 648 | DDI_DMA_DONTWAIT, |
| 649 | NULL, |
| 650 | &pRxPkt->dmaHandle)) != DDI_SUCCESS) |
| 651 | { |
| 652 | BnxeLogWarn(pUM, "Failed to alloc DMA handle for rx buffer"); |
| 653 | return -1; |
| 654 | } |
| 655 | |
| 656 | pRxPkt->rx_info.mem_size = MAX_L2_CLI_BUFFER_SIZE(&pUM->lm_dev, idx); |
| 657 | |
| 658 | if ((rc = ddi_dma_mem_alloc(pRxPkt->dmaHandle, |
| 659 | pRxPkt->rx_info.mem_size, |
| 660 | &bnxeAccessAttribBUF, |
| 661 | DDI_DMA_STREAMING, |
| 662 | DDI_DMA_DONTWAIT, |
| 663 | NULL, |
| 664 | (caddr_t *)&pRxPkt->rx_info.mem_virt, |
| 665 | &length, |
| 666 | &pRxPkt->dmaAccHandle)) != DDI_SUCCESS) |
| 667 | { |
| 668 | BnxeLogWarn(pUM, "Failed to alloc DMA memory for rx buffer"); |
| 669 | ddi_dma_free_handle(&pRxPkt->dmaHandle); |
| 670 | return -1; |
| 671 | } |
| 672 | |
| 673 | if ((rc = ddi_dma_addr_bind_handle(pRxPkt->dmaHandle, |
| 674 | NULL, |
| 675 | (caddr_t)pRxPkt->rx_info.mem_virt, |
| 676 | pRxPkt->rx_info.mem_size, |
| 677 | DDI_DMA_READ | DDI_DMA_STREAMING, |
| 678 | DDI_DMA_DONTWAIT, |
| 679 | NULL, |
| 680 | &cookie, |
| 681 | &count)) != DDI_DMA_MAPPED) |
| 682 | { |
| 683 | BnxeLogWarn(pUM, "Failed to bind DMA address for rx buffer"); |
| 684 | ddi_dma_mem_free(&pRxPkt->dmaAccHandle); |
| 685 | ddi_dma_free_handle(&pRxPkt->dmaHandle); |
| 686 | return -1; |
| 687 | } |
| 688 | |
| 689 | pRxPkt->lm_pkt.u1.rx.mem_phys[0].as_u64 = cookie.dmac_laddress; |
| 690 | |
| 691 | return 0; |
| 692 | } |
| 693 | |
| 694 | |
| 695 | static int BnxeRxPktsInitPostBuffersIdx(um_device_t * pUM, |
| 696 | int idx) |
| 697 | { |
| 698 | BNXE_LOCK_ENTER_RX(pUM, idx); |
| 699 | lm_post_buffers(&pUM->lm_dev, idx, NULL, 0); |
| 700 | BNXE_LOCK_EXIT_RX(pUM, idx); |
| 701 | |
| 702 | return 0; |
| 703 | } |
| 704 | |
| 705 | |
| 706 | int BnxeRxPktsInitPostBuffers(um_device_t * pUM, |
| 707 | int cliIdx) |
| 708 | { |
| 709 | int idx; |
| 710 | |
| 711 | switch (cliIdx) |
| 712 | { |
| 713 | case LM_CLI_IDX_FCOE: |
| 714 | |
| 715 | BnxeRxPktsInitPostBuffersIdx(pUM, FCOE_CID(&pUM->lm_dev)); |
| 716 | break; |
| 717 | |
| 718 | case LM_CLI_IDX_NDIS: |
| 719 | |
| 720 | LM_FOREACH_RSS_IDX(&pUM->lm_dev, idx) |
| 721 | { |
| 722 | BnxeRxPktsInitPostBuffersIdx(pUM, idx); |
| 723 | } |
| 724 | |
| 725 | break; |
| 726 | |
| 727 | default: |
| 728 | |
| 729 | BnxeLogWarn(pUM, "ERROR: Invalid cliIdx for BnxeRxPktsInit (%d)", cliIdx); |
| 730 | break; |
| 731 | } |
| 732 | |
| 733 | return 0; |
| 734 | } |
| 735 | |
| 736 | |
| 737 | static int BnxeRxPktsInitIdx(um_device_t * pUM, |
| 738 | int idx) |
| 739 | { |
| 740 | lm_device_t * pLM = &pUM->lm_dev; |
| 741 | lm_rx_chain_t * pLmRxChain; |
| 742 | um_rxpacket_t * pRxPkt; |
| 743 | lm_packet_t * pLmPkt; |
| 744 | u8_t * pTmp; |
| 745 | int postCnt, i; |
| 746 | |
| 747 | BNXE_LOCK_ENTER_RX(pUM, idx); |
| 748 | |
| 749 | pLmRxChain = &LM_RXQ(pLM, idx); |
| 750 | |
| 751 | s_list_clear(&pUM->rxq[idx].doneRxQ); |
| 752 | pUM->rxq[idx].rxLowWater = pLM->params.l2_rx_desc_cnt[LM_CHAIN_IDX_CLI(pLM, idx)]; |
| 753 | pUM->rxq[idx].rxDiscards = 0; |
| 754 | pUM->rxq[idx].rxCopied = 0; |
| 755 | |
| 756 | s_list_clear(&pUM->rxq[idx].waitRxQ); |
| 757 | |
| 758 | /* allocate the packet descriptors */ |
| 759 | for (i = 0; |
| 760 | i < pLM->params.l2_rx_desc_cnt[LM_CHAIN_IDX_CLI(pLM, idx)]; |
| 761 | i++) |
| 762 | { |
| 763 | if ((pTmp = kmem_zalloc(BnxeRxPktDescrSize(pUM), |
| 764 | KM_NOSLEEP)) == NULL) |
| 765 | { |
| 766 | BnxeLogWarn(pUM, "Failed to alloc an rx packet descriptor!!!"); |
| 767 | break; /* continue without error */ |
| 768 | } |
| 769 | |
| 770 | pRxPkt = (um_rxpacket_t *)(pTmp + SIZEOF_SIG); |
| 771 | SIG(pRxPkt) = L2PACKET_RX_SIG; |
| 772 | pRxPkt->signature = pUM->rxBufSignature[LM_CHAIN_IDX_CLI(pLM, idx)]; |
| 773 | |
| 774 | pLmPkt = (lm_packet_t *)pRxPkt; |
| 775 | pLmPkt->u1.rx.hash_val_ptr = &pRxPkt->hash_value; |
| 776 | pLmPkt->l2pkt_rx_info = &pRxPkt->rx_info; |
| 777 | |
| 778 | if (BnxeRxBufAlloc(pUM, idx, pRxPkt) != 0) |
| 779 | { |
| 780 | BnxeRxPktDescrFree(pUM, pRxPkt); |
| 781 | break; /* continue without error */ |
| 782 | } |
| 783 | |
| 784 | s_list_push_tail(&pLmRxChain->common.free_descq, &pLmPkt->link); |
| 785 | } |
| 786 | |
| 787 | postCnt = s_list_entry_cnt(&pLmRxChain->common.free_descq); |
| 788 | |
| 789 | if (postCnt != pLM->params.l2_rx_desc_cnt[LM_CHAIN_IDX_CLI(pLM, idx)]) |
| 790 | { |
| 791 | BnxeLogWarn(pUM, "%d rx buffers requested and only %d allocated!!!", |
| 792 | pLM->params.l2_rx_desc_cnt[LM_CHAIN_IDX_CLI(pLM, idx)], |
| 793 | postCnt); |
| 794 | } |
| 795 | |
| 796 | BNXE_LOCK_EXIT_RX(pUM, idx); |
| 797 | |
| 798 | return 0; |
| 799 | } |
| 800 | |
| 801 | |
| 802 | int BnxeRxPktsInit(um_device_t * pUM, |
| 803 | int cliIdx) |
| 804 | { |
| 805 | int idx; |
| 806 | |
| 807 | /* set the rx buffer signature for this plumb */ |
| 808 | atomic_swap_32(&pUM->rxBufSignature[cliIdx], (u32_t)ddi_get_time()); |
| 809 | |
| 810 | switch (cliIdx) |
| 811 | { |
| 812 | case LM_CLI_IDX_FCOE: |
| 813 | |
| 814 | BnxeRxPktsInitIdx(pUM, FCOE_CID(&pUM->lm_dev)); |
| 815 | break; |
| 816 | |
| 817 | case LM_CLI_IDX_NDIS: |
| 818 | |
| 819 | LM_FOREACH_RSS_IDX(&pUM->lm_dev, idx) |
| 820 | { |
| 821 | BnxeRxPktsInitIdx(pUM, idx); |
| 822 | } |
| 823 | |
| 824 | break; |
| 825 | |
| 826 | default: |
| 827 | |
| 828 | BnxeLogWarn(pUM, "ERROR: Invalid cliIdx for BnxeRxPktsInit (%d)", cliIdx); |
| 829 | break; |
| 830 | } |
| 831 | |
| 832 | return 0; |
| 833 | } |
| 834 | |
| 835 | |
| 836 | static void BnxeRxPktsFiniIdx(um_device_t * pUM, |
| 837 | int idx) |
| 838 | { |
| 839 | lm_rx_chain_t * pLmRxChain; |
| 840 | um_rxpacket_t * pRxPkt; |
| 841 | s_list_t tmpList; |
| 842 | |
| 843 | pLmRxChain = &LM_RXQ(&pUM->lm_dev, idx); |
| 844 | |
| 845 | s_list_clear(&tmpList); |
| 846 | |
| 847 | BNXE_LOCK_ENTER_RX(pUM, idx); |
| 848 | s_list_add_tail(&tmpList, &pLmRxChain->common.free_descq); |
| 849 | s_list_clear(&pLmRxChain->common.free_descq); |
| 850 | BNXE_LOCK_EXIT_RX(pUM, idx); |
| 851 | |
| 852 | BNXE_LOCK_ENTER_DONERX(pUM, idx); |
| 853 | s_list_add_tail(&tmpList, &pUM->rxq[idx].doneRxQ); |
| 854 | s_list_clear(&pUM->rxq[idx].doneRxQ); |
| 855 | BNXE_LOCK_EXIT_DONERX(pUM, idx); |
| 856 | |
| 857 | if (s_list_entry_cnt(&tmpList) != |
| 858 | pUM->lm_dev.params.l2_rx_desc_cnt[LM_CHAIN_IDX_CLI(&pUM->lm_dev, idx)]) |
| 859 | { |
| 860 | BnxeLogWarn(pUM, "WARNING Missing RX packets (idx:%d) (%lu / %d - %u in stack)", |
| 861 | idx, s_list_entry_cnt(&tmpList), |
| 862 | pUM->lm_dev.params.l2_rx_desc_cnt[LM_CHAIN_IDX_CLI(&pUM->lm_dev, idx)], |
| 863 | pUM->rxq[idx].rxBufUpInStack); |
| 864 | } |
| 865 | |
| 866 | /* |
| 867 | * Back out all the packets in the "available for hardware use" queue. |
| 868 | * Free the buffers associated with the descriptors as we go. |
| 869 | */ |
| 870 | while (1) |
| 871 | { |
| 872 | pRxPkt = (um_rxpacket_t *)s_list_pop_head(&tmpList); |
| 873 | if (pRxPkt == NULL) |
| 874 | { |
| 875 | break; |
| 876 | } |
| 877 | |
| 878 | pRxPkt->lm_pkt.u1.rx.mem_phys[0].as_u64 = 0; |
| 879 | pRxPkt->rx_info.mem_virt = NULL; |
| 880 | pRxPkt->rx_info.mem_size = 0; |
| 881 | |
| 882 | ddi_dma_unbind_handle(pRxPkt->dmaHandle); |
| 883 | ddi_dma_mem_free(&pRxPkt->dmaAccHandle); |
| 884 | ddi_dma_free_handle(&pRxPkt->dmaHandle); |
| 885 | |
| 886 | BnxeRxPktDescrFree(pUM, pRxPkt); |
| 887 | } |
| 888 | } |
| 889 | |
| 890 | |
| 891 | void BnxeRxPktsFini(um_device_t * pUM, |
| 892 | int cliIdx) |
| 893 | { |
| 894 | int idx; |
| 895 | |
| 896 | /* reset the signature for this unplumb */ |
| 897 | atomic_swap_32(&pUM->rxBufSignature[cliIdx], 0); |
| 898 | |
| 899 | switch (cliIdx) |
| 900 | { |
| 901 | case LM_CLI_IDX_FCOE: |
| 902 | |
| 903 | BnxeRxPktsFiniIdx(pUM, FCOE_CID(&pUM->lm_dev)); |
| 904 | break; |
| 905 | |
| 906 | case LM_CLI_IDX_NDIS: |
| 907 | |
| 908 | LM_FOREACH_RSS_IDX(&pUM->lm_dev, idx) |
| 909 | { |
| 910 | BnxeRxPktsFiniIdx(pUM, idx); |
| 911 | } |
| 912 | |
| 913 | break; |
| 914 | |
| 915 | default: |
| 916 | |
| 917 | BnxeLogWarn(pUM, "ERROR: Invalid cliIdx for BnxeRxPktsFini (%d)", cliIdx); |
| 918 | break; |
| 919 | } |
| 920 | } |
| 921 | |