xref: /reactos/drivers/network/dd/nvnet/send.c (revision b79fbe23)
1*b79fbe23SDmitry Borisov /*
2*b79fbe23SDmitry Borisov  * PROJECT:     ReactOS nVidia nForce Ethernet Controller Driver
3*b79fbe23SDmitry Borisov  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4*b79fbe23SDmitry Borisov  * PURPOSE:     Packet sending
5*b79fbe23SDmitry Borisov  * COPYRIGHT:   Copyright 2021-2022 Dmitry Borisov <di.sean@protonmail.com>
6*b79fbe23SDmitry Borisov  */
7*b79fbe23SDmitry Borisov 
8*b79fbe23SDmitry Borisov /* INCLUDES *******************************************************************/
9*b79fbe23SDmitry Borisov 
10*b79fbe23SDmitry Borisov #include "nvnet.h"
11*b79fbe23SDmitry Borisov 
12*b79fbe23SDmitry Borisov #define NDEBUG
13*b79fbe23SDmitry Borisov #include "debug.h"
14*b79fbe23SDmitry Borisov 
15*b79fbe23SDmitry Borisov /* FUNCTIONS ******************************************************************/
16*b79fbe23SDmitry Borisov 
17*b79fbe23SDmitry Borisov VOID
NvNetTransmitPacket32(_In_ PNVNET_ADAPTER Adapter,_In_ PNVNET_TCB Tcb,_In_ PSCATTER_GATHER_LIST SgList)18*b79fbe23SDmitry Borisov NvNetTransmitPacket32(
19*b79fbe23SDmitry Borisov     _In_ PNVNET_ADAPTER Adapter,
20*b79fbe23SDmitry Borisov     _In_ PNVNET_TCB Tcb,
21*b79fbe23SDmitry Borisov     _In_ PSCATTER_GATHER_LIST SgList)
22*b79fbe23SDmitry Borisov {
23*b79fbe23SDmitry Borisov     NVNET_TBD Tbd, LastTbd;
24*b79fbe23SDmitry Borisov     ULONG i, Flags;
25*b79fbe23SDmitry Borisov     ULONG Slots;
26*b79fbe23SDmitry Borisov 
27*b79fbe23SDmitry Borisov     Flags = 0;
28*b79fbe23SDmitry Borisov     Slots = 0;
29*b79fbe23SDmitry Borisov     Tbd = Adapter->Send.CurrentTbd;
30*b79fbe23SDmitry Borisov 
31*b79fbe23SDmitry Borisov     for (i = 0; i < SgList->NumberOfElements; ++i)
32*b79fbe23SDmitry Borisov     {
33*b79fbe23SDmitry Borisov         ULONG Address = NdisGetPhysicalAddressLow(SgList->Elements[i].Address);
34*b79fbe23SDmitry Borisov         ULONG Length = SgList->Elements[i].Length;
35*b79fbe23SDmitry Borisov 
36*b79fbe23SDmitry Borisov         if (Length > NV_MAXIMUM_SG_SIZE)
37*b79fbe23SDmitry Borisov         {
38*b79fbe23SDmitry Borisov             ULONG ImplicitEntries = NV_IMPLICIT_ENTRIES(Length);
39*b79fbe23SDmitry Borisov 
40*b79fbe23SDmitry Borisov             do
41*b79fbe23SDmitry Borisov             {
42*b79fbe23SDmitry Borisov                 ++Slots;
43*b79fbe23SDmitry Borisov 
44*b79fbe23SDmitry Borisov                 Tbd.x32->Address = Address;
45*b79fbe23SDmitry Borisov                 Tbd.x32->FlagsLength = Flags | (NV_MAXIMUM_SG_SIZE - 1);
46*b79fbe23SDmitry Borisov                 LastTbd = Tbd;
47*b79fbe23SDmitry Borisov                 Tbd = NV_NEXT_TBD_32(Adapter, Tbd);
48*b79fbe23SDmitry Borisov 
49*b79fbe23SDmitry Borisov                 Flags = NV_TX_VALID;
50*b79fbe23SDmitry Borisov 
51*b79fbe23SDmitry Borisov                 Length -= NV_MAXIMUM_SG_SIZE;
52*b79fbe23SDmitry Borisov                 Address += NV_MAXIMUM_SG_SIZE;
53*b79fbe23SDmitry Borisov 
54*b79fbe23SDmitry Borisov                 --ImplicitEntries;
55*b79fbe23SDmitry Borisov             }
56*b79fbe23SDmitry Borisov             while (ImplicitEntries);
57*b79fbe23SDmitry Borisov         }
58*b79fbe23SDmitry Borisov 
59*b79fbe23SDmitry Borisov         ++Slots;
60*b79fbe23SDmitry Borisov 
61*b79fbe23SDmitry Borisov         Tbd.x32->Address = Address;
62*b79fbe23SDmitry Borisov         Tbd.x32->FlagsLength = Flags | (Length - 1);
63*b79fbe23SDmitry Borisov         LastTbd = Tbd;
64*b79fbe23SDmitry Borisov         Tbd = NV_NEXT_TBD_32(Adapter, Tbd);
65*b79fbe23SDmitry Borisov 
66*b79fbe23SDmitry Borisov         Flags = NV_TX_VALID;
67*b79fbe23SDmitry Borisov     }
68*b79fbe23SDmitry Borisov 
69*b79fbe23SDmitry Borisov     Tcb->Slots = Slots;
70*b79fbe23SDmitry Borisov     Tcb->Tbd = LastTbd;
71*b79fbe23SDmitry Borisov 
72*b79fbe23SDmitry Borisov     if (Adapter->Features & DEV_HAS_LARGEDESC)
73*b79fbe23SDmitry Borisov     {
74*b79fbe23SDmitry Borisov         LastTbd.x32->FlagsLength |= NV_TX2_LASTPACKET;
75*b79fbe23SDmitry Borisov     }
76*b79fbe23SDmitry Borisov     else
77*b79fbe23SDmitry Borisov     {
78*b79fbe23SDmitry Borisov         LastTbd.x32->FlagsLength |= NV_TX_LASTPACKET;
79*b79fbe23SDmitry Borisov     }
80*b79fbe23SDmitry Borisov 
81*b79fbe23SDmitry Borisov     if (Tcb->Flags & NV_TCB_LARGE_SEND)
82*b79fbe23SDmitry Borisov     {
83*b79fbe23SDmitry Borisov         Flags |= (Tcb->Mss << NV_TX2_TSO_SHIFT) | NV_TX2_TSO;
84*b79fbe23SDmitry Borisov     }
85*b79fbe23SDmitry Borisov     else
86*b79fbe23SDmitry Borisov     {
87*b79fbe23SDmitry Borisov         if (Tcb->Flags & NV_TCB_CHECKSUM_IP)
88*b79fbe23SDmitry Borisov         {
89*b79fbe23SDmitry Borisov             Flags |= NV_TX2_CHECKSUM_L3;
90*b79fbe23SDmitry Borisov         }
91*b79fbe23SDmitry Borisov         if (Tcb->Flags & (NV_TCB_CHECKSUM_TCP | NV_TCB_CHECKSUM_UDP))
92*b79fbe23SDmitry Borisov         {
93*b79fbe23SDmitry Borisov             Flags |= NV_TX2_CHECKSUM_L4;
94*b79fbe23SDmitry Borisov         }
95*b79fbe23SDmitry Borisov     }
96*b79fbe23SDmitry Borisov 
97*b79fbe23SDmitry Borisov     Adapter->Send.CurrentTbd.x32->FlagsLength |= Flags;
98*b79fbe23SDmitry Borisov     Adapter->Send.CurrentTbd = Tbd;
99*b79fbe23SDmitry Borisov 
100*b79fbe23SDmitry Borisov     NV_WRITE(Adapter, NvRegTxRxControl, Adapter->TxRxControl | NVREG_TXRXCTL_KICK);
101*b79fbe23SDmitry Borisov }
102*b79fbe23SDmitry Borisov 
103*b79fbe23SDmitry Borisov VOID
NvNetTransmitPacket64(_In_ PNVNET_ADAPTER Adapter,_In_ PNVNET_TCB Tcb,_In_ PSCATTER_GATHER_LIST SgList)104*b79fbe23SDmitry Borisov NvNetTransmitPacket64(
105*b79fbe23SDmitry Borisov     _In_ PNVNET_ADAPTER Adapter,
106*b79fbe23SDmitry Borisov     _In_ PNVNET_TCB Tcb,
107*b79fbe23SDmitry Borisov     _In_ PSCATTER_GATHER_LIST SgList)
108*b79fbe23SDmitry Borisov {
109*b79fbe23SDmitry Borisov     NVNET_TBD Tbd, LastTbd;
110*b79fbe23SDmitry Borisov     ULONG i, Flags;
111*b79fbe23SDmitry Borisov     ULONG Slots;
112*b79fbe23SDmitry Borisov 
113*b79fbe23SDmitry Borisov     Flags = 0;
114*b79fbe23SDmitry Borisov     Slots = 0;
115*b79fbe23SDmitry Borisov     Tbd = Adapter->Send.CurrentTbd;
116*b79fbe23SDmitry Borisov 
117*b79fbe23SDmitry Borisov     for (i = 0; i < SgList->NumberOfElements; ++i)
118*b79fbe23SDmitry Borisov     {
119*b79fbe23SDmitry Borisov         ULONG64 Address = SgList->Elements[i].Address.QuadPart;
120*b79fbe23SDmitry Borisov         ULONG Length = SgList->Elements[i].Length;
121*b79fbe23SDmitry Borisov 
122*b79fbe23SDmitry Borisov         if (Length > NV_MAXIMUM_SG_SIZE)
123*b79fbe23SDmitry Borisov         {
124*b79fbe23SDmitry Borisov             ULONG ImplicitEntries = NV_IMPLICIT_ENTRIES(Length);
125*b79fbe23SDmitry Borisov 
126*b79fbe23SDmitry Borisov             do
127*b79fbe23SDmitry Borisov             {
128*b79fbe23SDmitry Borisov                 ++Slots;
129*b79fbe23SDmitry Borisov 
130*b79fbe23SDmitry Borisov                 Tbd.x64->AddressLow = (ULONG)Address;
131*b79fbe23SDmitry Borisov                 Tbd.x64->AddressHigh = Address >> 32;
132*b79fbe23SDmitry Borisov                 Tbd.x64->VlanTag = 0;
133*b79fbe23SDmitry Borisov                 Tbd.x64->FlagsLength = Flags | (NV_MAXIMUM_SG_SIZE - 1);
134*b79fbe23SDmitry Borisov                 LastTbd = Tbd;
135*b79fbe23SDmitry Borisov                 Tbd = NV_NEXT_TBD_64(Adapter, Tbd);
136*b79fbe23SDmitry Borisov 
137*b79fbe23SDmitry Borisov                 Flags = NV_TX2_VALID;
138*b79fbe23SDmitry Borisov 
139*b79fbe23SDmitry Borisov                 Length -= NV_MAXIMUM_SG_SIZE;
140*b79fbe23SDmitry Borisov                 Address += NV_MAXIMUM_SG_SIZE;
141*b79fbe23SDmitry Borisov 
142*b79fbe23SDmitry Borisov                 --ImplicitEntries;
143*b79fbe23SDmitry Borisov             }
144*b79fbe23SDmitry Borisov             while (ImplicitEntries);
145*b79fbe23SDmitry Borisov         }
146*b79fbe23SDmitry Borisov 
147*b79fbe23SDmitry Borisov         ++Slots;
148*b79fbe23SDmitry Borisov 
149*b79fbe23SDmitry Borisov         Tbd.x64->AddressLow = (ULONG)Address;
150*b79fbe23SDmitry Borisov         Tbd.x64->AddressHigh = Address >> 32;
151*b79fbe23SDmitry Borisov         Tbd.x64->VlanTag = 0;
152*b79fbe23SDmitry Borisov         Tbd.x64->FlagsLength = Flags | (Length - 1);
153*b79fbe23SDmitry Borisov         LastTbd = Tbd;
154*b79fbe23SDmitry Borisov         Tbd = NV_NEXT_TBD_64(Adapter, Tbd);
155*b79fbe23SDmitry Borisov 
156*b79fbe23SDmitry Borisov         Flags = NV_TX2_VALID;
157*b79fbe23SDmitry Borisov     }
158*b79fbe23SDmitry Borisov 
159*b79fbe23SDmitry Borisov     Tcb->Slots = Slots;
160*b79fbe23SDmitry Borisov     Tcb->Tbd = LastTbd;
161*b79fbe23SDmitry Borisov 
162*b79fbe23SDmitry Borisov     LastTbd.x64->FlagsLength |= NV_TX2_LASTPACKET;
163*b79fbe23SDmitry Borisov 
164*b79fbe23SDmitry Borisov     if (Adapter->Flags & NV_SEND_ERRATA_PRESENT)
165*b79fbe23SDmitry Borisov     {
166*b79fbe23SDmitry Borisov         if (Adapter->Send.PacketsCount == NV_TX_LIMIT_COUNT)
167*b79fbe23SDmitry Borisov         {
168*b79fbe23SDmitry Borisov             Tcb->DeferredTbd = Adapter->Send.CurrentTbd;
169*b79fbe23SDmitry Borisov 
170*b79fbe23SDmitry Borisov             if (!Adapter->Send.DeferredTcb)
171*b79fbe23SDmitry Borisov             {
172*b79fbe23SDmitry Borisov                 Adapter->Send.DeferredTcb = Tcb;
173*b79fbe23SDmitry Borisov             }
174*b79fbe23SDmitry Borisov 
175*b79fbe23SDmitry Borisov             Flags = 0;
176*b79fbe23SDmitry Borisov         }
177*b79fbe23SDmitry Borisov         else
178*b79fbe23SDmitry Borisov         {
179*b79fbe23SDmitry Borisov             ++Adapter->Send.PacketsCount;
180*b79fbe23SDmitry Borisov         }
181*b79fbe23SDmitry Borisov     }
182*b79fbe23SDmitry Borisov 
183*b79fbe23SDmitry Borisov     if (Tcb->Flags & NV_TCB_LARGE_SEND)
184*b79fbe23SDmitry Borisov     {
185*b79fbe23SDmitry Borisov         Flags |= (Tcb->Mss << NV_TX2_TSO_SHIFT) | NV_TX2_TSO;
186*b79fbe23SDmitry Borisov     }
187*b79fbe23SDmitry Borisov     else
188*b79fbe23SDmitry Borisov     {
189*b79fbe23SDmitry Borisov         if (Tcb->Flags & NV_TCB_CHECKSUM_IP)
190*b79fbe23SDmitry Borisov         {
191*b79fbe23SDmitry Borisov             Flags |= NV_TX2_CHECKSUM_L3;
192*b79fbe23SDmitry Borisov         }
193*b79fbe23SDmitry Borisov         if (Tcb->Flags & (NV_TCB_CHECKSUM_TCP | NV_TCB_CHECKSUM_UDP))
194*b79fbe23SDmitry Borisov         {
195*b79fbe23SDmitry Borisov             Flags |= NV_TX2_CHECKSUM_L4;
196*b79fbe23SDmitry Borisov         }
197*b79fbe23SDmitry Borisov     }
198*b79fbe23SDmitry Borisov 
199*b79fbe23SDmitry Borisov     // Adapter->Send.CurrentTbd.x64->VlanTag = NV_TX3_VLAN_TAG_PRESENT; TODO
200*b79fbe23SDmitry Borisov     Adapter->Send.CurrentTbd.x64->FlagsLength |= Flags;
201*b79fbe23SDmitry Borisov     Adapter->Send.CurrentTbd = Tbd;
202*b79fbe23SDmitry Borisov 
203*b79fbe23SDmitry Borisov     NV_WRITE(Adapter, NvRegTxRxControl, Adapter->TxRxControl | NVREG_TXRXCTL_KICK);
204*b79fbe23SDmitry Borisov }
205*b79fbe23SDmitry Borisov 
206*b79fbe23SDmitry Borisov static
207*b79fbe23SDmitry Borisov DECLSPEC_NOINLINE
208*b79fbe23SDmitry Borisov ULONG
NvNetQueryTcpIpHeaders(_In_ PNVNET_ADAPTER Adapter,_In_ PNDIS_PACKET Packet)209*b79fbe23SDmitry Borisov NvNetQueryTcpIpHeaders(
210*b79fbe23SDmitry Borisov     _In_ PNVNET_ADAPTER Adapter,
211*b79fbe23SDmitry Borisov     _In_ PNDIS_PACKET Packet)
212*b79fbe23SDmitry Borisov {
213*b79fbe23SDmitry Borisov     PNDIS_BUFFER CurrentBuffer;
214*b79fbe23SDmitry Borisov     PVOID Address;
215*b79fbe23SDmitry Borisov     UINT CurrentLength;
216*b79fbe23SDmitry Borisov     UINT PacketLength;
217*b79fbe23SDmitry Borisov     PIPv4_HEADER IpHeader;
218*b79fbe23SDmitry Borisov     PTCPv4_HEADER TcpHeader;
219*b79fbe23SDmitry Borisov     ULONG BytesCopied = 0;
220*b79fbe23SDmitry Borisov     UCHAR Buffer[136];
221*b79fbe23SDmitry Borisov 
222*b79fbe23SDmitry Borisov     NdisGetFirstBufferFromPacketSafe(Packet,
223*b79fbe23SDmitry Borisov                                      &CurrentBuffer,
224*b79fbe23SDmitry Borisov                                      &Address,
225*b79fbe23SDmitry Borisov                                      &CurrentLength,
226*b79fbe23SDmitry Borisov                                      &PacketLength,
227*b79fbe23SDmitry Borisov                                      HighPagePriority);
228*b79fbe23SDmitry Borisov     if (!Address)
229*b79fbe23SDmitry Borisov         return 0;
230*b79fbe23SDmitry Borisov 
231*b79fbe23SDmitry Borisov     while (TRUE)
232*b79fbe23SDmitry Borisov     {
233*b79fbe23SDmitry Borisov         CurrentLength = min(CurrentLength, sizeof(Buffer) - BytesCopied);
234*b79fbe23SDmitry Borisov 
235*b79fbe23SDmitry Borisov         NdisMoveMemory(&Buffer[BytesCopied], Address, CurrentLength);
236*b79fbe23SDmitry Borisov         BytesCopied += CurrentLength;
237*b79fbe23SDmitry Borisov 
238*b79fbe23SDmitry Borisov         if (BytesCopied >= sizeof(Buffer))
239*b79fbe23SDmitry Borisov             break;
240*b79fbe23SDmitry Borisov 
241*b79fbe23SDmitry Borisov         NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer);
242*b79fbe23SDmitry Borisov 
243*b79fbe23SDmitry Borisov         if (!CurrentBuffer)
244*b79fbe23SDmitry Borisov             return 0;
245*b79fbe23SDmitry Borisov 
246*b79fbe23SDmitry Borisov         NdisQueryBufferSafe(CurrentBuffer,
247*b79fbe23SDmitry Borisov                             &Address,
248*b79fbe23SDmitry Borisov                             &CurrentLength,
249*b79fbe23SDmitry Borisov                             HighPagePriority);
250*b79fbe23SDmitry Borisov     }
251*b79fbe23SDmitry Borisov 
252*b79fbe23SDmitry Borisov     IpHeader = (PIPv4_HEADER)&Buffer[Adapter->IpHeaderOffset];
253*b79fbe23SDmitry Borisov     TcpHeader = (PTCPv4_HEADER)((PUCHAR)IpHeader + IP_HEADER_LENGTH(IpHeader));
254*b79fbe23SDmitry Borisov 
255*b79fbe23SDmitry Borisov     return IP_HEADER_LENGTH(IpHeader) + TCP_HEADER_LENGTH(TcpHeader);
256*b79fbe23SDmitry Borisov }
257*b79fbe23SDmitry Borisov 
258*b79fbe23SDmitry Borisov static
259*b79fbe23SDmitry Borisov BOOLEAN
NvNetCopyPacket(_In_ PNVNET_ADAPTER Adapter,_In_ PNDIS_PACKET Packet,_In_ PNVNET_TX_BUFFER Buffer)260*b79fbe23SDmitry Borisov NvNetCopyPacket(
261*b79fbe23SDmitry Borisov     _In_ PNVNET_ADAPTER Adapter,
262*b79fbe23SDmitry Borisov     _In_ PNDIS_PACKET Packet,
263*b79fbe23SDmitry Borisov     _In_ PNVNET_TX_BUFFER Buffer)
264*b79fbe23SDmitry Borisov {
265*b79fbe23SDmitry Borisov     PNDIS_BUFFER CurrentBuffer;
266*b79fbe23SDmitry Borisov     PVOID Address;
267*b79fbe23SDmitry Borisov     UINT CurrentLength;
268*b79fbe23SDmitry Borisov     UINT PacketLength;
269*b79fbe23SDmitry Borisov     PUCHAR Destination;
270*b79fbe23SDmitry Borisov 
271*b79fbe23SDmitry Borisov     NdisGetFirstBufferFromPacketSafe(Packet,
272*b79fbe23SDmitry Borisov                                      &CurrentBuffer,
273*b79fbe23SDmitry Borisov                                      &Address,
274*b79fbe23SDmitry Borisov                                      &CurrentLength,
275*b79fbe23SDmitry Borisov                                      &PacketLength,
276*b79fbe23SDmitry Borisov                                      HighPagePriority);
277*b79fbe23SDmitry Borisov     if (!Address)
278*b79fbe23SDmitry Borisov         return FALSE;
279*b79fbe23SDmitry Borisov 
280*b79fbe23SDmitry Borisov     Destination = Buffer->VirtualAddress;
281*b79fbe23SDmitry Borisov 
282*b79fbe23SDmitry Borisov     while (TRUE)
283*b79fbe23SDmitry Borisov     {
284*b79fbe23SDmitry Borisov         NdisMoveMemory(Destination, Address, CurrentLength);
285*b79fbe23SDmitry Borisov         Destination += CurrentLength;
286*b79fbe23SDmitry Borisov 
287*b79fbe23SDmitry Borisov         NdisGetNextBuffer(CurrentBuffer, &CurrentBuffer);
288*b79fbe23SDmitry Borisov 
289*b79fbe23SDmitry Borisov         if (!CurrentBuffer)
290*b79fbe23SDmitry Borisov             break;
291*b79fbe23SDmitry Borisov 
292*b79fbe23SDmitry Borisov         NdisQueryBufferSafe(CurrentBuffer,
293*b79fbe23SDmitry Borisov                             &Address,
294*b79fbe23SDmitry Borisov                             &CurrentLength,
295*b79fbe23SDmitry Borisov                             HighPagePriority);
296*b79fbe23SDmitry Borisov         if (!Address)
297*b79fbe23SDmitry Borisov             return FALSE;
298*b79fbe23SDmitry Borisov     }
299*b79fbe23SDmitry Borisov 
300*b79fbe23SDmitry Borisov     return TRUE;
301*b79fbe23SDmitry Borisov }
302*b79fbe23SDmitry Borisov 
303*b79fbe23SDmitry Borisov static
304*b79fbe23SDmitry Borisov NDIS_STATUS
NvNetSendPacketLargeSend(_In_ PNVNET_ADAPTER Adapter,_In_ PNDIS_PACKET Packet,_In_ ULONG TotalLength)305*b79fbe23SDmitry Borisov NvNetSendPacketLargeSend(
306*b79fbe23SDmitry Borisov     _In_ PNVNET_ADAPTER Adapter,
307*b79fbe23SDmitry Borisov     _In_ PNDIS_PACKET Packet,
308*b79fbe23SDmitry Borisov     _In_ ULONG TotalLength)
309*b79fbe23SDmitry Borisov {
310*b79fbe23SDmitry Borisov     PSCATTER_GATHER_LIST SgList;
311*b79fbe23SDmitry Borisov     ULONG Mss, Length;
312*b79fbe23SDmitry Borisov     PNVNET_TCB Tcb;
313*b79fbe23SDmitry Borisov 
314*b79fbe23SDmitry Borisov     if (!Adapter->Send.TcbSlots)
315*b79fbe23SDmitry Borisov     {
316*b79fbe23SDmitry Borisov         return NDIS_STATUS_RESOURCES;
317*b79fbe23SDmitry Borisov     }
318*b79fbe23SDmitry Borisov 
319*b79fbe23SDmitry Borisov     SgList = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo);
320*b79fbe23SDmitry Borisov 
321*b79fbe23SDmitry Borisov     /* Make sure we have room to setup all fragments */
322*b79fbe23SDmitry Borisov     C_ASSERT(NVNET_TRANSMIT_DESCRIPTORS > ((NVNET_MAXIMUM_LSO_FRAME_SIZE / PAGE_SIZE) + 3));
323*b79fbe23SDmitry Borisov     ASSERT(SgList->NumberOfElements +
324*b79fbe23SDmitry Borisov            (NVNET_MAXIMUM_LSO_FRAME_SIZE / (NV_MAXIMUM_SG_SIZE + 1)) <=
325*b79fbe23SDmitry Borisov            NVNET_TRANSMIT_DESCRIPTORS);
326*b79fbe23SDmitry Borisov 
327*b79fbe23SDmitry Borisov     if (SgList->NumberOfElements +
328*b79fbe23SDmitry Borisov         (NVNET_MAXIMUM_LSO_FRAME_SIZE / (NV_MAXIMUM_SG_SIZE + 1)) < Adapter->Send.TbdSlots)
329*b79fbe23SDmitry Borisov     {
330*b79fbe23SDmitry Borisov         return NDIS_STATUS_RESOURCES;
331*b79fbe23SDmitry Borisov     }
332*b79fbe23SDmitry Borisov 
333*b79fbe23SDmitry Borisov     Length = NvNetQueryTcpIpHeaders(Adapter, Packet);
334*b79fbe23SDmitry Borisov     if (!Length)
335*b79fbe23SDmitry Borisov     {
336*b79fbe23SDmitry Borisov         return NDIS_STATUS_RESOURCES;
337*b79fbe23SDmitry Borisov     }
338*b79fbe23SDmitry Borisov 
339*b79fbe23SDmitry Borisov     NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, TcpLargeSendPacketInfo) =
340*b79fbe23SDmitry Borisov         UlongToPtr(TotalLength - Adapter->IpHeaderOffset - Length);
341*b79fbe23SDmitry Borisov 
342*b79fbe23SDmitry Borisov     --Adapter->Send.TcbSlots;
343*b79fbe23SDmitry Borisov 
344*b79fbe23SDmitry Borisov     Mss = PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, TcpLargeSendPacketInfo));
345*b79fbe23SDmitry Borisov 
346*b79fbe23SDmitry Borisov     Tcb = Adapter->Send.CurrentTcb;
347*b79fbe23SDmitry Borisov     Tcb->Mss = Mss;
348*b79fbe23SDmitry Borisov     Tcb->Packet = Packet;
349*b79fbe23SDmitry Borisov     Tcb->Flags = NV_TCB_LARGE_SEND;
350*b79fbe23SDmitry Borisov 
351*b79fbe23SDmitry Borisov     Adapter->TransmitPacket(Adapter, Tcb, SgList);
352*b79fbe23SDmitry Borisov 
353*b79fbe23SDmitry Borisov     ASSERT(Adapter->Send.TbdSlots >= Tcb->Slots);
354*b79fbe23SDmitry Borisov     Adapter->Send.TbdSlots -= Tcb->Slots;
355*b79fbe23SDmitry Borisov 
356*b79fbe23SDmitry Borisov     Adapter->Send.CurrentTcb = NV_NEXT_TCB(Adapter, Tcb);
357*b79fbe23SDmitry Borisov 
358*b79fbe23SDmitry Borisov     return NDIS_STATUS_SUCCESS;
359*b79fbe23SDmitry Borisov }
360*b79fbe23SDmitry Borisov 
361*b79fbe23SDmitry Borisov static
362*b79fbe23SDmitry Borisov ULONG
NvNetGetChecksumInfo(_In_ PNVNET_ADAPTER Adapter,_In_ PNDIS_PACKET Packet)363*b79fbe23SDmitry Borisov NvNetGetChecksumInfo(
364*b79fbe23SDmitry Borisov     _In_ PNVNET_ADAPTER Adapter,
365*b79fbe23SDmitry Borisov     _In_ PNDIS_PACKET Packet)
366*b79fbe23SDmitry Borisov {
367*b79fbe23SDmitry Borisov     ULONG Flags;
368*b79fbe23SDmitry Borisov     NDIS_TCP_IP_CHECKSUM_PACKET_INFO ChecksumInfo;
369*b79fbe23SDmitry Borisov 
370*b79fbe23SDmitry Borisov     if (NDIS_GET_PACKET_PROTOCOL_TYPE(Packet) != NDIS_PROTOCOL_ID_TCP_IP)
371*b79fbe23SDmitry Borisov         return 0;
372*b79fbe23SDmitry Borisov 
373*b79fbe23SDmitry Borisov     ChecksumInfo.Value = PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(Packet,
374*b79fbe23SDmitry Borisov                                                                      TcpIpChecksumPacketInfo));
375*b79fbe23SDmitry Borisov 
376*b79fbe23SDmitry Borisov     Flags = 0;
377*b79fbe23SDmitry Borisov     if (ChecksumInfo.Transmit.NdisPacketChecksumV4)
378*b79fbe23SDmitry Borisov     {
379*b79fbe23SDmitry Borisov         if (ChecksumInfo.Transmit.NdisPacketTcpChecksum && Adapter->Offload.SendTcpChecksum)
380*b79fbe23SDmitry Borisov         {
381*b79fbe23SDmitry Borisov             Flags |= NV_TCB_CHECKSUM_TCP;
382*b79fbe23SDmitry Borisov         }
383*b79fbe23SDmitry Borisov         if (ChecksumInfo.Transmit.NdisPacketUdpChecksum && Adapter->Offload.SendUdpChecksum)
384*b79fbe23SDmitry Borisov         {
385*b79fbe23SDmitry Borisov             Flags |= NV_TCB_CHECKSUM_UDP;
386*b79fbe23SDmitry Borisov         }
387*b79fbe23SDmitry Borisov         if (ChecksumInfo.Transmit.NdisPacketIpChecksum && Adapter->Offload.SendIpChecksum)
388*b79fbe23SDmitry Borisov         {
389*b79fbe23SDmitry Borisov             Flags |= NV_TCB_CHECKSUM_IP;
390*b79fbe23SDmitry Borisov         }
391*b79fbe23SDmitry Borisov     }
392*b79fbe23SDmitry Borisov 
393*b79fbe23SDmitry Borisov     return Flags;
394*b79fbe23SDmitry Borisov }
395*b79fbe23SDmitry Borisov 
396*b79fbe23SDmitry Borisov static
397*b79fbe23SDmitry Borisov NDIS_STATUS
NvNetSendPacket(_In_ PNVNET_ADAPTER Adapter,_In_ PNDIS_PACKET Packet,_In_ ULONG TotalLength)398*b79fbe23SDmitry Borisov NvNetSendPacket(
399*b79fbe23SDmitry Borisov     _In_ PNVNET_ADAPTER Adapter,
400*b79fbe23SDmitry Borisov     _In_ PNDIS_PACKET Packet,
401*b79fbe23SDmitry Borisov     _In_ ULONG TotalLength)
402*b79fbe23SDmitry Borisov {
403*b79fbe23SDmitry Borisov     PSCATTER_GATHER_LIST SgList;
404*b79fbe23SDmitry Borisov     SCATTER_GATHER_LIST LocalSgList;
405*b79fbe23SDmitry Borisov     PNVNET_TCB Tcb;
406*b79fbe23SDmitry Borisov     ULONG Flags;
407*b79fbe23SDmitry Borisov 
408*b79fbe23SDmitry Borisov     ASSERT(TotalLength <= Adapter->MaximumFrameSize);
409*b79fbe23SDmitry Borisov 
410*b79fbe23SDmitry Borisov     if (!Adapter->Send.TcbSlots)
411*b79fbe23SDmitry Borisov     {
412*b79fbe23SDmitry Borisov         return NDIS_STATUS_RESOURCES;
413*b79fbe23SDmitry Borisov     }
414*b79fbe23SDmitry Borisov 
415*b79fbe23SDmitry Borisov     Flags = NvNetGetChecksumInfo(Adapter, Packet);
416*b79fbe23SDmitry Borisov 
417*b79fbe23SDmitry Borisov     SgList = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo);
418*b79fbe23SDmitry Borisov 
419*b79fbe23SDmitry Borisov     if (SgList->NumberOfElements > NVNET_FRAGMENTATION_THRESHOLD)
420*b79fbe23SDmitry Borisov     {
421*b79fbe23SDmitry Borisov         if (!Adapter->Send.TbdSlots || !Adapter->Send.BufferList.Next)
422*b79fbe23SDmitry Borisov         {
423*b79fbe23SDmitry Borisov             return NDIS_STATUS_RESOURCES;
424*b79fbe23SDmitry Borisov         }
425*b79fbe23SDmitry Borisov         else
426*b79fbe23SDmitry Borisov         {
427*b79fbe23SDmitry Borisov             PNVNET_TX_BUFFER CoalesceBuffer;
428*b79fbe23SDmitry Borisov             BOOLEAN Success;
429*b79fbe23SDmitry Borisov 
430*b79fbe23SDmitry Borisov             --Adapter->Send.TcbSlots;
431*b79fbe23SDmitry Borisov 
432*b79fbe23SDmitry Borisov             CoalesceBuffer = (PNVNET_TX_BUFFER)PopEntryList(&Adapter->Send.BufferList);
433*b79fbe23SDmitry Borisov 
434*b79fbe23SDmitry Borisov             NdisDprReleaseSpinLock(&Adapter->Send.Lock);
435*b79fbe23SDmitry Borisov 
436*b79fbe23SDmitry Borisov             Success = NvNetCopyPacket(Adapter, Packet, CoalesceBuffer);
437*b79fbe23SDmitry Borisov 
438*b79fbe23SDmitry Borisov             NdisDprAcquireSpinLock(&Adapter->Send.Lock);
439*b79fbe23SDmitry Borisov 
440*b79fbe23SDmitry Borisov             if (!Success || !Adapter->Send.TbdSlots || !(Adapter->Flags & NV_ACTIVE))
441*b79fbe23SDmitry Borisov             {
442*b79fbe23SDmitry Borisov                 PushEntryList(&Adapter->Send.BufferList, &CoalesceBuffer->Link);
443*b79fbe23SDmitry Borisov 
444*b79fbe23SDmitry Borisov                 ++Adapter->Send.TcbSlots;
445*b79fbe23SDmitry Borisov 
446*b79fbe23SDmitry Borisov                 return NDIS_STATUS_RESOURCES;
447*b79fbe23SDmitry Borisov             }
448*b79fbe23SDmitry Borisov 
449*b79fbe23SDmitry Borisov             Flags |= NV_TCB_COALESCE;
450*b79fbe23SDmitry Borisov 
451*b79fbe23SDmitry Borisov             LocalSgList.NumberOfElements = 1;
452*b79fbe23SDmitry Borisov             LocalSgList.Elements[0].Address = CoalesceBuffer->PhysicalAddress;
453*b79fbe23SDmitry Borisov             LocalSgList.Elements[0].Length = TotalLength;
454*b79fbe23SDmitry Borisov             SgList = &LocalSgList;
455*b79fbe23SDmitry Borisov 
456*b79fbe23SDmitry Borisov             Tcb = Adapter->Send.CurrentTcb;
457*b79fbe23SDmitry Borisov             Tcb->Buffer = CoalesceBuffer;
458*b79fbe23SDmitry Borisov         }
459*b79fbe23SDmitry Borisov     }
460*b79fbe23SDmitry Borisov     else
461*b79fbe23SDmitry Borisov     {
462*b79fbe23SDmitry Borisov         if (SgList->NumberOfElements +
463*b79fbe23SDmitry Borisov             (NVNET_MAXIMUM_FRAME_SIZE_JUMBO / (NV_MAXIMUM_SG_SIZE + 1)) > Adapter->Send.TbdSlots)
464*b79fbe23SDmitry Borisov         {
465*b79fbe23SDmitry Borisov             return NDIS_STATUS_RESOURCES;
466*b79fbe23SDmitry Borisov         }
467*b79fbe23SDmitry Borisov 
468*b79fbe23SDmitry Borisov         --Adapter->Send.TcbSlots;
469*b79fbe23SDmitry Borisov 
470*b79fbe23SDmitry Borisov         Tcb = Adapter->Send.CurrentTcb;
471*b79fbe23SDmitry Borisov     }
472*b79fbe23SDmitry Borisov 
473*b79fbe23SDmitry Borisov     Tcb->Packet = Packet;
474*b79fbe23SDmitry Borisov     Tcb->Flags = Flags;
475*b79fbe23SDmitry Borisov 
476*b79fbe23SDmitry Borisov     Adapter->TransmitPacket(Adapter, Tcb, SgList);
477*b79fbe23SDmitry Borisov 
478*b79fbe23SDmitry Borisov     ASSERT(Adapter->Send.TbdSlots >= Tcb->Slots);
479*b79fbe23SDmitry Borisov     Adapter->Send.TbdSlots -= Tcb->Slots;
480*b79fbe23SDmitry Borisov 
481*b79fbe23SDmitry Borisov     Adapter->Send.CurrentTcb = NV_NEXT_TCB(Adapter, Tcb);
482*b79fbe23SDmitry Borisov 
483*b79fbe23SDmitry Borisov     return NDIS_STATUS_PENDING;
484*b79fbe23SDmitry Borisov }
485*b79fbe23SDmitry Borisov 
486*b79fbe23SDmitry Borisov /* FIXME: Use the proper send function (MiniportSendPackets) */
487*b79fbe23SDmitry Borisov NDIS_STATUS
488*b79fbe23SDmitry Borisov NTAPI
MiniportSend(_In_ NDIS_HANDLE MiniportAdapterContext,_In_ PNDIS_PACKET Packet,_In_ UINT Flags)489*b79fbe23SDmitry Borisov MiniportSend(
490*b79fbe23SDmitry Borisov     _In_ NDIS_HANDLE MiniportAdapterContext,
491*b79fbe23SDmitry Borisov     _In_ PNDIS_PACKET Packet,
492*b79fbe23SDmitry Borisov     _In_ UINT Flags)
493*b79fbe23SDmitry Borisov {
494*b79fbe23SDmitry Borisov     PNVNET_ADAPTER Adapter = (PNVNET_ADAPTER)MiniportAdapterContext;
495*b79fbe23SDmitry Borisov     UINT TotalLength;
496*b79fbe23SDmitry Borisov     NDIS_STATUS Status;
497*b79fbe23SDmitry Borisov 
498*b79fbe23SDmitry Borisov     NDIS_DbgPrint(MIN_TRACE, ("()\n"));
499*b79fbe23SDmitry Borisov 
500*b79fbe23SDmitry Borisov     NdisQueryPacketLength(Packet, &TotalLength);
501*b79fbe23SDmitry Borisov 
502*b79fbe23SDmitry Borisov     NdisDprAcquireSpinLock(&Adapter->Send.Lock);
503*b79fbe23SDmitry Borisov 
504*b79fbe23SDmitry Borisov     if (!(Adapter->Flags & NV_ACTIVE))
505*b79fbe23SDmitry Borisov     {
506*b79fbe23SDmitry Borisov         NdisDprReleaseSpinLock(&Adapter->Send.Lock);
507*b79fbe23SDmitry Borisov 
508*b79fbe23SDmitry Borisov         return NDIS_STATUS_FAILURE;
509*b79fbe23SDmitry Borisov     }
510*b79fbe23SDmitry Borisov 
511*b79fbe23SDmitry Borisov     if (Adapter->Flags & NV_SEND_LARGE_SEND &&
512*b79fbe23SDmitry Borisov         PtrToUlong(NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, TcpLargeSendPacketInfo)))
513*b79fbe23SDmitry Borisov     {
514*b79fbe23SDmitry Borisov         Status = NvNetSendPacketLargeSend(Adapter, Packet, TotalLength);
515*b79fbe23SDmitry Borisov     }
516*b79fbe23SDmitry Borisov     else
517*b79fbe23SDmitry Borisov     {
518*b79fbe23SDmitry Borisov         Status = NvNetSendPacket(Adapter, Packet, TotalLength);
519*b79fbe23SDmitry Borisov     }
520*b79fbe23SDmitry Borisov 
521*b79fbe23SDmitry Borisov     NdisDprReleaseSpinLock(&Adapter->Send.Lock);
522*b79fbe23SDmitry Borisov 
523*b79fbe23SDmitry Borisov     return Status;
524*b79fbe23SDmitry Borisov }
525