win-pvdrivers

view xenpci/gnttbl.c @ 790:467005e7f509

Big messy changes. Add grant ref tagging to better track when things go wrong (debug build only).
Fix a race in xennet that causes crashes under heavy traffic conditions on driver shutdown.
author James Harper <james.harper@bendigoit.com.au>
date Fri Mar 12 09:38:42 2010 +1100 (2010-03-12)
parents 5e3af133e8a6
children 4db4fd1c87fb
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
20 #include "xenpci.h"
22 VOID
23 GntTbl_PutRef(PVOID Context, grant_ref_t ref, ULONG tag)
24 {
25 PXENPCI_DEVICE_DATA xpdd = Context;
27 UNREFERENCED_PARAMETER(tag);
29 #if DBG
30 if (xpdd->gnttab_tag[ref] != tag)
31 KdPrint((__DRIVER_NAME " Grant Entry %d for %.4s doesn't match %.4s\n", ref, (PUCHAR)&tag, (PUCHAR)&xpdd->gnttab_tag[ref]));
32 ASSERT(xpdd->gnttab_tag[ref] == tag);
33 xpdd->gnttab_tag[ref] = 0;
34 #endif
35 stack_push(xpdd->gnttab_ss, (PVOID)ref);
36 }
38 grant_ref_t
39 GntTbl_GetRef(PVOID Context, ULONG tag)
40 {
41 PXENPCI_DEVICE_DATA xpdd = Context;
42 unsigned int ref;
43 PVOID ptr_ref;
45 UNREFERENCED_PARAMETER(tag);
47 if (!stack_pop(xpdd->gnttab_ss, &ptr_ref))
48 {
49 KdPrint((__DRIVER_NAME " No free grant refs\n"));
50 return INVALID_GRANT_REF;
51 }
52 ref = (grant_ref_t)(ULONG_PTR)ptr_ref;
53 #if DBG
54 if (xpdd->gnttab_tag[ref])
55 KdPrint((__DRIVER_NAME " Grant Entry %d for %.4s in use by %.4s\n", ref, (PUCHAR)&tag, (PUCHAR)&xpdd->gnttab_tag[ref]));
56 ASSERT(!xpdd->gnttab_tag[ref]);
57 xpdd->gnttab_tag[ref] = tag;
58 #endif
60 return ref;
61 }
63 int
64 GntTbl_Map(PVOID Context, unsigned int start_idx, unsigned int end_idx)
65 {
66 PXENPCI_DEVICE_DATA xpdd = Context;
67 struct xen_add_to_physmap xatp;
68 unsigned int i = end_idx;
70 /* Loop backwards, so that the first hypercall has the largest index, ensuring that the table will grow only once. */
71 do {
72 xatp.domid = DOMID_SELF;
73 xatp.idx = i;
74 xatp.space = XENMAPSPACE_grant_table;
75 xatp.gpfn = (xen_pfn_t)(xpdd->gnttab_table_physical.QuadPart >> PAGE_SHIFT) + i;
76 if (HYPERVISOR_memory_op(xpdd, XENMEM_add_to_physmap, &xatp))
77 {
78 KdPrint((__DRIVER_NAME " ***ERROR MAPPING FRAME***\n"));
79 }
80 } while (i-- > start_idx);
82 return 0;
83 }
85 grant_ref_t
86 GntTbl_GrantAccess(
87 PVOID Context,
88 domid_t domid,
89 uint32_t frame, // xen api limits pfn to 32bit, so no guests over 8TB
90 int readonly,
91 grant_ref_t ref,
92 ULONG tag)
93 {
94 PXENPCI_DEVICE_DATA xpdd = Context;
96 //KdPrint((__DRIVER_NAME " --> GntTbl_GrantAccess\n"));
98 if (ref == INVALID_GRANT_REF)
99 ref = GntTbl_GetRef(Context, tag);
100 if (ref == INVALID_GRANT_REF)
101 return ref;
103 ASSERT(xpdd->gnttab_tag[ref] == tag);
105 xpdd->gnttab_table[ref].frame = frame;
106 xpdd->gnttab_table[ref].domid = domid;
108 if (xpdd->gnttab_table[ref].flags)
109 {
110 #if DBG
111 KdPrint((__DRIVER_NAME " Grant Entry %d for %.4s still in use by %.4s\n", ref, (PUCHAR)&tag, (PUCHAR)&xpdd->gnttab_tag[ref]));
112 #else
113 KdPrint((__DRIVER_NAME " Grant Entry %d for %.4s still in use\n", ref, (PUCHAR)&tag));
114 #endif
115 }
116 ASSERT(!xpdd->gnttab_table[ref].flags);
118 KeMemoryBarrier();
119 readonly *= GTF_readonly;
120 xpdd->gnttab_table[ref].flags = GTF_permit_access | (uint16_t)readonly;
122 return ref;
123 }
125 BOOLEAN
126 GntTbl_EndAccess(
127 PVOID Context,
128 grant_ref_t ref,
129 BOOLEAN keepref,
130 ULONG tag)
131 {
132 PXENPCI_DEVICE_DATA xpdd = Context;
133 unsigned short flags, nflags;
135 ASSERT(ref != INVALID_GRANT_REF);
136 ASSERT(xpdd->gnttab_tag[ref] == tag);
138 nflags = xpdd->gnttab_table[ref].flags;
139 do {
140 if ((flags = nflags) & (GTF_reading|GTF_writing))
141 {
142 KdPrint((__DRIVER_NAME " Grant Entry %d for %.4s still use\n", ref, (PUCHAR)&tag));
143 return FALSE;
144 }
145 } while ((nflags = InterlockedCompareExchange16(
146 (volatile SHORT *)&xpdd->gnttab_table[ref].flags, 0, flags)) != flags);
148 if (!keepref)
149 GntTbl_PutRef(Context, ref, tag);
150 //KdPrint((__DRIVER_NAME " <-- GntTbl_EndAccess\n"));
151 return TRUE;
152 }
154 static unsigned int
155 GntTbl_QueryMaxFrames(PXENPCI_DEVICE_DATA xpdd)
156 {
157 struct gnttab_query_size query;
158 int rc;
160 query.dom = DOMID_SELF;
162 rc = HYPERVISOR_grant_table_op(xpdd, GNTTABOP_query_size, &query, 1);
163 if ((rc < 0) || (query.status != GNTST_okay))
164 {
165 KdPrint((__DRIVER_NAME " ***CANNOT QUERY MAX GRANT FRAME***\n"));
166 return 4; /* Legacy max supported number of frames */
167 }
168 return query.max_nr_frames;
169 }
171 VOID
172 GntTbl_Init(PXENPCI_DEVICE_DATA xpdd)
173 {
174 int i;
175 int grant_entries;
177 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
179 FUNCTION_ENTER();
181 xpdd->grant_frames = GntTbl_QueryMaxFrames(xpdd);
182 KdPrint((__DRIVER_NAME " grant_frames = %d\n", xpdd->grant_frames));
183 grant_entries = min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t)));
184 KdPrint((__DRIVER_NAME " grant_entries = %d\n", grant_entries));
185 #if DBG
186 xpdd->gnttab_tag = ExAllocatePoolWithTag(NonPagedPool, grant_entries * sizeof(ULONG), XENPCI_POOL_TAG);
187 RtlZeroMemory(xpdd->gnttab_tag, grant_entries * sizeof(ULONG));
188 #endif
189 xpdd->gnttab_table_copy = ExAllocatePoolWithTag(NonPagedPool, xpdd->grant_frames * PAGE_SIZE, XENPCI_POOL_TAG);
190 ASSERT(xpdd->gnttab_table_copy); // lazy
191 xpdd->gnttab_table_physical = XenPci_AllocMMIO(xpdd, PAGE_SIZE * xpdd->grant_frames);
192 xpdd->gnttab_table = MmMapIoSpace(xpdd->gnttab_table_physical, PAGE_SIZE * xpdd->grant_frames, MmNonCached);
193 if (!xpdd->gnttab_table)
194 {
195 KdPrint((__DRIVER_NAME " Error Mapping Grant Table Shared Memory\n"));
196 // this should be a show stopper...
197 return;
198 }
200 stack_new(&xpdd->gnttab_ss, grant_entries);
202 for (i = NR_RESERVED_ENTRIES; i < grant_entries; i++)
203 stack_push(xpdd->gnttab_ss, (PVOID)i);
205 GntTbl_Map(xpdd, 0, xpdd->grant_frames - 1);
207 RtlZeroMemory(xpdd->gnttab_table, PAGE_SIZE * xpdd->grant_frames);
209 FUNCTION_EXIT();
210 }
212 VOID
213 GntTbl_Suspend(PXENPCI_DEVICE_DATA xpdd)
214 {
215 memcpy(xpdd->gnttab_table_copy, xpdd->gnttab_table, xpdd->grant_frames * PAGE_SIZE);
216 }
218 VOID
219 GntTbl_Resume(PXENPCI_DEVICE_DATA xpdd)
220 {
221 ULONG new_grant_frames;
222 ULONG result;
224 FUNCTION_ENTER();
226 new_grant_frames = GntTbl_QueryMaxFrames(xpdd);
227 KdPrint((__DRIVER_NAME " new_grant_frames = %d\n", new_grant_frames));
228 ASSERT(new_grant_frames >= xpdd->grant_frames); // lazy
229 result = GntTbl_Map(xpdd, 0, xpdd->grant_frames - 1);
230 KdPrint((__DRIVER_NAME " GntTbl_Map result = %d\n", result));
231 memcpy(xpdd->gnttab_table, xpdd->gnttab_table_copy, xpdd->grant_frames * PAGE_SIZE);
233 FUNCTION_EXIT();
234 }