]>
Commit | Line | Data |
---|---|---|
86d968e0 | 1 | /** @file\r |
493dde94 | 2 | XenBus Bus driver implementation.\r |
86d968e0 AP |
3 | \r |
4 | This file implement the necessary to discover and enumerate Xen PV devices\r | |
5 | through XenStore.\r | |
6 | \r | |
7 | Copyright (C) 2010 Spectra Logic Corporation\r | |
8 | Copyright (C) 2008 Doug Rabson\r | |
9 | Copyright (C) 2005 Rusty Russell, IBM Corporation\r | |
10 | Copyright (C) 2005 Mike Wray, Hewlett-Packard\r | |
11 | Copyright (C) 2005 XenSource Ltd\r | |
12 | Copyright (C) 2014, Citrix Ltd.\r | |
13 | \r | |
14 | This file may be distributed separately from the Linux kernel, or\r | |
15 | incorporated into other software packages, subject to the following license:\r | |
16 | \r | |
34131e1b | 17 | SPDX-License-Identifier: MIT\r |
86d968e0 AP |
18 | **/\r |
19 | \r | |
20 | #include <Library/PrintLib.h>\r | |
21 | \r | |
22 | #include "XenBus.h"\r | |
23 | #include "GrantTable.h"\r | |
24 | #include "XenStore.h"\r | |
25 | #include "EventChannel.h"\r | |
26 | \r | |
27 | #include <IndustryStandard/Xen/io/xenbus.h>\r | |
28 | \r | |
29 | STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData;\r | |
30 | \r | |
31 | STATIC XENBUS_DEVICE_PATH gXenBusDevicePathTemplate = {\r | |
489c5c67 AP |
32 | { // Vendor\r |
33 | { // Vendor.Header\r | |
34 | HARDWARE_DEVICE_PATH, // Vendor.Header.Type\r | |
35 | HW_VENDOR_DP, // Vendor.Header.SubType\r | |
36 | {\r | |
37 | (UINT8) (sizeof (XENBUS_DEVICE_PATH)), // Vendor.Header.Length[0]\r | |
38 | (UINT8) (sizeof (XENBUS_DEVICE_PATH) >> 8), // Vendor.Header.Length[1]\r | |
39 | }\r | |
40 | },\r | |
41 | XENBUS_PROTOCOL_GUID, // Vendor.Guid\r | |
42 | },\r | |
43 | 0, // Type\r | |
44 | 0 // DeviceId\r | |
86d968e0 AP |
45 | };\r |
46 | \r | |
47 | \r | |
48 | /**\r | |
49 | Search our internal record of configured devices (not the XenStore) to\r | |
50 | determine if the XenBus device indicated by Node is known to the system.\r | |
51 | \r | |
52 | @param Dev The XENBUS_DEVICE instance to search for device children.\r | |
53 | @param Node The XenStore node path for the device to find.\r | |
54 | \r | |
55 | @return The XENBUS_PRIVATE_DATA of the found device if any, or NULL.\r | |
56 | */\r | |
57 | STATIC\r | |
58 | XENBUS_PRIVATE_DATA *\r | |
59 | XenBusDeviceInitialized (\r | |
60 | IN XENBUS_DEVICE *Dev,\r | |
61 | IN CONST CHAR8 *Node\r | |
62 | )\r | |
63 | {\r | |
64 | LIST_ENTRY *Entry;\r | |
65 | XENBUS_PRIVATE_DATA *Child;\r | |
66 | XENBUS_PRIVATE_DATA *Result;\r | |
67 | \r | |
68 | if (IsListEmpty (&Dev->ChildList)) {\r | |
69 | return NULL;\r | |
70 | }\r | |
71 | \r | |
72 | Result = NULL;\r | |
73 | for (Entry = GetFirstNode (&Dev->ChildList);\r | |
74 | !IsNodeAtEnd (&Dev->ChildList, Entry);\r | |
75 | Entry = GetNextNode (&Dev->ChildList, Entry)) {\r | |
76 | Child = XENBUS_PRIVATE_DATA_FROM_LINK (Entry);\r | |
77 | if (!AsciiStrCmp (Child->XenBusIo.Node, Node)) {\r | |
78 | Result = Child;\r | |
79 | break;\r | |
80 | }\r | |
81 | }\r | |
82 | \r | |
83 | return (Result);\r | |
84 | }\r | |
85 | \r | |
86 | STATIC\r | |
87 | XenbusState\r | |
88 | XenBusReadDriverState (\r | |
89 | IN CONST CHAR8 *Path\r | |
90 | )\r | |
91 | {\r | |
92 | XenbusState State;\r | |
93 | CHAR8 *Ptr = NULL;\r | |
94 | XENSTORE_STATUS Status;\r | |
95 | \r | |
96 | Status = XenStoreRead (XST_NIL, Path, "state", NULL, (VOID **)&Ptr);\r | |
97 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
98 | State = XenbusStateClosed;\r | |
99 | } else {\r | |
100 | State = AsciiStrDecimalToUintn (Ptr);\r | |
101 | }\r | |
102 | \r | |
103 | if (Ptr != NULL) {\r | |
104 | FreePool (Ptr);\r | |
105 | }\r | |
106 | \r | |
107 | return State;\r | |
108 | }\r | |
109 | \r | |
110 | //\r | |
111 | // Callers should ensure that they are only one calling XenBusAddDevice.\r | |
112 | //\r | |
113 | STATIC\r | |
114 | EFI_STATUS\r | |
115 | XenBusAddDevice (\r | |
116 | XENBUS_DEVICE *Dev,\r | |
117 | CONST CHAR8 *Type,\r | |
118 | CONST CHAR8 *Id)\r | |
119 | {\r | |
120 | CHAR8 DevicePath[XENSTORE_ABS_PATH_MAX];\r | |
121 | XENSTORE_STATUS StatusXenStore;\r | |
122 | XENBUS_PRIVATE_DATA *Private;\r | |
123 | EFI_STATUS Status;\r | |
124 | XENBUS_DEVICE_PATH *TempXenBusPath;\r | |
d9fdfd85 | 125 | VOID *ChildXenIo;\r |
86d968e0 AP |
126 | \r |
127 | AsciiSPrint (DevicePath, sizeof (DevicePath),\r | |
128 | "device/%a/%a", Type, Id);\r | |
129 | \r | |
130 | if (XenStorePathExists (XST_NIL, DevicePath, "")) {\r | |
131 | XENBUS_PRIVATE_DATA *Child;\r | |
132 | enum xenbus_state State;\r | |
133 | CHAR8 *BackendPath;\r | |
134 | \r | |
135 | Child = XenBusDeviceInitialized (Dev, DevicePath);\r | |
136 | if (Child != NULL) {\r | |
137 | /*\r | |
138 | * We are already tracking this node\r | |
139 | */\r | |
140 | Status = EFI_SUCCESS;\r | |
141 | goto out;\r | |
142 | }\r | |
143 | \r | |
144 | State = XenBusReadDriverState (DevicePath);\r | |
145 | if (State != XenbusStateInitialising) {\r | |
146 | /*\r | |
147 | * Device is not new, so ignore it. This can\r | |
148 | * happen if a device is going away after\r | |
149 | * switching to Closed.\r | |
150 | */\r | |
151 | DEBUG ((EFI_D_INFO, "XenBus: Device %a ignored. "\r | |
152 | "State %d\n", DevicePath, State));\r | |
153 | Status = EFI_SUCCESS;\r | |
154 | goto out;\r | |
155 | }\r | |
156 | \r | |
157 | StatusXenStore = XenStoreRead (XST_NIL, DevicePath, "backend",\r | |
158 | NULL, (VOID **) &BackendPath);\r | |
159 | if (StatusXenStore != XENSTORE_STATUS_SUCCESS) {\r | |
160 | DEBUG ((EFI_D_ERROR, "xenbus: %a no backend path.\n", DevicePath));\r | |
161 | Status = EFI_NOT_FOUND;\r | |
162 | goto out;\r | |
163 | }\r | |
164 | \r | |
165 | Private = AllocateCopyPool (sizeof (*Private), &gXenBusPrivateData);\r | |
166 | Private->XenBusIo.Type = AsciiStrDup (Type);\r | |
167 | Private->XenBusIo.Node = AsciiStrDup (DevicePath);\r | |
168 | Private->XenBusIo.Backend = BackendPath;\r | |
017a4866 | 169 | Private->XenBusIo.DeviceId = (UINT16)AsciiStrDecimalToUintn (Id);\r |
86d968e0 AP |
170 | Private->Dev = Dev;\r |
171 | \r | |
172 | TempXenBusPath = AllocateCopyPool (sizeof (XENBUS_DEVICE_PATH),\r | |
173 | &gXenBusDevicePathTemplate);\r | |
174 | if (!AsciiStrCmp (Private->XenBusIo.Type, "vbd")) {\r | |
175 | TempXenBusPath->Type = XENBUS_DEVICE_PATH_TYPE_VBD;\r | |
176 | }\r | |
177 | TempXenBusPath->DeviceId = Private->XenBusIo.DeviceId;\r | |
178 | Private->DevicePath = (XENBUS_DEVICE_PATH *)AppendDevicePathNode (\r | |
179 | Dev->DevicePath,\r | |
180 | &TempXenBusPath->Vendor.Header);\r | |
181 | FreePool (TempXenBusPath);\r | |
182 | \r | |
183 | InsertTailList (&Dev->ChildList, &Private->Link);\r | |
184 | \r | |
185 | Status = gBS->InstallMultipleProtocolInterfaces (\r | |
186 | &Private->Handle,\r | |
187 | &gEfiDevicePathProtocolGuid, Private->DevicePath,\r | |
188 | &gXenBusProtocolGuid, &Private->XenBusIo,\r | |
189 | NULL);\r | |
190 | if (EFI_ERROR (Status)) {\r | |
191 | goto ErrorInstallProtocol;\r | |
192 | }\r | |
193 | \r | |
194 | Status = gBS->OpenProtocol (Dev->ControllerHandle,\r | |
d9fdfd85 AB |
195 | &gXenIoProtocolGuid,\r |
196 | &ChildXenIo, Dev->This->DriverBindingHandle,\r | |
86d968e0 AP |
197 | Private->Handle,\r |
198 | EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);\r | |
199 | if (EFI_ERROR (Status)) {\r | |
200 | DEBUG ((EFI_D_ERROR, "open by child controller fail (%r)\n",\r | |
201 | Status));\r | |
202 | goto ErrorOpenProtocolByChild;\r | |
203 | }\r | |
204 | } else {\r | |
205 | DEBUG ((EFI_D_ERROR, "XenBus: does not exist: %a\n", DevicePath));\r | |
206 | Status = EFI_NOT_FOUND;\r | |
207 | }\r | |
208 | \r | |
209 | return Status;\r | |
210 | \r | |
211 | ErrorOpenProtocolByChild:\r | |
212 | gBS->UninstallMultipleProtocolInterfaces (\r | |
2ef0c27c | 213 | Private->Handle,\r |
86d968e0 AP |
214 | &gEfiDevicePathProtocolGuid, Private->DevicePath,\r |
215 | &gXenBusProtocolGuid, &Private->XenBusIo,\r | |
216 | NULL);\r | |
217 | ErrorInstallProtocol:\r | |
218 | RemoveEntryList (&Private->Link);\r | |
219 | FreePool (Private->DevicePath);\r | |
220 | FreePool ((VOID *) Private->XenBusIo.Backend);\r | |
221 | FreePool ((VOID *) Private->XenBusIo.Node);\r | |
222 | FreePool ((VOID *) Private->XenBusIo.Type);\r | |
223 | FreePool (Private);\r | |
224 | out:\r | |
225 | return Status;\r | |
226 | }\r | |
227 | \r | |
228 | /**\r | |
229 | Enumerate all devices of the given type on this bus.\r | |
230 | \r | |
231 | @param Dev A XENBUS_DEVICE instance.\r | |
232 | @param Type String indicating the device sub-tree (e.g. "vfb", "vif")\r | |
233 | to enumerate.\r | |
234 | \r | |
235 | Devices that are found are been initialize via XenBusAddDevice ().\r | |
236 | XenBusAddDevice () ignores duplicate detects and ignores duplicate devices,\r | |
237 | so it can be called unconditionally for any device found in the XenStore.\r | |
238 | */\r | |
239 | STATIC\r | |
240 | VOID\r | |
241 | XenBusEnumerateDeviceType (\r | |
242 | XENBUS_DEVICE *Dev,\r | |
243 | CONST CHAR8 *Type\r | |
244 | )\r | |
245 | {\r | |
246 | CONST CHAR8 **Directory;\r | |
247 | UINTN Index;\r | |
248 | UINT32 Count;\r | |
249 | XENSTORE_STATUS Status;\r | |
250 | \r | |
251 | Status = XenStoreListDirectory (XST_NIL,\r | |
252 | "device", Type,\r | |
253 | &Count, &Directory);\r | |
254 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
255 | return;\r | |
256 | }\r | |
257 | for (Index = 0; Index < Count; Index++) {\r | |
258 | XenBusAddDevice (Dev, Type, Directory[Index]);\r | |
259 | }\r | |
260 | \r | |
017a4866 | 261 | FreePool ((VOID*)Directory);\r |
86d968e0 AP |
262 | }\r |
263 | \r | |
264 | \r | |
265 | /**\r | |
266 | Enumerate the devices on a XenBus bus and install a XenBus Protocol instance.\r | |
267 | \r | |
268 | Caller should ensure that it is the only one to call this function. This\r | |
269 | function cannot be called concurrently.\r | |
270 | \r | |
271 | @param Dev A XENBUS_DEVICE instance.\r | |
272 | \r | |
273 | @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r | |
274 | indicating the type of failure.\r | |
275 | */\r | |
276 | XENSTORE_STATUS\r | |
277 | XenBusEnumerateBus (\r | |
278 | XENBUS_DEVICE *Dev\r | |
279 | )\r | |
280 | {\r | |
281 | CONST CHAR8 **Types;\r | |
282 | UINTN Index;\r | |
283 | UINT32 Count;\r | |
284 | XENSTORE_STATUS Status;\r | |
285 | \r | |
286 | Status = XenStoreListDirectory (XST_NIL,\r | |
287 | "device", "",\r | |
288 | &Count, &Types);\r | |
289 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
290 | return Status;\r | |
291 | }\r | |
292 | \r | |
293 | for (Index = 0; Index < Count; Index++) {\r | |
294 | XenBusEnumerateDeviceType (Dev, Types[Index]);\r | |
295 | }\r | |
296 | \r | |
017a4866 | 297 | FreePool ((VOID*)Types);\r |
86d968e0 AP |
298 | \r |
299 | return XENSTORE_STATUS_SUCCESS;\r | |
300 | }\r | |
301 | \r | |
302 | STATIC\r | |
303 | XENSTORE_STATUS\r | |
304 | EFIAPI\r | |
305 | XenBusSetState (\r | |
306 | IN XENBUS_PROTOCOL *This,\r | |
e26a83cd | 307 | IN CONST XENSTORE_TRANSACTION *Transaction,\r |
86d968e0 AP |
308 | IN enum xenbus_state NewState\r |
309 | )\r | |
310 | {\r | |
311 | enum xenbus_state CurrentState;\r | |
312 | XENSTORE_STATUS Status;\r | |
313 | CHAR8 *Temp;\r | |
314 | \r | |
315 | DEBUG ((EFI_D_INFO, "XenBus: Set state to %d\n", NewState));\r | |
316 | \r | |
317 | Status = XenStoreRead (Transaction, This->Node, "state", NULL, (VOID **)&Temp);\r | |
318 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
319 | goto Out;\r | |
320 | }\r | |
321 | CurrentState = AsciiStrDecimalToUintn (Temp);\r | |
322 | FreePool (Temp);\r | |
323 | if (CurrentState == NewState) {\r | |
324 | goto Out;\r | |
325 | }\r | |
326 | \r | |
327 | do {\r | |
328 | Status = XenStoreSPrint (Transaction, This->Node, "state", "%d", NewState);\r | |
329 | } while (Status == XENSTORE_STATUS_EAGAIN);\r | |
330 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
331 | DEBUG ((EFI_D_ERROR, "XenBus: failed to write new state\n"));\r | |
332 | goto Out;\r | |
333 | }\r | |
334 | DEBUG ((EFI_D_INFO, "XenBus: Set state to %d, done\n", NewState));\r | |
335 | \r | |
336 | Out:\r | |
337 | return Status;\r | |
338 | }\r | |
339 | \r | |
340 | STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData = {\r | |
43be9f4c AP |
341 | XENBUS_PRIVATE_DATA_SIGNATURE, // Signature\r |
342 | { NULL, NULL }, // Link\r | |
343 | NULL, // Handle\r | |
344 | { // XenBusIo\r | |
345 | XenBusXenStoreRead, // XenBusIo.XsRead\r | |
346 | XenBusXenStoreBackendRead, // XenBusIo.XsBackendRead\r | |
347 | XenBusXenStoreSPrint, // XenBusIo.XsPrintf\r | |
348 | XenBusXenStoreRemove, // XenBusIo.XsRemove\r | |
349 | XenBusXenStoreTransactionStart, // XenBusIo.XsTransactionStart\r | |
350 | XenBusXenStoreTransactionEnd, // XenBusIo.XsTransactionEnd\r | |
351 | XenBusSetState, // XenBusIo.SetState\r | |
352 | XenBusGrantAccess, // XenBusIo.GrantAccess\r | |
353 | XenBusGrantEndAccess, // XenBusIo.GrantEndAccess\r | |
354 | XenBusEventChannelAllocate, // XenBusIo.EventChannelAllocate\r | |
355 | XenBusEventChannelNotify, // XenBusIo.EventChannelNotify\r | |
356 | XenBusEventChannelClose, // XenBusIo.EventChannelClose\r | |
357 | XenBusRegisterWatch, // XenBusIo.RegisterWatch\r | |
358 | XenBusRegisterWatchBackend, // XenBusIo.RegisterWatchBackend\r | |
359 | XenBusUnregisterWatch, // XenBusIo.UnregisterWatch\r | |
360 | XenBusWaitForWatch, // XenBusIo.WaitForWatch\r | |
361 | \r | |
362 | NULL, // XenBusIo.Type\r | |
363 | 0, // XenBusIo.DeviceId\r | |
364 | NULL, // XenBusIo.Node\r | |
365 | NULL, // XenBusIo.Backend\r | |
366 | },\r | |
367 | \r | |
368 | NULL, // Dev\r | |
369 | NULL // DevicePath\r | |
86d968e0 | 370 | };\r |