Blame view

drivers/visorbus/visorchipset.c 46.6 KB
b79c0f4f5   Greg Kroah-Hartman   staging: unisys: ...
1
  // SPDX-License-Identifier: GPL-2.0
e517857b1   Zohaib Javed   staging: unisys: ...
2
  /*
6f14cc18f   Benjamin Romer   staging: unisys: ...
3
   * Copyright (C) 2010 - 2015 UNISYS CORPORATION
12e364b9f   Ken Cox   staging: visorchi...
4
   * All rights reserved.
12e364b9f   Ken Cox   staging: visorchi...
5
   */
55c67dcaa   Prarit Bhargava   staging: unisys: ...
6
  #include <linux/acpi.h>
1ba00980f   Benjamin Romer   staging: unisys: ...
7
  #include <linux/crash_dump.h>
93d3ad90c   David Kershner   drivers: visorbus...
8
  #include <linux/visorbus.h>
12e364b9f   Ken Cox   staging: visorchi...
9

55c67dcaa   Prarit Bhargava   staging: unisys: ...
10
  #include "visorbus_private.h"
f79e1dfdb   David Kershner   staging: unisys: ...
11
  /* {72120008-4AAB-11DC-8530-444553544200} */
1604ebecd   David Kershner   staging: unisys: ...
12
13
  #define VISOR_SIOVM_GUID GUID_INIT(0x72120008, 0x4AAB, 0x11DC, 0x85, 0x30, \
  				   0x44, 0x45, 0x53, 0x54, 0x42, 0x00)
f79e1dfdb   David Kershner   staging: unisys: ...
14

b32c5cb84   Andy Shevchenko   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   David Kershner   staging: unisys: ...
18
19
  #define POLLJIFFIES_CONTROLVM_FAST 1
  #define POLLJIFFIES_CONTROLVM_SLOW 100
12e364b9f   Ken Cox   staging: visorchi...
20

2c7e1d4e4   Bhaktipriya Shridhar   staging: unisys: ...
21
  #define MAX_CONTROLVM_PAYLOAD_BYTES (1024 * 128)
2ee0deec4   Prarit Bhargava   staging: unisys: ...
22

a27ded927   Sameer Wadgaonkar   staging: unisys: ...
23
  #define UNISYS_VISOR_LEAF_ID 0x40000000
d5b3f1dcc   Erik Arfvidson   staging: unisys: ...
24
25
  
  /* The s-Par leaf ID returns "UnisysSpar64" encoded across ebx, ecx, edx */
a27ded927   Sameer Wadgaonkar   staging: unisys: ...
26
27
28
  #define UNISYS_VISOR_ID_EBX 0x73696e55
  #define UNISYS_VISOR_ID_ECX 0x70537379
  #define UNISYS_VISOR_ID_EDX 0x34367261
d5b3f1dcc   Erik Arfvidson   staging: unisys: ...
29

b615d628b   Jes Sorensen   staging: unisys: ...
30
  /*
6577cbf1f   David Kershner   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   David Binder   staging: unisys: ...
34
   */
12e364b9f   Ken Cox   staging: visorchi...
35
  #define MIN_IDLE_SECONDS 10
12e364b9f   Ken Cox   staging: visorchi...
36

461688102   Erik Arfvidson   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   David Kershner   staging: unisys: ...
43
  	struct visor_controlvm_parameters_header data;
461688102   Erik Arfvidson   staging: unisys: ...
44
  };
12cbd4904   David Binder   staging: unisys: ...
45
  /* VMCALL_CONTROLVM_ADDR: Used by all guests, not just IO. */
c8684a9d8   David Binder   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   Sameer Wadgaonkar   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   Sameer Wadgaonkar   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   David Kershner   staging: unisys: ...
91
  	struct vmcall_io_controlvm_addr_params controlvm_params;
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
92
  };
12e364b9f   Ken Cox   staging: visorchi...
93

765b2f828   Sameer Wadgaonkar   staging: unisys: ...
94
  static struct visorchipset_device *chipset_dev;
12e364b9f   Ken Cox   staging: visorchi...
95

12e364b9f   Ken Cox   staging: visorchi...
96
97
98
99
  struct parahotplug_request {
  	struct list_head list;
  	int id;
  	unsigned long expiration;
3ab477012   Benjamin Romer   staging: unisys: ...
100
  	struct controlvm_message msg;
12e364b9f   Ken Cox   staging: visorchi...
101
  };
