]>
Commit | Line | Data |
---|---|---|
e517857b | 1 | /* |
6f14cc18 | 2 | * Copyright (C) 2010 - 2015 UNISYS CORPORATION |
12e364b9 KC |
3 | * All rights reserved. |
4 | * | |
6f14cc18 BR |
5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms and conditions of the GNU General Public License, | |
7 | * version 2, as published by the Free Software Foundation. | |
12e364b9 KC |
8 | * |
9 | * This program is distributed in the hope that it will be useful, but | |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | |
12 | * NON INFRINGEMENT. See the GNU General Public License for more | |
13 | * details. | |
14 | */ | |
15 | ||
55c67dca | 16 | #include <linux/acpi.h> |
1ba00980 | 17 | #include <linux/crash_dump.h> |
12e364b9 | 18 | |
55c67dca PB |
19 | #include "visorbus.h" |
20 | #include "visorbus_private.h" | |
21 | ||
f79e1dfd | 22 | /* {72120008-4AAB-11DC-8530-444553544200} */ |
1604ebec DK |
23 | #define VISOR_SIOVM_GUID GUID_INIT(0x72120008, 0x4AAB, 0x11DC, 0x85, 0x30, \ |
24 | 0x44, 0x45, 0x53, 0x54, 0x42, 0x00) | |
f79e1dfd | 25 | |
b32c5cb8 AS |
26 | static const guid_t visor_vhba_channel_guid = VISOR_VHBA_CHANNEL_GUID; |
27 | static const guid_t visor_siovm_guid = VISOR_SIOVM_GUID; | |
28 | static const guid_t visor_controlvm_channel_guid = VISOR_CONTROLVM_CHANNEL_GUID; | |
29 | ||
3fbee197 DK |
30 | #define POLLJIFFIES_CONTROLVM_FAST 1 |
31 | #define POLLJIFFIES_CONTROLVM_SLOW 100 | |
12e364b9 | 32 | |
2c7e1d4e | 33 | #define MAX_CONTROLVM_PAYLOAD_BYTES (1024 * 128) |
2ee0deec | 34 | |
a27ded92 | 35 | #define UNISYS_VISOR_LEAF_ID 0x40000000 |
d5b3f1dc EA |
36 | |
37 | /* The s-Par leaf ID returns "UnisysSpar64" encoded across ebx, ecx, edx */ | |
a27ded92 SW |
38 | #define UNISYS_VISOR_ID_EBX 0x73696e55 |
39 | #define UNISYS_VISOR_ID_ECX 0x70537379 | |
40 | #define UNISYS_VISOR_ID_EDX 0x34367261 | |
d5b3f1dc | 41 | |
ec17f452 | 42 | /* |
6577cbf1 DK |
43 | * When the controlvm channel is idle for at least MIN_IDLE_SECONDS, we switch |
44 | * to slow polling mode. As soon as we get a controlvm message, we switch back | |
45 | * to fast polling mode. | |
ec17f452 | 46 | */ |
12e364b9 | 47 | #define MIN_IDLE_SECONDS 10 |
12e364b9 | 48 | |
46168810 EA |
49 | struct parser_context { |
50 | unsigned long allocbytes; | |
51 | unsigned long param_bytes; | |
52 | u8 *curr; | |
53 | unsigned long bytes_remaining; | |
54 | bool byte_stream; | |
26a42c25 | 55 | struct visor_controlvm_parameters_header data; |
46168810 EA |
56 | }; |
57 | ||
12cbd490 | 58 | /* VMCALL_CONTROLVM_ADDR: Used by all guests, not just IO. */ |
c8684a9d DB |
59 | #define VMCALL_CONTROLVM_ADDR 0x0501 |
60 | ||
61 | enum vmcall_result { | |
62 | VMCALL_RESULT_SUCCESS = 0, | |
63 | VMCALL_RESULT_INVALID_PARAM = 1, | |
64 | VMCALL_RESULT_DATA_UNAVAILABLE = 2, | |
65 | VMCALL_RESULT_FAILURE_UNAVAILABLE = 3, | |
66 | VMCALL_RESULT_DEVICE_ERROR = 4, | |
67 | VMCALL_RESULT_DEVICE_NOT_READY = 5 | |
68 | }; | |
69 | ||
70 | /* | |
71 | * struct vmcall_io_controlvm_addr_params - Structure for IO VMCALLS. Has | |
72 | * parameters to VMCALL_CONTROLVM_ADDR | |
73 | * interface. | |
74 | * @address: The Guest-relative physical address of the ControlVm channel. | |
75 | * This VMCall fills this in with the appropriate address. | |
76 | * Contents provided by this VMCALL (OUT). | |
77 | * @channel_bytes: The size of the ControlVm channel in bytes This VMCall fills | |
78 | * this in with the appropriate address. Contents provided by | |
79 | * this VMCALL (OUT). | |
80 | * @unused: Unused Bytes in the 64-Bit Aligned Struct. | |
81 | */ | |
82 | struct vmcall_io_controlvm_addr_params { | |
83 | u64 address; | |
84 | u32 channel_bytes; | |
85 | u8 unused[4]; | |
86 | } __packed; | |
87 | ||
765b2f82 SW |
88 | struct visorchipset_device { |
89 | struct acpi_device *acpi_device; | |
90 | unsigned long poll_jiffies; | |
91 | /* when we got our last controlvm message */ | |
92 | unsigned long most_recent_message_jiffies; | |
93 | struct delayed_work periodic_controlvm_work; | |
765b2f82 SW |
94 | struct visorchannel *controlvm_channel; |
95 | unsigned long controlvm_payload_bytes_buffered; | |
96 | /* | |
97 | * The following variables are used to handle the scenario where we are | |
98 | * unable to offload the payload from a controlvm message due to memory | |
99 | * requirements. In this scenario, we simply stash the controlvm | |
100 | * message, then attempt to process it again the next time | |
101 | * controlvm_periodic_work() runs. | |
102 | */ | |
103 | struct controlvm_message controlvm_pending_msg; | |
104 | bool controlvm_pending_msg_valid; | |
800da5fb | 105 | struct vmcall_io_controlvm_addr_params controlvm_params; |
765b2f82 | 106 | }; |
12e364b9 | 107 | |
765b2f82 | 108 | static struct visorchipset_device *chipset_dev; |
12e364b9 | 109 | |
12e364b9 KC |
110 | struct parahotplug_request { |
111 | struct list_head list; | |
112 | int id; | |
113 | unsigned long expiration; | |
3ab47701 | 114 | struct controlvm_message msg; |
12e364b9 KC |
115 | }; |
116 | ||
19f6634f BR |
117 | /* prototypes for attributes */ |
118 | static ssize_t toolaction_show(struct device *dev, | |
84efd207 DK |
119 | struct device_attribute *attr, |
120 | char *buf) | |
121 | { | |
122 | u8 tool_action = 0; | |
002a5abb DK |
123 | int err; |
124 | ||
125 | err = visorchannel_read(chipset_dev->controlvm_channel, | |
545f0913 | 126 | offsetof(struct visor_controlvm_channel, |
002a5abb DK |
127 | tool_action), |
128 | &tool_action, sizeof(u8)); | |
129 | if (err) | |
130 | return err; | |
746fb137 | 131 | return sprintf(buf, "%u\n", tool_action); |
84efd207 DK |
132 | } |
133 | ||
19f6634f | 134 | static ssize_t toolaction_store(struct device *dev, |
8e76e695 | 135 | struct device_attribute *attr, |
84efd207 DK |
136 | const char *buf, size_t count) |
137 | { | |
138 | u8 tool_action; | |
dc35cdf3 | 139 | int err; |
84efd207 DK |
140 | |
141 | if (kstrtou8(buf, 10, &tool_action)) | |
142 | return -EINVAL; | |
545f0913 SW |
143 | err = visorchannel_write(chipset_dev->controlvm_channel, |
144 | offsetof(struct visor_controlvm_channel, | |
145 | tool_action), | |
146 | &tool_action, sizeof(u8)); | |
dc35cdf3 DK |
147 | if (err) |
148 | return err; | |
84efd207 DK |
149 | return count; |
150 | } | |
19f6634f BR |
151 | static DEVICE_ATTR_RW(toolaction); |
152 | ||
54b31229 | 153 | static ssize_t boottotool_show(struct device *dev, |
1b1d463d DK |
154 | struct device_attribute *attr, |
155 | char *buf) | |
156 | { | |
545f0913 | 157 | struct efi_visor_indication efi_visor_indication; |
0b01c6ce DK |
158 | int err; |
159 | ||
160 | err = visorchannel_read(chipset_dev->controlvm_channel, | |
545f0913 SW |
161 | offsetof(struct visor_controlvm_channel, |
162 | efi_visor_ind), | |
163 | &efi_visor_indication, | |
164 | sizeof(struct efi_visor_indication)); | |
0b01c6ce DK |
165 | if (err) |
166 | return err; | |
545f0913 | 167 | return sprintf(buf, "%u\n", efi_visor_indication.boot_to_tool); |
1b1d463d DK |
168 | } |
169 | ||
54b31229 | 170 | static ssize_t boottotool_store(struct device *dev, |
1b1d463d DK |
171 | struct device_attribute *attr, |
172 | const char *buf, size_t count) | |
173 | { | |
b309266e | 174 | int val, err; |
545f0913 | 175 | struct efi_visor_indication efi_visor_indication; |
1b1d463d DK |
176 | |
177 | if (kstrtoint(buf, 10, &val)) | |
178 | return -EINVAL; | |
545f0913 SW |
179 | efi_visor_indication.boot_to_tool = val; |
180 | err = visorchannel_write(chipset_dev->controlvm_channel, | |
181 | offsetof(struct visor_controlvm_channel, | |
182 | efi_visor_ind), | |
183 | &(efi_visor_indication), | |
184 | sizeof(struct efi_visor_indication)); | |
b309266e DK |
185 | if (err) |
186 | return err; | |
1b1d463d DK |
187 | return count; |
188 | } | |
54b31229 BR |
189 | static DEVICE_ATTR_RW(boottotool); |
190 | ||
422af17c | 191 | static ssize_t error_show(struct device *dev, struct device_attribute *attr, |
8a4a8a03 DK |
192 | char *buf) |
193 | { | |
194 | u32 error = 0; | |
d9857c79 | 195 | int err; |
8a4a8a03 | 196 | |
d9857c79 | 197 | err = visorchannel_read(chipset_dev->controlvm_channel, |
545f0913 | 198 | offsetof(struct visor_controlvm_channel, |
d9857c79 DK |
199 | installation_error), |
200 | &error, sizeof(u32)); | |
201 | if (err) | |
202 | return err; | |
6df555c1 | 203 | return sprintf(buf, "%u\n", error); |
8a4a8a03 DK |
204 | } |
205 | ||
422af17c | 206 | static ssize_t error_store(struct device *dev, struct device_attribute *attr, |
8a4a8a03 DK |
207 | const char *buf, size_t count) |
208 | { | |
209 | u32 error; | |
ea295857 | 210 | int err; |
8a4a8a03 DK |
211 | |
212 | if (kstrtou32(buf, 10, &error)) | |
213 | return -EINVAL; | |
545f0913 SW |
214 | err = visorchannel_write(chipset_dev->controlvm_channel, |
215 | offsetof(struct visor_controlvm_channel, | |
216 | installation_error), | |
217 | &error, sizeof(u32)); | |
ea295857 DK |
218 | if (err) |
219 | return err; | |
8a4a8a03 DK |
220 | return count; |
221 | } | |
422af17c BR |
222 | static DEVICE_ATTR_RW(error); |
223 | ||
224 | static ssize_t textid_show(struct device *dev, struct device_attribute *attr, | |
79730c7c DK |
225 | char *buf) |
226 | { | |
227 | u32 text_id = 0; | |
0d406436 DK |
228 | int err; |
229 | ||
545f0913 SW |
230 | err = visorchannel_read(chipset_dev->controlvm_channel, |
231 | offsetof(struct visor_controlvm_channel, | |
232 | installation_text_id), | |
233 | &text_id, sizeof(u32)); | |
0d406436 DK |
234 | if (err) |
235 | return err; | |
6df555c1 | 236 | return sprintf(buf, "%u\n", text_id); |
79730c7c DK |
237 | } |
238 | ||
422af17c | 239 | static ssize_t textid_store(struct device *dev, struct device_attribute *attr, |
79730c7c DK |
240 | const char *buf, size_t count) |
241 | { | |
242 | u32 text_id; | |
08a55d2d | 243 | int err; |
79730c7c DK |
244 | |
245 | if (kstrtou32(buf, 10, &text_id)) | |
246 | return -EINVAL; | |
545f0913 SW |
247 | err = visorchannel_write(chipset_dev->controlvm_channel, |
248 | offsetof(struct visor_controlvm_channel, | |
249 | installation_text_id), | |
250 | &text_id, sizeof(u32)); | |
08a55d2d DK |
251 | if (err) |
252 | return err; | |
79730c7c DK |
253 | return count; |
254 | } | |
422af17c BR |
255 | static DEVICE_ATTR_RW(textid); |
256 | ||
257 | static ssize_t remaining_steps_show(struct device *dev, | |
97f792ee DK |
258 | struct device_attribute *attr, char *buf) |
259 | { | |
260 | u16 remaining_steps = 0; | |
c53578bd DK |
261 | int err; |
262 | ||
263 | err = visorchannel_read(chipset_dev->controlvm_channel, | |
545f0913 | 264 | offsetof(struct visor_controlvm_channel, |
c53578bd DK |
265 | installation_remaining_steps), |
266 | &remaining_steps, sizeof(u16)); | |
267 | if (err) | |
268 | return err; | |
746fb137 | 269 | return sprintf(buf, "%hu\n", remaining_steps); |
97f792ee DK |
270 | } |
271 | ||
422af17c | 272 | static ssize_t remaining_steps_store(struct device *dev, |
8e76e695 | 273 | struct device_attribute *attr, |
97f792ee DK |
274 | const char *buf, size_t count) |
275 | { | |
276 | u16 remaining_steps; | |
e030d39d | 277 | int err; |
97f792ee DK |
278 | |
279 | if (kstrtou16(buf, 10, &remaining_steps)) | |
280 | return -EINVAL; | |
545f0913 SW |
281 | err = visorchannel_write(chipset_dev->controlvm_channel, |
282 | offsetof(struct visor_controlvm_channel, | |
283 | installation_remaining_steps), | |
284 | &remaining_steps, sizeof(u16)); | |
e030d39d DK |
285 | if (err) |
286 | return err; | |
97f792ee DK |
287 | return count; |
288 | } | |
422af17c BR |
289 | static DEVICE_ATTR_RW(remaining_steps); |
290 | ||
e80ffd4b CD |
291 | static void controlvm_init_response(struct controlvm_message *msg, |
292 | struct controlvm_message_header *msg_hdr, | |
293 | int response) | |
5f251395 DK |
294 | { |
295 | memset(msg, 0, sizeof(struct controlvm_message)); | |
296 | memcpy(&msg->hdr, msg_hdr, sizeof(struct controlvm_message_header)); | |
297 | msg->hdr.payload_bytes = 0; | |
298 | msg->hdr.payload_vm_offset = 0; | |
299 | msg->hdr.payload_max_bytes = 0; | |
300 | if (response < 0) { | |
301 | msg->hdr.flags.failed = 1; | |
302 | msg->hdr.completion_status = (u32)(-response); | |
303 | } | |
304 | } | |
305 | ||
e80ffd4b CD |
306 | static int controlvm_respond_chipset_init( |
307 | struct controlvm_message_header *msg_hdr, | |
308 | int response, | |
309 | enum visor_chipset_feature features) | |
5f251395 DK |
310 | { |
311 | struct controlvm_message outmsg; | |
312 | ||
313 | controlvm_init_response(&outmsg, msg_hdr, response); | |
314 | outmsg.cmd.init_chipset.features = features; | |
765b2f82 | 315 | return visorchannel_signalinsert(chipset_dev->controlvm_channel, |
1d7f5522 | 316 | CONTROLVM_QUEUE_REQUEST, &outmsg); |
5f251395 DK |
317 | } |
318 | ||
e80ffd4b | 319 | static int chipset_init(struct controlvm_message *inmsg) |
12e364b9 KC |
320 | { |
321 | static int chipset_inited; | |
d3ad6e69 | 322 | enum visor_chipset_feature features = 0; |
12e364b9 | 323 | int rc = CONTROLVM_RESP_SUCCESS; |
79c3f971 | 324 | int res = 0; |
12e364b9 | 325 | |
12e364b9 | 326 | if (chipset_inited) { |
98f9ed9e | 327 | rc = -CONTROLVM_RESP_ALREADY_DONE; |
79c3f971 | 328 | res = -EIO; |
5233d1eb | 329 | goto out_respond; |
12e364b9 KC |
330 | } |
331 | chipset_inited = 1; | |
ec17f452 | 332 | /* |
6577cbf1 | 333 | * Set features to indicate we support parahotplug (if Command also |
977980ac DK |
334 | * supports it). Set the "reply" bit so Command knows this is a |
335 | * features-aware driver. | |
2ee0d052 | 336 | */ |
0762188b | 337 | features = inmsg->cmd.init_chipset.features & |
d3ad6e69 | 338 | VISOR_CHIPSET_FEATURE_PARA_HOTPLUG; |
d3ad6e69 | 339 | features |= VISOR_CHIPSET_FEATURE_REPLY; |
12e364b9 | 340 | |
5233d1eb | 341 | out_respond: |
98d7b594 | 342 | if (inmsg->hdr.flags.response_expected) |
79c3f971 DK |
343 | res = controlvm_respond_chipset_init(&inmsg->hdr, rc, features); |
344 | ||
345 | return res; | |
12e364b9 KC |
346 | } |
347 | ||
e80ffd4b | 348 | static int controlvm_respond(struct controlvm_message_header *msg_hdr, |
040b78f7 | 349 | int response, struct visor_segment_state *state) |
12e364b9 | 350 | { |
3ab47701 | 351 | struct controlvm_message outmsg; |
26eb2c0c | 352 | |
b3168c70 | 353 | controlvm_init_response(&outmsg, msg_hdr, response); |
2098dbd1 | 354 | if (outmsg.hdr.flags.test_message == 1) |
2d26aeb7 | 355 | return -EINVAL; |
4c0e65f8 DK |
356 | if (state) { |
357 | outmsg.cmd.device_change_state.state = *state; | |
358 | outmsg.cmd.device_change_state.flags.phys_device = 1; | |
359 | } | |
765b2f82 | 360 | return visorchannel_signalinsert(chipset_dev->controlvm_channel, |
2c4ef563 | 361 | CONTROLVM_QUEUE_REQUEST, &outmsg); |
12e364b9 KC |
362 | } |
363 | ||
2ee0deec PB |
364 | enum crash_obj_type { |
365 | CRASH_DEV, | |
366 | CRASH_BUS, | |
367 | }; | |
368 | ||
e80ffd4b CD |
369 | static int save_crash_message(struct controlvm_message *msg, |
370 | enum crash_obj_type cr_type) | |
12c957dc TS |
371 | { |
372 | u32 local_crash_msg_offset; | |
373 | u16 local_crash_msg_count; | |
8dff01f7 | 374 | int err; |
12c957dc | 375 | |
765b2f82 | 376 | err = visorchannel_read(chipset_dev->controlvm_channel, |
545f0913 | 377 | offsetof(struct visor_controlvm_channel, |
8dff01f7 DK |
378 | saved_crash_message_count), |
379 | &local_crash_msg_count, sizeof(u16)); | |
380 | if (err) { | |
35301b87 DK |
381 | dev_err(&chipset_dev->acpi_device->dev, |
382 | "failed to read message count\n"); | |
8dff01f7 | 383 | return err; |
12c957dc | 384 | } |
12c957dc | 385 | if (local_crash_msg_count != CONTROLVM_CRASHMSG_MAX) { |
35301b87 DK |
386 | dev_err(&chipset_dev->acpi_device->dev, |
387 | "invalid number of messages\n"); | |
8dff01f7 | 388 | return -EIO; |
12c957dc | 389 | } |
765b2f82 | 390 | err = visorchannel_read(chipset_dev->controlvm_channel, |
545f0913 | 391 | offsetof(struct visor_controlvm_channel, |
8dff01f7 DK |
392 | saved_crash_message_offset), |
393 | &local_crash_msg_offset, sizeof(u32)); | |
394 | if (err) { | |
35301b87 DK |
395 | dev_err(&chipset_dev->acpi_device->dev, |
396 | "failed to read offset\n"); | |
8dff01f7 | 397 | return err; |
12c957dc | 398 | } |
603a1989 | 399 | switch (cr_type) { |
36309d3b DB |
400 | case CRASH_DEV: |
401 | local_crash_msg_offset += sizeof(struct controlvm_message); | |
765b2f82 | 402 | err = visorchannel_write(chipset_dev->controlvm_channel, |
040b78f7 | 403 | local_crash_msg_offset, msg, |
36309d3b | 404 | sizeof(struct controlvm_message)); |
8dff01f7 | 405 | if (err) { |
35301b87 DK |
406 | dev_err(&chipset_dev->acpi_device->dev, |
407 | "failed to write dev msg\n"); | |
8dff01f7 | 408 | return err; |
12c957dc | 409 | } |
36309d3b DB |
410 | break; |
411 | case CRASH_BUS: | |
765b2f82 | 412 | err = visorchannel_write(chipset_dev->controlvm_channel, |
040b78f7 | 413 | local_crash_msg_offset, msg, |
8dff01f7 DK |
414 | sizeof(struct controlvm_message)); |
415 | if (err) { | |
35301b87 DK |
416 | dev_err(&chipset_dev->acpi_device->dev, |
417 | "failed to write bus msg\n"); | |
8dff01f7 | 418 | return err; |
12c957dc | 419 | } |
36309d3b DB |
420 | break; |
421 | default: | |
35301b87 DK |
422 | dev_err(&chipset_dev->acpi_device->dev, |
423 | "Invalid crash_obj_type\n"); | |
36309d3b | 424 | break; |
12c957dc | 425 | } |
8dff01f7 | 426 | return 0; |
12c957dc TS |
427 | } |
428 | ||
e80ffd4b CD |
429 | static int controlvm_responder(enum controlvm_id cmd_id, |
430 | struct controlvm_message_header *pending_msg_hdr, | |
431 | int response) | |
12e364b9 | 432 | { |
0274b5ae | 433 | if (pending_msg_hdr->id != (u32)cmd_id) |
734ad93a | 434 | return -EINVAL; |
0aca7844 | 435 | |
4c0e65f8 | 436 | return controlvm_respond(pending_msg_hdr, response, NULL); |
12e364b9 KC |
437 | } |
438 | ||
e80ffd4b CD |
439 | static int device_changestate_responder( |
440 | enum controlvm_id cmd_id, | |
441 | struct visor_device *p, int response, | |
442 | struct visor_segment_state response_state) | |
12e364b9 | 443 | { |
3ab47701 | 444 | struct controlvm_message outmsg; |
12e364b9 | 445 | |
0274b5ae | 446 | if (p->pending_msg_hdr->id != cmd_id) |
68f99d49 | 447 | return -EINVAL; |
12e364b9 | 448 | |
0274b5ae | 449 | controlvm_init_response(&outmsg, p->pending_msg_hdr, response); |
b253ff5b DK |
450 | outmsg.cmd.device_change_state.bus_no = p->chipset_bus_no; |
451 | outmsg.cmd.device_change_state.dev_no = p->chipset_dev_no; | |
fbb31f48 | 452 | outmsg.cmd.device_change_state.state = response_state; |
765b2f82 | 453 | return visorchannel_signalinsert(chipset_dev->controlvm_channel, |
68f99d49 | 454 | CONTROLVM_QUEUE_REQUEST, &outmsg); |
12e364b9 KC |
455 | } |
456 | ||
e80ffd4b | 457 | static int visorbus_create(struct controlvm_message *inmsg) |
12e364b9 | 458 | { |
2ea5117b | 459 | struct controlvm_message_packet *cmd = &inmsg->cmd; |
ef7b9dcb | 460 | struct controlvm_message_header *pmsg_hdr; |
52063eca | 461 | u32 bus_no = cmd->create_bus.bus_no; |
d32517e3 | 462 | struct visor_device *bus_info; |
b32c4997 | 463 | struct visorchannel *visorchannel; |
33161a29 | 464 | int err; |
12e364b9 | 465 | |
d32517e3 | 466 | bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL); |
6c5fed35 | 467 | if (bus_info && (bus_info->state.created == 1)) { |
055bc909 | 468 | dev_err(&chipset_dev->acpi_device->dev, |
87408fe0 | 469 | "failed %s: already exists\n", __func__); |
33161a29 DK |
470 | err = -EEXIST; |
471 | goto err_respond; | |
12e364b9 | 472 | } |
6c5fed35 BR |
473 | bus_info = kzalloc(sizeof(*bus_info), GFP_KERNEL); |
474 | if (!bus_info) { | |
33161a29 DK |
475 | err = -ENOMEM; |
476 | goto err_respond; | |
12e364b9 | 477 | } |
4abce83d | 478 | INIT_LIST_HEAD(&bus_info->list_all); |
d32517e3 DZ |
479 | bus_info->chipset_bus_no = bus_no; |
480 | bus_info->chipset_dev_no = BUS_ROOT_DEVICE; | |
b32c5cb8 | 481 | if (guid_equal(&cmd->create_bus.bus_inst_guid, &visor_siovm_guid)) { |
300ed612 DK |
482 | err = save_crash_message(inmsg, CRASH_BUS); |
483 | if (err) | |
484 | goto err_free_bus_info; | |
485 | } | |
8f334e30 | 486 | if (inmsg->hdr.flags.response_expected == 1) { |
040b78f7 | 487 | pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL); |
8f334e30 | 488 | if (!pmsg_hdr) { |
33161a29 DK |
489 | err = -ENOMEM; |
490 | goto err_free_bus_info; | |
8f334e30 | 491 | } |
8f334e30 DK |
492 | memcpy(pmsg_hdr, &inmsg->hdr, |
493 | sizeof(struct controlvm_message_header)); | |
494 | bus_info->pending_msg_hdr = pmsg_hdr; | |
495 | } | |
33161a29 | 496 | visorchannel = visorchannel_create(cmd->create_bus.channel_addr, |
33161a29 | 497 | GFP_KERNEL, |
b32c5cb8 | 498 | &cmd->create_bus.bus_data_type_guid); |
33161a29 | 499 | if (!visorchannel) { |
33161a29 DK |
500 | err = -ENOMEM; |
501 | goto err_free_pending_msg; | |
502 | } | |
503 | bus_info->visorchannel = visorchannel; | |
fdf5b9ac DK |
504 | /* Response will be handled by visorbus_create_instance on success */ |
505 | err = visorbus_create_instance(bus_info); | |
621f5e18 DK |
506 | if (err) |
507 | goto err_destroy_channel; | |
33161a29 DK |
508 | return 0; |
509 | ||
621f5e18 DK |
510 | err_destroy_channel: |
511 | visorchannel_destroy(visorchannel); | |
512 | ||
33161a29 DK |
513 | err_free_pending_msg: |
514 | kfree(bus_info->pending_msg_hdr); | |
8f334e30 | 515 | |
33161a29 | 516 | err_free_bus_info: |
8f334e30 | 517 | kfree(bus_info); |
12e364b9 | 518 | |
33161a29 | 519 | err_respond: |
8f334e30 | 520 | if (inmsg->hdr.flags.response_expected == 1) |
4fb2539c | 521 | controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err); |
33161a29 | 522 | return err; |
12e364b9 KC |
523 | } |
524 | ||
e80ffd4b | 525 | static int visorbus_destroy(struct controlvm_message *inmsg) |
12e364b9 | 526 | { |
ef7b9dcb | 527 | struct controlvm_message_header *pmsg_hdr; |
3f5a562b | 528 | u32 bus_no = inmsg->cmd.destroy_bus.bus_no; |
d32517e3 | 529 | struct visor_device *bus_info; |
30f6c3f5 | 530 | int err; |
12e364b9 | 531 | |
d32517e3 | 532 | bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL); |
3e0e8db9 | 533 | if (!bus_info) { |
30f6c3f5 DK |
534 | err = -ENODEV; |
535 | goto err_respond; | |
3e0e8db9 DK |
536 | } |
537 | if (bus_info->state.created == 0) { | |
30f6c3f5 DK |
538 | err = -ENOENT; |
539 | goto err_respond; | |
3e0e8db9 DK |
540 | } |
541 | if (bus_info->pending_msg_hdr) { | |
542 | /* only non-NULL if dev is still waiting on a response */ | |
30f6c3f5 DK |
543 | err = -EEXIST; |
544 | goto err_respond; | |
3e0e8db9 DK |
545 | } |
546 | if (inmsg->hdr.flags.response_expected == 1) { | |
547 | pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL); | |
548 | if (!pmsg_hdr) { | |
30f6c3f5 DK |
549 | err = -ENOMEM; |
550 | goto err_respond; | |
3e0e8db9 | 551 | } |
3e0e8db9 DK |
552 | memcpy(pmsg_hdr, &inmsg->hdr, |
553 | sizeof(struct controlvm_message_header)); | |
554 | bus_info->pending_msg_hdr = pmsg_hdr; | |
555 | } | |
a7093ba1 SW |
556 | /* Response will be handled by visorbus_remove_instance */ |
557 | visorbus_remove_instance(bus_info); | |
30f6c3f5 | 558 | return 0; |
3e0e8db9 | 559 | |
30f6c3f5 | 560 | err_respond: |
3e0e8db9 | 561 | if (inmsg->hdr.flags.response_expected == 1) |
4fb2539c | 562 | controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err); |
30f6c3f5 | 563 | return err; |
12e364b9 KC |
564 | } |
565 | ||
39b486d6 DK |
566 | static const guid_t *parser_id_get(struct parser_context *ctx) |
567 | { | |
568 | return &ctx->data.id; | |
569 | } | |
570 | ||
90d1ecf0 | 571 | static void *parser_string_get(u8 *pscan, int nscan) |
39b486d6 | 572 | { |
39b486d6 DK |
573 | int value_length; |
574 | void *value; | |
39b486d6 | 575 | |
39b486d6 DK |
576 | if (nscan == 0) |
577 | return NULL; | |
578 | ||
90d1ecf0 DK |
579 | value_length = strnlen(pscan, nscan); |
580 | value = kzalloc(value_length + 1, GFP_KERNEL); | |
39b486d6 DK |
581 | if (!value) |
582 | return NULL; | |
583 | if (value_length > 0) | |
584 | memcpy(value, pscan, value_length); | |
39b486d6 DK |
585 | return value; |
586 | } | |
587 | ||
588 | static void *parser_name_get(struct parser_context *ctx) | |
589 | { | |
ef7b9dcb | 590 | struct visor_controlvm_parameters_header *phdr; |
39b486d6 DK |
591 | |
592 | phdr = &ctx->data; | |
39b486d6 DK |
593 | if (phdr->name_offset + phdr->name_length > ctx->param_bytes) |
594 | return NULL; | |
39b486d6 DK |
595 | ctx->curr = (char *)&phdr + phdr->name_offset; |
596 | ctx->bytes_remaining = phdr->name_length; | |
90d1ecf0 | 597 | return parser_string_get(ctx->curr, phdr->name_length); |
39b486d6 DK |
598 | } |
599 | ||
e80ffd4b CD |
600 | static int visorbus_configure(struct controlvm_message *inmsg, |
601 | struct parser_context *parser_ctx) | |
12e364b9 | 602 | { |
2ea5117b | 603 | struct controlvm_message_packet *cmd = &inmsg->cmd; |
e82ba62e | 604 | u32 bus_no; |
d32517e3 | 605 | struct visor_device *bus_info; |
c71529fe | 606 | int err = 0; |
12e364b9 | 607 | |
654bada0 | 608 | bus_no = cmd->configure_bus.bus_no; |
d32517e3 | 609 | bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL); |
654bada0 | 610 | if (!bus_info) { |
c71529fe DK |
611 | err = -EINVAL; |
612 | goto err_respond; | |
af53ce41 DK |
613 | } |
614 | if (bus_info->state.created == 0) { | |
c71529fe DK |
615 | err = -EINVAL; |
616 | goto err_respond; | |
af53ce41 DK |
617 | } |
618 | if (bus_info->pending_msg_hdr) { | |
c71529fe DK |
619 | err = -EIO; |
620 | goto err_respond; | |
12e364b9 | 621 | } |
34fbf6a0 DK |
622 | err = visorchannel_set_clientpartition(bus_info->visorchannel, |
623 | cmd->configure_bus.guest_handle); | |
c71529fe DK |
624 | if (err) |
625 | goto err_respond; | |
046f93dc | 626 | if (parser_ctx) { |
b32c5cb8 AS |
627 | const guid_t *partition_guid = parser_id_get(parser_ctx); |
628 | ||
629 | guid_copy(&bus_info->partition_guid, partition_guid); | |
046f93dc DK |
630 | bus_info->name = parser_name_get(parser_ctx); |
631 | } | |
c71529fe | 632 | if (inmsg->hdr.flags.response_expected == 1) |
4fb2539c | 633 | controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err); |
c71529fe DK |
634 | return 0; |
635 | ||
636 | err_respond: | |
71a0265d | 637 | dev_err(&chipset_dev->acpi_device->dev, |
9a8dc900 | 638 | "%s exited with err: %d\n", __func__, err); |
b6b057d8 | 639 | if (inmsg->hdr.flags.response_expected == 1) |
4fb2539c | 640 | controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err); |
c71529fe | 641 | return err; |
12e364b9 KC |
642 | } |
643 | ||
e80ffd4b | 644 | static int visorbus_device_create(struct controlvm_message *inmsg) |
12e364b9 | 645 | { |
2ea5117b | 646 | struct controlvm_message_packet *cmd = &inmsg->cmd; |
ef7b9dcb | 647 | struct controlvm_message_header *pmsg_hdr; |
52063eca JS |
648 | u32 bus_no = cmd->create_device.bus_no; |
649 | u32 dev_no = cmd->create_device.dev_no; | |
ef7b9dcb | 650 | struct visor_device *dev_info; |
d32517e3 | 651 | struct visor_device *bus_info; |
b32c4997 | 652 | struct visorchannel *visorchannel; |
ad2a7d65 | 653 | int err; |
12e364b9 | 654 | |
a298bc0b DZ |
655 | bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL); |
656 | if (!bus_info) { | |
a8c26e4b DK |
657 | dev_err(&chipset_dev->acpi_device->dev, |
658 | "failed to get bus by id: %d\n", bus_no); | |
ad2a7d65 DK |
659 | err = -ENODEV; |
660 | goto err_respond; | |
12e364b9 | 661 | } |
a298bc0b | 662 | if (bus_info->state.created == 0) { |
a8c26e4b DK |
663 | dev_err(&chipset_dev->acpi_device->dev, |
664 | "bus not created, id: %d\n", bus_no); | |
ad2a7d65 DK |
665 | err = -EINVAL; |
666 | goto err_respond; | |
12e364b9 | 667 | } |
a298bc0b DZ |
668 | dev_info = visorbus_get_device_by_id(bus_no, dev_no, NULL); |
669 | if (dev_info && (dev_info->state.created == 1)) { | |
a8c26e4b DK |
670 | dev_err(&chipset_dev->acpi_device->dev, |
671 | "failed to get bus by id: %d/%d\n", bus_no, dev_no); | |
ad2a7d65 DK |
672 | err = -EEXIST; |
673 | goto err_respond; | |
12e364b9 | 674 | } |
a298bc0b | 675 | |
c60c8e26 BR |
676 | dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL); |
677 | if (!dev_info) { | |
ad2a7d65 DK |
678 | err = -ENOMEM; |
679 | goto err_respond; | |
12e364b9 | 680 | } |
a298bc0b DZ |
681 | dev_info->chipset_bus_no = bus_no; |
682 | dev_info->chipset_dev_no = dev_no; | |
b32c5cb8 | 683 | guid_copy(&dev_info->inst, &cmd->create_device.dev_inst_guid); |
a298bc0b | 684 | dev_info->device.parent = &bus_info->device; |
a3ef1a8e DK |
685 | visorchannel = |
686 | visorchannel_create_with_lock(cmd->create_device.channel_addr, | |
a3ef1a8e | 687 | GFP_KERNEL, |
b32c5cb8 | 688 | &cmd->create_device.data_type_guid); |
b32c4997 | 689 | if (!visorchannel) { |
a8c26e4b DK |
690 | dev_err(&chipset_dev->acpi_device->dev, |
691 | "failed to create visorchannel: %d/%d\n", | |
692 | bus_no, dev_no); | |
ad2a7d65 DK |
693 | err = -ENOMEM; |
694 | goto err_free_dev_info; | |
b32c4997 DZ |
695 | } |
696 | dev_info->visorchannel = visorchannel; | |
b32c5cb8 AS |
697 | guid_copy(&dev_info->channel_type_guid, &cmd->create_device.data_type_guid); |
698 | if (guid_equal(&cmd->create_device.data_type_guid, &visor_vhba_channel_guid)) { | |
ad2a7d65 DK |
699 | err = save_crash_message(inmsg, CRASH_DEV); |
700 | if (err) | |
3f49a21d | 701 | goto err_destroy_visorchannel; |
ad2a7d65 | 702 | } |
5a80e98a DK |
703 | if (inmsg->hdr.flags.response_expected == 1) { |
704 | pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL); | |
705 | if (!pmsg_hdr) { | |
ad2a7d65 | 706 | err = -ENOMEM; |
3f49a21d | 707 | goto err_destroy_visorchannel; |
5a80e98a | 708 | } |
5a80e98a DK |
709 | memcpy(pmsg_hdr, &inmsg->hdr, |
710 | sizeof(struct controlvm_message_header)); | |
711 | dev_info->pending_msg_hdr = pmsg_hdr; | |
712 | } | |
51c0f81c SW |
713 | /* create_visor_device will send response */ |
714 | err = create_visor_device(dev_info); | |
3f49a21d DK |
715 | if (err) |
716 | goto err_destroy_visorchannel; | |
717 | ||
ad2a7d65 | 718 | return 0; |
5a80e98a | 719 | |
3f49a21d DK |
720 | err_destroy_visorchannel: |
721 | visorchannel_destroy(visorchannel); | |
722 | ||
ad2a7d65 | 723 | err_free_dev_info: |
5a80e98a DK |
724 | kfree(dev_info); |
725 | ||
ad2a7d65 | 726 | err_respond: |
5a80e98a | 727 | if (inmsg->hdr.flags.response_expected == 1) |
4fb2539c | 728 | controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err); |
ad2a7d65 | 729 | return err; |
12e364b9 KC |
730 | } |
731 | ||
e80ffd4b | 732 | static int visorbus_device_changestate(struct controlvm_message *inmsg) |
12e364b9 | 733 | { |
2ea5117b | 734 | struct controlvm_message_packet *cmd = &inmsg->cmd; |
ef7b9dcb | 735 | struct controlvm_message_header *pmsg_hdr; |
52063eca JS |
736 | u32 bus_no = cmd->device_change_state.bus_no; |
737 | u32 dev_no = cmd->device_change_state.dev_no; | |
545f0913 | 738 | struct visor_segment_state state = cmd->device_change_state.state; |
a298bc0b | 739 | struct visor_device *dev_info; |
b4a8e6ae | 740 | int err = 0; |
12e364b9 | 741 | |
a298bc0b | 742 | dev_info = visorbus_get_device_by_id(bus_no, dev_no, NULL); |
0278a905 | 743 | if (!dev_info) { |
40fc79f9 | 744 | err = -ENODEV; |
0825f191 DK |
745 | goto err_respond; |
746 | } | |
747 | if (dev_info->state.created == 0) { | |
40fc79f9 | 748 | err = -EINVAL; |
0825f191 | 749 | goto err_respond; |
12e364b9 | 750 | } |
8e609b5b DK |
751 | if (dev_info->pending_msg_hdr) { |
752 | /* only non-NULL if dev is still waiting on a response */ | |
40fc79f9 | 753 | err = -EIO; |
8e609b5b DK |
754 | goto err_respond; |
755 | } | |
9116ae7a | 756 | |
8e609b5b DK |
757 | if (inmsg->hdr.flags.response_expected == 1) { |
758 | pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL); | |
759 | if (!pmsg_hdr) { | |
40fc79f9 | 760 | err = -ENOMEM; |
8e609b5b DK |
761 | goto err_respond; |
762 | } | |
8e609b5b DK |
763 | memcpy(pmsg_hdr, &inmsg->hdr, |
764 | sizeof(struct controlvm_message_header)); | |
765 | dev_info->pending_msg_hdr = pmsg_hdr; | |
766 | } | |
8e609b5b DK |
767 | if (state.alive == segment_state_running.alive && |
768 | state.operating == segment_state_running.operating) | |
c0b44136 SW |
769 | /* Response will be sent from visorchipset_device_resume */ |
770 | err = visorchipset_device_resume(dev_info); | |
8e609b5b DK |
771 | /* ServerNotReady / ServerLost / SegmentStateStandby */ |
772 | else if (state.alive == segment_state_standby.alive && | |
773 | state.operating == segment_state_standby.operating) | |
774 | /* | |
775 | * technically this is standby case where server is lost. | |
c0b44136 | 776 | * Response will be sent from visorchipset_device_pause. |
8e609b5b | 777 | */ |
c0b44136 | 778 | err = visorchipset_device_pause(dev_info); |
b4a8e6ae DK |
779 | if (err) |
780 | goto err_respond; | |
40fc79f9 | 781 | return 0; |
0825f191 DK |
782 | |
783 | err_respond: | |
03662df8 | 784 | dev_err(&chipset_dev->acpi_device->dev, "failed: %d\n", err); |
8e609b5b | 785 | if (inmsg->hdr.flags.response_expected == 1) |
4fb2539c | 786 | controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err); |
40fc79f9 | 787 | return err; |
12e364b9 KC |
788 | } |
789 | ||
e80ffd4b | 790 | static int visorbus_device_destroy(struct controlvm_message *inmsg) |
12e364b9 | 791 | { |
2ea5117b | 792 | struct controlvm_message_packet *cmd = &inmsg->cmd; |
ef7b9dcb | 793 | struct controlvm_message_header *pmsg_hdr; |
52063eca JS |
794 | u32 bus_no = cmd->destroy_device.bus_no; |
795 | u32 dev_no = cmd->destroy_device.dev_no; | |
a298bc0b | 796 | struct visor_device *dev_info; |
e7954918 | 797 | int err; |
12e364b9 | 798 | |
a298bc0b | 799 | dev_info = visorbus_get_device_by_id(bus_no, dev_no, NULL); |
9e9eec6b | 800 | if (!dev_info) { |
e7954918 | 801 | err = -ENODEV; |
9e9eec6b DK |
802 | goto err_respond; |
803 | } | |
804 | if (dev_info->state.created == 0) { | |
e7954918 | 805 | err = -EINVAL; |
9e9eec6b DK |
806 | goto err_respond; |
807 | } | |
9e9eec6b DK |
808 | if (dev_info->pending_msg_hdr) { |
809 | /* only non-NULL if dev is still waiting on a response */ | |
e7954918 | 810 | err = -EIO; |
9e9eec6b DK |
811 | goto err_respond; |
812 | } | |
813 | if (inmsg->hdr.flags.response_expected == 1) { | |
814 | pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL); | |
815 | if (!pmsg_hdr) { | |
e7954918 | 816 | err = -ENOMEM; |
9e9eec6b DK |
817 | goto err_respond; |
818 | } | |
819 | ||
820 | memcpy(pmsg_hdr, &inmsg->hdr, | |
821 | sizeof(struct controlvm_message_header)); | |
822 | dev_info->pending_msg_hdr = pmsg_hdr; | |
823 | } | |
661a215b | 824 | kfree(dev_info->name); |
b74856b4 | 825 | remove_visor_device(dev_info); |
e7954918 | 826 | return 0; |
9e9eec6b DK |
827 | |
828 | err_respond: | |
829 | if (inmsg->hdr.flags.response_expected == 1) | |
4fb2539c | 830 | controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err); |
e7954918 | 831 | return err; |
12e364b9 KC |
832 | } |
833 | ||
12e364b9 | 834 | /* |
5d501ef4 DB |
835 | * The general parahotplug flow works as follows. The visorchipset receives |
836 | * a DEVICE_CHANGESTATE message from Command specifying a physical device | |
837 | * to enable or disable. The CONTROLVM message handler calls | |
838 | * parahotplug_process_message, which then adds the message to a global list | |
839 | * and kicks off a udev event which causes a user level script to enable or | |
840 | * disable the specified device. The udev script then writes to | |
841 | * /sys/devices/platform/visorchipset/parahotplug, which causes the | |
842 | * parahotplug store functions to get called, at which point the | |
904ee62a | 843 | * appropriate CONTROLVM message is retrieved from the list and responded to. |
12e364b9 KC |
844 | */ |
845 | ||
846 | #define PARAHOTPLUG_TIMEOUT_MS 2000 | |
847 | ||
04dbfea6 | 848 | /* |
5d501ef4 DB |
849 | * parahotplug_next_id() - generate unique int to match an outstanding |
850 | * CONTROLVM message with a udev script /sys | |
851 | * response | |
ec17f452 DB |
852 | * |
853 | * Return: a unique integer value | |
12e364b9 | 854 | */ |
e80ffd4b | 855 | static int parahotplug_next_id(void) |
12e364b9 KC |
856 | { |
857 | static atomic_t id = ATOMIC_INIT(0); | |
26eb2c0c | 858 | |
12e364b9 KC |
859 | return atomic_inc_return(&id); |
860 | } | |
861 | ||
04dbfea6 | 862 | /* |
ec17f452 DB |
863 | * parahotplug_next_expiration() - returns the time (in jiffies) when a |
864 | * CONTROLVM message on the list should expire | |
865 | * -- PARAHOTPLUG_TIMEOUT_MS in the future | |
866 | * | |
867 | * Return: expected expiration time (in jiffies) | |
12e364b9 | 868 | */ |
e80ffd4b | 869 | static unsigned long parahotplug_next_expiration(void) |
12e364b9 | 870 | { |
2cc1a1b3 | 871 | return jiffies + msecs_to_jiffies(PARAHOTPLUG_TIMEOUT_MS); |
12e364b9 KC |
872 | } |
873 | ||
04dbfea6 | 874 | /* |
ec17f452 DB |
875 | * parahotplug_request_create() - create a parahotplug_request, which is |
876 | * basically a wrapper for a CONTROLVM_MESSAGE | |
877 | * that we can stick on a list | |
878 | * @msg: the message to insert in the request | |
879 | * | |
880 | * Return: the request containing the provided message | |
12e364b9 | 881 | */ |
e80ffd4b CD |
882 | static struct parahotplug_request *parahotplug_request_create( |
883 | struct controlvm_message *msg) | |
12e364b9 | 884 | { |
ea0dcfcf QL |
885 | struct parahotplug_request *req; |
886 | ||
8c8c975f | 887 | req = kmalloc(sizeof(*req), GFP_KERNEL); |
38f736e9 | 888 | if (!req) |
12e364b9 | 889 | return NULL; |
12e364b9 KC |
890 | req->id = parahotplug_next_id(); |
891 | req->expiration = parahotplug_next_expiration(); | |
892 | req->msg = *msg; | |
12e364b9 KC |
893 | return req; |
894 | } | |
895 | ||
04dbfea6 | 896 | /* |
ec17f452 DB |
897 | * parahotplug_request_destroy() - free a parahotplug_request |
898 | * @req: the request to deallocate | |
12e364b9 | 899 | */ |
e80ffd4b | 900 | static void parahotplug_request_destroy(struct parahotplug_request *req) |
12e364b9 KC |
901 | { |
902 | kfree(req); | |
903 | } | |
904 | ||
51319662 | 905 | static LIST_HEAD(parahotplug_request_list); |
ac0aba67 SW |
906 | /* lock for above */ |
907 | static DEFINE_SPINLOCK(parahotplug_request_list_lock); | |
51319662 | 908 | |
04dbfea6 | 909 | /* |
ec17f452 DB |
910 | * parahotplug_request_complete() - mark request as complete |
911 | * @id: the id of the request | |
912 | * @active: indicates whether the request is assigned to active partition | |
913 | * | |
5d501ef4 | 914 | * Called from the /sys handler, which means the user script has |
ec17f452 | 915 | * finished the enable/disable. Find the matching identifier, and |
12e364b9 | 916 | * respond to the CONTROLVM message with success. |
ec17f452 DB |
917 | * |
918 | * Return: 0 on success or -EINVAL on failure | |
12e364b9 | 919 | */ |
e80ffd4b | 920 | static int parahotplug_request_complete(int id, u16 active) |
12e364b9 | 921 | { |
e82ba62e JS |
922 | struct list_head *pos; |
923 | struct list_head *tmp; | |
040b78f7 | 924 | struct parahotplug_request *req; |
12e364b9 | 925 | |
ddf5de53 | 926 | spin_lock(¶hotplug_request_list_lock); |
12e364b9 | 927 | /* Look for a request matching "id". */ |
ddf5de53 | 928 | list_for_each_safe(pos, tmp, ¶hotplug_request_list) { |
040b78f7 | 929 | req = list_entry(pos, struct parahotplug_request, list); |
12e364b9 | 930 | if (req->id == id) { |
ec17f452 DB |
931 | /* |
932 | * Found a match. Remove it from the list and | |
12e364b9 KC |
933 | * respond. |
934 | */ | |
935 | list_del(pos); | |
ddf5de53 | 936 | spin_unlock(¶hotplug_request_list_lock); |
2ea5117b | 937 | req->msg.cmd.device_change_state.state.active = active; |
98d7b594 | 938 | if (req->msg.hdr.flags.response_expected) |
4c0e65f8 DK |
939 | controlvm_respond( |
940 | &req->msg.hdr, CONTROLVM_RESP_SUCCESS, | |
941 | &req->msg.cmd.device_change_state.state); | |
12e364b9 KC |
942 | parahotplug_request_destroy(req); |
943 | return 0; | |
944 | } | |
945 | } | |
ddf5de53 | 946 | spin_unlock(¶hotplug_request_list_lock); |
119296ea | 947 | return -EINVAL; |
12e364b9 KC |
948 | } |
949 | ||
04dbfea6 | 950 | /* |
ebeff055 DK |
951 | * devicedisabled_store() - disables the hotplug device |
952 | * @dev: sysfs interface variable not utilized in this function | |
953 | * @attr: sysfs interface variable not utilized in this function | |
954 | * @buf: buffer containing the device id | |
955 | * @count: the size of the buffer | |
956 | * | |
957 | * The parahotplug/devicedisabled interface gets called by our support script | |
958 | * when an SR-IOV device has been shut down. The ID is passed to the script | |
959 | * and then passed back when the device has been removed. | |
960 | * | |
961 | * Return: the size of the buffer for success or negative for error | |
962 | */ | |
963 | static ssize_t devicedisabled_store(struct device *dev, | |
964 | struct device_attribute *attr, | |
965 | const char *buf, size_t count) | |
966 | { | |
967 | unsigned int id; | |
968 | int err; | |
969 | ||
970 | if (kstrtouint(buf, 10, &id)) | |
971 | return -EINVAL; | |
ebeff055 DK |
972 | err = parahotplug_request_complete(id, 0); |
973 | if (err < 0) | |
974 | return err; | |
975 | return count; | |
976 | } | |
977 | static DEVICE_ATTR_WO(devicedisabled); | |
978 | ||
04dbfea6 | 979 | /* |
ebeff055 DK |
980 | * deviceenabled_store() - enables the hotplug device |
981 | * @dev: sysfs interface variable not utilized in this function | |
982 | * @attr: sysfs interface variable not utilized in this function | |
983 | * @buf: buffer containing the device id | |
984 | * @count: the size of the buffer | |
985 | * | |
986 | * The parahotplug/deviceenabled interface gets called by our support script | |
987 | * when an SR-IOV device has been recovered. The ID is passed to the script | |
988 | * and then passed back when the device has been brought back up. | |
989 | * | |
990 | * Return: the size of the buffer for success or negative for error | |
991 | */ | |
992 | static ssize_t deviceenabled_store(struct device *dev, | |
993 | struct device_attribute *attr, | |
994 | const char *buf, size_t count) | |
995 | { | |
996 | unsigned int id; | |
997 | ||
998 | if (kstrtouint(buf, 10, &id)) | |
999 | return -EINVAL; | |
ebeff055 DK |
1000 | parahotplug_request_complete(id, 1); |
1001 | return count; | |
1002 | } | |
1003 | static DEVICE_ATTR_WO(deviceenabled); | |
1004 | ||
1005 | static struct attribute *visorchipset_install_attrs[] = { | |
1006 | &dev_attr_toolaction.attr, | |
1007 | &dev_attr_boottotool.attr, | |
1008 | &dev_attr_error.attr, | |
1009 | &dev_attr_textid.attr, | |
1010 | &dev_attr_remaining_steps.attr, | |
1011 | NULL | |
1012 | }; | |
1013 | ||
a2d1e428 | 1014 | static const struct attribute_group visorchipset_install_group = { |
ebeff055 DK |
1015 | .name = "install", |
1016 | .attrs = visorchipset_install_attrs | |
1017 | }; | |
1018 | ||
1019 | static struct attribute *visorchipset_parahotplug_attrs[] = { | |
1020 | &dev_attr_devicedisabled.attr, | |
1021 | &dev_attr_deviceenabled.attr, | |
1022 | NULL | |
1023 | }; | |
1024 | ||
1722270b | 1025 | static const struct attribute_group visorchipset_parahotplug_group = { |
ebeff055 DK |
1026 | .name = "parahotplug", |
1027 | .attrs = visorchipset_parahotplug_attrs | |
1028 | }; | |
1029 | ||
1030 | static const struct attribute_group *visorchipset_dev_groups[] = { | |
1031 | &visorchipset_install_group, | |
1032 | &visorchipset_parahotplug_group, | |
1033 | NULL | |
1034 | }; | |
1035 | ||
04dbfea6 | 1036 | /* |
ebeff055 DK |
1037 | * parahotplug_request_kickoff() - initiate parahotplug request |
1038 | * @req: the request to initiate | |
1039 | * | |
1040 | * Cause uevent to run the user level script to do the disable/enable specified | |
1041 | * in the parahotplug_request. | |
1042 | */ | |
e80ffd4b | 1043 | static int parahotplug_request_kickoff(struct parahotplug_request *req) |
ebeff055 DK |
1044 | { |
1045 | struct controlvm_message_packet *cmd = &req->msg.cmd; | |
1046 | char env_cmd[40], env_id[40], env_state[40], env_bus[40], env_dev[40], | |
1047 | env_func[40]; | |
1048 | char *envp[] = { | |
1049 | env_cmd, env_id, env_state, env_bus, env_dev, env_func, NULL | |
1050 | }; | |
1051 | ||
c5a28902 SW |
1052 | sprintf(env_cmd, "VISOR_PARAHOTPLUG=1"); |
1053 | sprintf(env_id, "VISOR_PARAHOTPLUG_ID=%d", req->id); | |
1054 | sprintf(env_state, "VISOR_PARAHOTPLUG_STATE=%d", | |
ebeff055 | 1055 | cmd->device_change_state.state.active); |
c5a28902 | 1056 | sprintf(env_bus, "VISOR_PARAHOTPLUG_BUS=%d", |
ebeff055 | 1057 | cmd->device_change_state.bus_no); |
c5a28902 | 1058 | sprintf(env_dev, "VISOR_PARAHOTPLUG_DEVICE=%d", |
ebeff055 | 1059 | cmd->device_change_state.dev_no >> 3); |
c5a28902 | 1060 | sprintf(env_func, "VISOR_PARAHOTPLUG_FUNCTION=%d", |
ebeff055 | 1061 | cmd->device_change_state.dev_no & 0x7); |
ae0fa822 DK |
1062 | return kobject_uevent_env(&chipset_dev->acpi_device->dev.kobj, |
1063 | KOBJ_CHANGE, envp); | |
ebeff055 DK |
1064 | } |
1065 | ||
04dbfea6 | 1066 | /* |
ec17f452 DB |
1067 | * parahotplug_process_message() - enables or disables a PCI device by kicking |
1068 | * off a udev script | |
1069 | * @inmsg: the message indicating whether to enable or disable | |
12e364b9 | 1070 | */ |
e80ffd4b | 1071 | static int parahotplug_process_message(struct controlvm_message *inmsg) |
12e364b9 KC |
1072 | { |
1073 | struct parahotplug_request *req; | |
ae0fa822 | 1074 | int err; |
12e364b9 KC |
1075 | |
1076 | req = parahotplug_request_create(inmsg); | |
38f736e9 | 1077 | if (!req) |
114d5dcf | 1078 | return -ENOMEM; |
d02bde9d DK |
1079 | /* |
1080 | * For enable messages, just respond with success right away, we don't | |
1081 | * need to wait to see if the enable was successful. | |
1082 | */ | |
2ea5117b | 1083 | if (inmsg->cmd.device_change_state.state.active) { |
ae0fa822 DK |
1084 | err = parahotplug_request_kickoff(req); |
1085 | if (err) | |
1086 | goto err_respond; | |
4c0e65f8 DK |
1087 | controlvm_respond(&inmsg->hdr, CONTROLVM_RESP_SUCCESS, |
1088 | &inmsg->cmd.device_change_state.state); | |
12e364b9 | 1089 | parahotplug_request_destroy(req); |
ae0fa822 | 1090 | return 0; |
12e364b9 | 1091 | } |
ae0fa822 | 1092 | /* |
6577cbf1 DK |
1093 | * For disable messages, add the request to the request list before |
1094 | * kicking off the udev script. It won't get responded to until the | |
1095 | * script has indicated it's done. | |
ae0fa822 DK |
1096 | */ |
1097 | spin_lock(¶hotplug_request_list_lock); | |
1098 | list_add_tail(&req->list, ¶hotplug_request_list); | |
1099 | spin_unlock(¶hotplug_request_list_lock); | |
ae0fa822 DK |
1100 | err = parahotplug_request_kickoff(req); |
1101 | if (err) | |
1102 | goto err_respond; | |
114d5dcf | 1103 | return 0; |
ae0fa822 DK |
1104 | |
1105 | err_respond: | |
4c0e65f8 DK |
1106 | controlvm_respond(&inmsg->hdr, err, |
1107 | &inmsg->cmd.device_change_state.state); | |
ae0fa822 | 1108 | return err; |
12e364b9 KC |
1109 | } |
1110 | ||
7289a8dd DB |
1111 | /* |
1112 | * chipset_ready_uevent() - sends chipset_ready action | |
ebeff055 DK |
1113 | * |
1114 | * Send ACTION=online for DEVPATH=/sys/devices/platform/visorchipset. | |
1115 | * | |
7289a8dd | 1116 | * Return: 0 on success, negative on failure |
ebeff055 | 1117 | */ |
e80ffd4b | 1118 | static int chipset_ready_uevent(struct controlvm_message_header *msg_hdr) |
ebeff055 | 1119 | { |
deeeca6d DK |
1120 | int res; |
1121 | ||
040b78f7 | 1122 | res = kobject_uevent(&chipset_dev->acpi_device->dev.kobj, KOBJ_ONLINE); |
7289a8dd | 1123 | if (msg_hdr->flags.response_expected) |
4c0e65f8 | 1124 | controlvm_respond(msg_hdr, res, NULL); |
deeeca6d | 1125 | return res; |
ebeff055 DK |
1126 | } |
1127 | ||
7289a8dd DB |
1128 | /* |
1129 | * chipset_selftest_uevent() - sends chipset_selftest action | |
1130 | * | |
1131 | * Send ACTION=online for DEVPATH=/sys/devices/platform/visorchipset. | |
1132 | * | |
1133 | * Return: 0 on success, negative on failure | |
1134 | */ | |
e80ffd4b | 1135 | static int chipset_selftest_uevent(struct controlvm_message_header *msg_hdr) |
ebeff055 DK |
1136 | { |
1137 | char env_selftest[20]; | |
1138 | char *envp[] = { env_selftest, NULL }; | |
deeeca6d | 1139 | int res; |
ebeff055 DK |
1140 | |
1141 | sprintf(env_selftest, "SPARSP_SELFTEST=%d", 1); | |
deeeca6d DK |
1142 | res = kobject_uevent_env(&chipset_dev->acpi_device->dev.kobj, |
1143 | KOBJ_CHANGE, envp); | |
7289a8dd | 1144 | if (msg_hdr->flags.response_expected) |
4c0e65f8 | 1145 | controlvm_respond(msg_hdr, res, NULL); |
deeeca6d | 1146 | return res; |
ebeff055 DK |
1147 | } |
1148 | ||
7289a8dd DB |
1149 | /* |
1150 | * chipset_notready_uevent() - sends chipset_notready action | |
ebeff055 DK |
1151 | * |
1152 | * Send ACTION=offline for DEVPATH=/sys/devices/platform/visorchipset. | |
1153 | * | |
7289a8dd | 1154 | * Return: 0 on success, negative on failure |
ebeff055 | 1155 | */ |
e80ffd4b | 1156 | static int chipset_notready_uevent(struct controlvm_message_header *msg_hdr) |
ebeff055 | 1157 | { |
904ee62a | 1158 | int res = kobject_uevent(&chipset_dev->acpi_device->dev.kobj, |
34fbf6a0 | 1159 | KOBJ_OFFLINE); |
904ee62a | 1160 | |
ebeff055 | 1161 | if (msg_hdr->flags.response_expected) |
4c0e65f8 | 1162 | controlvm_respond(msg_hdr, res, NULL); |
deeeca6d | 1163 | return res; |
ebeff055 DK |
1164 | } |
1165 | ||
88845f40 DK |
1166 | static int unisys_vmcall(unsigned long tuple, unsigned long param) |
1167 | { | |
1168 | int result = 0; | |
1169 | unsigned int cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx; | |
1170 | unsigned long reg_ebx; | |
1171 | unsigned long reg_ecx; | |
1172 | ||
1173 | reg_ebx = param & 0xFFFFFFFF; | |
1174 | reg_ecx = param >> 32; | |
88845f40 DK |
1175 | cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx); |
1176 | if (!(cpuid_ecx & 0x80000000)) | |
1177 | return -EPERM; | |
88845f40 | 1178 | __asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) : |
34fbf6a0 | 1179 | "a"(tuple), "b"(reg_ebx), "c"(reg_ecx)); |
bd801a07 DK |
1180 | if (result) |
1181 | goto error; | |
bd801a07 | 1182 | return 0; |
9116ae7a | 1183 | |
ac0aba67 SW |
1184 | /* Need to convert from VMCALL error codes to Linux */ |
1185 | error: | |
bd801a07 DK |
1186 | switch (result) { |
1187 | case VMCALL_RESULT_INVALID_PARAM: | |
1188 | return -EINVAL; | |
1189 | case VMCALL_RESULT_DATA_UNAVAILABLE: | |
1190 | return -ENODEV; | |
1191 | default: | |
1192 | return -EFAULT; | |
1193 | } | |
88845f40 | 1194 | } |
ab61097c | 1195 | |
f1f537c2 | 1196 | static int controlvm_channel_create(struct visorchipset_device *dev) |
5f3a7e36 | 1197 | { |
f1f537c2 DK |
1198 | struct visorchannel *chan; |
1199 | u64 addr; | |
800da5fb DK |
1200 | int err; |
1201 | ||
f1f537c2 DK |
1202 | err = unisys_vmcall(VMCALL_CONTROLVM_ADDR, |
1203 | virt_to_phys(&dev->controlvm_params)); | |
800da5fb DK |
1204 | if (err) |
1205 | return err; | |
f1f537c2 | 1206 | addr = dev->controlvm_params.address; |
d7f1589a | 1207 | chan = visorchannel_create_with_lock(addr, GFP_KERNEL, |
f1f537c2 DK |
1208 | &visor_controlvm_channel_guid); |
1209 | if (!chan) | |
1210 | return -ENOMEM; | |
1211 | dev->controlvm_channel = chan; | |
bd801a07 | 1212 | return 0; |
5f3a7e36 DK |
1213 | } |
1214 | ||
e80ffd4b | 1215 | static void setup_crash_devices_work_queue(struct work_struct *work) |
12e364b9 | 1216 | { |
e6bdb904 BR |
1217 | struct controlvm_message local_crash_bus_msg; |
1218 | struct controlvm_message local_crash_dev_msg; | |
3ab47701 | 1219 | struct controlvm_message msg; |
e6bdb904 BR |
1220 | u32 local_crash_msg_offset; |
1221 | u16 local_crash_msg_count; | |
12e364b9 | 1222 | |
12e364b9 | 1223 | /* send init chipset msg */ |
98d7b594 | 1224 | msg.hdr.id = CONTROLVM_CHIPSET_INIT; |
2ea5117b BR |
1225 | msg.cmd.init_chipset.bus_count = 23; |
1226 | msg.cmd.init_chipset.switch_count = 0; | |
12e364b9 | 1227 | chipset_init(&msg); |
12e364b9 | 1228 | /* get saved message count */ |
765b2f82 | 1229 | if (visorchannel_read(chipset_dev->controlvm_channel, |
545f0913 | 1230 | offsetof(struct visor_controlvm_channel, |
d19642f6 | 1231 | saved_crash_message_count), |
e6bdb904 | 1232 | &local_crash_msg_count, sizeof(u16)) < 0) { |
0f7453af DK |
1233 | dev_err(&chipset_dev->acpi_device->dev, |
1234 | "failed to read channel\n"); | |
12e364b9 KC |
1235 | return; |
1236 | } | |
e6bdb904 | 1237 | if (local_crash_msg_count != CONTROLVM_CRASHMSG_MAX) { |
040b78f7 | 1238 | dev_err(&chipset_dev->acpi_device->dev, "invalid count\n"); |
12e364b9 KC |
1239 | return; |
1240 | } | |
12e364b9 | 1241 | /* get saved crash message offset */ |
765b2f82 | 1242 | if (visorchannel_read(chipset_dev->controlvm_channel, |
545f0913 | 1243 | offsetof(struct visor_controlvm_channel, |
d19642f6 | 1244 | saved_crash_message_offset), |
e6bdb904 | 1245 | &local_crash_msg_offset, sizeof(u32)) < 0) { |
0f7453af DK |
1246 | dev_err(&chipset_dev->acpi_device->dev, |
1247 | "failed to read channel\n"); | |
12e364b9 KC |
1248 | return; |
1249 | } | |
12e364b9 | 1250 | /* read create device message for storage bus offset */ |
765b2f82 | 1251 | if (visorchannel_read(chipset_dev->controlvm_channel, |
e6bdb904 BR |
1252 | local_crash_msg_offset, |
1253 | &local_crash_bus_msg, | |
3ab47701 | 1254 | sizeof(struct controlvm_message)) < 0) { |
0f7453af DK |
1255 | dev_err(&chipset_dev->acpi_device->dev, |
1256 | "failed to read channel\n"); | |
12e364b9 KC |
1257 | return; |
1258 | } | |
12e364b9 | 1259 | /* read create device message for storage device */ |
765b2f82 | 1260 | if (visorchannel_read(chipset_dev->controlvm_channel, |
e6bdb904 | 1261 | local_crash_msg_offset + |
3ab47701 | 1262 | sizeof(struct controlvm_message), |
e6bdb904 | 1263 | &local_crash_dev_msg, |
3ab47701 | 1264 | sizeof(struct controlvm_message)) < 0) { |
0f7453af DK |
1265 | dev_err(&chipset_dev->acpi_device->dev, |
1266 | "failed to read channel\n"); | |
12e364b9 KC |
1267 | return; |
1268 | } | |
12e364b9 | 1269 | /* reuse IOVM create bus message */ |
d9b89ef1 | 1270 | if (!local_crash_bus_msg.cmd.create_bus.channel_addr) { |
0f7453af DK |
1271 | dev_err(&chipset_dev->acpi_device->dev, |
1272 | "no valid create_bus message\n"); | |
12e364b9 KC |
1273 | return; |
1274 | } | |
ec17cb8a | 1275 | visorbus_create(&local_crash_bus_msg); |
12e364b9 | 1276 | /* reuse create device message for storage device */ |
d9b89ef1 | 1277 | if (!local_crash_dev_msg.cmd.create_device.channel_addr) { |
0f7453af DK |
1278 | dev_err(&chipset_dev->acpi_device->dev, |
1279 | "no valid create_device message\n"); | |
12e364b9 KC |
1280 | return; |
1281 | } | |
8b0a6cfa | 1282 | visorbus_device_create(&local_crash_dev_msg); |
12e364b9 KC |
1283 | } |
1284 | ||
76956aa7 SW |
1285 | void visorbus_response(struct visor_device *bus_info, int response, |
1286 | int controlvm_id) | |
12e364b9 | 1287 | { |
fd9e450c DK |
1288 | if (!bus_info->pending_msg_hdr) |
1289 | return; | |
0274b5ae | 1290 | |
fd9e450c | 1291 | controlvm_responder(controlvm_id, bus_info->pending_msg_hdr, response); |
0274b5ae DZ |
1292 | kfree(bus_info->pending_msg_hdr); |
1293 | bus_info->pending_msg_hdr = NULL; | |
12e364b9 KC |
1294 | } |
1295 | ||
722e73d5 SW |
1296 | void visorbus_device_changestate_response(struct visor_device *dev_info, |
1297 | int response, | |
1298 | struct visor_segment_state state) | |
12e364b9 | 1299 | { |
fd9e450c DK |
1300 | if (!dev_info->pending_msg_hdr) |
1301 | return; | |
1302 | ||
040b78f7 DK |
1303 | device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE, dev_info, |
1304 | response, state); | |
0274b5ae DZ |
1305 | kfree(dev_info->pending_msg_hdr); |
1306 | dev_info->pending_msg_hdr = NULL; | |
12e364b9 KC |
1307 | } |
1308 | ||
39b486d6 DK |
1309 | static void parser_done(struct parser_context *ctx) |
1310 | { | |
1311 | chipset_dev->controlvm_payload_bytes_buffered -= ctx->param_bytes; | |
1312 | kfree(ctx); | |
1313 | } | |
1314 | ||
45311439 DK |
1315 | static struct parser_context *parser_init_stream(u64 addr, u32 bytes, |
1316 | bool *retry) | |
612b81c9 | 1317 | { |
26a42c25 | 1318 | int allocbytes; |
612b81c9 | 1319 | struct parser_context *ctx; |
a35e3268 | 1320 | void *mapping; |
612b81c9 | 1321 | |
3e4273db | 1322 | *retry = false; |
26a42c25 DK |
1323 | /* alloc an extra byte to ensure payload is \0 terminated */ |
1324 | allocbytes = bytes + 1 + (sizeof(struct parser_context) - | |
1325 | sizeof(struct visor_controlvm_parameters_header)); | |
040b78f7 DK |
1326 | if ((chipset_dev->controlvm_payload_bytes_buffered + bytes) > |
1327 | MAX_CONTROLVM_PAYLOAD_BYTES) { | |
3e4273db | 1328 | *retry = true; |
612b81c9 DK |
1329 | return NULL; |
1330 | } | |
8c8c975f | 1331 | ctx = kzalloc(allocbytes, GFP_KERNEL); |
612b81c9 | 1332 | if (!ctx) { |
3e4273db | 1333 | *retry = true; |
612b81c9 DK |
1334 | return NULL; |
1335 | } | |
612b81c9 DK |
1336 | ctx->allocbytes = allocbytes; |
1337 | ctx->param_bytes = bytes; | |
a35e3268 EA |
1338 | mapping = memremap(addr, bytes, MEMREMAP_WB); |
1339 | if (!mapping) | |
1340 | goto err_finish_ctx; | |
26a42c25 | 1341 | memcpy(&ctx->data, mapping, bytes); |
a35e3268 | 1342 | memunmap(mapping); |
612b81c9 | 1343 | ctx->byte_stream = true; |
765b2f82 | 1344 | chipset_dev->controlvm_payload_bytes_buffered += ctx->param_bytes; |
612b81c9 DK |
1345 | return ctx; |
1346 | ||
1347 | err_finish_ctx: | |
90544cb1 | 1348 | kfree(ctx); |
612b81c9 DK |
1349 | return NULL; |
1350 | } | |
1351 | ||
04dbfea6 | 1352 | /* |
511474a5 DK |
1353 | * handle_command() - process a controlvm message |
1354 | * @inmsg: the message to process | |
1355 | * @channel_addr: address of the controlvm channel | |
1356 | * | |
1357 | * Return: | |
25a5128e DK |
1358 | * 0 - Successfully processed the message |
1359 | * -EAGAIN - ControlVM message was not processed and should be retried | |
1360 | * reading the next controlvm message; a scenario where this can | |
1361 | * occur is when we need to throttle the allocation of memory in | |
1362 | * which to copy out controlvm payload data. | |
1363 | * < 0 - error: ControlVM message was processed but an error occurred. | |
511474a5 | 1364 | */ |
e80ffd4b | 1365 | static int handle_command(struct controlvm_message inmsg, u64 channel_addr) |
511474a5 DK |
1366 | { |
1367 | struct controlvm_message_packet *cmd = &inmsg.cmd; | |
1368 | u64 parm_addr; | |
1369 | u32 parm_bytes; | |
1370 | struct parser_context *parser_ctx = NULL; | |
511474a5 | 1371 | struct controlvm_message ackmsg; |
25a5128e | 1372 | int err = 0; |
511474a5 DK |
1373 | |
1374 | /* create parsing context if necessary */ | |
511474a5 DK |
1375 | parm_addr = channel_addr + inmsg.hdr.payload_vm_offset; |
1376 | parm_bytes = inmsg.hdr.payload_bytes; | |
511474a5 DK |
1377 | /* |
1378 | * Parameter and channel addresses within test messages actually lie | |
1379 | * within our OS-controlled memory. We need to know that, because it | |
1380 | * makes a difference in how we compute the virtual address. | |
1381 | */ | |
4d77e606 | 1382 | if (parm_bytes) { |
ef7b9dcb | 1383 | bool retry; |
511474a5 | 1384 | |
45311439 | 1385 | parser_ctx = parser_init_stream(parm_addr, parm_bytes, &retry); |
511474a5 | 1386 | if (!parser_ctx && retry) |
25a5128e | 1387 | return -EAGAIN; |
511474a5 | 1388 | } |
a35e3268 EA |
1389 | controlvm_init_response(&ackmsg, &inmsg.hdr, CONTROLVM_RESP_SUCCESS); |
1390 | err = visorchannel_signalinsert(chipset_dev->controlvm_channel, | |
1391 | CONTROLVM_QUEUE_ACK, &ackmsg); | |
1392 | if (err) | |
1393 | return err; | |
511474a5 DK |
1394 | switch (inmsg.hdr.id) { |
1395 | case CONTROLVM_CHIPSET_INIT: | |
25a5128e | 1396 | err = chipset_init(&inmsg); |
511474a5 DK |
1397 | break; |
1398 | case CONTROLVM_BUS_CREATE: | |
ec17cb8a | 1399 | err = visorbus_create(&inmsg); |
511474a5 DK |
1400 | break; |
1401 | case CONTROLVM_BUS_DESTROY: | |
ec17cb8a | 1402 | err = visorbus_destroy(&inmsg); |
511474a5 DK |
1403 | break; |
1404 | case CONTROLVM_BUS_CONFIGURE: | |
ec17cb8a | 1405 | err = visorbus_configure(&inmsg, parser_ctx); |
511474a5 DK |
1406 | break; |
1407 | case CONTROLVM_DEVICE_CREATE: | |
8b0a6cfa | 1408 | err = visorbus_device_create(&inmsg); |
511474a5 DK |
1409 | break; |
1410 | case CONTROLVM_DEVICE_CHANGESTATE: | |
1411 | if (cmd->device_change_state.flags.phys_device) { | |
25a5128e | 1412 | err = parahotplug_process_message(&inmsg); |
511474a5 DK |
1413 | } else { |
1414 | /* | |
6577cbf1 DK |
1415 | * save the hdr and cmd structures for later use when |
1416 | * sending back the response to Command | |
511474a5 | 1417 | */ |
8b0a6cfa | 1418 | err = visorbus_device_changestate(&inmsg); |
511474a5 DK |
1419 | break; |
1420 | } | |
1421 | break; | |
1422 | case CONTROLVM_DEVICE_DESTROY: | |
8b0a6cfa | 1423 | err = visorbus_device_destroy(&inmsg); |
511474a5 DK |
1424 | break; |
1425 | case CONTROLVM_DEVICE_CONFIGURE: | |
25a5128e | 1426 | /* no op just send a respond that we passed */ |
511474a5 | 1427 | if (inmsg.hdr.flags.response_expected) |
4c0e65f8 DK |
1428 | controlvm_respond(&inmsg.hdr, CONTROLVM_RESP_SUCCESS, |
1429 | NULL); | |
511474a5 DK |
1430 | break; |
1431 | case CONTROLVM_CHIPSET_READY: | |
25a5128e | 1432 | err = chipset_ready_uevent(&inmsg.hdr); |
511474a5 DK |
1433 | break; |
1434 | case CONTROLVM_CHIPSET_SELFTEST: | |
25a5128e | 1435 | err = chipset_selftest_uevent(&inmsg.hdr); |
511474a5 DK |
1436 | break; |
1437 | case CONTROLVM_CHIPSET_STOP: | |
25a5128e | 1438 | err = chipset_notready_uevent(&inmsg.hdr); |
511474a5 DK |
1439 | break; |
1440 | default: | |
25a5128e | 1441 | err = -ENOMSG; |
511474a5 | 1442 | if (inmsg.hdr.flags.response_expected) |
25a5128e | 1443 | controlvm_respond(&inmsg.hdr, |
4c0e65f8 | 1444 | -CONTROLVM_RESP_ID_UNKNOWN, NULL); |
511474a5 DK |
1445 | break; |
1446 | } | |
511474a5 DK |
1447 | if (parser_ctx) { |
1448 | parser_done(parser_ctx); | |
1449 | parser_ctx = NULL; | |
1450 | } | |
25a5128e | 1451 | return err; |
511474a5 DK |
1452 | } |
1453 | ||
04dbfea6 | 1454 | /* |
8a285327 DK |
1455 | * read_controlvm_event() - retreives the next message from the |
1456 | * CONTROLVM_QUEUE_EVENT queue in the controlvm | |
1457 | * channel | |
1458 | * @msg: pointer to the retrieved message | |
1459 | * | |
25a5128e | 1460 | * Return: 0 if valid message was retrieved or -error |
8a285327 | 1461 | */ |
e80ffd4b | 1462 | static int read_controlvm_event(struct controlvm_message *msg) |
8a285327 | 1463 | { |
904ee62a | 1464 | int err = visorchannel_signalremove(chipset_dev->controlvm_channel, |
25a5128e | 1465 | CONTROLVM_QUEUE_EVENT, msg); |
9116ae7a | 1466 | |
25a5128e DK |
1467 | if (err) |
1468 | return err; | |
25a5128e DK |
1469 | /* got a message */ |
1470 | if (msg->hdr.flags.test_message == 1) | |
1471 | return -EINVAL; | |
25a5128e | 1472 | return 0; |
8a285327 DK |
1473 | } |
1474 | ||
04dbfea6 | 1475 | /* |
a9c73937 DK |
1476 | * parahotplug_process_list() - remove any request from the list that's been on |
1477 | * there too long and respond with an error | |
1478 | */ | |
e80ffd4b | 1479 | static void parahotplug_process_list(void) |
a9c73937 DK |
1480 | { |
1481 | struct list_head *pos; | |
1482 | struct list_head *tmp; | |
1483 | ||
1484 | spin_lock(¶hotplug_request_list_lock); | |
a9c73937 DK |
1485 | list_for_each_safe(pos, tmp, ¶hotplug_request_list) { |
1486 | struct parahotplug_request *req = | |
1487 | list_entry(pos, struct parahotplug_request, list); | |
1488 | ||
1489 | if (!time_after_eq(jiffies, req->expiration)) | |
1490 | continue; | |
a9c73937 DK |
1491 | list_del(pos); |
1492 | if (req->msg.hdr.flags.response_expected) | |
4c0e65f8 | 1493 | controlvm_respond( |
a9c73937 | 1494 | &req->msg.hdr, |
98f9ed9e | 1495 | CONTROLVM_RESP_DEVICE_UDEV_TIMEOUT, |
4c0e65f8 | 1496 | &req->msg.cmd.device_change_state.state); |
a9c73937 DK |
1497 | parahotplug_request_destroy(req); |
1498 | } | |
a9c73937 DK |
1499 | spin_unlock(¶hotplug_request_list_lock); |
1500 | } | |
1501 | ||
e80ffd4b | 1502 | static void controlvm_periodic_work(struct work_struct *work) |
3d8394c8 DK |
1503 | { |
1504 | struct controlvm_message inmsg; | |
04dbc09b | 1505 | int count = 0; |
fbc1023a DK |
1506 | int err; |
1507 | ||
1508 | /* Drain the RESPONSE queue make it empty */ | |
1509 | do { | |
1510 | err = visorchannel_signalremove(chipset_dev->controlvm_channel, | |
1511 | CONTROLVM_QUEUE_RESPONSE, | |
1512 | &inmsg); | |
04dbc09b | 1513 | } while ((!err) && (++count < CONTROLVM_MESSAGE_MAX)); |
fbc1023a DK |
1514 | if (err != -EAGAIN) |
1515 | goto schedule_out; | |
fbc1023a DK |
1516 | if (chipset_dev->controlvm_pending_msg_valid) { |
1517 | /* | |
6577cbf1 DK |
1518 | * we throttled processing of a prior msg, so try to process |
1519 | * it again rather than reading a new one | |
fbc1023a DK |
1520 | */ |
1521 | inmsg = chipset_dev->controlvm_pending_msg; | |
1522 | chipset_dev->controlvm_pending_msg_valid = false; | |
1523 | err = 0; | |
1524 | } else { | |
1525 | err = read_controlvm_event(&inmsg); | |
3d8394c8 | 1526 | } |
fbc1023a | 1527 | while (!err) { |
765b2f82 | 1528 | chipset_dev->most_recent_message_jiffies = jiffies; |
fbc1023a DK |
1529 | err = handle_command(inmsg, |
1530 | visorchannel_get_physaddr | |
1531 | (chipset_dev->controlvm_channel)); | |
1532 | if (err == -EAGAIN) { | |
765b2f82 SW |
1533 | chipset_dev->controlvm_pending_msg = inmsg; |
1534 | chipset_dev->controlvm_pending_msg_valid = true; | |
fbc1023a | 1535 | break; |
3d8394c8 | 1536 | } |
fbc1023a DK |
1537 | |
1538 | err = read_controlvm_event(&inmsg); | |
3d8394c8 | 1539 | } |
3d8394c8 DK |
1540 | /* parahotplug_worker */ |
1541 | parahotplug_process_list(); | |
1542 | ||
d36c4857 SW |
1543 | /* |
1544 | * The controlvm messages are sent in a bulk. If we start receiving messages, we | |
1545 | * want the polling to be fast. If we do not receive any message for | |
1546 | * MIN_IDLE_SECONDS, we can slow down the polling. | |
1547 | */ | |
fbc1023a | 1548 | schedule_out: |
765b2f82 SW |
1549 | if (time_after(jiffies, chipset_dev->most_recent_message_jiffies + |
1550 | (HZ * MIN_IDLE_SECONDS))) { | |
3d8394c8 | 1551 | /* |
6577cbf1 DK |
1552 | * it's been longer than MIN_IDLE_SECONDS since we processed |
1553 | * our last controlvm message; slow down the polling | |
3d8394c8 | 1554 | */ |
3fbee197 DK |
1555 | if (chipset_dev->poll_jiffies != POLLJIFFIES_CONTROLVM_SLOW) |
1556 | chipset_dev->poll_jiffies = POLLJIFFIES_CONTROLVM_SLOW; | |
3d8394c8 | 1557 | } else { |
3fbee197 DK |
1558 | if (chipset_dev->poll_jiffies != POLLJIFFIES_CONTROLVM_FAST) |
1559 | chipset_dev->poll_jiffies = POLLJIFFIES_CONTROLVM_FAST; | |
3d8394c8 | 1560 | } |
765b2f82 SW |
1561 | schedule_delayed_work(&chipset_dev->periodic_controlvm_work, |
1562 | chipset_dev->poll_jiffies); | |
3d8394c8 DK |
1563 | } |
1564 | ||
e80ffd4b | 1565 | static int visorchipset_init(struct acpi_device *acpi_device) |
12e364b9 | 1566 | { |
1366a3db | 1567 | int err = -ENODEV; |
765b2f82 | 1568 | struct visorchannel *controlvm_channel; |
d3368a58 | 1569 | |
765b2f82 SW |
1570 | chipset_dev = kzalloc(sizeof(*chipset_dev), GFP_KERNEL); |
1571 | if (!chipset_dev) | |
1366a3db | 1572 | goto error; |
f1f537c2 DK |
1573 | err = controlvm_channel_create(chipset_dev); |
1574 | if (err) | |
1575 | goto error_free_chipset_dev; | |
765b2f82 | 1576 | acpi_device->driver_data = chipset_dev; |
765b2f82 | 1577 | chipset_dev->acpi_device = acpi_device; |
3fbee197 | 1578 | chipset_dev->poll_jiffies = POLLJIFFIES_CONTROLVM_FAST; |
15c012d5 SW |
1579 | err = sysfs_create_groups(&chipset_dev->acpi_device->dev.kobj, |
1580 | visorchipset_dev_groups); | |
1581 | if (err < 0) | |
1582 | goto error_destroy_channel; | |
f1f537c2 | 1583 | controlvm_channel = chipset_dev->controlvm_channel; |
403043c4 | 1584 | if (!visor_check_channel(visorchannel_get_header(controlvm_channel), |
e25201d6 | 1585 | &chipset_dev->acpi_device->dev, |
b32c5cb8 | 1586 | &visor_controlvm_channel_guid, |
403043c4 SW |
1587 | "controlvm", |
1588 | sizeof(struct visor_controlvm_channel), | |
1589 | VISOR_CONTROLVM_CHANNEL_VERSIONID, | |
1590 | VISOR_CHANNEL_SIGNATURE)) | |
15c012d5 | 1591 | goto error_delete_groups; |
4da3336c DK |
1592 | /* if booting in a crash kernel */ |
1593 | if (is_kdump_kernel()) | |
765b2f82 | 1594 | INIT_DELAYED_WORK(&chipset_dev->periodic_controlvm_work, |
4da3336c DK |
1595 | setup_crash_devices_work_queue); |
1596 | else | |
765b2f82 | 1597 | INIT_DELAYED_WORK(&chipset_dev->periodic_controlvm_work, |
4da3336c | 1598 | controlvm_periodic_work); |
765b2f82 | 1599 | chipset_dev->most_recent_message_jiffies = jiffies; |
3fbee197 | 1600 | chipset_dev->poll_jiffies = POLLJIFFIES_CONTROLVM_FAST; |
765b2f82 SW |
1601 | schedule_delayed_work(&chipset_dev->periodic_controlvm_work, |
1602 | chipset_dev->poll_jiffies); | |
1366a3db DK |
1603 | err = visorbus_init(); |
1604 | if (err < 0) | |
15c012d5 | 1605 | goto error_cancel_work; |
1366a3db DK |
1606 | return 0; |
1607 | ||
1366a3db | 1608 | error_cancel_work: |
765b2f82 | 1609 | cancel_delayed_work_sync(&chipset_dev->periodic_controlvm_work); |
1366a3db | 1610 | |
15c012d5 SW |
1611 | error_delete_groups: |
1612 | sysfs_remove_groups(&chipset_dev->acpi_device->dev.kobj, | |
1613 | visorchipset_dev_groups); | |
1614 | ||
1366a3db | 1615 | error_destroy_channel: |
765b2f82 SW |
1616 | visorchannel_destroy(chipset_dev->controlvm_channel); |
1617 | ||
1618 | error_free_chipset_dev: | |
1619 | kfree(chipset_dev); | |
1366a3db DK |
1620 | |
1621 | error: | |
372b9f22 | 1622 | dev_err(&acpi_device->dev, "failed with error %d\n", err); |
1366a3db | 1623 | return err; |
e3420ed6 EA |
1624 | } |
1625 | ||
e80ffd4b | 1626 | static int visorchipset_exit(struct acpi_device *acpi_device) |
12e364b9 | 1627 | { |
c79b28f7 | 1628 | visorbus_exit(); |
765b2f82 | 1629 | cancel_delayed_work_sync(&chipset_dev->periodic_controlvm_work); |
15c012d5 SW |
1630 | sysfs_remove_groups(&chipset_dev->acpi_device->dev.kobj, |
1631 | visorchipset_dev_groups); | |
765b2f82 | 1632 | visorchannel_destroy(chipset_dev->controlvm_channel); |
765b2f82 | 1633 | kfree(chipset_dev); |
55c67dca PB |
1634 | return 0; |
1635 | } | |
1636 | ||
1637 | static const struct acpi_device_id unisys_device_ids[] = { | |
1638 | {"PNP0A07", 0}, | |
1639 | {"", 0}, | |
1640 | }; | |
55c67dca PB |
1641 | |
1642 | static struct acpi_driver unisys_acpi_driver = { | |
1643 | .name = "unisys_acpi", | |
1644 | .class = "unisys_acpi_class", | |
1645 | .owner = THIS_MODULE, | |
1646 | .ids = unisys_device_ids, | |
1647 | .ops = { | |
1648 | .add = visorchipset_init, | |
1649 | .remove = visorchipset_exit, | |
027b03e7 | 1650 | }, |
55c67dca | 1651 | }; |
1fc07f99 DK |
1652 | |
1653 | MODULE_DEVICE_TABLE(acpi, unisys_device_ids); | |
1654 | ||
c1d28da7 | 1655 | static __init int visorutil_spar_detect(void) |
d5b3f1dc EA |
1656 | { |
1657 | unsigned int eax, ebx, ecx, edx; | |
1658 | ||
0c9f3536 | 1659 | if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) { |
d5b3f1dc | 1660 | /* check the ID */ |
a27ded92 SW |
1661 | cpuid(UNISYS_VISOR_LEAF_ID, &eax, &ebx, &ecx, &edx); |
1662 | return (ebx == UNISYS_VISOR_ID_EBX) && | |
1663 | (ecx == UNISYS_VISOR_ID_ECX) && | |
1664 | (edx == UNISYS_VISOR_ID_EDX); | |
d5b3f1dc | 1665 | } |
e4a06430 | 1666 | return 0; |
d5b3f1dc | 1667 | } |
55c67dca PB |
1668 | |
1669 | static int init_unisys(void) | |
1670 | { | |
1671 | int result; | |
35e606de | 1672 | |
d5b3f1dc | 1673 | if (!visorutil_spar_detect()) |
55c67dca | 1674 | return -ENODEV; |
55c67dca PB |
1675 | result = acpi_bus_register_driver(&unisys_acpi_driver); |
1676 | if (result) | |
1677 | return -ENODEV; | |
55c67dca PB |
1678 | pr_info("Unisys Visorchipset Driver Loaded.\n"); |
1679 | return 0; | |
1680 | }; | |
1681 | ||
1682 | static void exit_unisys(void) | |
1683 | { | |
1684 | acpi_bus_unregister_driver(&unisys_acpi_driver); | |
12e364b9 KC |
1685 | } |
1686 | ||
55c67dca PB |
1687 | module_init(init_unisys); |
1688 | module_exit(exit_unisys); | |
12e364b9 KC |
1689 | |
1690 | MODULE_AUTHOR("Unisys"); | |
1691 | MODULE_LICENSE("GPL"); | |
bff8c1a1 | 1692 | MODULE_DESCRIPTION("s-Par visorbus driver for virtual device buses"); |