win-pvdrivers

view xennet/xennet_common.c @ 266:b88529df8b60

More wdm updates
author James Harper <james.harper@bendigoit.com.au>
date Wed May 07 10:47:03 2008 +1000 (2008-05-07)
parents 6c1ab34c1bda
children 8fef16f8fc08 da9b1e17fbc0
line source
1 /*
2 PV Net Driver for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
4 Copyright (C) 2007 Andrew Grover <andy.grover@oracle.com>
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
21 #include "xennet.h"
23 ULONG
24 XenNet_ParsePacketHeader(
25 packet_info_t *pi
26 )
27 {
28 UINT header_length;
30 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
32 ASSERT(pi->mdls[0]);
34 NdisQueryBufferSafe(pi->mdls[0], &pi->header, &header_length, NormalPagePriority);
36 // what about if the buffer isn't completely on one page???
37 if (ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(pi->mdls[0]), header_length) != 1)
38 KdPrint((__DRIVER_NAME " header crosses a page!\n"));
41 if (header_length < XN_HDR_SIZE + 20 + 20) // minimum size of first buffer is ETH + IP + TCP header
42 {
43 return PARSE_TOO_SMALL;
44 }
46 switch (GET_NET_USHORT(pi->header[12])) // L2 protocol field
47 {
48 case 0x0800:
49 pi->ip_version = (pi->header[XN_HDR_SIZE + 0] & 0xF0) >> 4;
50 if (pi->ip_version != 4)
51 {
52 KdPrint((__DRIVER_NAME " ip_version = %d\n", pi->ip_version));
53 return PARSE_UNKNOWN_TYPE;
54 }
55 pi->ip4_header_length = (pi->header[XN_HDR_SIZE + 0] & 0x0F) << 2;
56 if (header_length < (ULONG)(pi->ip4_header_length + 20))
57 {
58 KdPrint((__DRIVER_NAME " first buffer is only %d bytes long, must be >= %d\n", XN_HDR_SIZE + header_length, (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + 20)));
59 // we need to do something conclusive here...
60 return PARSE_TOO_SMALL;
61 }
62 break;
63 default:
64 // KdPrint((__DRIVER_NAME " Not IP\n"));
65 return PARSE_UNKNOWN_TYPE;
66 }
67 pi->ip_proto = pi->header[XN_HDR_SIZE + 9];
68 switch (pi->ip_proto)
69 {
70 case 6: // TCP
71 case 17: // UDP
72 break;
73 default:
74 return PARSE_UNKNOWN_TYPE;
75 }
76 pi->ip4_length = GET_NET_USHORT(pi->header[XN_HDR_SIZE + 2]);
77 pi->tcp_header_length = (pi->header[XN_HDR_SIZE + pi->ip4_header_length + 12] & 0xf0) >> 2;
79 if (header_length < (ULONG)(pi->ip4_header_length + pi->tcp_header_length))
80 {
81 KdPrint((__DRIVER_NAME " first buffer is only %d bytes long, must be >= %d\n", XN_HDR_SIZE + header_length, (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + pi->tcp_header_length)));
82 return PARSE_TOO_SMALL;
83 }
85 pi->tcp_length = pi->ip4_length - pi->ip4_header_length - pi->tcp_header_length;
86 pi->tcp_remaining = pi->tcp_length;
87 pi->tcp_seq = GET_NET_ULONG(pi->header[XN_HDR_SIZE + pi->ip4_header_length + 4]);
88 if (pi->mss > 0 && pi->tcp_length > pi->mss)
89 pi->split_required = TRUE;
90 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
91 return PARSE_OK;
92 }
94 VOID
95 XenNet_SumIpHeader(
96 PUCHAR header,
97 USHORT ip4_header_length
98 )
99 {
100 ULONG csum = 0;
101 USHORT i;
103 ASSERT(ip4_header_length > 12);
104 ASSERT(!(ip4_header_length & 1));
106 header[XN_HDR_SIZE + 10] = 0;
107 header[XN_HDR_SIZE + 11] = 0;
108 for (i = 0; i < ip4_header_length; i += 2)
109 {
110 csum += GET_NET_USHORT(header[XN_HDR_SIZE + i]);
111 }
112 while (csum & 0xFFFF0000)
113 csum = (csum & 0xFFFF) + (csum >> 16);
114 csum = ~csum;
115 SET_NET_USHORT(header[XN_HDR_SIZE + 10], csum);
116 }
118 PUCHAR
119 XenNet_GetData(
120 packet_info_t *pi,
121 USHORT req_length,
122 PUSHORT length
123 )
124 {
125 PNDIS_BUFFER mdl = pi->mdls[pi->curr_mdl];
126 PUCHAR buffer = (PUCHAR)MmGetMdlVirtualAddress(mdl) + pi->curr_mdl_offset;
128 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
130 *length = (USHORT)min(req_length, MmGetMdlByteCount(mdl) - pi->curr_mdl_offset);
132 // KdPrint((__DRIVER_NAME " req_length = %d, length = %d\n", req_length, *length));
134 pi->curr_mdl_offset = pi->curr_mdl_offset + *length;
135 if (pi->curr_mdl_offset == MmGetMdlByteCount(mdl))
136 {
137 pi->curr_mdl++;
138 pi->curr_mdl_offset = 0;
139 }
141 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
143 return buffer;
144 }
147 static VOID
148 XenFreelist_Timer(
149 PVOID SystemSpecific1,
150 PVOID FunctionContext,
151 PVOID SystemSpecific2,
152 PVOID SystemSpecific3
153 )
154 {
155 freelist_t *fl = (freelist_t *)FunctionContext;
156 PMDL mdl;
157 int i;
159 UNREFERENCED_PARAMETER(SystemSpecific1);
160 UNREFERENCED_PARAMETER(SystemSpecific2);
161 UNREFERENCED_PARAMETER(SystemSpecific3);
163 KeAcquireSpinLockAtDpcLevel(fl->lock);
165 KdPrint((__DRIVER_NAME " --- timer - page_free_lowest = %d\n", fl->page_free_lowest));
166 // KdPrint((__DRIVER_NAME " --- rx_outstanding = %d, rx_id_free = %d\n", xi->rx_outstanding, xi->rx_id_free));
168 if (fl->page_free_lowest > fl->page_free_target) // lots of potential for tuning here
169 {
170 for (i = 0; i < (int)min(16, fl->page_free_lowest - fl->page_free_target); i++)
171 {
172 mdl = XenFreelist_GetPage(fl);
173 fl->xi->XenInterface.GntTbl_EndAccess(fl->xi->XenInterface.InterfaceHeader.Context,
174 *(grant_ref_t *)(((UCHAR *)mdl) + MmSizeOfMdl(0, PAGE_SIZE)), 0);
175 FreePages(mdl);
176 }
177 KdPrint((__DRIVER_NAME " --- timer - freed %d pages\n", i));
178 }
180 fl->page_free_lowest = fl->page_free;
182 KeReleaseSpinLockFromDpcLevel(fl->lock);
184 return;
185 }
187 VOID
188 XenFreelist_Init(struct xennet_info *xi, freelist_t *fl, PKSPIN_LOCK lock)
189 {
190 fl->xi = xi;
191 fl->lock = lock;
192 fl->page_free = 0;
193 fl->page_free_lowest = 0;
194 fl->page_free_target = 16; /* tune this */
195 NdisMInitializeTimer(&fl->timer, fl->xi->adapter_handle, XenFreelist_Timer, fl);
196 NdisMSetPeriodicTimer(&fl->timer, 1000);
197 }
199 PMDL
200 XenFreelist_GetPage(freelist_t *fl)
201 {
202 PMDL mdl;
204 if (fl->page_free == 0)
205 {
206 mdl = AllocatePagesExtra(1, sizeof(grant_ref_t));
207 *(grant_ref_t *)(((UCHAR *)mdl) + MmSizeOfMdl(0, PAGE_SIZE)) = fl->xi->XenInterface.GntTbl_GrantAccess(
208 fl->xi->XenInterface.InterfaceHeader.Context, 0,
209 *MmGetMdlPfnArray(mdl), FALSE, 0);
210 }
211 else
212 {
213 fl->page_free--;
214 if (fl->page_free < fl->page_free_lowest)
215 fl->page_free_lowest = fl->page_free;
216 mdl = fl->page_list[fl->page_free];
217 }
219 return mdl;
220 }
222 VOID
223 XenFreelist_PutPage(freelist_t *fl, PMDL mdl)
224 {
225 fl->page_list[fl->page_free] = mdl;
226 fl->page_free++;
227 }
229 VOID
230 XenFreelist_Dispose(freelist_t *fl)
231 {
232 PMDL mdl;
233 BOOLEAN TimerCancelled;
235 NdisMCancelTimer(&fl->timer, &TimerCancelled);
237 while(fl->page_free != 0)
238 {
239 fl->page_free--;
240 mdl = fl->page_list[fl->page_free];
241 fl->xi->XenInterface.GntTbl_EndAccess(fl->xi->XenInterface.InterfaceHeader.Context,
242 *(grant_ref_t *)(((UCHAR *)mdl) + MmSizeOfMdl(0, PAGE_SIZE)), 0);
243 FreePages(mdl);
244 }
245 }