19f6634f4   Benjamin Romer   staging: unisys: ...
102
103
  /* prototypes for attributes */
  static ssize_t toolaction_show(struct device *dev,
84efd2077   David Kershner   staging: unisys: ...
104
105
106
107
  			       struct device_attribute *attr,
  			       char *buf)
  {
  	u8 tool_action = 0;
002a5abb2   David Kershner   staging: unisys: ...
108
109
110
  	int err;
  
  	err = visorchannel_read(chipset_dev->controlvm_channel,
545f09138   Sameer Wadgaonkar   staging: unisys: ...
111
  				offsetof(struct visor_controlvm_channel,
002a5abb2   David Kershner   staging: unisys: ...
112
113
114
115
  					 tool_action),
  				&tool_action, sizeof(u8));
  	if (err)
  		return err;
746fb137c   David Binder   staging: unisys: ...
116
117
  	return sprintf(buf, "%u
  ", tool_action);
84efd2077   David Kershner   staging: unisys: ...
118
  }
19f6634f4   Benjamin Romer   staging: unisys: ...
119
  static ssize_t toolaction_store(struct device *dev,
8e76e695f   Benjamin Romer   staging: unisys: ...
120
  				struct device_attribute *attr,
84efd2077   David Kershner   staging: unisys: ...
121
122
123
  				const char *buf, size_t count)
  {
  	u8 tool_action;
dc35cdf31   David Kershner   staging: unisys: ...
124
  	int err;
84efd2077   David Kershner   staging: unisys: ...
125
126
127
  
  	if (kstrtou8(buf, 10, &tool_action))
  		return -EINVAL;
545f09138   Sameer Wadgaonkar   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   David Kershner   staging: unisys: ...
132
133
  	if (err)
  		return err;
84efd2077   David Kershner   staging: unisys: ...
134
135
  	return count;
  }
19f6634f4   Benjamin Romer   staging: unisys: ...
136
  static DEVICE_ATTR_RW(toolaction);
54b312290   Benjamin Romer   staging: unisys: ...
137
  static ssize_t boottotool_show(struct device *dev,
1b1d463d0   David Kershner   staging: unisys: ...
138
139
140
  			       struct device_attribute *attr,
  			       char *buf)
  {
545f09138   Sameer Wadgaonkar   staging: unisys: ...
141
  	struct efi_visor_indication efi_visor_indication;
0b01c6ce5   David Kershner   staging: unisys: ...
142
143
144
  	int err;
  
  	err = visorchannel_read(chipset_dev->controlvm_channel,
545f09138   Sameer Wadgaonkar   staging: unisys: ...
145
146
147
148
  				offsetof(struct visor_controlvm_channel,
  					 efi_visor_ind),
  				&efi_visor_indication,
  				sizeof(struct efi_visor_indication));
0b01c6ce5   David Kershner   staging: unisys: ...
149
150
  	if (err)
  		return err;
545f09138   Sameer Wadgaonkar   staging: unisys: ...
151
152
  	return sprintf(buf, "%u
  ", efi_visor_indication.boot_to_tool);
1b1d463d0   David Kershner   staging: unisys: ...
153
  }
54b312290   Benjamin Romer   staging: unisys: ...
154
  static ssize_t boottotool_store(struct device *dev,
1b1d463d0   David Kershner   staging: unisys: ...
155
156
157
  				struct device_attribute *attr,
  				const char *buf, size_t count)
  {
b309266ed   David Kershner   staging: unisys: ...
158
  	int val, err;
545f09138   Sameer Wadgaonkar   staging: unisys: ...
159
  	struct efi_visor_indication efi_visor_indication;
1b1d463d0   David Kershner   staging: unisys: ...
160
161
162
  
  	if (kstrtoint(buf, 10, &val))
  		return -EINVAL;
545f09138   Sameer Wadgaonkar   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   David Kershner   staging: unisys: ...
169
170
  	if (err)
  		return err;
1b1d463d0   David Kershner   staging: unisys: ...
171
172
  	return count;
  }
54b312290   Benjamin Romer   staging: unisys: ...
173
  static DEVICE_ATTR_RW(boottotool);
422af17c6   Benjamin Romer   staging: unisys: ...
174
  static ssize_t error_show(struct device *dev, struct device_attribute *attr,
8a4a8a03d   David Kershner   staging: unisys: ...
175
176
177
  			  char *buf)
  {
  	u32 error = 0;
d9857c794   David Kershner   staging: unisys: ...
178
  	int err;
8a4a8a03d   David Kershner   staging: unisys: ...
179

d9857c794   David Kershner   staging: unisys: ...
180
  	err = visorchannel_read(chipset_dev->controlvm_channel,
545f09138   Sameer Wadgaonkar   staging: unisys: ...
181
  				offsetof(struct visor_controlvm_channel,
d9857c794   David Kershner   staging: unisys: ...
182
183
184
185
  					 installation_error),
  				&error, sizeof(u32));
  	if (err)
  		return err;
6df555c13   David Binder   staging: unisys: ...
186
187
  	return sprintf(buf, "%u
  ", error);
8a4a8a03d   David Kershner   staging: unisys: ...
188
  }
422af17c6   Benjamin Romer   staging: unisys: ...
189
  static ssize_t error_store(struct device *dev, struct device_attribute *attr,
8a4a8a03d   David Kershner   staging: unisys: ...
190
191
192
  			   const char *buf, size_t count)
  {
  	u32 error;
ea295857f   David Kershner   staging: unisys: ...
193
  	int err;
8a4a8a03d   David Kershner   staging: unisys: ...
194
195
196
  
  	if (kstrtou32(buf, 10, &error))
  		return -EINVAL;
545f09138   Sameer Wadgaonkar   staging: unisys: ...
197
198
199
200
  	err = visorchannel_write(chipset_dev->controlvm_channel,
  				 offsetof(struct visor_controlvm_channel,
  					  installation_error),
  				 &error, sizeof(u32));
ea295857f   David Kershner   staging: unisys: ...
201
202
  	if (err)
  		return err;
8a4a8a03d   David Kershner   staging: unisys: ...
203
204
  	return count;
  }
422af17c6   Benjamin Romer   staging: unisys: ...
205
206
207
  static DEVICE_ATTR_RW(error);
  
  static ssize_t textid_show(struct device *dev, struct device_attribute *attr,
79730c7c8   David Kershner   staging: unisys: ...
208
209
210
  			   char *buf)
  {
  	u32 text_id = 0;
0d4064367   David Kershner   staging: unisys: ...
211
  	int err;
545f09138   Sameer Wadgaonkar   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   David Kershner   staging: unisys: ...
216
217
  	if (err)
  		return err;
6df555c13   David Binder   staging: unisys: ...
218
219
  	return sprintf(buf, "%u
  ", text_id);
79730c7c8   David Kershner   staging: unisys: ...
220
  }
422af17c6   Benjamin Romer   staging: unisys: ...
221
  static ssize_t textid_store(struct device *dev, struct device_attribute *attr,
79730c7c8   David Kershner   staging: unisys: ...
222
223
224
  			    const char *buf, size_t count)
  {
  	u32 text_id;
08a55d2d2   David Kershner   staging: unisys: ...
225
  	int err;
79730c7c8   David Kershner   staging: unisys: ...
226
227
228
  
  	if (kstrtou32(buf, 10, &text_id))
  		return -EINVAL;
545f09138   Sameer Wadgaonkar   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   David Kershner   staging: unisys: ...
233
234
  	if (err)
  		return err;
79730c7c8   David Kershner   staging: unisys: ...
235
236
  	return count;
  }
422af17c6   Benjamin Romer   staging: unisys: ...
237
238
239
  static DEVICE_ATTR_RW(textid);
  
  static ssize_t remaining_steps_show(struct device *dev,
97f792ee3   David Kershner   staging: unisys: ...
240
241
242
  				    struct device_attribute *attr, char *buf)
  {
  	u16 remaining_steps = 0;
c53578bd6   David Kershner   staging: unisys: ...
243
244
245
  	int err;
  
  	err = visorchannel_read(chipset_dev->controlvm_channel,
545f09138   Sameer Wadgaonkar   staging: unisys: ...
246
  				offsetof(struct visor_controlvm_channel,
c53578bd6   David Kershner   staging: unisys: ...
247
248
249
250
  					 installation_remaining_steps),
  				&remaining_steps, sizeof(u16));
  	if (err)
  		return err;
746fb137c   David Binder   staging: unisys: ...
251
252
  	return sprintf(buf, "%hu
  ", remaining_steps);
97f792ee3   David Kershner   staging: unisys: ...
253
  }
422af17c6   Benjamin Romer   staging: unisys: ...
254
  static ssize_t remaining_steps_store(struct device *dev,
8e76e695f   Benjamin Romer   staging: unisys: ...
255
  				     struct device_attribute *attr,
97f792ee3   David Kershner   staging: unisys: ...
256
257
258
  				     const char *buf, size_t count)
  {
  	u16 remaining_steps;
e030d39d5   David Kershner   staging: unisys: ...
259
  	int err;
97f792ee3   David Kershner   staging: unisys: ...
260
261
262
  
  	if (kstrtou16(buf, 10, &remaining_steps))
  		return -EINVAL;
545f09138   Sameer Wadgaonkar   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   David Kershner   staging: unisys: ...
267
268
  	if (err)
  		return err;
97f792ee3   David Kershner   staging: unisys: ...
269
270
  	return count;
  }
422af17c6   Benjamin Romer   staging: unisys: ...
271
  static DEVICE_ATTR_RW(remaining_steps);
e80ffd4b2   Charles Daniels   staging: unisys: ...
272
273
274
  static void controlvm_init_response(struct controlvm_message *msg,
  				    struct controlvm_message_header *msg_hdr,
  				    int response)
5f2513950   David Kershner   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   Charles Daniels   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   David Kershner   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   Sameer Wadgaonkar   staging: unisys: ...
295
  	return visorchannel_signalinsert(chipset_dev->controlvm_channel,
1d7f55220   David Kershner   staging: unisys: ...
296
  					 CONTROLVM_QUEUE_REQUEST, &outmsg);
5f2513950   David Kershner   staging: unisys: ...
297
  }
e80ffd4b2   Charles Daniels   staging: unisys: ...
298
  static int chipset_init(struct controlvm_message *inmsg)
12e364b9f   Ken Cox   staging: visorchi...
299
300
  {
  	static int chipset_inited;
d3ad6e69c   Sameer Wadgaonkar   staging: unisys: ...
301
  	enum visor_chipset_feature features = 0;
12e364b9f   Ken Cox   staging: visorchi...
302
  	int rc = CONTROLVM_RESP_SUCCESS;
79c3f971d   David Kershner   staging: unisys: ...
303
  	int res = 0;
12e364b9f   Ken Cox   staging: visorchi...
304

12e364b9f   Ken Cox   staging: visorchi...
305
  	if (chipset_inited) {
98f9ed9ec   Sameer Wadgaonkar   staging: unisys: ...
306
  		rc = -CONTROLVM_RESP_ALREADY_DONE;
79c3f971d   David Kershner   staging: unisys: ...
307
  		res = -EIO;
5233d1ebb   David Kershner   staging: unisys: ...
308
  		goto out_respond;
12e364b9f   Ken Cox   staging: visorchi...
309
310
  	}
  	chipset_inited = 1;
ec17f452f   David Binder   staging: unisys: ...
311
  	/*
6577cbf1f   David Kershner   staging: unisys: ...
312
  	 * Set features to indicate we support parahotplug (if Command also
977980ac5   David Kershner   staging: unisys: ...
313
314
  	 * supports it). Set the "reply" bit so Command knows this is a
  	 * features-aware driver.
2ee0d0524   Erik Arfvidson   staging: unisys: ...
315
  	 */
0762188b8   David Binder   staging: unisys: ...
316
  	features = inmsg->cmd.init_chipset.features &
d3ad6e69c   Sameer Wadgaonkar   staging: unisys: ...
317
  		   VISOR_CHIPSET_FEATURE_PARA_HOTPLUG;
d3ad6e69c   Sameer Wadgaonkar   staging: unisys: ...
318
  	features |= VISOR_CHIPSET_FEATURE_REPLY;
12e364b9f   Ken Cox   staging: visorchi...
319

5233d1ebb   David Kershner   staging: unisys: ...
320
  out_respond:
98d7b5947   Benjamin Romer   staging: unisys: ...
321
  	if (inmsg->hdr.flags.response_expected)
79c3f971d   David Kershner   staging: unisys: ...
322
323
324
  		res = controlvm_respond_chipset_init(&inmsg->hdr, rc, features);
  
  	return res;
12e364b9f   Ken Cox   staging: visorchi...
325
  }
e80ffd4b2   Charles Daniels   staging: unisys: ...
326
  static int controlvm_respond(struct controlvm_message_header *msg_hdr,
040b78f7a   David Kershner   staging: unisys; ...
327
  			     int response, struct visor_segment_state *state)
12e364b9f   Ken Cox   staging: visorchi...
328
  {
3ab477012   Benjamin Romer   staging: unisys: ...
329
  	struct controlvm_message outmsg;
26eb2c0c5   Benjamin Romer   staging: unisys: ...
330

b3168c70b   Benjamin Romer   staging: unisys: ...
331
  	controlvm_init_response(&outmsg, msg_hdr, response);
2098dbd1b   Benjamin Romer   staging: unisys: ...
332
  	if (outmsg.hdr.flags.test_message == 1)
2d26aeb77   David Kershner   staging: unisys: ...
333
  		return -EINVAL;
4c0e65f83   David Kershner   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   Sameer Wadgaonkar   staging: unisys: ...
338
  	return visorchannel_signalinsert(chipset_dev->controlvm_channel,
2c4ef563f   David Kershner   staging: unisys: ...
339
  					 CONTROLVM_QUEUE_REQUEST, &outmsg);
12e364b9f   Ken Cox   staging: visorchi...
340
  }
2ee0deec4   Prarit Bhargava   staging: unisys: ...
341
342
343
344
  enum crash_obj_type {
  	CRASH_DEV,
  	CRASH_BUS,
  };
e80ffd4b2   Charles Daniels   staging: unisys: ...
345
346
  static int save_crash_message(struct controlvm_message *msg,
  			      enum crash_obj_type cr_type)
12c957dc9   Tim Sell   staging: unisys: ...
347
348
349
  {
  	u32 local_crash_msg_offset;
  	u16 local_crash_msg_count;
8dff01f7d   David Kershner   staging: unisys: ...
350
  	int err;
12c957dc9   Tim Sell   staging: unisys: ...
351

765b2f828   Sameer Wadgaonkar   staging: unisys: ...
352
  	err = visorchannel_read(chipset_dev->controlvm_channel,
545f09138   Sameer Wadgaonkar   staging: unisys: ...
353
  				offsetof(struct visor_controlvm_channel,
8dff01f7d   David Kershner   staging: unisys: ...
354
355
356
  					 saved_crash_message_count),
  				&local_crash_msg_count, sizeof(u16));
  	if (err) {
35301b876   David Kershner   staging: unisys: ...
357
358
359
  		dev_err(&chipset_dev->acpi_device->dev,
  			"failed to read message count
  ");
8dff01f7d   David Kershner   staging: unisys: ...
360
  		return err;
12c957dc9   Tim Sell   staging: unisys: ...
361
  	}
12c957dc9   Tim Sell   staging: unisys: ...
362
  	if (local_crash_msg_count != CONTROLVM_CRASHMSG_MAX) {
35301b876   David Kershner   staging: unisys: ...
363
364
365
  		dev_err(&chipset_dev->acpi_device->dev,
  			"invalid number of messages
  ");
8dff01f7d   David Kershner   staging: unisys: ...
366
  		return -EIO;
12c957dc9   Tim Sell   staging: unisys: ...
367
  	}
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
368
  	err = visorchannel_read(chipset_dev->controlvm_channel,
545f09138   Sameer Wadgaonkar   staging: unisys: ...
369
  				offsetof(struct visor_controlvm_channel,
8dff01f7d   David Kershner   staging: unisys: ...
370
371
372
  					 saved_crash_message_offset),
  				&local_crash_msg_offset, sizeof(u32));
  	if (err) {
35301b876   David Kershner   staging: unisys: ...
373
374
375
  		dev_err(&chipset_dev->acpi_device->dev,
  			"failed to read offset
  ");
8dff01f7d   David Kershner   staging: unisys: ...
376
  		return err;
12c957dc9   Tim Sell   staging: unisys: ...
377
  	}
603a1989c   Jon Frisch   staging: unisys: ...
378
  	switch (cr_type) {
36309d3b1   David Binder   staging: unisys: ...
379
380
  	case CRASH_DEV:
  		local_crash_msg_offset += sizeof(struct controlvm_message);
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
381
  		err = visorchannel_write(chipset_dev->controlvm_channel,
040b78f7a   David Kershner   staging: unisys; ...
382
  					 local_crash_msg_offset, msg,
36309d3b1   David Binder   staging: unisys: ...
383
  					 sizeof(struct controlvm_message));
8dff01f7d   David Kershner   staging: unisys: ...
384
  		if (err) {
35301b876   David Kershner   staging: unisys: ...
385
386
387
  			dev_err(&chipset_dev->acpi_device->dev,
  				"failed to write dev msg
  ");
8dff01f7d   David Kershner   staging: unisys: ...
388
  			return err;
12c957dc9   Tim Sell   staging: unisys: ...
389
  		}
36309d3b1   David Binder   staging: unisys: ...
390
391
  		break;
  	case CRASH_BUS:
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
392
  		err = visorchannel_write(chipset_dev->controlvm_channel,
040b78f7a   David Kershner   staging: unisys; ...
393
  					 local_crash_msg_offset, msg,
8dff01f7d   David Kershner   staging: unisys: ...
394
395
  					 sizeof(struct controlvm_message));
  		if (err) {
35301b876   David Kershner   staging: unisys: ...
396
397
398
  			dev_err(&chipset_dev->acpi_device->dev,
  				"failed to write bus msg
  ");
8dff01f7d   David Kershner   staging: unisys: ...
399
  			return err;
12c957dc9   Tim Sell   staging: unisys: ...
400
  		}
36309d3b1   David Binder   staging: unisys: ...
401
402
  		break;
  	default:
35301b876   David Kershner   staging: unisys: ...
403
404
405
  		dev_err(&chipset_dev->acpi_device->dev,
  			"Invalid crash_obj_type
  ");
36309d3b1   David Binder   staging: unisys: ...
406
  		break;
12c957dc9   Tim Sell   staging: unisys: ...
407
  	}
8dff01f7d   David Kershner   staging: unisys: ...
408
  	return 0;
12c957dc9   Tim Sell   staging: unisys: ...
409
  }
e80ffd4b2   Charles Daniels   staging: unisys: ...
410
411
412
  static int controlvm_responder(enum controlvm_id cmd_id,
  			       struct controlvm_message_header *pending_msg_hdr,
  			       int response)
12e364b9f   Ken Cox   staging: visorchi...
413
  {
0274b5aec   Don Zickus   staging: unisys: ...
414
  	if (pending_msg_hdr->id != (u32)cmd_id)
734ad93a2   David Kershner   staging: unisys: ...
415
  		return -EINVAL;
0aca78449   Benjamin Romer   staging: unisys: ...
416

4c0e65f83   David Kershner   staging: unisys: ...
417
  	return controlvm_respond(pending_msg_hdr, response, NULL);
12e364b9f   Ken Cox   staging: visorchi...
418
  }
da56cb048   David Kershner   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   Ken Cox   staging: visorchi...
422
  {
3ab477012   Benjamin Romer   staging: unisys: ...
423
  	struct controlvm_message outmsg;
12e364b9f   Ken Cox   staging: visorchi...
424

0274b5aec   Don Zickus   staging: unisys: ...
425
  	if (p->pending_msg_hdr->id != cmd_id)
68f99d491   David Kershner   staging: unisys: ...
426
  		return -EINVAL;
12e364b9f   Ken Cox   staging: visorchi...
427

0274b5aec   Don Zickus   staging: unisys: ...
428
  	controlvm_init_response(&outmsg, p->pending_msg_hdr, response);
b253ff5bf   David Kershner   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   David Kershner   staging: unisys: ...
431
  	outmsg.cmd.device_change_state.state = state;
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
432
  	return visorchannel_signalinsert(chipset_dev->controlvm_channel,
68f99d491   David Kershner   staging: unisys: ...
433
  					 CONTROLVM_QUEUE_REQUEST, &outmsg);
12e364b9f   Ken Cox   staging: visorchi...
434
  }
e80ffd4b2   Charles Daniels   staging: unisys: ...
435
  static int visorbus_create(struct controlvm_message *inmsg)
12e364b9f   Ken Cox   staging: visorchi...
436
  {
2ea5117b5   Benjamin Romer   staging: unisys: ...
437
  	struct controlvm_message_packet *cmd = &inmsg->cmd;
ef7b9dcb1   David Kershner   staging: unisys: ...
438
  	struct controlvm_message_header *pmsg_hdr;
52063eca7   Jes Sorensen   staging: unisys: ...
439
  	u32 bus_no = cmd->create_bus.bus_no;
d32517e39   Don Zickus   staging: unisys: ...
440
  	struct visor_device *bus_info;
b32c4997c   Don Zickus   staging: unisys: ...
441
  	struct visorchannel *visorchannel;
33161a29c   David Kershner   staging: unisys: ...
442
  	int err;
12e364b9f   Ken Cox   staging: visorchi...
443

d32517e39   Don Zickus   staging: unisys: ...
444
  	bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL);
614b083d7   David Kershner   staging: unisys: ...
445
  	if (bus_info && bus_info->state.created == 1) {
055bc9093   David Kershner   staging: unisys: ...
446
  		dev_err(&chipset_dev->acpi_device->dev,
87408fe0d   Zachary Dremann   staging: unisys: ...
447
448
  			"failed %s: already exists
  ", __func__);
33161a29c   David Kershner   staging: unisys: ...
449
450
  		err = -EEXIST;
  		goto err_respond;
12e364b9f   Ken Cox   staging: visorchi...
451
  	}
6c5fed359   Benjamin Romer   staging: unisys: ...
452
453
  	bus_info = kzalloc(sizeof(*bus_info), GFP_KERNEL);
  	if (!bus_info) {
33161a29c   David Kershner   staging: unisys: ...
454
455
  		err = -ENOMEM;
  		goto err_respond;
12e364b9f   Ken Cox   staging: visorchi...
456
  	}
4abce83dc   David Kershner   staging: unisys: ...
457
  	INIT_LIST_HEAD(&bus_info->list_all);
d32517e39   Don Zickus   staging: unisys: ...
458
459
  	bus_info->chipset_bus_no = bus_no;
  	bus_info->chipset_dev_no = BUS_ROOT_DEVICE;
b32c5cb84   Andy Shevchenko   staging: unisys: ...
460
  	if (guid_equal(&cmd->create_bus.bus_inst_guid, &visor_siovm_guid)) {
300ed6125   David Kershner   staging: unisys: ...
461
462
463
464
  		err = save_crash_message(inmsg, CRASH_BUS);
  		if (err)
  			goto err_free_bus_info;
  	}
8f334e30c   David Kershner   staging: unisys: ...
465
  	if (inmsg->hdr.flags.response_expected == 1) {
040b78f7a   David Kershner   staging: unisys; ...
466
  		pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL);
8f334e30c   David Kershner   staging: unisys: ...
467
  		if (!pmsg_hdr) {
33161a29c   David Kershner   staging: unisys: ...
468
469
  			err = -ENOMEM;
  			goto err_free_bus_info;
8f334e30c   David Kershner   staging: unisys: ...
470
  		}
8f334e30c   David Kershner   staging: unisys: ...
471
472
473
474
  		memcpy(pmsg_hdr, &inmsg->hdr,
  		       sizeof(struct controlvm_message_header));
  		bus_info->pending_msg_hdr = pmsg_hdr;
  	}
33161a29c   David Kershner   staging: unisys: ...
475
  	visorchannel = visorchannel_create(cmd->create_bus.channel_addr,
33161a29c   David Kershner   staging: unisys: ...
476
  					   GFP_KERNEL,
90476670a   Sameer Wadgaonkar   staging: unisys: ...
477
478
  					   &cmd->create_bus.bus_data_type_guid,
  					   false);
33161a29c   David Kershner   staging: unisys: ...
479
  	if (!visorchannel) {
33161a29c   David Kershner   staging: unisys: ...
480
481
482
483
  		err = -ENOMEM;
  		goto err_free_pending_msg;
  	}
  	bus_info->visorchannel = visorchannel;
fdf5b9ac3   David Kershner   staging: unisys: ...
484
485
  	/* Response will be handled by visorbus_create_instance on success */
  	err = visorbus_create_instance(bus_info);
621f5e185   David Kershner   staging: unisys: ...
486
487
  	if (err)
  		goto err_destroy_channel;
33161a29c   David Kershner   staging: unisys: ...
488
  	return 0;
621f5e185   David Kershner   staging: unisys: ...
489
490
  err_destroy_channel:
  	visorchannel_destroy(visorchannel);
33161a29c   David Kershner   staging: unisys: ...
491
492
  err_free_pending_msg:
  	kfree(bus_info->pending_msg_hdr);
8f334e30c   David Kershner   staging: unisys: ...
493

33161a29c   David Kershner   staging: unisys: ...
494
  err_free_bus_info:
8f334e30c   David Kershner   staging: unisys: ...
495
  	kfree(bus_info);
12e364b9f   Ken Cox   staging: visorchi...
496

33161a29c   David Kershner   staging: unisys: ...
497
  err_respond:
8f334e30c   David Kershner   staging: unisys: ...
498
  	if (inmsg->hdr.flags.response_expected == 1)
4fb2539c8   David Kershner   staging: unisys: ...
499
  		controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err);
33161a29c   David Kershner   staging: unisys: ...
500
  	return err;
12e364b9f   Ken Cox   staging: visorchi...
501
  }
e80ffd4b2   Charles Daniels   staging: unisys: ...
502
  static int visorbus_destroy(struct controlvm_message *inmsg)
12e364b9f   Ken Cox   staging: visorchi...
503
  {
ef7b9dcb1   David Kershner   staging: unisys: ...
504
  	struct controlvm_message_header *pmsg_hdr;
3f5a562b1   David Kershner   staging: unisys: ...
505
  	u32 bus_no = inmsg->cmd.destroy_bus.bus_no;
d32517e39   Don Zickus   staging: unisys: ...
506
  	struct visor_device *bus_info;
30f6c3f5f   David Kershner   staging: unisys: ...
507
  	int err;
12e364b9f   Ken Cox   staging: visorchi...
508

d32517e39   Don Zickus   staging: unisys: ...
509
  	bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL);
3e0e8db92   David Kershner   staging: unisys: ...
510
  	if (!bus_info) {
30f6c3f5f   David Kershner   staging: unisys: ...
511
512
  		err = -ENODEV;
  		goto err_respond;
3e0e8db92   David Kershner   staging: unisys: ...
513
514
  	}
  	if (bus_info->state.created == 0) {
30f6c3f5f   David Kershner   staging: unisys: ...
515
516
  		err = -ENOENT;
  		goto err_respond;
3e0e8db92   David Kershner   staging: unisys: ...
517
518
519
  	}
  	if (bus_info->pending_msg_hdr) {
  		/* only non-NULL if dev is still waiting on a response */
30f6c3f5f   David Kershner   staging: unisys: ...
520
521
  		err = -EEXIST;
  		goto err_respond;
3e0e8db92   David Kershner   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   David Kershner   staging: unisys: ...
526
527
  			err = -ENOMEM;
  			goto err_respond;
3e0e8db92   David Kershner   staging: unisys: ...
528
  		}
3e0e8db92   David Kershner   staging: unisys: ...
529
530
531
532
  		memcpy(pmsg_hdr, &inmsg->hdr,
  		       sizeof(struct controlvm_message_header));
  		bus_info->pending_msg_hdr = pmsg_hdr;
  	}
a7093ba16   Sameer Wadgaonkar   staging: unisys: ...
533
534
  	/* Response will be handled by visorbus_remove_instance */
  	visorbus_remove_instance(bus_info);
30f6c3f5f   David Kershner   staging: unisys: ...
535
  	return 0;
3e0e8db92   David Kershner   staging: unisys: ...
536

30f6c3f5f   David Kershner   staging: unisys: ...
537
  err_respond:
3e0e8db92   David Kershner   staging: unisys: ...
538
  	if (inmsg->hdr.flags.response_expected == 1)
4fb2539c8   David Kershner   staging: unisys: ...
539
  		controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err);
30f6c3f5f   David Kershner   staging: unisys: ...
540
  	return err;
12e364b9f   Ken Cox   staging: visorchi...
541
  }
39b486d6e   David Kershner   staging: unisys: ...
542
543
544
545
  static const guid_t *parser_id_get(struct parser_context *ctx)
  {
  	return &ctx->data.id;
  }
90d1ecf04   David Kershner   staging: unisys: ...
546
  static void *parser_string_get(u8 *pscan, int nscan)
39b486d6e   David Kershner   staging: unisys: ...
547
  {
39b486d6e   David Kershner   staging: unisys: ...
548
549
  	int value_length;
  	void *value;
39b486d6e   David Kershner   staging: unisys: ...
550

39b486d6e   David Kershner   staging: unisys: ...
551
552
  	if (nscan == 0)
  		return NULL;
90d1ecf04   David Kershner   staging: unisys: ...
553
554
  	value_length = strnlen(pscan, nscan);
  	value = kzalloc(value_length + 1, GFP_KERNEL);
39b486d6e   David Kershner   staging: unisys: ...
555
556
557
558
  	if (!value)
  		return NULL;
  	if (value_length > 0)
  		memcpy(value, pscan, value_length);
39b486d6e   David Kershner   staging: unisys: ...
559
560
561
562
563
  	return value;
  }
  
  static void *parser_name_get(struct parser_context *ctx)
  {
ef7b9dcb1   David Kershner   staging: unisys: ...
564
  	struct visor_controlvm_parameters_header *phdr;
39b486d6e   David Kershner   staging: unisys: ...
565
566
  
  	phdr = &ctx->data;
a5eb2188f   Tim Sell   staging: unisys: ...
567
568
  	if ((unsigned long)phdr->name_offset +
  	    (unsigned long)phdr->name_length > ctx->param_bytes)
39b486d6e   David Kershner   staging: unisys: ...
569
  		return NULL;
39b486d6e   David Kershner   staging: unisys: ...
570
571
  	ctx->curr = (char *)&phdr + phdr->name_offset;
  	ctx->bytes_remaining = phdr->name_length;
90d1ecf04   David Kershner   staging: unisys: ...
572
  	return parser_string_get(ctx->curr, phdr->name_length);
39b486d6e   David Kershner   staging: unisys: ...
573
  }
e80ffd4b2   Charles Daniels   staging: unisys: ...
574
575
  static int visorbus_configure(struct controlvm_message *inmsg,
  			      struct parser_context *parser_ctx)
12e364b9f   Ken Cox   staging: visorchi...
576
  {
2ea5117b5   Benjamin Romer   staging: unisys: ...
577
  	struct controlvm_message_packet *cmd = &inmsg->cmd;
e82ba62e2   Jes Sorensen   staging: unisys: ...
578
  	u32 bus_no;
d32517e39   Don Zickus   staging: unisys: ...
579
  	struct visor_device *bus_info;
c71529fef   David Kershner   staging: unisys: ...
580
  	int err = 0;
12e364b9f   Ken Cox   staging: visorchi...
581

654bada02   Benjamin Romer   staging: unisys: ...
582
  	bus_no = cmd->configure_bus.bus_no;
d32517e39   Don Zickus   staging: unisys: ...
583
  	bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL);
654bada02   Benjamin Romer   staging: unisys: ...
584
  	if (!bus_info) {
c71529fef   David Kershner   staging: unisys: ...
585
586
  		err = -EINVAL;
  		goto err_respond;
af53ce418   David Kershner   staging: unisys: ...
587
588
  	}
  	if (bus_info->state.created == 0) {
c71529fef   David Kershner   staging: unisys: ...
589
590
  		err = -EINVAL;
  		goto err_respond;
af53ce418   David Kershner   staging: unisys: ...
591
592
  	}
  	if (bus_info->pending_msg_hdr) {
c71529fef   David Kershner   staging: unisys: ...
593
594
  		err = -EIO;
  		goto err_respond;
12e364b9f   Ken Cox   staging: visorchi...
595
  	}
34fbf6a09   David Kershner   staging: unisys: ...
596
597
  	err = visorchannel_set_clientpartition(bus_info->visorchannel,
  					       cmd->configure_bus.guest_handle);
c71529fef   David Kershner   staging: unisys: ...
598
599
  	if (err)
  		goto err_respond;
046f93dc7   David Kershner   staging: unisys: ...
600
  	if (parser_ctx) {
b32c5cb84   Andy Shevchenko   staging: unisys: ...
601
602
603
  		const guid_t *partition_guid = parser_id_get(parser_ctx);
  
  		guid_copy(&bus_info->partition_guid, partition_guid);
046f93dc7   David Kershner   staging: unisys: ...
604
605
  		bus_info->name = parser_name_get(parser_ctx);
  	}
c71529fef   David Kershner   staging: unisys: ...
606
  	if (inmsg->hdr.flags.response_expected == 1)
4fb2539c8   David Kershner   staging: unisys: ...
607
  		controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err);
c71529fef   David Kershner   staging: unisys: ...
608
609
610
  	return 0;
  
  err_respond:
71a0265d2   David Kershner   staging: unisys: ...
611
  	dev_err(&chipset_dev->acpi_device->dev,
9a8dc900e   David Kershner   staging: unisys: ...
612
613
  		"%s exited with err: %d
  ", __func__, err);
b6b057d86   David Kershner   staging: unisys: ...
614
  	if (inmsg->hdr.flags.response_expected == 1)
4fb2539c8   David Kershner   staging: unisys: ...
615
  		controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err);
c71529fef   David Kershner   staging: unisys: ...
616
  	return err;
12e364b9f   Ken Cox   staging: visorchi...
617
  }
e80ffd4b2   Charles Daniels   staging: unisys: ...
618
  static int visorbus_device_create(struct controlvm_message *inmsg)
12e364b9f   Ken Cox   staging: visorchi...
619
  {
2ea5117b5   Benjamin Romer   staging: unisys: ...
620
  	struct controlvm_message_packet *cmd = &inmsg->cmd;
ef7b9dcb1   David Kershner   staging: unisys: ...
621
  	struct controlvm_message_header *pmsg_hdr;
52063eca7   Jes Sorensen   staging: unisys: ...
622
623
  	u32 bus_no = cmd->create_device.bus_no;
  	u32 dev_no = cmd->create_device.dev_no;
ef7b9dcb1   David Kershner   staging: unisys: ...
624
  	struct visor_device *dev_info;
d32517e39   Don Zickus   staging: unisys: ...
625
  	struct visor_device *bus_info;
b32c4997c   Don Zickus   staging: unisys: ...
626
  	struct visorchannel *visorchannel;
ad2a7d65b   David Kershner   staging: unisys: ...
627
  	int err;
12e364b9f   Ken Cox   staging: visorchi...
628

a298bc0b5   Don Zickus   staging: unisys: ...
629
630
  	bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL);
  	if (!bus_info) {
a8c26e4bc   David Kershner   staging: unisys: ...
631
632
633
  		dev_err(&chipset_dev->acpi_device->dev,
  			"failed to get bus by id: %d
  ", bus_no);
ad2a7d65b   David Kershner   staging: unisys: ...
634
635
  		err = -ENODEV;
  		goto err_respond;
12e364b9f   Ken Cox   staging: visorchi...
636
  	}
a298bc0b5   Don Zickus   staging: unisys: ...
637
  	if (bus_info->state.created == 0) {
a8c26e4bc   David Kershner   staging: unisys: ...
638
639
640
  		dev_err(&chipset_dev->acpi_device->dev,
  			"bus not created, id: %d
  ", bus_no);
ad2a7d65b   David Kershner   staging: unisys: ...
641
642
  		err = -EINVAL;
  		goto err_respond;
12e364b9f   Ken Cox   staging: visorchi...
643
  	}
a298bc0b5   Don Zickus   staging: unisys: ...
644
  	dev_info = visorbus_get_device_by_id(bus_no, dev_no, NULL);
614b083d7   David Kershner   staging: unisys: ...
645
  	if (dev_info && dev_info->state.created == 1) {
a8c26e4bc   David Kershner   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   David Kershner   staging: unisys: ...
649
650
  		err = -EEXIST;
  		goto err_respond;
12e364b9f   Ken Cox   staging: visorchi...
651
  	}
a298bc0b5   Don Zickus   staging: unisys: ...
652

c60c8e269   Benjamin Romer   staging: unisys: ...
653
654
  	dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL);
  	if (!dev_info) {
ad2a7d65b   David Kershner   staging: unisys: ...
655
656
  		err = -ENOMEM;
  		goto err_respond;
12e364b9f   Ken Cox   staging: visorchi...
657
  	}
a298bc0b5   Don Zickus   staging: unisys: ...
658
659
  	dev_info->chipset_bus_no = bus_no;
  	dev_info->chipset_dev_no = dev_no;
b32c5cb84   Andy Shevchenko   staging: unisys: ...
660
  	guid_copy(&dev_info->inst, &cmd->create_device.dev_inst_guid);
a298bc0b5   Don Zickus   staging: unisys: ...
661
  	dev_info->device.parent = &bus_info->device;
90476670a   Sameer Wadgaonkar   staging: unisys: ...
662
663
664
665
  	visorchannel = visorchannel_create(cmd->create_device.channel_addr,
  					   GFP_KERNEL,
  					   &cmd->create_device.data_type_guid,
  					   true);
b32c4997c   Don Zickus   staging: unisys: ...
666
  	if (!visorchannel) {
a8c26e4bc   David Kershner   staging: unisys: ...
667
668
669
670
  		dev_err(&chipset_dev->acpi_device->dev,
  			"failed to create visorchannel: %d/%d
  ",
  			bus_no, dev_no);
ad2a7d65b   David Kershner   staging: unisys: ...
671
672
  		err = -ENOMEM;
  		goto err_free_dev_info;
b32c4997c   Don Zickus   staging: unisys: ...
673
674
  	}
  	dev_info->visorchannel = visorchannel;
fe9f4b53f   Sameer Wadgaonkar   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   David Kershner   staging: unisys: ...
679
680
  		err = save_crash_message(inmsg, CRASH_DEV);
  		if (err)
3f49a21de   David Kershner   staging: unisys: ...
681
  			goto err_destroy_visorchannel;
ad2a7d65b   David Kershner   staging: unisys: ...
682
  	}
5a80e98aa   David Kershner   staging: unisys: ...
683
684
685
  	if (inmsg->hdr.flags.response_expected == 1) {
  		pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL);
  		if (!pmsg_hdr) {
ad2a7d65b   David Kershner   staging: unisys: ...
686
  			err = -ENOMEM;
3f49a21de   David Kershner   staging: unisys: ...
687
  			goto err_destroy_visorchannel;
5a80e98aa   David Kershner   staging: unisys: ...
688
  		}
5a80e98aa   David Kershner   staging: unisys: ...
689
690
691
692
  		memcpy(pmsg_hdr, &inmsg->hdr,
  		       sizeof(struct controlvm_message_header));
  		dev_info->pending_msg_hdr = pmsg_hdr;
  	}
51c0f81cc   Sameer Wadgaonkar   staging: unisys: ...
693
694
  	/* create_visor_device will send response */
  	err = create_visor_device(dev_info);
3f49a21de   David Kershner   staging: unisys: ...
695
696
  	if (err)
  		goto err_destroy_visorchannel;
ad2a7d65b   David Kershner   staging: unisys: ...
697
  	return 0;
5a80e98aa   David Kershner   staging: unisys: ...
698

3f49a21de   David Kershner   staging: unisys: ...
699
700
  err_destroy_visorchannel:
  	visorchannel_destroy(visorchannel);
ad2a7d65b   David Kershner   staging: unisys: ...
701
  err_free_dev_info:
5a80e98aa   David Kershner   staging: unisys: ...
702
  	kfree(dev_info);
ad2a7d65b   David Kershner   staging: unisys: ...
703
  err_respond:
5a80e98aa   David Kershner   staging: unisys: ...
704
  	if (inmsg->hdr.flags.response_expected == 1)
4fb2539c8   David Kershner   staging: unisys: ...
705
  		controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err);
ad2a7d65b   David Kershner   staging: unisys: ...
706
  	return err;
12e364b9f   Ken Cox   staging: visorchi...
707
  }
