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