win-pvdrivers

view xennet/xennet_common.c @ 433:b1da81cc9868

updates
author James Harper <james.harper@bendigoit.com.au>
date Tue Oct 14 10:45:56 2008 +1100 (2008-10-14)
parents 718d4567551d
children c4204f69c506
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], (PVOID) &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_PUSHORT(&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 (1)\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_PUSHORT(&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 + 20)) // pi->tcp_header_length))
80 {
81 KdPrint((__DRIVER_NAME " first buffer is only %d bytes long, must be >= %d (2)\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_PULONG(&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_PUSHORT(&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], (USHORT)csum);
116 }
118 /* Called at DISPATCH LEVEL */
119 static VOID DDKAPI
120 XenFreelist_Timer(
121 PVOID SystemSpecific1,
122 PVOID FunctionContext,
123 PVOID SystemSpecific2,
124 PVOID SystemSpecific3
125 )
126 {
127 freelist_t *fl = (freelist_t *)FunctionContext;
128 PMDL mdl;
129 int i;
131 UNREFERENCED_PARAMETER(SystemSpecific1);
132 UNREFERENCED_PARAMETER(SystemSpecific2);
133 UNREFERENCED_PARAMETER(SystemSpecific3);
135 if (fl->xi->device_state->resume_state != RESUME_STATE_RUNNING && !fl->grants_resumed)
136 return;
138 KeAcquireSpinLockAtDpcLevel(fl->lock);
140 //FUNCTION_MSG((" --- timer - page_free_lowest = %d\n", fl->page_free_lowest));
142 if (fl->page_free_lowest > fl->page_free_target) // lots of potential for tuning here
143 {
144 for (i = 0; i < (int)min(16, fl->page_free_lowest - fl->page_free_target); i++)
145 {
146 mdl = XenFreelist_GetPage(fl);
147 if (!mdl)
148 break;
149 fl->xi->vectors.GntTbl_EndAccess(fl->xi->vectors.context,
150 *(grant_ref_t *)(((UCHAR *)mdl) + MmSizeOfMdl(0, PAGE_SIZE)), 0);
151 FreePages(mdl);
152 }
153 //FUNCTION_MSG((__DRIVER_NAME " --- timer - freed %d pages\n", i));
154 }
156 fl->page_free_lowest = fl->page_free;
158 KeReleaseSpinLockFromDpcLevel(fl->lock);
159 }
161 VOID
162 XenFreelist_Init(struct xennet_info *xi, freelist_t *fl, PKSPIN_LOCK lock)
163 {
164 fl->xi = xi;
165 fl->lock = lock;
166 fl->page_free = 0;
167 fl->page_free_lowest = 0;
168 fl->page_free_target = 16; /* tune this */
169 fl->grants_resumed = FALSE;
170 NdisMInitializeTimer(&fl->timer, fl->xi->adapter_handle, XenFreelist_Timer, fl);
171 NdisMSetPeriodicTimer(&fl->timer, 1000);
172 }
174 PMDL
175 XenFreelist_GetPage(freelist_t *fl)
176 {
177 PMDL mdl;
178 PFN_NUMBER pfn;
179 grant_ref_t gref;
181 //ASSERT(!KeTestSpinLock(fl->lock));
183 if (fl->page_free == 0)
184 {
185 mdl = AllocatePagesExtra(1, sizeof(grant_ref_t));
186 if (!mdl)
187 return NULL;
188 pfn = *MmGetMdlPfnArray(mdl);
189 gref = fl->xi->vectors.GntTbl_GrantAccess(
190 fl->xi->vectors.context, 0,
191 (uint32_t)pfn, FALSE, INVALID_GRANT_REF);
192 if (gref == INVALID_GRANT_REF)
193 KdPrint((__DRIVER_NAME " No more grefs\n"));
194 *(grant_ref_t *)(((UCHAR *)mdl) + MmSizeOfMdl(0, PAGE_SIZE)) = gref;
195 /* we really should check if our grant was successful... */
196 }
197 else
198 {
199 fl->page_free--;
200 if (fl->page_free < fl->page_free_lowest)
201 fl->page_free_lowest = fl->page_free;
202 mdl = fl->page_list[fl->page_free];
203 }
205 return mdl;
206 }
208 VOID
209 XenFreelist_PutPage(freelist_t *fl, PMDL mdl)
210 {
211 //ASSERT(!KeTestSpinLock(fl->lock));
213 ASSERT(NdisBufferLength(mdl) == PAGE_SIZE);
215 if (fl->page_free == PAGE_LIST_SIZE)
216 {
217 KdPrint((__DRIVER_NAME " page free list full - releasing page\n"));
218 /* our page list is full. free the buffer instead. This will be a bit sucky performancewise... */
219 fl->xi->vectors.GntTbl_EndAccess(fl->xi->vectors.context,
220 *(grant_ref_t *)(((UCHAR *)mdl) + MmSizeOfMdl(0, PAGE_SIZE)), FALSE);
221 FreePages(mdl);
222 }
223 else
224 {
225 fl->page_list[fl->page_free] = mdl;
226 fl->page_free++;
227 }
228 }
230 VOID
231 XenFreelist_Dispose(freelist_t *fl)
232 {
233 PMDL mdl;
234 BOOLEAN TimerCancelled;
236 NdisMCancelTimer(&fl->timer, &TimerCancelled);
238 while(fl->page_free != 0)
239 {
240 fl->page_free--;
241 mdl = fl->page_list[fl->page_free];
242 fl->xi->vectors.GntTbl_EndAccess(fl->xi->vectors.context,
243 *(grant_ref_t *)(((UCHAR *)mdl) + MmSizeOfMdl(0, PAGE_SIZE)), 0);
244 FreePages(mdl);
245 }
246 }
248 static VOID
249 XenFreelist_ReGrantMdl(freelist_t *fl, PMDL mdl)
250 {
251 PFN_NUMBER pfn;
252 pfn = *MmGetMdlPfnArray(mdl);
253 *(grant_ref_t *)(((UCHAR *)mdl) + MmSizeOfMdl(0, PAGE_SIZE)) = fl->xi->vectors.GntTbl_GrantAccess(
254 fl->xi->vectors.context, 0,
255 (uint32_t)pfn, FALSE, INVALID_GRANT_REF);
256 }
258 /* re-grant all the pages, as the grant table was wiped on resume */
259 VOID
260 XenFreelist_ResumeStart(freelist_t *fl)
261 {
262 ULONG i;
264 for (i = 0; i < fl->page_free; i++)
265 {
266 XenFreelist_ReGrantMdl(fl, fl->page_list[i]);
267 }
268 fl->grants_resumed = TRUE;
269 }
271 VOID
272 XenFreelist_ResumeEnd(freelist_t *fl)
273 {
274 fl->grants_resumed = FALSE;
275 }