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