|
|
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.