e80ffd4b2   Charles Daniels   staging: unisys: ...
708
  static int visorbus_device_changestate(struct controlvm_message *inmsg)
12e364b9f   Ken Cox   staging: visorchi...
709
  {
2ea5117b5   Benjamin Romer   staging: unisys: ...
710
  	struct controlvm_message_packet *cmd = &inmsg->cmd;
ef7b9dcb1   David Kershner   staging: unisys: ...
711
  	struct controlvm_message_header *pmsg_hdr;
52063eca7   Jes Sorensen   staging: unisys: ...
712
713
  	u32 bus_no = cmd->device_change_state.bus_no;
  	u32 dev_no = cmd->device_change_state.dev_no;
545f09138   Sameer Wadgaonkar   staging: unisys: ...
714
  	struct visor_segment_state state = cmd->device_change_state.state;
a298bc0b5   Don Zickus   staging: unisys: ...
715
  	struct visor_device *dev_info;
b4a8e6ae1   David Kershner   staging: unisys: ...
716
  	int err = 0;
12e364b9f   Ken Cox   staging: visorchi...
717

a298bc0b5   Don Zickus   staging: unisys: ...
718
  	dev_info = visorbus_get_device_by_id(bus_no, dev_no, NULL);
0278a9055   Benjamin Romer   staging: unisys: ...
719
  	if (!dev_info) {
40fc79f9b   David Kershner   staging: unisys: ...
720
  		err = -ENODEV;
0825f191e   David Kershner   staging: unisys: ...
721
722
723
  		goto err_respond;
  	}
  	if (dev_info->state.created == 0) {
40fc79f9b   David Kershner   staging: unisys: ...
724
  		err = -EINVAL;
0825f191e   David Kershner   staging: unisys: ...
725
  		goto err_respond;
12e364b9f   Ken Cox   staging: visorchi...
726
  	}
8e609b5b6   David Kershner   staging: unisys: ...
727
728
  	if (dev_info->pending_msg_hdr) {
  		/* only non-NULL if dev is still waiting on a response */
40fc79f9b   David Kershner   staging: unisys: ...
729
  		err = -EIO;
8e609b5b6   David Kershner   staging: unisys: ...
730
731
  		goto err_respond;
  	}
9116ae7af   David Kershner   staging: unisys: ...
732

8e609b5b6   David Kershner   staging: unisys: ...
733
734
735
  	if (inmsg->hdr.flags.response_expected == 1) {
  		pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL);
  		if (!pmsg_hdr) {
40fc79f9b   David Kershner   staging: unisys: ...
736
  			err = -ENOMEM;
8e609b5b6   David Kershner   staging: unisys: ...
737
738
  			goto err_respond;
  		}
8e609b5b6   David Kershner   staging: unisys: ...
739
740
741
742
  		memcpy(pmsg_hdr, &inmsg->hdr,
  		       sizeof(struct controlvm_message_header));
  		dev_info->pending_msg_hdr = pmsg_hdr;
  	}
