|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1990-1992 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: The overall structure and most of the code is taken from
29: the Lance driver by Tony Ercolano.
30:
31: Author:
32:
33: Anthony V. Ercolano (Tonye) 12-Sept-1990
34: Adam Barr (adamba) 16-Nov-1990
35:
36: Environment:
37:
38: Kernel Mode - Or whatever is the equivalent.
39:
40: Revision History:
41:
42:
43: --*/
44:
45:
46: #include <ndis.h>
47:
48: #include <efilter.h>
49: #include <sonichrd.h>
50: #include <sonicsft.h>
51:
52:
53:
54: //
55: // This macro will poke the sonic hardware into noticing that
56: // there is a packet available for transmit.
57: //
58:
59: #define START_TRANSMIT(_Adapter) \
60: SONIC_WRITE_PORT(_Adapter, SONIC_COMMAND, SONIC_CR_TRANSMIT_PACKETS)
61:
62:
63: STATIC
64: BOOLEAN
65: DeterminePacketAddressing(
66: IN PNDIS_PACKET Packet
67: );
68:
69: STATIC
70: VOID
71: StagedAllocation(
72: IN PSONIC_ADAPTER Adapter
73: );
74:
75: STATIC
76: VOID
77: AssignPacketToDescriptor(
78: IN PSONIC_ADAPTER Adapter,
79: IN PNDIS_PACKET Packet,
80: IN UINT DescriptorIndex
81: );
82:
83: STATIC
84: VOID
85: RelinquishPacket(
86: IN PSONIC_ADAPTER Adapter,
87: IN PNDIS_PACKET Packet,
88: IN UINT RingIndex
89: );
90:
91: STATIC
92: VOID
93: CalculatePacketConstraints(
94: IN PSONIC_ADAPTER Adapter,
95: IN PNDIS_PACKET Packet
96: );
97:
98: STATIC
99: BOOLEAN
100: ConstrainPacket(
101: IN PSONIC_ADAPTER Adapter,
102: IN PNDIS_PACKET Packet
103: );
104:
105:
106: #ifdef CHECK_DUP_SENDS
107:
108: #define PACKET_LIST_SIZE 20
109:
110: PNDIS_PACKET SonicPacketList[PACKET_LIST_SIZE];
111: UINT SonicPacketListSize = 0;
112:
113: VOID
114: SonicAddPacketToList(
115: PSONIC_ADAPTER Adapter,
116: PNDIS_PACKET NewPacket
117: )
118: {
119: INT i;
120:
121: for (i=0; i<SonicPacketListSize; i++) {
122:
123: if (SonicPacketList[i] == NewPacket) {
124:
125: DbgPrint("SONIC: dup send of %lx\n", NewPacket);
126:
127: }
128:
129: }
130:
131: SonicPacketList[SonicPacketListSize] = NewPacket;
132: ++SonicPacketListSize;
133:
134: }
135:
136: VOID
137: SonicRemovePacketFromList(
138: PSONIC_ADAPTER Adapter,
139: PNDIS_PACKET OldPacket
140: )
141: {
142: INT i;
143:
144: for (i=0; i<SonicPacketListSize; i++) {
145:
146: if (SonicPacketList[i] == OldPacket) {
147:
148: break;
149:
150: }
151:
152: }
153:
154: if (i == SonicPacketListSize) {
155:
156: DbgPrint("SONIC: bad remove of %lx\n", OldPacket);
157:
158: } else {
159:
160: --SonicPacketListSize;
161: SonicPacketList[i] = SonicPacketList[SonicPacketListSize];
162:
163: }
164:
165: }
166: #endif // CHECK_DUP_SENDS
167:
168:
169: extern
170: NDIS_STATUS
171: SonicSend(
172: IN NDIS_HANDLE MacBindingHandle,
173: IN PNDIS_PACKET Packet
174: )
175:
176: /*++
177:
178: Routine Description:
179:
180: The SonicSend request instructs a MAC to transmit a packet through
181: the adapter onto the medium.
182:
183: Arguments:
184:
185: MacBindingHandle - The context value returned by the MAC when the
186: adapter was opened. In reality, it is a pointer to SONIC_OPEN.
187:
188: Packet - A pointer to a descriptor for the packet that is to be
189: transmitted.
190:
191: Return Value:
192:
193: The function value is the status of the operation.
194:
195: --*/
196:
197: {
198:
199: //
200: // Holds the status that should be returned to the caller.
201: //
202: NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING;
203:
204: //
205: // Pointer to the adapter.
206: //
207: PSONIC_ADAPTER Adapter;
208:
209:
210: Adapter = PSONIC_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
211:
212: NdisAcquireSpinLock(&Adapter->Lock);
213:
214: if (Adapter->Removed) {
215:
216: NdisReleaseSpinLock(&Adapter->Lock);
217:
218: return(NDIS_STATUS_FAILURE);
219:
220: }
221:
222: Adapter->References++;
223:
224: if (!Adapter->ResetInProgress) {
225:
226: PSONIC_OPEN Open;
227: PSONIC_PACKET_RESERVED Reserved;
228:
229: Open = PSONIC_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
230:
231: if (!Open->BindingShuttingDown) {
232:
233: //
234: // Increment the references on the open while we are
235: // accessing it in the interface.
236: //
237:
238: #ifdef CHECK_DUP_SENDS
239: SonicAddPacketToList(Adapter, Packet);
240: #endif
241:
242: Open->References++;
243:
244: //
245: // Check to see if the packet should even make it out to
246: // the media. The primary reason this shouldn't *actually*
247: // be sent is if the destination is equal to the source
248: // address.
249: //
250: // If it doesn't need to be placed on the wire then we can
251: // simply put it onto the loopback queue.
252: //
253:
254: Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
255:
256: ASSERT(sizeof(SONIC_PACKET_RESERVED) <=
257: sizeof(Packet->MacReserved));
258:
259: Reserved->MacBindingHandle = MacBindingHandle;
260:
261: if (DeterminePacketAddressing(Packet)) {
262:
263: //
264: // The packet needs to be placed out on the wire.
265: //
266: //
267: // Determine if and how much adapter space would need to be allocated
268: // to meet hardware constraints.
269: //
270:
271: CalculatePacketConstraints(
272: Adapter,
273: Packet
274: );
275:
276: //
277: // Put on the send stage queue.
278: //
279:
280: if (!Adapter->LastSendStagePacket) {
281:
282: Adapter->FirstSendStagePacket = Packet;
283:
284: } else {
285:
286: PSONIC_RESERVED_FROM_PACKET(Adapter->LastSendStagePacket)->Next = Packet;
287:
288: }
289:
290: Adapter->LastSendStagePacket = Packet;
291:
292: ++Adapter->GeneralOptional[GO_TRANSMIT_QUEUE_LENGTH - GO_ARRAY_START];
293:
294: Reserved->Next = NULL;
295:
296: //
297: // Only try to push it through the send stage queue
298: // if somebody else isn't already doing it and
299: // there is some hope of moving some packets
300: // ahead.
301: //
302:
303: while ((!Adapter->AlreadyProcessingSendStage) &&
304: Adapter->FirstSendStagePacket &&
305: Adapter->SendStageOpen) {
306:
307: SonicStagedAllocation(Adapter);
308:
309: }
310:
311: } else {
312:
313: //
314: // It is a packet directed to ourselves. Put it directly
315: // on the loopback queue.
316: //
317:
318: SonicPutPacketOnLoopBack(
319: Adapter,
320: Packet,
321: TRUE
322: );
323:
324:
325: //
326: // Tally statistics now; assume that loopback
327: // always "succeeds". These packets are always
328: // directed (to us), so add to those counts.
329: //
330:
331: ++Adapter->GeneralMandatory[GM_TRANSMIT_GOOD];
332:
333: ++Adapter->GeneralOptionalFrameCount[GO_DIRECTED_TRANSMITS];
334:
335: SonicAddUlongToLargeInteger(
336: &Adapter->GeneralOptionalByteCount[GO_DIRECTED_TRANSMITS],
337: Reserved->PacketLength);
338:
339:
340: }
341:
342:
343: } else {
344:
345: StatusToReturn = NDIS_STATUS_CLOSING;
346:
347: }
348:
349: } else {
350:
351: StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
352:
353: }
354:
355:
356: //
357: // This macro assumes it is called with the lock held,
358: // and releases it.
359: //
360:
361: SONIC_DO_DEFERRED(Adapter);
362: return StatusToReturn;
363: }
364:
365: STATIC
366: BOOLEAN
367: DeterminePacketAddressing(
368: IN PNDIS_PACKET Packet
369: )
370:
371: /*++
372:
373: Routine Description:
374:
375: Calculates the packet type for this packet. It also determines
376: if this packet should go out on the wire.
377:
378: Arguments:
379:
380: Packet - Packet whose source and destination addresses are tested.
381:
382: Return Value:
383:
384: Returns FALSE if the source is equal to the destination.
385:
386:
387: --*/
388:
389: {
390: //
391: // MacReserved section of the packet.
392: //
393: PSONIC_PACKET_RESERVED Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
394:
395: //
396: // Hold the first Ndis buffer;
397: //
398: PNDIS_BUFFER FirstBuffer;
399:
400: //
401: // Holds the address of the data in the first buffer
402: //
403: PVOID BufferVirtualAddress;
404:
405: //
406: // Number of bytes in the first buffer.
407: //
408: UINT BufferLength;
409:
410: //
411: // Holds result of address check
412: //
413: UINT Result;
414:
415: NdisQueryPacket(
416: Packet,
417: NULL,
418: NULL,
419: &FirstBuffer,
420: NULL
421: );
422:
423: //
424: // Get VA of first buffer
425: //
426:
427: NdisQueryBuffer(
428: FirstBuffer,
429: &BufferVirtualAddress,
430: &BufferLength
431: );
432:
433: //
434: // Ndis spec says that the ethernet header must be in the first
435: // buffer.
436: //
437:
438: ASSERT(BufferLength >= 14);
439:
440: if (ETH_IS_MULTICAST(BufferVirtualAddress)) {
441:
442: if (ETH_IS_BROADCAST(BufferVirtualAddress)) {
443:
444: Reserved->PacketType = SONIC_BROADCAST;
445:
446: } else {
447:
448: Reserved->PacketType = SONIC_MULTICAST;
449:
450: }
451:
452: } else {
453:
454: Reserved->PacketType = SONIC_DIRECTED;
455:
456: ETH_COMPARE_NETWORK_ADDRESSES(
457: ((PUCHAR)BufferVirtualAddress) + ETH_LENGTH_OF_ADDRESS,
458: (PUCHAR)BufferVirtualAddress,
459: &Result
460: );
461:
462: if (!Result) {
463:
464: Reserved->PacketType = SONIC_LOOPBACK;
465:
466: }
467:
468: }
469:
470: //
471: // If the two addresses are equal then the
472: // packet shouldn't go out on the wire.
473: //
474:
475: return ((Reserved->PacketType == SONIC_LOOPBACK) ? FALSE : TRUE);
476:
477: }
478:
479: extern
480: VOID
481: SonicStagedAllocation(
482: IN PSONIC_ADAPTER Adapter
483: )
484:
485: /*++
486:
487: Routine Description:
488:
489: This routine attempts to take a packet through a stage of allocation.
490:
491: NOTE : It is called with the lock held and returns with the lock held.
492:
493: NOTE : It is called with the stage open, a packet on the queue and
494: no one already processing the stage.
495:
496: Arguments:
497:
498: Adapter - The adapter that the packets are coming through.
499:
500: Return Value:
501:
502: None.
503:
504: --*/
505:
506: {
507: //
508: // Holds whether the packet has been constrained
509: // to the hardware requirements.
510: //
511: BOOLEAN SuitableForHardware;
512:
513: //
514: // Packet to process
515: //
516: PNDIS_PACKET FirstPacket = Adapter->FirstSendStagePacket;
517:
518: //
519: // MacReserved section of the packet.
520: //
521: PSONIC_PACKET_RESERVED Reserved = PSONIC_RESERVED_FROM_PACKET(FirstPacket);
522:
523: //
524: // If we successfully acquire some ring entries, this
525: // is the index of the first one.
526: //
527: UINT DescriptorIndex;
528:
529: ASSERT(Adapter->SendStageOpen &&
530: !Adapter->AlreadyProcessingSendStage &&
531: Adapter->FirstSendStagePacket
532: );
533:
534:
535: //
536: // We look to see if there are enough ring entries.
537: // If there aren't then stage will close.
538: //
539:
540: if (Adapter->NumberOfAvailableDescriptors > 1) {
541:
542: DescriptorIndex = Adapter->AllocateableDescriptor - Adapter->TransmitDescriptorArea;
543:
544: if (Adapter->AllocateableDescriptor == Adapter->LastTransmitDescriptor) {
545:
546: Adapter->AllocateableDescriptor = Adapter->TransmitDescriptorArea;
547:
548: } else {
549:
550: ++(Adapter->AllocateableDescriptor);
551:
552: }
553:
554: --(Adapter->NumberOfAvailableDescriptors);
555:
556: if (Reserved->UsedSonicBuffer == TRUE) {
557:
558: //
559: // ConstrainPacket returns FALSE if an adapter buffer
560: // is needed and none is available such that the
561: // spinlock will not have been release. It will also close
562: // stage in that case.
563: //
564: // If it did use an adapter buffer it will release the spinlock
565: // to do the copy to the buffer.
566: //
567:
568: Adapter->AlreadyProcessingSendStage = TRUE;
569:
570: SuitableForHardware = ConstrainPacket(
571: Adapter,
572: FirstPacket
573: );
574:
575: Adapter->AlreadyProcessingSendStage = FALSE;
576:
577: if (!SuitableForHardware) {
578:
579: //
580: // Return transmit descriptor
581: //
582:
583: Adapter->AllocateableDescriptor = Adapter->TransmitDescriptorArea +
584: DescriptorIndex;
585:
586:
587: ++(Adapter->NumberOfAvailableDescriptors);
588:
589: return;
590:
591:
592: }
593:
594: }
595:
596: //
597: // Remove packet from wait queue and put it on transmit complete queue.
598: //
599:
600: if (Adapter->LastSendStagePacket == FirstPacket) {
601:
602: Adapter->FirstSendStagePacket = NULL;
603: Adapter->LastSendStagePacket = NULL;
604:
605: } else {
606:
607: Adapter->FirstSendStagePacket = Reserved->Next;
608:
609: }
610:
611: if (Adapter->FirstFinishTransmit == NULL) {
612:
613: Adapter->FirstFinishTransmit = FirstPacket;
614:
615: } else {
616:
617: PSONIC_RESERVED_FROM_PACKET(Adapter->LastFinishTransmit)->Next = FirstPacket;
618:
619: }
620:
621: Adapter->LastFinishTransmit = FirstPacket;
622:
623: Reserved->Next = NULL;
624:
625: --Adapter->GeneralOptional[GO_TRANSMIT_QUEUE_LENGTH - GO_ARRAY_START];
626:
627: //
628: // We have the number of buffers that we need.
629: // We assign all of the buffers to the ring entries.
630: //
631:
632: AssignPacketToDescriptor(
633: Adapter,
634: FirstPacket,
635: DescriptorIndex
636: );
637:
638: RelinquishPacket(
639: Adapter,
640: FirstPacket,
641: DescriptorIndex
642: );
643:
644: } else {
645:
646: Adapter->SendStageOpen = FALSE;
647:
648: }
649:
650: }
651:
652: STATIC
653: BOOLEAN
654: ConstrainPacket(
655: IN PSONIC_ADAPTER Adapter,
656: IN PNDIS_PACKET Packet
657: )
658:
659: /*++
660:
661: Routine Description:
662:
663: Given a packet and necessary attempt to acquire adapter
664: buffer resources so that the packet meets sonic hardware
665: contraints. If a buffer is needed and is not available then
666: stage is closed.
667:
668: The constraints are that the packet must have SONIC_MAX_FRAGMENTS
669: or fewer physical pieces and no piece may be less than
670: SONIC_MIN_PIECE_SIZE bytes. The first constraint is based on
671: the size of the SONIC_TRANSMIT_DESCRIPTOR, and the second
672: is to prevent underflow in the Silo.
673:
674: If a packet violates either of the constraints then it
675: will be copied in its entirety into an adapter buffer.
676:
677: NOTE: Called with lock held!!
678:
679: Arguments:
680:
681: Adapter - The adapter the packet is coming through.
682:
683: Packet - The packet whose buffers are to be constrained.
684: The packet reserved section is filled with information
685: detailing how the packet needs to be adjusted.
686:
687: Return Value:
688:
689: Returns TRUE if the packet is suitable for the hardware.
690:
691: --*/
692:
693: {
694:
695: //
696: // Pointer to the reserved section of the packet to be contrained.
697: //
698: PSONIC_PACKET_RESERVED Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
699:
700: //
701: // Holds the adapter buffer index available for allocation.
702: //
703: INT SonicBuffersIndex;
704:
705: //
706: // Points to a successfully allocated adapter buffer descriptor.
707: //
708: PSONIC_BUFFER_DESCRIPTOR BufferDescriptor;
709:
710: //
711: // Will point into the virtual address space addressed
712: // by the adapter buffer if one was successfully allocated.
713: //
714: PCHAR CurrentDestination;
715:
716: //
717: // Will hold the total amount of data copied to the
718: // adapter buffer.
719: //
720: UINT TotalDataMoved = 0;
721:
722: //
723: // Will point to the current source buffer.
724: //
725: PNDIS_BUFFER SourceBuffer;
726:
727: //
728: // Points to the virtual address of the source buffers data.
729: //
730: PVOID SourceData;
731:
732: //
733: // Will point to the number of bytes of data in the source
734: // buffer.
735: //
736: UINT SourceLength;
737:
738: //
739: // Simple iteration variable.
740: //
741: INT i;
742:
743: if (Reserved->PacketLength <= SONIC_SMALL_BUFFER_SIZE) {
744:
745: i = 1;
746:
747: } else if (Reserved->PacketLength <= SONIC_MEDIUM_BUFFER_SIZE) {
748:
749: i = 2;
750:
751: } else {
752:
753: i = 3;
754:
755: }
756:
757:
758: for (
759: ;
760: i <= 3;
761: i++
762: ) {
763:
764: if ((SonicBuffersIndex = Adapter->SonicBufferListHeads[i]) != -1) {
765:
766: BufferDescriptor = Adapter->SonicBuffers + SonicBuffersIndex;
767: Adapter->SonicBufferListHeads[i] = BufferDescriptor->Next;
768: break;
769:
770: }
771:
772: }
773:
774: if (SonicBuffersIndex == -1) {
775:
776: //
777: // Nothing available for the packet.
778: //
779:
780: Adapter->SendStageOpen = FALSE;
781:
782: return FALSE;
783:
784: }
785:
786: NdisReleaseSpinLock(&Adapter->Lock);
787:
788: //
789: // Save the list head index in the buffer descriptor
790: // to permit easy deallocation later.
791: //
792:
793: BufferDescriptor->Next = i;
794:
795: //
796: // Fill in the adapter buffer with the data from the users
797: // buffers.
798: //
799:
800: CurrentDestination = BufferDescriptor->VirtualSonicBuffer;
801:
802: NdisQueryPacket(
803: Packet,
804: NULL,
805: NULL,
806: &SourceBuffer,
807: NULL
808: );
809:
810: while (SourceBuffer) {
811:
812: NdisQueryBuffer(
813: SourceBuffer,
814: &SourceData,
815: &SourceLength
816: );
817:
818: SONIC_MOVE_MEMORY(
819: CurrentDestination,
820: SourceData,
821: SourceLength
822: );
823:
824: CurrentDestination = (PCHAR)CurrentDestination + SourceLength;
825:
826: TotalDataMoved += SourceLength;
827:
828: NdisGetNextBuffer(
829: SourceBuffer,
830: &SourceBuffer
831: );
832:
833: }
834:
835: //
836: // If the packet is less then the minimum size then we
837: // need to zero out the rest of the packet.
838: //
839:
840: if (TotalDataMoved < SONIC_MIN_PACKET_SIZE) {
841:
842: SONIC_ZERO_MEMORY(
843: CurrentDestination,
844: SONIC_MIN_PACKET_SIZE - TotalDataMoved
845: );
846:
847: BufferDescriptor->DataLength = SONIC_MIN_PACKET_SIZE;
848:
849: } else {
850:
851: BufferDescriptor->DataLength = TotalDataMoved;
852:
853: }
854:
855: NdisAcquireSpinLock(&Adapter->Lock);
856:
857: //
858: // We need to save in the packet which adapter buffer descriptor
859: // it is using so that we can deallocate it later.
860: //
861:
862: Reserved->SonicBuffersIndex = SonicBuffersIndex;
863:
864: return TRUE;
865: }
866:
867: STATIC
868: VOID
869: CalculatePacketConstraints(
870: IN PSONIC_ADAPTER Adapter,
871: IN PNDIS_PACKET Packet
872: )
873:
874: /*++
875:
876: Routine Description:
877:
878: Given a packet calculate how the packet will have to be
879: adjusted to meet with hardware constraints.
880:
881: The constraints are that the packet must have SONIC_MAX_FRAGMENTS
882: or fewer physical pieces and no piece may be less than
883: SONIC_MIN_FRAGMENT_SIZE bytes. The first constraint is based on
884: the size of the SONIC_TRANSMIT_DESCRIPTOR, and the second
885: is to prevent underflow in the Silo.
886:
887: If the packet is found to violate the constraints, then
888: UsedSonicBuffer will be set to TRUE. This will cause the entire packet to
889: be copied into the adapter buffer (which is guaranteed
890: to be physically contiguous).
891:
892: Note: This is called with the lock held! Merely for convience to
893: reduce the number of times we acquire and release the spinlock.
894:
895: Arguments:
896:
897: Adapter - The adapter the packet is coming through.
898:
899: Packet - The packet whose buffers are to be reallocated.
900: The packet reserved section is filled with information
901: detailing how the packet needs to be adjusted.
902:
903: Return Value:
904:
905: None.
906:
907: --*/
908:
909: {
910:
911: //
912: // Points to the MacReserved portion of the packet.
913: //
914: PSONIC_PACKET_RESERVED Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
915:
916: //
917: // The number of physical buffers in the entire packet.
918: //
919: UINT PacketPhysicalSegments;
920:
921: //
922: // Points to the current ndis buffer being walked.
923: //
924: PNDIS_BUFFER CurrentBuffer;
925:
926: //
927: // The virtual address of the current ndis buffer.
928: //
929: PVOID BufferVirtualAddress;
930:
931: //
932: // The length in bytes of the current ndis buffer.
933: //
934: UINT BufferVirtualLength;
935:
936: //
937: // The total amount of data contained within the ndis packet.
938: //
939: UINT PacketVirtualLength;
940:
941: //
942: // The number of physical buffers in a single buffer.
943: //
944: UINT BufferPhysicalSegments;
945:
946: //
947: // TRUE once we find a constraint violation
948: //
949: BOOLEAN ViolatedConstraints = FALSE;
950:
951: #ifndef NO_CHIP_FIXUP
952: //
953: // Used to keep track of the total number of fragments
954: // that the packet will occupy when assigned to a
955: // transmit descriptor (may be more than PacketPhysicalSegments
956: // if we have to worry about packets starting or ending
957: // on non-longword boundaries.
958: //
959: UINT TotalTransmitSegments = 0;
960: #endif
961:
962:
963:
964: //
965: // Get the first buffer in the packet.
966: //
967:
968: NdisQueryPacket(
969: Packet,
970: &PacketPhysicalSegments,
971: NULL,
972: &CurrentBuffer,
973: &PacketVirtualLength
974: );
975:
976: //
977: // Save this value for later
978: //
979:
980: Reserved->PacketLength = PacketVirtualLength;
981:
982: //
983: // We only allow SONIC_MAX_FRAGMENTS physical pieces.
984: //
985:
986: if (PacketPhysicalSegments > SONIC_MAX_FRAGMENTS) {
987: ViolatedConstraints = TRUE;
988: goto DoneExamining;
989: }
990:
991: //
992: // For short packets we can only allow SONIC_MAX_FRAGMENTS-1
993: // (to allow for the blank padding buffer). Also, we can't
994: // allow the padding itself to be less than the minimum
995: // fragment size.
996: //
997:
998: if (PacketVirtualLength < SONIC_MIN_PACKET_SIZE &&
999: ((PacketPhysicalSegments > (SONIC_MAX_FRAGMENTS-1)) ||
1000: (PacketVirtualLength >
1001: (SONIC_MIN_PACKET_SIZE - SONIC_MIN_FRAGMENT_SIZE)))) {
1002: ViolatedConstraints = TRUE;
1003: goto DoneExamining;
1004: }
1005:
1006:
1007: //
1008: // Now loop making sure no fragment is less than
1009: // SONIC_MIN_FRAGMENT_SIZE bytes.
1010: //
1011:
1012: while (CurrentBuffer) {
1013:
1014: NdisQueryBuffer(
1015: CurrentBuffer,
1016: &BufferVirtualAddress,
1017: &BufferVirtualLength
1018: );
1019:
1020:
1021: //
1022: // See if there is only one piece in the buffer.
1023: //
1024:
1025: NdisGetBufferPhysicalArraySize(
1026: CurrentBuffer,
1027: &BufferPhysicalSegments
1028: );
1029:
1030: if (BufferPhysicalSegments == 1) {
1031:
1032: //
1033: // Only one piece, make sure it is large enough.
1034: //
1035:
1036: if (BufferVirtualLength < SONIC_MIN_FRAGMENT_SIZE) {
1037: ViolatedConstraints = TRUE;
1038: goto DoneExamining;
1039: }
1040:
1041: #ifndef NO_CHIP_FIXUP
1042:
1043: //
1044: // See if the beginning AND end of this piece are
1045: // not longword-aligned.
1046: //
1047:
1048: if (((ULONG)BufferVirtualAddress & 0x03) &&
1049: (((ULONG)BufferVirtualAddress + BufferVirtualLength) & 0x03)) {
1050:
1051: //
1052: // Now see if this piece is large enough to
1053: // be split into two.
1054: //
1055:
1056: if (BufferVirtualLength >
1057: (UINT)(4 - ((ULONG)BufferVirtualAddress & 0x03) +
1058: (2*SONIC_MIN_FRAGMENT_SIZE))) {
1059:
1060: //
1061: // Have enough to let the first fragment be
1062: // SONIC_MIN_FRAGMENT_SIZE plus the extra
1063: // few bytes at the beginning, and the
1064: // second piece SONIC_MIN_FRAGMENT_SIZE.
1065: //
1066:
1067: TotalTransmitSegments += 2;
1068:
1069: } else {
1070:
1071: ViolatedConstraints = TRUE;
1072: goto DoneExamining;
1073:
1074: }
1075:
1076: } else {
1077:
1078: //
1079: // This piece won't have to be split, so
1080: // just count it as one.
1081: //
1082:
1083: TotalTransmitSegments += 1;
1084:
1085: }
1086:
1087: #endif
1088:
1089: } else {
1090:
1091: //
1092: // Multiple pieces. We assume that the relevant low bits
1093: // will be the same in a physical and virtual address, so
1094: // we can check using the virtual address whether a
1095: // physical segment may be too short (we are being over-
1096: // cautious here, but this allows us to avoid actually
1097: // querying the physical addresses here.
1098: //
1099:
1100: //
1101: // See if this buffer starts less than MIN_FRAGMENT_SIZE
1102: // bytes before a page boundary.
1103: //
1104:
1105: if (PAGE_SIZE - ((ULONG)BufferVirtualAddress & (PAGE_SIZE-1)) <
1106: SONIC_MIN_FRAGMENT_SIZE) {
1107: ViolatedConstraints = TRUE;
1108: goto DoneExamining;
1109: }
1110:
1111: //
1112: // See if this buffer ends less than MIN_FRAGMENT_SIZE
1113: // bytes after a page boundary.
1114: //
1115:
1116: if (((ULONG)BufferVirtualAddress + BufferVirtualLength) & (PAGE_SIZE-1) <
1117: SONIC_MIN_FRAGMENT_SIZE) {
1118: ViolatedConstraints = TRUE;
1119: goto DoneExamining;
1120: }
1121:
1122: #ifndef NO_CHIP_FIXUP
1123:
1124: //
1125: // Add the number of fragments in this piece.
1126: // We assume that physical gaps will always be
1127: // on at least a 4 byte boundary, so we won't
1128: // need to split this piece.
1129: //
1130:
1131: TotalTransmitSegments += BufferPhysicalSegments;
1132:
1133: #endif
1134:
1135: }
1136:
1137:
1138: NdisGetNextBuffer(
1139: CurrentBuffer,
1140: &CurrentBuffer
1141: );
1142:
1143: }
1144:
1145:
1146: #ifndef NO_CHIP_FIXUP
1147:
1148: //
1149: // If the packet is short, we have to allow for the
1150: // padding fragment at the end.
1151: //
1152:
1153: if (PacketVirtualLength < SONIC_MIN_PACKET_SIZE) {
1154:
1155: TotalTransmitSegments += 1;
1156:
1157: }
1158:
1159: #endif
1160:
1161:
1162: DoneExamining: ;
1163:
1164: #ifndef NO_CHIP_FIXUP
1165: if (ViolatedConstraints || (TotalTransmitSegments > SONIC_MAX_FRAGMENTS)) {
1166: #else
1167: if (ViolatedConstraints) {
1168: #endif
1169:
1170: Reserved->UsedSonicBuffer = TRUE;
1171:
1172: } else {
1173:
1174: Reserved->UsedSonicBuffer = FALSE;
1175:
1176: }
1177:
1178: }
1179:
1180: STATIC
1181: VOID
1182: AssignPacketToDescriptor(
1183: IN PSONIC_ADAPTER Adapter,
1184: IN PNDIS_PACKET Packet,
1185: IN UINT DescriptorIndex
1186: )
1187:
1188: /*++
1189:
1190: Routine Description:
1191:
1192: Given a packet and a ring index, assign all of the buffers
1193: in the packet to ring entries.
1194:
1195: NOTE : Called with lock held!!
1196:
1197: Arguments:
1198:
1199: Adapter - The adapter that the packets are coming through.
1200:
1201: Packet - The packet whose buffers are to be assigned
1202: ring entries.
1203:
1204: DescriptorIndex - The index of the start of the ring entries to
1205: be assigned buffers.
1206:
1207: Return Value:
1208:
1209: None.
1210:
1211: --*/
1212:
1213: {
1214:
1215: //
1216: // Points to the reserved portion of the packet.
1217: //
1218: PSONIC_PACKET_RESERVED Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
1219:
1220: //
1221: // Pointer to the ring entry to be filled with buffer information.
1222: //
1223: PSONIC_TRANSMIT_DESCRIPTOR TransmitDescriptor = Adapter->TransmitDescriptorArea
1224: + DescriptorIndex;
1225:
1226: //
1227: // Pointer to the ring to packet entry that records the info about
1228: // this packet.
1229: //
1230: PSONIC_DESCRIPTOR_TO_PACKET DescriptorToPacket = Adapter->DescriptorToPacket + DescriptorIndex;
1231:
1232: //
1233: // The total amount of data in the ndis packet.
1234: //
1235: UINT TotalDataLength;
1236:
1237: //
1238: // Points to the current ndis buffer being walked.
1239: //
1240: PNDIS_BUFFER CurrentBuffer;
1241:
1242: //
1243: // The number of physical segments in this buffer.
1244: //
1245: UINT BufferPhysicalSegments;
1246:
1247: //
1248: // An array to hold the physical segments.
1249: //
1250: NDIS_PHYSICAL_ADDRESS_UNIT PhysicalSegmentArray[SONIC_MAX_FRAGMENTS];
1251:
1252: //
1253: // We record the owning packet information in the ring packet packet
1254: // structure.
1255: //
1256:
1257:
1258: DescriptorToPacket->OwningPacket = Packet;
1259: DescriptorToPacket->UsedSonicBuffer = (BOOLEAN)
1260: Reserved->UsedSonicBuffer;
1261: DescriptorToPacket->SonicBuffersIndex =
1262: Reserved->SonicBuffersIndex;
1263:
1264:
1265: //
1266: // First initialize the fields that don't depend on
1267: // how many fragments there are in the packet.
1268: //
1269:
1270: TransmitDescriptor->TransmitStatus = 0;
1271:
1272: //
1273: // Set the programmable interrupt if it has been a long
1274: // time since transmit complete interrupts were processed.
1275: //
1276:
1277: if (Adapter->PacketsSinceLastInterrupt >=
1278: (SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS/2)) {
1279:
1280: TransmitDescriptor->TransmitConfiguration = (UINT)SONIC_TCR_PROG_INTERRUPT;
1281: Adapter->PacketsSinceLastInterrupt = 0;
1282:
1283: } else {
1284:
1285: TransmitDescriptor->TransmitConfiguration = 0;
1286: ++Adapter->PacketsSinceLastInterrupt;
1287:
1288: }
1289:
1290:
1291: //
1292: // Now check to see if the packet has been copied into an
1293: // adapter buffer.
1294: //
1295:
1296: if (Reserved->UsedSonicBuffer) {
1297:
1298: //
1299: // Points to the adapter buffer descriptor allocated
1300: // for this packet.
1301: //
1302: PSONIC_BUFFER_DESCRIPTOR BufferDescriptor;
1303:
1304: BufferDescriptor = Adapter->SonicBuffers
1305: + Reserved->SonicBuffersIndex;
1306:
1307: TransmitDescriptor->FragmentCount = 1;
1308: TransmitDescriptor->PacketSize = (UINT)BufferDescriptor->DataLength;
1309:
1310: SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(
1311: &(TransmitDescriptor->Fragments[0]),
1312: NdisGetPhysicalAddressLow(BufferDescriptor->PhysicalSonicBuffer)
1313: );
1314:
1315: SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
1316: &(TransmitDescriptor->Fragments[0]),
1317: BufferDescriptor->DataLength
1318: );
1319:
1320:
1321: //
1322: // This sets end-of-list for this descriptor.
1323: //
1324:
1325: SONIC_SET_TRANSMIT_LINK(
1326: &(TransmitDescriptor->Fragments[1]),
1327: TransmitDescriptor->Link
1328: );
1329:
1330: DescriptorToPacket->LinkPointer = (SONIC_PHYSICAL_ADDRESS *)
1331: &(TransmitDescriptor->Fragments[1]);
1332:
1333:
1334: //
1335: // Flush the buffer that contains the packet.
1336: //
1337:
1338: SONIC_FLUSH_WRITE_BUFFER(BufferDescriptor->FlushBuffer);
1339:
1340: } else {
1341:
1342: //
1343: // The total length of the packet (including padding)
1344: //
1345: UINT TotalPacketLength;
1346:
1347: //
1348: // Which fragment we are filling;
1349: //
1350: UINT CurFragment;
1351:
1352: //
1353: // Which map register we use for this buffer.
1354: //
1355: UINT CurMapRegister;
1356:
1357: //
1358: // Simple iteration variable.
1359: //
1360: UINT i;
1361:
1362:
1363: CurFragment = 0;
1364: CurMapRegister = DescriptorIndex * SONIC_MAX_FRAGMENTS;
1365:
1366: NdisQueryPacket(
1367: Packet,
1368: NULL,
1369: NULL,
1370: &CurrentBuffer,
1371: &TotalDataLength
1372: );
1373:
1374:
1375: while (CurrentBuffer) {
1376:
1377: NdisStartBufferPhysicalMapping(
1378: Adapter->NdisAdapterHandle,
1379: CurrentBuffer,
1380: CurMapRegister,
1381: TRUE,
1382: PhysicalSegmentArray,
1383: &BufferPhysicalSegments
1384: );
1385:
1386: ++CurMapRegister;
1387:
1388: //
1389: // Put the physical segments for this buffer into
1390: // the transmit descriptors.
1391: //
1392:
1393: for (i=0; i<BufferPhysicalSegments; i++) {
1394:
1395: ASSERT (NdisGetPhysicalAddressHigh(PhysicalSegmentArray[i].PhysicalAddress) == 0);
1396:
1397: SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(
1398: &(TransmitDescriptor->Fragments[CurFragment]),
1399: NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress)
1400: );
1401:
1402: SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
1403: &(TransmitDescriptor->Fragments[CurFragment]),
1404: PhysicalSegmentArray[i].Length
1405: );
1406:
1407: ++CurFragment;
1408:
1409: #ifndef NO_CHIP_FIXUP
1410:
1411: //
1412: // If the fragment starts and ends not on a longword
1413: // boundary, split it into two fragments, the first
1414: // being SONIC_MIN_FRAGMENT_SIZE plus the extra bits
1415: // at the beginning, the other the rest.
1416: //
1417:
1418: if ((NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress) & 0x03) &&
1419: ((NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress) + PhysicalSegmentArray[i].Length) & 0x03)) {
1420:
1421: UINT FirstSegmentLength;
1422:
1423: FirstSegmentLength = (4 - ((NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress) & 0x03))) +
1424: SONIC_MIN_FRAGMENT_SIZE;
1425:
1426: SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
1427: &(TransmitDescriptor->Fragments[CurFragment-1]),
1428: FirstSegmentLength
1429: );
1430:
1431: SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(
1432: &(TransmitDescriptor->Fragments[CurFragment]),
1433: SONIC_GET_TRANSMIT_FRAGMENT_ADDRESS(
1434: &(TransmitDescriptor->Fragments[CurFragment-1])) +
1435: FirstSegmentLength
1436: );
1437:
1438: SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
1439: &(TransmitDescriptor->Fragments[CurFragment]),
1440: PhysicalSegmentArray[i].Length - FirstSegmentLength
1441: );
1442:
1443: ++CurFragment;
1444:
1445: }
1446: #endif
1447: }
1448:
1449:
1450: SONIC_FLUSH_WRITE_BUFFER (CurrentBuffer);
1451:
1452: NdisGetNextBuffer(
1453: CurrentBuffer,
1454: &CurrentBuffer
1455: );
1456:
1457: }
1458:
1459: if (TotalDataLength < SONIC_MIN_PACKET_SIZE) {
1460:
1461: SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(
1462: &(TransmitDescriptor->Fragments[CurFragment]),
1463: NdisGetPhysicalAddressLow(Adapter->BlankBufferAddress)
1464: );
1465:
1466: SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
1467: &(TransmitDescriptor->Fragments[CurFragment]),
1468: SONIC_MIN_PACKET_SIZE - TotalDataLength
1469: );
1470:
1471: //
1472: // Note that BlankBuffer has already been flushed.
1473: //
1474:
1475: ++CurFragment;
1476:
1477: TotalPacketLength = SONIC_MIN_PACKET_SIZE;
1478:
1479: } else {
1480:
1481: TotalPacketLength = TotalDataLength;
1482:
1483: }
1484:
1485: //
1486: // Make sure we didn't mess up and use up too
1487: // many fragments.
1488: //
1489: ASSERT(CurFragment <= SONIC_MAX_FRAGMENTS);
1490:
1491: TransmitDescriptor->FragmentCount = (UINT)CurFragment;
1492: TransmitDescriptor->PacketSize = (UINT)TotalPacketLength;
1493:
1494:
1495: //
1496: // This sets end-of-list for this descriptor.
1497: //
1498:
1499: SONIC_SET_TRANSMIT_LINK(
1500: &(TransmitDescriptor->Fragments[CurFragment]),
1501: TransmitDescriptor->Link
1502: );
1503:
1504: DescriptorToPacket->LinkPointer = (SONIC_PHYSICAL_ADDRESS *)
1505: &(TransmitDescriptor->Fragments[CurFragment]);
1506:
1507: }
1508:
1509: if (DescriptorIndex == (Adapter->NumberOfTransmitDescriptors-1)) {
1510:
1511: Adapter->DescriptorToPacket->PrevLinkPointer = DescriptorToPacket->LinkPointer;
1512:
1513: } else {
1514:
1515: (DescriptorToPacket+1)->PrevLinkPointer = DescriptorToPacket->LinkPointer;
1516:
1517: }
1518:
1519: Reserved->DescriptorIndex = DescriptorIndex;
1520:
1521: }
1522:
1523: STATIC
1524: VOID
1525: RelinquishPacket(
1526: IN PSONIC_ADAPTER Adapter,
1527: IN PNDIS_PACKET Packet,
1528: IN UINT RingIndex
1529: )
1530:
1531: /*++
1532:
1533: Routine Description:
1534:
1535: Relinquish the ring entries owned by the packet to the chip.
1536: We also update the first uncommitted ring pointer.
1537:
1538: NOTE: Called with the lock held!!
1539:
1540: Arguments:
1541:
1542: Adapter - The adapter that points to the ring entry structures.
1543:
1544: Packet - The packet contains the ring index of the ring
1545: entry for the packet.
1546:
1547: RingIndex - Holds the index of the ring entry used
1548: by this packet.
1549:
1550: Return Value:
1551:
1552: None.
1553:
1554: --*/
1555:
1556: {
1557:
1558: //
1559: // Holds the previous link pointer, where we turn off
1560: // end-of-list.
1561: //
1562:
1563: PSONIC_PHYSICAL_ADDRESS PrevLinkPointer;
1564:
1565: #ifdef NDIS_NT
1566:
1567: //
1568: // NOTE: We have to raise the IRQL to POWER_LEVEL around the
1569: // calls to SONIC_REMOVE_END_OF_LIST and START_TRANSMIT.
1570: // This is to prevent a delay between these two instructions.
1571: // If a delay happens right after SONIC_REMOVE_END_OF_LIST, the
1572: // Sonic could transmit the packet and stop, then the call
1573: // to START_TRANSMIT would cause it to retransmit all the
1574: // packets in the descriptor ring.
1575: //
1576: KIRQL OldIrql;
1577:
1578: #endif
1579:
1580:
1581: PrevLinkPointer = Adapter->DescriptorToPacket[RingIndex].PrevLinkPointer;
1582:
1583: #ifdef NDIS_NT
1584:
1585: //
1586: // See NOTE above.
1587: //
1588:
1589: KeRaiseIrql(POWER_LEVEL, &OldIrql);
1590:
1591: #endif
1592:
1593:
1594: //
1595: // Turn off END_OF_LIST for the last one.
1596: //
1597:
1598: SONIC_REMOVE_END_OF_LIST(PrevLinkPointer);
1599:
1600: //
1601: // This turns on the correct bit in the SONIC_CONTROL
1602: // register.
1603: //
1604:
1605: START_TRANSMIT(Adapter);
1606:
1607:
1608: #ifdef NDIS_NT
1609:
1610: //
1611: // See NOTE above.
1612: //
1613:
1614: KeLowerIrql(OldIrql);
1615:
1616: #endif
1617:
1618: //
1619: // We want FirstUncommittedDescriptor to point to right after us.
1620: //
1621:
1622: if (RingIndex == (Adapter->NumberOfTransmitDescriptors-1)) {
1623:
1624: Adapter->FirstUncommittedDescriptor = Adapter->TransmitDescriptorArea;
1625:
1626: } else {
1627:
1628: Adapter->FirstUncommittedDescriptor =
1629: Adapter->TransmitDescriptorArea + (RingIndex + 1);
1630:
1631: }
1632:
1633: }
1634:
1635:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.