|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1990 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: send.c ! 8: ! 9: Abstract: ! 10: ! 11: This file contains the code for putting a packet through the ! 12: staged allocation for transmission. ! 13: ! 14: This is a process of ! 15: ! 16: 1) Calculating the what would need to be done to the ! 17: packet so that the packet can be transmitted on the hardware. ! 18: ! 19: 2) Potentially allocating adapter buffers and copying user data ! 20: to those buffers so that the packet data is transmitted under ! 21: the hardware constraints. ! 22: ! 23: 3) Allocating enough hardware ring entries so that the packet ! 24: can be transmitted. ! 25: ! 26: 4) Relinquish thos ring entries to the hardware. ! 27: ! 28: Author: ! 29: ! 30: Anthony V. Ercolano (Tonye) 12-Sept-1990 ! 31: ! 32: Environment: ! 33: ! 34: Kernel Mode - Or whatever is the equivalent on OS/2 and DOS. ! 35: ! 36: Revision History: ! 37: ! 38: 31-Jul-1992 R.D. Lanser: ! 39: ! 40: Removed PhysicalBuffersContained and UsedLanceBuffer field from ! 41: _ADAPTER structure. SeanSe says that the code related to this ! 42: field was used for adevice that is no longer supported. I removed ! 43: the dependent code(or at least what was obvious) from 'send.c'. ! 44: This old code was generating an erroneous ring buffer count on the ! 45: MIPS R3000. I did not test it on the MIPS R4000. The problem goes ! 46: away with the removal of the offending code. ! 47: ! 48: --*/ ! 49: ! 50: #include <ndis.h> ! 51: #include <efilter.h> ! 52: #include <lancehrd.h> ! 53: #include <lancesft.h> ! 54: ! 55: ! 56: // ! 57: // Minimum packet size that a transport can send. We subtract 4 bytes ! 58: // because we add a 4 byte CRC on the end. ! 59: // ! 60: ! 61: #define MIN_SINGLE_BUFFER ((UINT)LANCE_SMALL_BUFFER_SIZE - 4) ! 62: ! 63: ! 64: // ! 65: // It will poke the lance hardware into noticing that there is a packet ! 66: // available for transmit. ! 67: // ! 68: // Note that there is the assumption that the register address ! 69: // port (RAP) is already set to zero. ! 70: // ! 71: #define PROD_TRANSMIT(A) \ ! 72: LANCE_WRITE_RDP( \ ! 73: A, \ ! 74: LANCE_CSR0_TRANSMIT_DEMAND | LANCE_CSR0_INTERRUPT_ENABLE \ ! 75: ); ! 76: ! 77: VOID ! 78: SetupAllocate( ! 79: IN PLANCE_ADAPTER Adapter, ! 80: IN NDIS_HANDLE MacBindingHandle, ! 81: IN PNDIS_PACKET Packet ! 82: ); ! 83: ! 84: VOID ! 85: StagedAllocation( ! 86: IN PLANCE_ADAPTER Adapter ! 87: ); ! 88: ! 89: VOID ! 90: CopyPacketIntoBuffer( ! 91: IN PLANCE_ADAPTER Adapter, ! 92: IN PNDIS_PACKET Packet, ! 93: IN PLANCE_BUFFER_DESCRIPTOR BufferDescriptor ! 94: ); ! 95: ! 96: ! 97: ! 98: extern ! 99: NDIS_STATUS ! 100: LanceSend( ! 101: IN NDIS_HANDLE MacBindingHandle, ! 102: IN PNDIS_PACKET Packet ! 103: ) ! 104: ! 105: /*++ ! 106: ! 107: Routine Description: ! 108: ! 109: The LanceSend request instructs a MAC to transmit a packet through ! 110: the adapter onto the medium. ! 111: ! 112: Arguments: ! 113: ! 114: MacBindingHandle - The context value returned by the MAC when the ! 115: adapter was opened. In reality, it is a pointer to LANCE_OPEN. ! 116: ! 117: Packet - A pointer to a descriptor for the packet that is to be ! 118: transmitted. ! 119: ! 120: Return Value: ! 121: ! 122: The function value is the status of the operation. ! 123: ! 124: ! 125: --*/ ! 126: ! 127: { ! 128: ! 129: // ! 130: // Holds the status that should be returned to the caller. ! 131: // ! 132: NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING; ! 133: ! 134: // ! 135: // Pointer to the adapter. ! 136: // ! 137: PLANCE_ADAPTER Adapter; ! 138: ! 139: PLANCE_OPEN Open; ! 140: ! 141: Open = PLANCE_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); ! 142: ! 143: #if LANCE_TRACE ! 144: DbgPrint("In LanceSend\n"); ! 145: #endif ! 146: ! 147: Adapter = PLANCE_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle); ! 148: ! 149: if (Adapter->HardwareFailure) { ! 150: ! 151: return(NDIS_STATUS_FAILURE); ! 152: ! 153: } ! 154: ! 155: NdisAcquireSpinLock(&Adapter->Lock); ! 156: Adapter->References++; ! 157: ! 158: LOG(IN_SEND); ! 159: ! 160: if (!Adapter->ResetInProgress) { ! 161: ! 162: if (!Open->BindingShuttingDown) { ! 163: ! 164: UINT TotalPacketSize; ! 165: ! 166: // ! 167: // Increment the references on the open while we are ! 168: // accessing it in the interface. ! 169: // ! 170: ! 171: Open->References++; ! 172: ! 173: // ! 174: // It is reasonable to do a quick check and fail if the packet ! 175: // is larger than the maximum an ethernet can handle. ! 176: // ! 177: ! 178: NdisQueryPacket( ! 179: Packet, ! 180: NULL, ! 181: NULL, ! 182: NULL, ! 183: &TotalPacketSize ! 184: ); ! 185: ! 186: if ((!TotalPacketSize) || ! 187: (TotalPacketSize > LANCE_LARGE_BUFFER_SIZE)) { ! 188: ! 189: StatusToReturn = NDIS_STATUS_RESOURCES; ! 190: ! 191: } else { ! 192: ! 193: // ! 194: // There is an assumption in the code that no pointer ! 195: // (which are really handles) to an ndis packet will have ! 196: // its low bit set. (Always have even byte alignment.) ! 197: // ! 198: ! 199: ASSERT(!((UINT)Packet & 1)); ! 200: ! 201: SetupAllocate( ! 202: Adapter, ! 203: MacBindingHandle, ! 204: Packet ! 205: ); ! 206: ! 207: // ! 208: // Add a reference for the pending send ! 209: // ! 210: ! 211: Open->References++; ! 212: ! 213: // ! 214: // Only try to push it through the stage queues ! 215: // if somebody else isn't already doing it and ! 216: // there is some hope of moving some packets ! 217: // ahead. ! 218: // ! 219: ! 220: while ((!Adapter->AlreadyProcessingStage ! 221: ) && ! 222: (Adapter->FirstStage1Packet && ! 223: Adapter->StageOpen ! 224: ) ! 225: ) { ! 226: ! 227: LanceStagedAllocation(Adapter); ! 228: ! 229: } ! 230: ! 231: } ! 232: ! 233: // ! 234: // The interface is no longer referencing the open. ! 235: // ! 236: ! 237: Open->References--; ! 238: ! 239: } else { ! 240: ! 241: StatusToReturn = NDIS_STATUS_CLOSING; ! 242: ! 243: } ! 244: ! 245: } else if (Adapter->ResetRequestType == NdisRequestGeneric1) { ! 246: ! 247: StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS; ! 248: ! 249: } else { ! 250: ! 251: // ! 252: // Reset is from a SetInfo or internal call and this packet needs ! 253: // to be pended. ! 254: // ! 255: ! 256: SetupAllocate( ! 257: Adapter, ! 258: MacBindingHandle, ! 259: Packet ! 260: ); ! 261: ! 262: // ! 263: // Add one to reference fore pending send ! 264: // ! 265: Open->References++; ! 266: ! 267: StatusToReturn = NDIS_STATUS_PENDING; ! 268: ! 269: } ! 270: ! 271: LOG(OUT_SEND); ! 272: ! 273: LANCE_DO_DEFERRED(Adapter); ! 274: ! 275: #if LANCE_TRACE ! 276: DbgPrint("Out LanceSend\n"); ! 277: #endif ! 278: ! 279: return StatusToReturn; ! 280: } ! 281: ! 282: VOID ! 283: SetupAllocate( ! 284: IN PLANCE_ADAPTER Adapter, ! 285: IN NDIS_HANDLE MacBindingHandle, ! 286: IN PNDIS_PACKET Packet ! 287: ) ! 288: ! 289: /*++ ! 290: ! 291: Routine Description: ! 292: ! 293: This sets up the MAC reserved portion of the packet so that ! 294: later allocation routines can determine what is left to be ! 295: done in the allocation cycle. ! 296: ! 297: NOTE: This assumes it is called with the spinlock held!! ! 298: ! 299: Arguments: ! 300: ! 301: Adapter - The adapter that this packet is coming through. ! 302: ! 303: MacBindingHandle - Points to the open binding structure. ! 304: ! 305: Packet - The packet that is to be transmitted. ! 306: ! 307: Return Value: ! 308: ! 309: None. ! 310: ! 311: --*/ ! 312: ! 313: { ! 314: ! 315: // ! 316: // Points to the MAC reserved portion of this packet. This ! 317: // interpretation of the reserved section is only valid during ! 318: // the allocation phase of the packet. ! 319: // ! 320: PLANCE_RESERVED Reserved = PLANCE_RESERVED_FROM_PACKET(Packet); ! 321: ! 322: ! 323: ASSERT(sizeof(LANCE_RESERVED) <= ! 324: sizeof(Packet->MacReserved)); ! 325: ! 326: Reserved->LanceBuffersIndex = 0; ! 327: Reserved->MacBindingHandle = MacBindingHandle; ! 328: ! 329: // ! 330: // Put on the stage 1 queue. ! 331: // ! 332: ! 333: if (!Adapter->LastStage1Packet) { ! 334: ! 335: Adapter->FirstStage1Packet = Packet; ! 336: ! 337: } else { ! 338: ! 339: PLANCE_RESERVED_FROM_PACKET(Adapter->LastStage1Packet)->Next = Packet; ! 340: ! 341: } ! 342: ! 343: Adapter->LastStage1Packet = Packet; ! 344: ! 345: Reserved->Next = NULL; ! 346: ! 347: } ! 348: ! 349: extern ! 350: VOID ! 351: LanceStagedAllocation( ! 352: IN PLANCE_ADAPTER Adapter ! 353: ) ! 354: ! 355: /*++ ! 356: ! 357: Routine Description: ! 358: ! 359: This routine attempts to take a packet through a stage of allocation. ! 360: ! 361: NOTE: THIS IS CALLED WITH THE LOCK HELD!! ! 362: ! 363: NOTE: MUST BE CALLED WITH ! 364: ! 365: Adapter->StageOpen && ! 366: !Adapter->AlreadyProcessingStage && ! 367: Adapter->FirstStage1Packet ! 368: ! 369: ! 370: ! 371: Arguments: ! 372: ! 373: Adapter - The adapter that the packets are coming through. ! 374: ! 375: Return Value: ! 376: ! 377: None. ! 378: ! 379: --*/ ! 380: ! 381: { ! 382: // ! 383: // Pointer to the ring entry to be filled with buffer information. ! 384: // ! 385: PLANCE_TRANSMIT_ENTRY CurrentRingElement; ! 386: ! 387: // ! 388: // Pointer to the ring to packet entry that records the info about ! 389: // this packet. ! 390: // ! 391: PLANCE_RING_TO_PACKET RingToPacket; ! 392: ! 393: // ! 394: // Length of the packet ! 395: // ! 396: ULONG TotalVirtualLength; ! 397: ! 398: // ! 399: // Holds the adapter buffer index available for allocation. ! 400: // ! 401: INT LanceBuffersIndex; ! 402: ! 403: // ! 404: // Points to a successfully allocated adapter buffer descriptor. ! 405: // ! 406: PLANCE_BUFFER_DESCRIPTOR BufferDescriptor; ! 407: ! 408: // ! 409: // Simple iteration variable. ! 410: // ! 411: INT i; ! 412: ! 413: // ! 414: // Size of Lance Buffer needed (1==Small, 2==Medium, 3==Large) ! 415: // ! 416: UCHAR BufferSize; ! 417: ! 418: // ! 419: // If we successfully acquire some ring entries, this ! 420: // is the index of the first one. ! 421: // ! 422: UINT RingIndex; ! 423: ! 424: PNDIS_PACKET FirstPacket; ! 425: ! 426: PLANCE_RESERVED Reserved; ! 427: ! 428: ! 429: if (Adapter->NumberOfAvailableRings == 0) { ! 430: ! 431: Adapter->StageOpen = FALSE; ! 432: return ; ! 433: ! 434: } ! 435: ! 436: Adapter->AlreadyProcessingStage = TRUE; ! 437: ! 438: FirstPacket = Adapter->FirstStage1Packet; ! 439: ! 440: // ! 441: // Determine if and how much adapter space would need to be allocated ! 442: // to meet hardware constraints. ! 443: // ! 444: ! 445: NdisQueryPacket( ! 446: FirstPacket, ! 447: NULL, ! 448: NULL, ! 449: NULL, ! 450: &TotalVirtualLength ! 451: ); ! 452: ! 453: // ! 454: // Certain hardware implementation (Decstation) use a dual ported ! 455: // memory to communicate with the hardware. This is reasonable since ! 456: // it reduces bus contention. When using the dual ported memory, all ! 457: // send data must be moved to buffers allocated from the dual ported ! 458: // memory. ! 459: // ! 460: ! 461: if (TotalVirtualLength <= LANCE_SMALL_BUFFER_SIZE) { ! 462: ! 463: BufferSize = 1; ! 464: ! 465: } else if (TotalVirtualLength <= LANCE_MEDIUM_BUFFER_SIZE) { ! 466: ! 467: BufferSize = 2; ! 468: ! 469: } else { ! 470: ! 471: BufferSize = 3; ! 472: ! 473: } ! 474: ! 475: // ! 476: // Find a buffer ! 477: // ! 478: for ( ! 479: i = BufferSize; ! 480: i <= 3; ! 481: i++ ! 482: ) { ! 483: ! 484: if ((LanceBuffersIndex = Adapter->LanceBufferListHeads[i]) != -1) { ! 485: ! 486: BufferDescriptor = Adapter->LanceBuffers + LanceBuffersIndex; ! 487: Adapter->LanceBufferListHeads[i] = BufferDescriptor->Next; ! 488: break; ! 489: ! 490: } ! 491: ! 492: } ! 493: ! 494: if (LanceBuffersIndex == -1) { ! 495: ! 496: // ! 497: // Nothing available for the packet. ! 498: // ! 499: ! 500: Adapter->StageOpen = FALSE; ! 501: Adapter->AlreadyProcessingStage = FALSE; ! 502: ! 503: return; ! 504: ! 505: } ! 506: ! 507: // ! 508: // We need to save in the packet which adapter buffere descriptor ! 509: // it is using so that we can deallocate it later. We also store ! 510: // the number of buffers contained so that we can allocate ring ! 511: // entries. ! 512: // ! 513: ! 514: Reserved = PLANCE_RESERVED_FROM_PACKET(FirstPacket); ! 515: ! 516: Reserved->LanceBuffersIndex = LanceBuffersIndex; ! 517: ! 518: // ! 519: // Now remove this packet from the queue ! 520: // ! 521: ! 522: Adapter->FirstStage1Packet = Reserved->Next; ! 523: ! 524: if (Adapter->FirstStage1Packet == NULL) { ! 525: ! 526: Adapter->LastStage1Packet = NULL; ! 527: ! 528: } ! 529: ! 530: // ! 531: // Save the list head index in the buffer descriptor ! 532: // to permit easy deallocation later. ! 533: // ! 534: BufferDescriptor->Next = i; ! 535: ! 536: // ! 537: // Now Acquire the ring ! 538: // ! 539: RingIndex = Adapter->AllocateableRing - Adapter->TransmitRing; ! 540: ! 541: // ! 542: // Store the info ! 543: // ! 544: CurrentRingElement = Adapter->AllocateableRing; ! 545: ! 546: // ! 547: // NOTE NOTE NOTE NOTE NOTE NOTE ! 548: // ! 549: // We can do the next calculation because we know that the number ! 550: // or ring entries is a power of two! ! 551: // ! 552: ! 553: Adapter->AllocateableRing = Adapter->TransmitRing + ! 554: (((RingIndex) + 1) & ! 555: (Adapter->NumberOfTransmitRings-1)); ! 556: ! 557: Adapter->NumberOfAvailableRings--; ! 558: ! 559: // ! 560: // Copy into buffer ! 561: // ! 562: CopyPacketIntoBuffer(Adapter, FirstPacket, BufferDescriptor); ! 563: ! 564: // ! 565: // Get the position for mapping ring entries to packets. ! 566: // We record the owning packet information in the ring packet packet ! 567: // structure. ! 568: // ! 569: RingToPacket = Adapter->RingToPacket + RingIndex; ! 570: RingToPacket->OwningPacket = FirstPacket; ! 571: RingToPacket->LanceBuffersIndex = Reserved->LanceBuffersIndex; ! 572: RingToPacket->RingIndex = RingIndex; ! 573: ! 574: // ! 575: // Make sure that the ring descriptor is clean. ! 576: // ! 577: ! 578: LANCE_ZERO_MEMORY_FOR_HARDWARE(CurrentRingElement,sizeof(LANCE_TRANSMIT_ENTRY)); ! 579: ! 580: LANCE_SET_TRANSMIT_BUFFER_LENGTH( ! 581: CurrentRingElement, ! 582: BufferDescriptor->DataLength ! 583: ); ! 584: ! 585: ! 586: LANCE_SET_TRANSMIT_BUFFER_ADDRESS( ! 587: Adapter, ! 588: CurrentRingElement, ! 589: BufferDescriptor->VirtualLanceBuffer ! 590: ); ! 591: ! 592: LOG(TRANSMIT); ! 593: ! 594: // ! 595: // We update the ring ownership of the last packet under ! 596: // the protection of the lock so that the uncommitted packet ! 597: // pointer can be updated before the transmit post processing ! 598: // can examine it. ! 599: // ! 600: ! 601: LANCE_SET_RING_BITS( ! 602: CurrentRingElement->TransmitSummaryBits, ! 603: LANCE_TRANSMIT_START_OF_PACKET | ! 604: LANCE_TRANSMIT_OWNED_BY_CHIP | ! 605: LANCE_TRANSMIT_END_OF_PACKET ! 606: ); ! 607: ! 608: ! 609: if (RingIndex == (Adapter->NumberOfTransmitRings-1)) { ! 610: ! 611: Adapter->FirstUncommittedRing = Adapter->TransmitRing ; ! 612: ! 613: } else { ! 614: ! 615: Adapter->FirstUncommittedRing = Adapter->TransmitRing + RingIndex + 1; ! 616: ! 617: } ! 618: ! 619: // ! 620: // Prod the chip into checking for packets to send. ! 621: // ! 622: ! 623: PROD_TRANSMIT(Adapter); ! 624: ! 625: if (Adapter->LastFinishTransmit) { ! 626: ! 627: PLANCE_RESERVED LastReserved = ! 628: PLANCE_RESERVED_FROM_PACKET(Adapter->LastFinishTransmit); ! 629: ! 630: LastReserved->Next = FirstPacket; ! 631: ! 632: } ! 633: ! 634: Reserved->Next = NULL; ! 635: ! 636: Adapter->LastFinishTransmit = FirstPacket; ! 637: ! 638: if (!Adapter->FirstFinishTransmit) { ! 639: ! 640: Adapter->FirstFinishTransmit = FirstPacket; ! 641: ! 642: } ! 643: ! 644: Adapter->AlreadyProcessingStage = FALSE; ! 645: ! 646: } ! 647: ! 648: ! 649: VOID ! 650: CopyPacketIntoBuffer( ! 651: IN PLANCE_ADAPTER Adapter, ! 652: IN PNDIS_PACKET Packet, ! 653: IN PLANCE_BUFFER_DESCRIPTOR BufferDescriptor ! 654: ) ! 655: ! 656: /*++ ! 657: ! 658: Routine Description: ! 659: ! 660: Copy a packet down to the hardware. ! 661: ! 662: Note : MUST BE CALLED WITH LOCK HELD! ! 663: ! 664: Arguments: ! 665: ! 666: Adapter - The adapter the packet is coming through. ! 667: ! 668: Packet - The packet whose buffers are to be copied. ! 669: ! 670: Return Value: ! 671: ! 672: none ! 673: ! 674: --*/ ! 675: ! 676: { ! 677: // ! 678: // Will point into the virtual address space addressed ! 679: // by the adapter buffer if one was successfully allocated. ! 680: // ! 681: PCHAR CurrentDestination; ! 682: ! 683: // ! 684: // Will hold the total amount of data copied to the ! 685: // adapter buffer. ! 686: // ! 687: UINT TotalVirtualLength; ! 688: ! 689: // ! 690: // Will point to the current source buffer. ! 691: // ! 692: PNDIS_BUFFER SourceBuffer; ! 693: ! 694: // ! 695: // Points to the virtual address of the source buffers data. ! 696: // ! 697: PVOID SourceData; ! 698: ! 699: // ! 700: // Will point to the number of bytes of data in the source ! 701: // buffer. ! 702: // ! 703: UINT SourceLength; ! 704: ! 705: NdisReleaseSpinLock(&Adapter->Lock); ! 706: ! 707: // ! 708: // Fill in the adapter buffer with the data from the users ! 709: // buffers. ! 710: // ! 711: ! 712: CurrentDestination = BufferDescriptor->VirtualLanceBuffer; ! 713: ! 714: NdisQueryPacket( ! 715: Packet, ! 716: NULL, ! 717: NULL, ! 718: &SourceBuffer, ! 719: &TotalVirtualLength ! 720: ); ! 721: ! 722: while ( SourceBuffer != NULL ) { ! 723: ! 724: NdisQueryBuffer( ! 725: SourceBuffer, ! 726: &SourceData, ! 727: &SourceLength ! 728: ); ! 729: ! 730: LANCE_MOVE_MEMORY_TO_HARDWARE( ! 731: CurrentDestination, ! 732: SourceData, ! 733: SourceLength ! 734: ); ! 735: ! 736: CurrentDestination = (PCHAR)CurrentDestination + SourceLength; ! 737: ! 738: NdisGetNextBuffer( ! 739: SourceBuffer, ! 740: &SourceBuffer ! 741: ); ! 742: ! 743: } ! 744: ! 745: // ! 746: // If the packet is less then the minimum size then we ! 747: // need to zero out the rest of the packet. ! 748: // ! 749: ! 750: if (TotalVirtualLength < MIN_SINGLE_BUFFER) { ! 751: ! 752: LANCE_ZERO_MEMORY_FOR_HARDWARE( ! 753: CurrentDestination, ! 754: MIN_SINGLE_BUFFER - TotalVirtualLength ! 755: ); ! 756: ! 757: BufferDescriptor->DataLength = MIN_SINGLE_BUFFER; ! 758: ! 759: } else { ! 760: ! 761: BufferDescriptor->DataLength = TotalVirtualLength; ! 762: ! 763: } ! 764: ! 765: NdisAcquireSpinLock(&Adapter->Lock); ! 766: ! 767: return; ! 768: } ! 769:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.