8e609b5b6   David Kershner   staging: unisys: ...
743
744
  	if (state.alive == segment_state_running.alive &&
  	    state.operating == segment_state_running.operating)
c0b44136c   Sameer Wadgaonkar   staging: unisys: ...
745
746
  		/* Response will be sent from visorchipset_device_resume */
  		err = visorchipset_device_resume(dev_info);
8e609b5b6   David Kershner   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   Sameer Wadgaonkar   staging: unisys: ...
752
  		 * Response will be sent from visorchipset_device_pause.
8e609b5b6   David Kershner   staging: unisys: ...
753
  		 */
c0b44136c   Sameer Wadgaonkar   staging: unisys: ...
754
  		err = visorchipset_device_pause(dev_info);
b4a8e6ae1   David Kershner   staging: unisys: ...
755
756
  	if (err)
  		goto err_respond;
40fc79f9b   David Kershner   staging: unisys: ...
757
  	return 0;
0825f191e   David Kershner   staging: unisys: ...
758
759
  
  err_respond:
03662df81   David Kershner   staging: unisys: ...
760
761
  	dev_err(&chipset_dev->acpi_device->dev, "failed: %d
  ", err);
8e609b5b6   David Kershner   staging: unisys: ...
762
  	if (inmsg->hdr.flags.response_expected == 1)
4fb2539c8   David Kershner   staging: unisys: ...
763
  		controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err);
40fc79f9b   David Kershner   staging: unisys: ...
764
  	return err;
12e364b9f   Ken Cox   staging: visorchi...
765
  }
e80ffd4b2   Charles Daniels   staging: unisys: ...
766
  static int visorbus_device_destroy(struct controlvm_message *inmsg)
12e364b9f   Ken Cox   staging: visorchi...
767
  {
2ea5117b5   Benjamin Romer   staging: unisys: ...
768
  	struct controlvm_message_packet *cmd = &inmsg->cmd;
ef7b9dcb1   David Kershner   staging: unisys: ...
769
  	struct controlvm_message_header *pmsg_hdr;
52063eca7   Jes Sorensen   staging: unisys: ...
770
771
  	u32 bus_no = cmd->destroy_device.bus_no;
  	u32 dev_no = cmd->destroy_device.dev_no;
a298bc0b5   Don Zickus   staging: unisys: ...
772
  	struct visor_device *dev_info;
e79549182   David Kershner   staging: unisys: ...
773
  	int err;
12e364b9f   Ken Cox   staging: visorchi...
774

a298bc0b5   Don Zickus   staging: unisys: ...
775
  	dev_info = visorbus_get_device_by_id(bus_no, dev_no, NULL);
9e9eec6b8   David Kershner   staging: unisys: ...
776
  	if (!dev_info) {
e79549182   David Kershner   staging: unisys: ...
777
  		err = -ENODEV;
9e9eec6b8   David Kershner   staging: unisys: ...
778
779
780
  		goto err_respond;
  	}
  	if (dev_info->state.created == 0) {
e79549182   David Kershner   staging: unisys: ...
781
  		err = -EINVAL;
9e9eec6b8   David Kershner   staging: unisys: ...
782
783
  		goto err_respond;
  	}
9e9eec6b8   David Kershner   staging: unisys: ...
784
785
  	if (dev_info->pending_msg_hdr) {
  		/* only non-NULL if dev is still waiting on a response */
e79549182   David Kershner   staging: unisys: ...
786
  		err = -EIO;
9e9eec6b8   David Kershner   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   David Kershner   staging: unisys: ...
792
  			err = -ENOMEM;
9e9eec6b8   David Kershner   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   Zachary Dremann   staging: unisys: ...
800
  	kfree(dev_info->name);
b74856b41   Sameer Wadgaonkar   staging: unisys: ...
801
  	remove_visor_device(dev_info);
e79549182   David Kershner   staging: unisys: ...
802
  	return 0;
9e9eec6b8   David Kershner   staging: unisys: ...
803
804
805
  
  err_respond:
  	if (inmsg->hdr.flags.response_expected == 1)
4fb2539c8   David Kershner   staging: unisys: ...
806
  		controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err);
e79549182   David Kershner   staging: unisys: ...
807
  	return err;
12e364b9f   Ken Cox   staging: visorchi...
808
  }
12e364b9f   Ken Cox   staging: visorchi...
809
  /*
5d501ef44   David Binder   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   David Binder   staging: unisys: ...
818
   * appropriate CONTROLVM message is retrieved from the list and responded to.
12e364b9f   Ken Cox   staging: visorchi...
819
820
821
   */
  
  #define PARAHOTPLUG_TIMEOUT_MS 2000
04dbfea65   David Binder   staging: unisys: ...
822
  /*
5d501ef44   David Binder   staging: unisys: ...
823
824
825
   * parahotplug_next_id() - generate unique int to match an outstanding
   *                         CONTROLVM message with a udev script /sys
   *                         response
ec17f452f   David Binder   staging: unisys: ...
826
827
   *
   * Return: a unique integer value
12e364b9f   Ken Cox   staging: visorchi...
828
   */
e80ffd4b2   Charles Daniels   staging: unisys: ...
829
  static int parahotplug_next_id(void)
12e364b9f   Ken Cox   staging: visorchi...
830
831
  {
  	static atomic_t id = ATOMIC_INIT(0);
26eb2c0c5   Benjamin Romer   staging: unisys: ...
832

12e364b9f   Ken Cox   staging: visorchi...
833
834
  	return atomic_inc_return(&id);
  }
04dbfea65   David Binder   staging: unisys: ...
835
  /*
ec17f452f   David Binder   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   Ken Cox   staging: visorchi...
841
   */
e80ffd4b2   Charles Daniels   staging: unisys: ...
842
  static unsigned long parahotplug_next_expiration(void)
12e364b9f   Ken Cox   staging: visorchi...
843
  {
2cc1a1b3e   Nicholas Mc Guire   staging: unisys: ...
844
  	return jiffies + msecs_to_jiffies(PARAHOTPLUG_TIMEOUT_MS);
12e364b9f   Ken Cox   staging: visorchi...
845
  }
04dbfea65   David Binder   staging: unisys: ...
846
  /*
ec17f452f   David Binder   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   Ken Cox   staging: visorchi...
853
   */
e80ffd4b2   Charles Daniels   staging: unisys: ...
854
855
  static struct parahotplug_request *parahotplug_request_create(
  						struct controlvm_message *msg)
12e364b9f   Ken Cox   staging: visorchi...
856
  {
ea0dcfcf6   Quentin Lambert   staging: unisys: ...
857
  	struct parahotplug_request *req;
8c8c975f3   David Kershner   staging: unisys: ...
858
  	req = kmalloc(sizeof(*req), GFP_KERNEL);
38f736e97   Benjamin Romer   staging: unisys: ...
859
  	if (!req)
12e364b9f   Ken Cox   staging: visorchi...
860
  		return NULL;
12e364b9f   Ken Cox   staging: visorchi...
861
862
863
  	req->id = parahotplug_next_id();
  	req->expiration = parahotplug_next_expiration();
  	req->msg = *msg;
12e364b9f   Ken Cox   staging: visorchi...
864
865
  	return req;
  }
04dbfea65   David Binder   staging: unisys: ...
866
  /*
ec17f452f   David Binder   staging: unisys: ...
867
868
   * parahotplug_request_destroy() - free a parahotplug_request
   * @req: the request to deallocate
12e364b9f   Ken Cox   staging: visorchi...
869
   */
e80ffd4b2   Charles Daniels   staging: unisys: ...
870
  static void parahotplug_request_destroy(struct parahotplug_request *req)
12e364b9f   Ken Cox   staging: visorchi...
871
872
873
  {
  	kfree(req);
  }
51319662d   David Kershner   staging: unisys: ...
874
  static LIST_HEAD(parahotplug_request_list);
ac0aba672   Sameer Wadgaonkar   staging: unisys: ...
875
876
  /* lock for above */
  static DEFINE_SPINLOCK(parahotplug_request_list_lock);
51319662d   David Kershner   staging: unisys: ...
877

04dbfea65   David Binder   staging: unisys: ...
878
  /*
ec17f452f   David Binder   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   David Binder   staging: unisys: ...
883
   * Called from the /sys handler, which means the user script has
ec17f452f   David Binder   staging: unisys: ...
884
   * finished the enable/disable. Find the matching identifier, and
12e364b9f   Ken Cox   staging: visorchi...
885
   * respond to the CONTROLVM message with success.
ec17f452f   David Binder   staging: unisys: ...
886
887
   *
   * Return: 0 on success or -EINVAL on failure
12e364b9f   Ken Cox   staging: visorchi...
888
   */
e80ffd4b2   Charles Daniels   staging: unisys: ...
889
  static int parahotplug_request_complete(int id, u16 active)
12e364b9f   Ken Cox   staging: visorchi...
890
  {
e82ba62e2   Jes Sorensen   staging: unisys: ...
891
892
  	struct list_head *pos;
  	struct list_head *tmp;
040b78f7a   David Kershner   staging: unisys; ...
893
  	struct parahotplug_request *req;
12e364b9f   Ken Cox   staging: visorchi...
894

ddf5de536   Benjamin Romer   staging: unisys: ...
895
  	spin_lock(&parahotplug_request_list_lock);
12e364b9f   Ken Cox   staging: visorchi...
896
  	/* Look for a request matching "id". */
ddf5de536   Benjamin Romer   staging: unisys: ...
897
  	list_for_each_safe(pos, tmp, &parahotplug_request_list) {
040b78f7a   David Kershner   staging: unisys; ...
898
  		req = list_entry(pos, struct parahotplug_request, list);
12e364b9f   Ken Cox   staging: visorchi...
899
  		if (req->id == id) {
ec17f452f   David Binder   staging: unisys: ...
900
901
  			/*
  			 * Found a match. Remove it from the list and
12e364b9f   Ken Cox   staging: visorchi...
902
903
904
  			 * respond.
  			 */
  			list_del(pos);
ddf5de536   Benjamin Romer   staging: unisys: ...
905
  			spin_unlock(&parahotplug_request_list_lock);
2ea5117b5   Benjamin Romer   staging: unisys: ...
906
  			req->msg.cmd.device_change_state.state.active = active;
98d7b5947   Benjamin Romer   staging: unisys: ...
907
  			if (req->msg.hdr.flags.response_expected)
4c0e65f83   David Kershner   staging: unisys: ...
908
909
910
  				controlvm_respond(
  				       &req->msg.hdr, CONTROLVM_RESP_SUCCESS,
  				       &req->msg.cmd.device_change_state.state);
12e364b9f   Ken Cox   staging: visorchi...
911
912
913
914
  			parahotplug_request_destroy(req);
  			return 0;
  		}
  	}
ddf5de536   Benjamin Romer   staging: unisys: ...
915
  	spin_unlock(&parahotplug_request_list_lock);
119296eaa   Erik Arfvidson   staging: unisys: ...
916
  	return -EINVAL;
12e364b9f   Ken Cox   staging: visorchi...
917
  }
04dbfea65   David Binder   staging: unisys: ...
918
  /*
ebeff0558   David Kershner   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   David Kershner   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   David Binder   staging: unisys: ...
946
  /*
ebeff0558   David Kershner   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   David Kershner   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   Mihaela Muraru   Staging: unisys: ...
980
  static const struct attribute_group visorchipset_install_group = {
ebeff0558   David Kershner   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   Arvind Yadav   staging: unisys: ...
990
  static const struct attribute_group visorchipset_parahotplug_group = {
ebeff0558   David Kershner   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   David Binder   staging: unisys: ...
1000
  /*
ebeff0558   David Kershner   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   Charles Daniels   staging: unisys: ...
1007
  static int parahotplug_request_kickoff(struct parahotplug_request *req)
ebeff0558   David Kershner   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   David Kershner   staging: unisys: ...
1011
1012
1013
  	     env_func[40];
  	char *envp[] = { env_cmd, env_id, env_state, env_bus, env_dev,
  			 env_func, NULL
ebeff0558   David Kershner   staging: unisys: ...
1014
  	};
c5a28902b   Sameer Wadgaonkar   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   David Kershner   staging: unisys: ...
1018
  		cmd->device_change_state.state.active);
c5a28902b   Sameer Wadgaonkar   staging: unisys: ...
1019
  	sprintf(env_bus, "VISOR_PARAHOTPLUG_BUS=%d",
ebeff0558   David Kershner   staging: unisys: ...
1020
  		cmd->device_change_state.bus_no);
c5a28902b   Sameer Wadgaonkar   staging: unisys: ...
1021
  	sprintf(env_dev, "VISOR_PARAHOTPLUG_DEVICE=%d",
ebeff0558   David Kershner   staging: unisys: ...
1022
  		cmd->device_change_state.dev_no >> 3);
c5a28902b   Sameer Wadgaonkar   staging: unisys: ...
1023
  	sprintf(env_func, "VISOR_PARAHOTPLUG_FUNCTION=%d",
ebeff0558   David Kershner   staging: unisys: ...
1024
  		cmd->device_change_state.dev_no & 0x7);
ae0fa822d   David Kershner   staging: unisys: ...
1025
1026
  	return kobject_uevent_env(&chipset_dev->acpi_device->dev.kobj,
  				  KOBJ_CHANGE, envp);
ebeff0558   David Kershner   staging: unisys: ...
1027
  }
04dbfea65   David Binder   staging: unisys: ...
1028
  /*
ec17f452f   David Binder   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   Ken Cox   staging: visorchi...
1032
   */
e80ffd4b2   Charles Daniels   staging: unisys: ...
1033
  static int parahotplug_process_message(struct controlvm_message *inmsg)
12e364b9f   Ken Cox   staging: visorchi...
1034
1035
  {
  	struct parahotplug_request *req;
ae0fa822d   David Kershner   staging: unisys: ...
1036
  	int err;
12e364b9f   Ken Cox   staging: visorchi...
1037
1038
  
  	req = parahotplug_request_create(inmsg);
38f736e97   Benjamin Romer   staging: unisys: ...
1039
  	if (!req)
114d5dcf2   David Kershner   staging: unisys: ...
1040
  		return -ENOMEM;
d02bde9d3   David Kershner   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   Benjamin Romer   staging: unisys: ...
1045
  	if (inmsg->cmd.device_change_state.state.active) {
ae0fa822d   David Kershner   staging: unisys: ...
1046
1047
1048
  		err = parahotplug_request_kickoff(req);
  		if (err)
  			goto err_respond;
4c0e65f83   David Kershner   staging: unisys: ...
1049
1050
  		controlvm_respond(&inmsg->hdr, CONTROLVM_RESP_SUCCESS,
  				  &inmsg->cmd.device_change_state.state);
12e364b9f   Ken Cox   staging: visorchi...
1051
  		parahotplug_request_destroy(req);
ae0fa822d   David Kershner   staging: unisys: ...
1052
  		return 0;
12e364b9f   Ken Cox   staging: visorchi...
1053
  	}
ae0fa822d   David Kershner   staging: unisys: ...
1054
  	/*
6577cbf1f   David Kershner   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   David Kershner   staging: unisys: ...
1058
1059
1060
1061
  	 */
  	spin_lock(&parahotplug_request_list_lock);
  	list_add_tail(&req->list, &parahotplug_request_list);
  	spin_unlock(&parahotplug_request_list_lock);
ae0fa822d   David Kershner   staging: unisys: ...
1062
1063
1064
  	err = parahotplug_request_kickoff(req);
  	if (err)
  		goto err_respond;
114d5dcf2   David Kershner   staging: unisys: ...
1065
  	return 0;
ae0fa822d   David Kershner   staging: unisys: ...
1066
1067
  
  err_respond:
4c0e65f83   David Kershner   staging: unisys: ...
1068
1069
  	controlvm_respond(&inmsg->hdr, err,
  			  &inmsg->cmd.device_change_state.state);
ae0fa822d   David Kershner   staging: unisys: ...
1070
  	return err;
12e364b9f   Ken Cox   staging: visorchi...
1071
  }
7289a8dd2   David Binder   staging: unisys: ...
1072
1073
  /*
   * chipset_ready_uevent() - sends chipset_ready action
ebeff0558   David Kershner   staging: unisys: ...
1074
1075
1076
   *
   * Send ACTION=online for DEVPATH=/sys/devices/platform/visorchipset.
   *
7289a8dd2   David Binder   staging: unisys: ...
1077
   * Return: 0 on success, negative on failure
ebeff0558   David Kershner   staging: unisys: ...
1078
   */
e80ffd4b2   Charles Daniels   staging: unisys: ...
1079
  static int chipset_ready_uevent(struct controlvm_message_header *msg_hdr)
ebeff0558   David Kershner   staging: unisys: ...
1080
  {
deeeca6db   David Kershner   staging: unisys: ...
1081
  	int res;
040b78f7a   David Kershner   staging: unisys; ...
1082
  	res = kobject_uevent(&chipset_dev->acpi_device->dev.kobj, KOBJ_ONLINE);
7289a8dd2   David Binder   staging: unisys: ...
1083
  	if (msg_hdr->flags.response_expected)
4c0e65f83   David Kershner   staging: unisys: ...
1084
  		controlvm_respond(msg_hdr, res, NULL);
deeeca6db   David Kershner   staging: unisys: ...
1085
  	return res;
ebeff0558   David Kershner   staging: unisys: ...
1086
  }
7289a8dd2   David Binder   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   Charles Daniels   staging: unisys: ...
1094
  static int chipset_selftest_uevent(struct controlvm_message_header *msg_hdr)
ebeff0558   David Kershner   staging: unisys: ...
1095
1096
1097
  {
  	char env_selftest[20];
  	char *envp[] = { env_selftest, NULL };
deeeca6db   David Kershner   staging: unisys: ...
1098
  	int res;
ebeff0558   David Kershner   staging: unisys: ...
1099
1100
  
  	sprintf(env_selftest, "SPARSP_SELFTEST=%d", 1);
deeeca6db   David Kershner   staging: unisys: ...
1101
1102
  	res = kobject_uevent_env(&chipset_dev->acpi_device->dev.kobj,
  				 KOBJ_CHANGE, envp);
7289a8dd2   David Binder   staging: unisys: ...
1103
  	if (msg_hdr->flags.response_expected)
4c0e65f83   David Kershner   staging: unisys: ...
1104
  		controlvm_respond(msg_hdr, res, NULL);
deeeca6db   David Kershner   staging: unisys: ...
1105
  	return res;
ebeff0558   David Kershner   staging: unisys: ...
1106
  }
7289a8dd2   David Binder   staging: unisys: ...
1107
1108
  /*
   * chipset_notready_uevent() - sends chipset_notready action
ebeff0558   David Kershner   staging: unisys: ...
1109
1110
1111
   *
   * Send ACTION=offline for DEVPATH=/sys/devices/platform/visorchipset.
   *
7289a8dd2   David Binder   staging: unisys: ...
1112
   * Return: 0 on success, negative on failure
ebeff0558   David Kershner   staging: unisys: ...
1113
   */
e80ffd4b2   Charles Daniels   staging: unisys: ...
1114
  static int chipset_notready_uevent(struct controlvm_message_header *msg_hdr)
ebeff0558   David Kershner   staging: unisys: ...
1115
  {
904ee62ac   David Binder   staging: unisys: ...
1116
  	int res = kobject_uevent(&chipset_dev->acpi_device->dev.kobj,
34fbf6a09   David Kershner   staging: unisys: ...
1117
  				 KOBJ_OFFLINE);
904ee62ac   David Binder   staging: unisys: ...
1118

ebeff0558   David Kershner   staging: unisys: ...
1119
  	if (msg_hdr->flags.response_expected)
4c0e65f83   David Kershner   staging: unisys: ...
1120
  		controlvm_respond(msg_hdr, res, NULL);
deeeca6db   David Kershner   staging: unisys: ...
1121
  	return res;
ebeff0558   David Kershner   staging: unisys: ...
1122
  }
88845f407   David Kershner   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   David Kershner   staging: unisys: ...
1132
1133
1134
  	cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx);
  	if (!(cpuid_ecx & 0x80000000))
  		return -EPERM;
88845f407   David Kershner   staging: unisys: ...
1135
  	__asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) :
34fbf6a09   David Kershner   staging: unisys: ...
1136
  			     "a"(tuple), "b"(reg_ebx), "c"(reg_ecx));
bd801a072   David Kershner   staging: unisys: ...
1137
1138
  	if (result)
  		goto error;
bd801a072   David Kershner   staging: unisys: ...
1139
  	return 0;
9116ae7af   David Kershner   staging: unisys: ...
1140

ac0aba672   Sameer Wadgaonkar   staging: unisys: ...
1141
1142
  /* Need to convert from VMCALL error codes to Linux */
  error:
bd801a072   David Kershner   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   David Kershner   staging: unisys: ...
1151
  }
ab61097c7   Zohaib Javed   staging: unisys: ...
1152

f1f537c2e   David Kershner   staging: unisys: ...
1153
  static int controlvm_channel_create(struct visorchipset_device *dev)
5f3a7e364   David Kershner   staging: unisys: ...
1154
  {
f1f537c2e   David Kershner   staging: unisys: ...
1155
1156
  	struct visorchannel *chan;
  	u64 addr;
800da5fb3   David Kershner   staging: unisys: ...
1157
  	int err;
f1f537c2e   David Kershner   staging: unisys: ...
1158
1159
  	err = unisys_vmcall(VMCALL_CONTROLVM_ADDR,
  			    virt_to_phys(&dev->controlvm_params));
800da5fb3   David Kershner   staging: unisys: ...
1160
1161
  	if (err)
  		return err;
f1f537c2e   David Kershner   staging: unisys: ...
1162
  	addr = dev->controlvm_params.address;
90476670a   Sameer Wadgaonkar   staging: unisys: ...
1163
1164
  	chan = visorchannel_create(addr, GFP_KERNEL,
  				   &visor_controlvm_channel_guid, true);
f1f537c2e   David Kershner   staging: unisys: ...
1165
1166
1167
  	if (!chan)
  		return -ENOMEM;
  	dev->controlvm_channel = chan;
bd801a072   David Kershner   staging: unisys: ...
1168
  	return 0;
5f3a7e364   David Kershner   staging: unisys: ...
1169
  }
e80ffd4b2   Charles Daniels   staging: unisys: ...
1170
  static void setup_crash_devices_work_queue(struct work_struct *work)
12e364b9f   Ken Cox   staging: visorchi...
1171
  {
e6bdb904c   Benjamin Romer   staging: unisys: ...
1172
1173
  	struct controlvm_message local_crash_bus_msg;
  	struct controlvm_message local_crash_dev_msg;
caf82f727   Arnd Bergmann   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   Benjamin Romer   staging: unisys: ...
1181
1182
  	u32 local_crash_msg_offset;
  	u16 local_crash_msg_count;
12e364b9f   Ken Cox   staging: visorchi...
1183

12e364b9f   Ken Cox   staging: visorchi...
1184
  	/* send init chipset msg */
12e364b9f   Ken Cox   staging: visorchi...
1185
  	chipset_init(&msg);
12e364b9f   Ken Cox   staging: visorchi...
1186
  	/* get saved message count */
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1187
  	if (visorchannel_read(chipset_dev->controlvm_channel,
545f09138   Sameer Wadgaonkar   staging: unisys: ...
1188
  			      offsetof(struct visor_controlvm_channel,
d19642f65   Benjamin Romer   staging: unisys: ...
1189
  				       saved_crash_message_count),
e6bdb904c   Benjamin Romer   staging: unisys: ...
1190
  			      &local_crash_msg_count, sizeof(u16)) < 0) {
0f7453af9   David Kershner   staging: unisys: ...
1191
1192
1193
  		dev_err(&chipset_dev->acpi_device->dev,
  			"failed to read channel
  ");
12e364b9f   Ken Cox   staging: visorchi...
1194
1195
  		return;
  	}
e6bdb904c   Benjamin Romer   staging: unisys: ...
1196
  	if (local_crash_msg_count != CONTROLVM_CRASHMSG_MAX) {
040b78f7a   David Kershner   staging: unisys; ...
1197
1198
  		dev_err(&chipset_dev->acpi_device->dev, "invalid count
  ");
12e364b9f   Ken Cox   staging: visorchi...
1199
1200
  		return;
  	}
12e364b9f   Ken Cox   staging: visorchi...
1201
  	/* get saved crash message offset */
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1202
  	if (visorchannel_read(chipset_dev->controlvm_channel,
545f09138   Sameer Wadgaonkar   staging: unisys: ...
1203
  			      offsetof(struct visor_controlvm_channel,
d19642f65   Benjamin Romer   staging: unisys: ...
1204
  				       saved_crash_message_offset),
e6bdb904c   Benjamin Romer   staging: unisys: ...
1205
  			      &local_crash_msg_offset, sizeof(u32)) < 0) {
0f7453af9   David Kershner   staging: unisys: ...
1206
1207
1208
  		dev_err(&chipset_dev->acpi_device->dev,
  			"failed to read channel
  ");
12e364b9f   Ken Cox   staging: visorchi...
1209
1210
  		return;
  	}
12e364b9f   Ken Cox   staging: visorchi...
1211
  	/* read create device message for storage bus offset */
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1212
  	if (visorchannel_read(chipset_dev->controlvm_channel,
e6bdb904c   Benjamin Romer   staging: unisys: ...
1213
1214
  			      local_crash_msg_offset,
  			      &local_crash_bus_msg,
3ab477012   Benjamin Romer   staging: unisys: ...
1215
  			      sizeof(struct controlvm_message)) < 0) {
0f7453af9   David Kershner   staging: unisys: ...
1216
1217
1218
  		dev_err(&chipset_dev->acpi_device->dev,
  			"failed to read channel
  ");
12e364b9f   Ken Cox   staging: visorchi...
1219
1220
  		return;
  	}
12e364b9f   Ken Cox   staging: visorchi...
1221
  	/* read create device message for storage device */
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1222
  	if (visorchannel_read(chipset_dev->controlvm_channel,
e6bdb904c   Benjamin Romer   staging: unisys: ...
1223
  			      local_crash_msg_offset +
3ab477012   Benjamin Romer   staging: unisys: ...
1224
  			      sizeof(struct controlvm_message),
e6bdb904c   Benjamin Romer   staging: unisys: ...
1225
  			      &local_crash_dev_msg,
3ab477012   Benjamin Romer   staging: unisys: ...
1226
  			      sizeof(struct controlvm_message)) < 0) {
0f7453af9   David Kershner   staging: unisys: ...
1227
1228
1229
  		dev_err(&chipset_dev->acpi_device->dev,
  			"failed to read channel
  ");
12e364b9f   Ken Cox   staging: visorchi...
1230
1231
  		return;
  	}
12e364b9f   Ken Cox   staging: visorchi...
1232
  	/* reuse IOVM create bus message */
d9b89ef18   David Kershner   staging: unisys: ...
1233
  	if (!local_crash_bus_msg.cmd.create_bus.channel_addr) {
0f7453af9   David Kershner   staging: unisys: ...
1234
1235
1236
  		dev_err(&chipset_dev->acpi_device->dev,
  			"no valid create_bus message
  ");
12e364b9f   Ken Cox   staging: visorchi...
1237
1238
  		return;
  	}
ec17cb8a6   Sameer Wadgaonkar   staging: unisys: ...
1239
  	visorbus_create(&local_crash_bus_msg);
12e364b9f   Ken Cox   staging: visorchi...
1240
  	/* reuse create device message for storage device */
d9b89ef18   David Kershner   staging: unisys: ...
1241
  	if (!local_crash_dev_msg.cmd.create_device.channel_addr) {
0f7453af9   David Kershner   staging: unisys: ...
1242
1243
1244
  		dev_err(&chipset_dev->acpi_device->dev,
  			"no valid create_device message
  ");
12e364b9f   Ken Cox   staging: visorchi...
1245
1246
  		return;
  	}
8b0a6cfa7   Sameer Wadgaonkar   staging: unisys: ...
1247
  	visorbus_device_create(&local_crash_dev_msg);
12e364b9f   Ken Cox   staging: visorchi...
1248
  }
76956aa7b   Sameer Wadgaonkar   staging: unisys: ...
1249
1250
  void visorbus_response(struct visor_device *bus_info, int response,
  		       int controlvm_id)
12e364b9f   Ken Cox   staging: visorchi...
1251
  {
fd9e450cf   David Kershner   staging: unisys: ...
1252
1253
  	if (!bus_info->pending_msg_hdr)
  		return;
0274b5aec   Don Zickus   staging: unisys: ...
1254

fd9e450cf   David Kershner   staging: unisys: ...
1255
  	controlvm_responder(controlvm_id, bus_info->pending_msg_hdr, response);
0274b5aec   Don Zickus   staging: unisys: ...
1256
1257
  	kfree(bus_info->pending_msg_hdr);
  	bus_info->pending_msg_hdr = NULL;
12e364b9f   Ken Cox   staging: visorchi...
1258
  }
722e73d55   Sameer Wadgaonkar   staging: unisys: ...
1259
1260
1261
  void visorbus_device_changestate_response(struct visor_device *dev_info,
  					  int response,
  					  struct visor_segment_state state)
12e364b9f   Ken Cox   staging: visorchi...
1262
  {
fd9e450cf   David Kershner   staging: unisys: ...
1263
1264
  	if (!dev_info->pending_msg_hdr)
  		return;
040b78f7a   David Kershner   staging: unisys; ...
1265
1266
  	device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE, dev_info,
  				     response, state);
0274b5aec   Don Zickus   staging: unisys: ...
1267
1268
  	kfree(dev_info->pending_msg_hdr);
  	dev_info->pending_msg_hdr = NULL;
12e364b9f   Ken Cox   staging: visorchi...
1269
  }
39b486d6e   David Kershner   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   David Kershner   staging: unisys: ...
1275
1276
  static struct parser_context *parser_init_stream(u64 addr, u32 bytes,
  						 bool *retry)
612b81c93   David Kershner   staging: unisys: ...
1277
  {
a5eb2188f   Tim Sell   staging: unisys: ...
1278
  	unsigned long allocbytes;
612b81c93   David Kershner   staging: unisys: ...
1279
  	struct parser_context *ctx;
a35e3268d   Erik Arfvidson   staging: unisys: ...
1280
  	void *mapping;
612b81c93   David Kershner   staging: unisys: ...
1281

3e4273db1   David Binder   staging: unisys: ...
1282
  	*retry = false;
26a42c251   David Kershner   staging: unisys: ...
1283
  	/* alloc an extra byte to ensure payload is \0 terminated */
a5eb2188f   Tim Sell   staging: unisys: ...
1284
  	allocbytes = (unsigned long)bytes + 1 + (sizeof(struct parser_context) -
26a42c251   David Kershner   staging: unisys: ...
1285
  		     sizeof(struct visor_controlvm_parameters_header));
040b78f7a   David Kershner   staging: unisys; ...
1286
1287
  	if ((chipset_dev->controlvm_payload_bytes_buffered + bytes) >
  	     MAX_CONTROLVM_PAYLOAD_BYTES) {
3e4273db1   David Binder   staging: unisys: ...
1288
  		*retry = true;
612b81c93   David Kershner   staging: unisys: ...
1289
1290
  		return NULL;
  	}
8c8c975f3   David Kershner   staging: unisys: ...
1291
  	ctx = kzalloc(allocbytes, GFP_KERNEL);
612b81c93   David Kershner   staging: unisys: ...
1292
  	if (!ctx) {
3e4273db1   David Binder   staging: unisys: ...
1293
  		*retry = true;
612b81c93   David Kershner   staging: unisys: ...
1294
1295
  		return NULL;
  	}
612b81c93   David Kershner   staging: unisys: ...
1296
1297
  	ctx->allocbytes = allocbytes;
  	ctx->param_bytes = bytes;
a35e3268d   Erik Arfvidson   staging: unisys: ...
1298
1299
1300
  	mapping = memremap(addr, bytes, MEMREMAP_WB);
  	if (!mapping)
  		goto err_finish_ctx;
26a42c251   David Kershner   staging: unisys: ...
1301
  	memcpy(&ctx->data, mapping, bytes);
a35e3268d   Erik Arfvidson   staging: unisys: ...
1302
  	memunmap(mapping);
612b81c93   David Kershner   staging: unisys: ...
1303
  	ctx->byte_stream = true;
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1304
  	chipset_dev->controlvm_payload_bytes_buffered += ctx->param_bytes;
612b81c93   David Kershner   staging: unisys: ...
1305
1306
1307
  	return ctx;
  
  err_finish_ctx:
90544cb10   Sameer Wadgaonkar   staging: unisys: ...
1308
  	kfree(ctx);
612b81c93   David Kershner   staging: unisys: ...
1309
1310
  	return NULL;
  }
04dbfea65   David Binder   staging: unisys: ...
1311
  /*
511474a50   David Kershner   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   David Kershner   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   David Kershner   staging: unisys: ...
1323
   */
e80ffd4b2   Charles Daniels   staging: unisys: ...
1324
  static int handle_command(struct controlvm_message inmsg, u64 channel_addr)
511474a50   David Kershner   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   David Kershner   staging: unisys: ...
1330
  	struct controlvm_message ackmsg;
25a5128e8   David Kershner   staging: unisys: ...
1331
  	int err = 0;
511474a50   David Kershner   staging: unisys: ...
1332
1333
  
  	/* create parsing context if necessary */
511474a50   David Kershner   staging: unisys: ...
1334
1335
  	parm_addr = channel_addr + inmsg.hdr.payload_vm_offset;
  	parm_bytes = inmsg.hdr.payload_bytes;
511474a50   David Kershner   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   David Kershner   staging: unisys: ...
1341
  	if (parm_bytes) {
ef7b9dcb1   David Kershner   staging: unisys: ...
1342
  		bool retry;
511474a50   David Kershner   staging: unisys: ...
1343

45311439d   David Kershner   staging: unisys: ...
1344
  		parser_ctx = parser_init_stream(parm_addr, parm_bytes, &retry);
511474a50   David Kershner   staging: unisys: ...
1345
  		if (!parser_ctx && retry)
25a5128e8   David Kershner   staging: unisys: ...
1346
  			return -EAGAIN;
511474a50   David Kershner   staging: unisys: ...
1347
  	}
a35e3268d   Erik Arfvidson   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   David Kershner   staging: unisys: ...
1353
1354
  	switch (inmsg.hdr.id) {
  	case CONTROLVM_CHIPSET_INIT:
25a5128e8   David Kershner   staging: unisys: ...
1355
  		err = chipset_init(&inmsg);
511474a50   David Kershner   staging: unisys: ...
1356
1357
  		break;
  	case CONTROLVM_BUS_CREATE:
ec17cb8a6   Sameer Wadgaonkar   staging: unisys: ...
1358
  		err = visorbus_create(&inmsg);
511474a50   David Kershner   staging: unisys: ...
1359
1360
  		break;
  	case CONTROLVM_BUS_DESTROY:
ec17cb8a6   Sameer Wadgaonkar   staging: unisys: ...
1361
  		err = visorbus_destroy(&inmsg);
511474a50   David Kershner   staging: unisys: ...
1362
1363
  		break;
  	case CONTROLVM_BUS_CONFIGURE:
ec17cb8a6   Sameer Wadgaonkar   staging: unisys: ...
1364
  		err = visorbus_configure(&inmsg, parser_ctx);
511474a50   David Kershner   staging: unisys: ...
1365
1366
  		break;
  	case CONTROLVM_DEVICE_CREATE:
8b0a6cfa7   Sameer Wadgaonkar   staging: unisys: ...
1367
  		err = visorbus_device_create(&inmsg);
511474a50   David Kershner   staging: unisys: ...
1368
1369
1370
  		break;
  	case CONTROLVM_DEVICE_CHANGESTATE:
  		if (cmd->device_change_state.flags.phys_device) {
25a5128e8   David Kershner   staging: unisys: ...
1371
  			err = parahotplug_process_message(&inmsg);
511474a50   David Kershner   staging: unisys: ...
1372
1373
  		} else {
  			/*
6577cbf1f   David Kershner   staging: unisys: ...
1374
1375
  			 * save the hdr and cmd structures for later use when
  			 * sending back the response to Command
511474a50   David Kershner   staging: unisys: ...
1376
  			 */
8b0a6cfa7   Sameer Wadgaonkar   staging: unisys: ...
1377
  			err = visorbus_device_changestate(&inmsg);
511474a50   David Kershner   staging: unisys: ...
1378
1379
1380
1381
  			break;
  		}
  		break;
  	case CONTROLVM_DEVICE_DESTROY:
8b0a6cfa7   Sameer Wadgaonkar   staging: unisys: ...
1382
  		err = visorbus_device_destroy(&inmsg);
511474a50   David Kershner   staging: unisys: ...
1383
1384
  		break;
  	case CONTROLVM_DEVICE_CONFIGURE:
25a5128e8   David Kershner   staging: unisys: ...
1385
  		/* no op just send a respond that we passed */
511474a50   David Kershner   staging: unisys: ...
1386
  		if (inmsg.hdr.flags.response_expected)
4c0e65f83   David Kershner   staging: unisys: ...
1387
1388
  			controlvm_respond(&inmsg.hdr, CONTROLVM_RESP_SUCCESS,
  					  NULL);
511474a50   David Kershner   staging: unisys: ...
1389
1390
  		break;
  	case CONTROLVM_CHIPSET_READY:
25a5128e8   David Kershner   staging: unisys: ...
1391
  		err = chipset_ready_uevent(&inmsg.hdr);
511474a50   David Kershner   staging: unisys: ...
1392
1393
  		break;
  	case CONTROLVM_CHIPSET_SELFTEST:
25a5128e8   David Kershner   staging: unisys: ...
1394
  		err = chipset_selftest_uevent(&inmsg.hdr);
511474a50   David Kershner   staging: unisys: ...
1395
1396
  		break;
  	case CONTROLVM_CHIPSET_STOP:
25a5128e8   David Kershner   staging: unisys: ...
1397
  		err = chipset_notready_uevent(&inmsg.hdr);
511474a50   David Kershner   staging: unisys: ...
1398
1399
  		break;
  	default:
25a5128e8   David Kershner   staging: unisys: ...
1400
  		err = -ENOMSG;
511474a50   David Kershner   staging: unisys: ...
1401
  		if (inmsg.hdr.flags.response_expected)
25a5128e8   David Kershner   staging: unisys: ...
1402
  			controlvm_respond(&inmsg.hdr,
4c0e65f83   David Kershner   staging: unisys: ...
1403
  					  -CONTROLVM_RESP_ID_UNKNOWN, NULL);
511474a50   David Kershner   staging: unisys: ...
1404
1405
  		break;
  	}
511474a50   David Kershner   staging: unisys: ...
1406
1407
1408
1409
  	if (parser_ctx) {
  		parser_done(parser_ctx);
  		parser_ctx = NULL;
  	}
25a5128e8   David Kershner   staging: unisys: ...
1410
  	return err;
511474a50   David Kershner   staging: unisys: ...
1411
  }
04dbfea65   David Binder   staging: unisys: ...
1412
  /*
8a2853279   David Kershner   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   David Kershner   staging: unisys: ...
1418
   * Return: 0 if valid message was retrieved or -error
8a2853279   David Kershner   staging: unisys: ...
1419
   */
e80ffd4b2   Charles Daniels   staging: unisys: ...
1420
  static int read_controlvm_event(struct controlvm_message *msg)
8a2853279   David Kershner   staging: unisys: ...
1421
  {
904ee62ac   David Binder   staging: unisys: ...
1422
  	int err = visorchannel_signalremove(chipset_dev->controlvm_channel,
da56cb048   David Kershner   staging: unisys: ...
1423
  					    CONTROLVM_QUEUE_EVENT, msg);
9116ae7af   David Kershner   staging: unisys: ...
1424

25a5128e8   David Kershner   staging: unisys: ...
1425
1426
  	if (err)
  		return err;
25a5128e8   David Kershner   staging: unisys: ...
1427
1428
1429
  	/* got a message */
  	if (msg->hdr.flags.test_message == 1)
  		return -EINVAL;
25a5128e8   David Kershner   staging: unisys: ...
1430
  	return 0;
8a2853279   David Kershner   staging: unisys: ...
1431
  }
04dbfea65   David Binder   staging: unisys: ...
1432
  /*
a9c739374   David Kershner   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   Charles Daniels   staging: unisys: ...
1436
  static void parahotplug_process_list(void)
a9c739374   David Kershner   staging: unisys: ...
1437
1438
1439
1440
1441
  {
  	struct list_head *pos;
  	struct list_head *tmp;
  
  	spin_lock(&parahotplug_request_list_lock);
a9c739374   David Kershner   staging: unisys: ...
1442
1443
1444
1445
1446
1447
  	list_for_each_safe(pos, tmp, &parahotplug_request_list) {
  		struct parahotplug_request *req =
  		    list_entry(pos, struct parahotplug_request, list);
  
  		if (!time_after_eq(jiffies, req->expiration))
  			continue;
a9c739374   David Kershner   staging: unisys: ...
1448
1449
  		list_del(pos);
  		if (req->msg.hdr.flags.response_expected)
4c0e65f83   David Kershner   staging: unisys: ...
1450
  			controlvm_respond(
a9c739374   David Kershner   staging: unisys: ...
1451
  				&req->msg.hdr,
98f9ed9ec   Sameer Wadgaonkar   staging: unisys: ...
1452
  				CONTROLVM_RESP_DEVICE_UDEV_TIMEOUT,
4c0e65f83   David Kershner   staging: unisys: ...
1453
  				&req->msg.cmd.device_change_state.state);
a9c739374   David Kershner   staging: unisys: ...
1454
1455
  		parahotplug_request_destroy(req);
  	}
a9c739374   David Kershner   staging: unisys: ...
1456
1457
  	spin_unlock(&parahotplug_request_list_lock);
  }
e80ffd4b2   Charles Daniels   staging: unisys: ...
1458
  static void controlvm_periodic_work(struct work_struct *work)
3d8394c86   David Kershner   staging: unisys: ...
1459
1460
  {
  	struct controlvm_message inmsg;
04dbc09b2   David Kershner   staging: unisys: ...
1461
  	int count = 0;
fbc1023af   David Kershner   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   David Kershner   staging: unisys: ...
1469
  	} while ((!err) && (++count < CONTROLVM_MESSAGE_MAX));
fbc1023af   David Kershner   staging: unisys: ...
1470
1471
  	if (err != -EAGAIN)
  		goto schedule_out;
fbc1023af   David Kershner   staging: unisys: ...
1472
1473
  	if (chipset_dev->controlvm_pending_msg_valid) {
  		/*
6577cbf1f   David Kershner   staging: unisys: ...
1474
1475
  		 * we throttled processing of a prior msg, so try to process
  		 * it again rather than reading a new one
fbc1023af   David Kershner   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   David Kershner   staging: unisys: ...
1482
  	}
fbc1023af   David Kershner   staging: unisys: ...
1483
  	while (!err) {
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1484
  		chipset_dev->most_recent_message_jiffies = jiffies;
fbc1023af   David Kershner   staging: unisys: ...
1485
1486
1487
1488
  		err = handle_command(inmsg,
  				     visorchannel_get_physaddr
  				     (chipset_dev->controlvm_channel));
  		if (err == -EAGAIN) {
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1489
1490
  			chipset_dev->controlvm_pending_msg = inmsg;
  			chipset_dev->controlvm_pending_msg_valid = true;
fbc1023af   David Kershner   staging: unisys: ...
1491
  			break;
3d8394c86   David Kershner   staging: unisys: ...
1492
  		}
fbc1023af   David Kershner   staging: unisys: ...
1493
1494
  
  		err = read_controlvm_event(&inmsg);
3d8394c86   David Kershner   staging: unisys: ...
1495
  	}
3d8394c86   David Kershner   staging: unisys: ...
1496
1497
  	/* parahotplug_worker */
  	parahotplug_process_list();
d36c4857c   Sameer Wadgaonkar   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   David Kershner   staging: unisys: ...
1503
  schedule_out:
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1504
1505
  	if (time_after(jiffies, chipset_dev->most_recent_message_jiffies +
  				(HZ * MIN_IDLE_SECONDS))) {
3d8394c86   David Kershner   staging: unisys: ...
1506
  		/*
6577cbf1f   David Kershner   staging: unisys: ...
1507
1508
  		 * it's been longer than MIN_IDLE_SECONDS since we processed
  		 * our last controlvm message; slow down the polling
3d8394c86   David Kershner   staging: unisys: ...
1509
  		 */
3fbee1971   David Kershner   staging: unisys: ...
1510
1511
  		if (chipset_dev->poll_jiffies != POLLJIFFIES_CONTROLVM_SLOW)
  			chipset_dev->poll_jiffies = POLLJIFFIES_CONTROLVM_SLOW;
3d8394c86   David Kershner   staging: unisys: ...
1512
  	} else {
3fbee1971   David Kershner   staging: unisys: ...
1513
1514
  		if (chipset_dev->poll_jiffies != POLLJIFFIES_CONTROLVM_FAST)
  			chipset_dev->poll_jiffies = POLLJIFFIES_CONTROLVM_FAST;
3d8394c86   David Kershner   staging: unisys: ...
1515
  	}
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1516
1517
  	schedule_delayed_work(&chipset_dev->periodic_controlvm_work,
  			      chipset_dev->poll_jiffies);
3d8394c86   David Kershner   staging: unisys: ...
1518
  }
e80ffd4b2   Charles Daniels   staging: unisys: ...
1519
  static int visorchipset_init(struct acpi_device *acpi_device)
12e364b9f   Ken Cox   staging: visorchi...
1520
  {
1366a3db3   David Kershner   staging: unisys: ...
1521
  	int err = -ENODEV;
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1522
  	struct visorchannel *controlvm_channel;
d3368a587   Jes Sorensen   staging: unisys: ...
1523

765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1524
1525
  	chipset_dev = kzalloc(sizeof(*chipset_dev), GFP_KERNEL);
  	if (!chipset_dev)
1366a3db3   David Kershner   staging: unisys: ...
1526
  		goto error;
f1f537c2e   David Kershner   staging: unisys: ...
1527
1528
1529
  	err = controlvm_channel_create(chipset_dev);
  	if (err)
  		goto error_free_chipset_dev;
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1530
  	acpi_device->driver_data = chipset_dev;
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1531
  	chipset_dev->acpi_device = acpi_device;
3fbee1971   David Kershner   staging: unisys: ...
1532
  	chipset_dev->poll_jiffies = POLLJIFFIES_CONTROLVM_FAST;
15c012d54   Sameer Wadgaonkar   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   David Kershner   staging: unisys: ...
1537
  	controlvm_channel = chipset_dev->controlvm_channel;
403043c4e   Sameer Wadgaonkar   staging: unisys: ...
1538
  	if (!visor_check_channel(visorchannel_get_header(controlvm_channel),
e25201d66   Sameer Wadgaonkar   staging: unisys: ...
1539
  				 &chipset_dev->acpi_device->dev,
b32c5cb84   Andy Shevchenko   staging: unisys: ...
1540
  				 &visor_controlvm_channel_guid,
403043c4e   Sameer Wadgaonkar   staging: unisys: ...
1541
1542
1543
1544
  				 "controlvm",
  				 sizeof(struct visor_controlvm_channel),
  				 VISOR_CONTROLVM_CHANNEL_VERSIONID,
  				 VISOR_CHANNEL_SIGNATURE))
15c012d54   Sameer Wadgaonkar   staging: unisys: ...
1545
  		goto error_delete_groups;
4da3336c2   David Kershner   staging: unisys: ...
1546
1547
  	/* if booting in a crash kernel */
  	if (is_kdump_kernel())
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1548
  		INIT_DELAYED_WORK(&chipset_dev->periodic_controlvm_work,
4da3336c2   David Kershner   staging: unisys: ...
1549
1550
  				  setup_crash_devices_work_queue);
  	else
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1551
  		INIT_DELAYED_WORK(&chipset_dev->periodic_controlvm_work,
4da3336c2   David Kershner   staging: unisys: ...
1552
  				  controlvm_periodic_work);
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1553
  	chipset_dev->most_recent_message_jiffies = jiffies;
3fbee1971   David Kershner   staging: unisys: ...
1554
  	chipset_dev->poll_jiffies = POLLJIFFIES_CONTROLVM_FAST;
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1555
1556
  	schedule_delayed_work(&chipset_dev->periodic_controlvm_work,
  			      chipset_dev->poll_jiffies);
1366a3db3   David Kershner   staging: unisys: ...
1557
1558
  	err = visorbus_init();
  	if (err < 0)
15c012d54   Sameer Wadgaonkar   staging: unisys: ...
1559
  		goto error_cancel_work;
1366a3db3   David Kershner   staging: unisys: ...
1560
  	return 0;
1366a3db3   David Kershner   staging: unisys: ...
1561
  error_cancel_work:
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1562
  	cancel_delayed_work_sync(&chipset_dev->periodic_controlvm_work);
1366a3db3   David Kershner   staging: unisys: ...
1563

15c012d54   Sameer Wadgaonkar   staging: unisys: ...
1564
1565
1566
  error_delete_groups:
  	sysfs_remove_groups(&chipset_dev->acpi_device->dev.kobj,
  			    visorchipset_dev_groups);
1366a3db3   David Kershner   staging: unisys: ...
1567
  error_destroy_channel:
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1568
1569
1570
1571
  	visorchannel_destroy(chipset_dev->controlvm_channel);
  
  error_free_chipset_dev:
  	kfree(chipset_dev);
1366a3db3   David Kershner   staging: unisys: ...
1572
1573
  
  error:
372b9f227   David Kershner   staging: unisys: ...
1574
1575
  	dev_err(&acpi_device->dev, "failed with error %d
  ", err);
1366a3db3   David Kershner   staging: unisys: ...
1576
  	return err;
e3420ed66   Erik Arfvidson   staging: unisys: ...
1577
  }
e80ffd4b2   Charles Daniels   staging: unisys: ...
1578
  static int visorchipset_exit(struct acpi_device *acpi_device)
12e364b9f   Ken Cox   staging: visorchi...
1579
  {
c79b28f73   Prarit Bhargava   staging: unisys: ...
1580
  	visorbus_exit();
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1581
  	cancel_delayed_work_sync(&chipset_dev->periodic_controlvm_work);
15c012d54   Sameer Wadgaonkar   staging: unisys: ...
1582
1583
  	sysfs_remove_groups(&chipset_dev->acpi_device->dev.kobj,
  			    visorchipset_dev_groups);
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1584
  	visorchannel_destroy(chipset_dev->controlvm_channel);
765b2f828   Sameer Wadgaonkar   staging: unisys: ...
1585
  	kfree(chipset_dev);
55c67dcaa   Prarit Bhargava   staging: unisys: ...
1586
1587
1588
1589
1590
1591
1592
  	return 0;
  }
  
  static const struct acpi_device_id unisys_device_ids[] = {
  	{"PNP0A07", 0},
  	{"", 0},
  };
55c67dcaa   Prarit Bhargava   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   David Kershner   staging: unisys: ...
1602
  	},
55c67dcaa   Prarit Bhargava   staging: unisys: ...
1603
  };
1fc07f991   David Kershner   staging: unisys: ...
1604
1605
  
  MODULE_DEVICE_TABLE(acpi, unisys_device_ids);
c1d28da7a   David Kershner   staging; unisys: ...
1606
  static __init int visorutil_spar_detect(void)
d5b3f1dcc   Erik Arfvidson   staging: unisys: ...
1607
1608
  {
  	unsigned int eax, ebx, ecx, edx;
0c9f3536c   Borislav Petkov   x86/cpufeature: R...
1609
  	if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) {
d5b3f1dcc   Erik Arfvidson   staging: unisys: ...
1610
  		/* check the ID */
a27ded927   Sameer Wadgaonkar   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   Erik Arfvidson   staging: unisys: ...
1615
  	}
e4a064300   David Kershner   staging: unisys: ...
1616
  	return 0;
d5b3f1dcc   Erik Arfvidson   staging: unisys: ...
1617
  }
55c67dcaa   Prarit Bhargava   staging: unisys: ...
1618

056e4fc20   Arnd Bergmann   staging: unisys/v...
1619
  static int __init init_unisys(void)
55c67dcaa   Prarit Bhargava   staging: unisys: ...
1620
1621
  {
  	int result;
35e606de5   Alessandro Parini   staging: unisys: ...
1622

d5b3f1dcc   Erik Arfvidson   staging: unisys: ...
1623
  	if (!visorutil_spar_detect())
55c67dcaa   Prarit Bhargava   staging: unisys: ...
1624
  		return -ENODEV;
55c67dcaa   Prarit Bhargava   staging: unisys: ...
1625
1626
1627
  	result = acpi_bus_register_driver(&unisys_acpi_driver);
  	if (result)
  		return -ENODEV;
55c67dcaa   Prarit Bhargava   staging: unisys: ...
1628
1629
1630
1631
  	pr_info("Unisys Visorchipset Driver Loaded.
  ");
  	return 0;
  };
056e4fc20   Arnd Bergmann   staging: unisys/v...
1632
  static void __exit exit_unisys(void)
55c67dcaa   Prarit Bhargava   staging: unisys: ...
1633
1634
  {
  	acpi_bus_unregister_driver(&unisys_acpi_driver);
12e364b9f   Ken Cox   staging: visorchi...
1635
  }
55c67dcaa   Prarit Bhargava   staging: unisys: ...
1636
1637
  module_init(init_unisys);
  module_exit(exit_unisys);
12e364b9f   Ken Cox   staging: visorchi...
1638
1639
1640
  
  MODULE_AUTHOR("Unisys");
  MODULE_LICENSE("GPL");
bff8c1a16   Jon Frisch   staging: unisys: ...
1641
  MODULE_DESCRIPTION("s-Par visorbus driver for virtual device buses");