blob: b6b332c27150a56e266fc8e6750f1a4d257ed67e [file] [log] [blame]
Ken Cox12e364b2014-03-04 07:58:07 -06001/* visorchipset_main.c
2 *
Benjamin Romerf6d0c1e2014-04-23 14:58:34 -04003 * Copyright (C) 2010 - 2013 UNISYS CORPORATION
Ken Cox12e364b2014-03-04 07:58:07 -06004 * All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
14 * NON INFRINGEMENT. See the GNU General Public License for more
15 * details.
16 */
17
Prarit Bhargava55c67dc2015-05-05 18:37:02 -040018#include <linux/acpi.h>
Erik Arfvidsonc0a14642015-05-05 18:37:06 -040019#include <linux/cdev.h>
Erik Arfvidson46168812015-05-05 18:36:14 -040020#include <linux/ctype.h>
Erik Arfvidsone3420ed2015-05-05 18:36:13 -040021#include <linux/fs.h>
22#include <linux/mm.h>
Ken Cox12e364b2014-03-04 07:58:07 -060023#include <linux/nls.h>
24#include <linux/netdevice.h>
25#include <linux/platform_device.h>
Benjamin Romer90addb02014-05-06 09:58:23 -040026#include <linux/uuid.h>
Benjamin Romer1ba00982015-04-06 10:27:40 -040027#include <linux/crash_dump.h>
Ken Cox12e364b2014-03-04 07:58:07 -060028
Prarit Bhargava55c67dc2015-05-05 18:37:02 -040029#include "controlvmchannel.h"
30#include "controlvmcompletionstatus.h"
31#include "guestlinuxdebug.h"
32#include "periodic_work.h"
Prarit Bhargava55c67dc2015-05-05 18:37:02 -040033#include "uisutils.h"
34#include "version.h"
35#include "visorbus.h"
36#include "visorbus_private.h"
37
Ken Cox12e364b2014-03-04 07:58:07 -060038#define CURRENT_FILE_PC VISOR_CHIPSET_PC_visorchipset_main_c
Ken Cox12e364b2014-03-04 07:58:07 -060039
40#define MAX_NAME_SIZE 128
41#define MAX_IP_SIZE 50
42#define MAXOUTSTANDINGCHANNELCOMMAND 256
43#define POLLJIFFIES_CONTROLVMCHANNEL_FAST 1
44#define POLLJIFFIES_CONTROLVMCHANNEL_SLOW 100
45
Erik Arfvidson46168812015-05-05 18:36:14 -040046#define MAX_CONTROLVM_PAYLOAD_BYTES (1024*128)
Prarit Bhargava2ee0dee2015-05-05 18:36:16 -040047
48#define VISORCHIPSET_MMAP_CONTROLCHANOFFSET 0x00000000
49
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -040050
51#define UNISYS_SPAR_LEAF_ID 0x40000000
52
53/* The s-Par leaf ID returns "UnisysSpar64" encoded across ebx, ecx, edx */
54#define UNISYS_SPAR_ID_EBX 0x73696e55
55#define UNISYS_SPAR_ID_ECX 0x70537379
56#define UNISYS_SPAR_ID_EDX 0x34367261
57
Jes Sorensenb615d622015-05-05 18:35:38 -040058/*
59 * Module parameters
60 */
Jes Sorensenb615d622015-05-05 18:35:38 -040061static int visorchipset_major;
David Kershner4da33362015-05-05 18:36:39 -040062static int visorchipset_visorbusregwait = 1; /* default is on */
Jes Sorensenb615d622015-05-05 18:35:38 -040063static int visorchipset_holdchipsetready;
Erik Arfvidson46168812015-05-05 18:36:14 -040064static unsigned long controlvm_payload_bytes_buffered;
Jes Sorensenb615d622015-05-05 18:35:38 -040065
Erik Arfvidsone3420ed2015-05-05 18:36:13 -040066static int
67visorchipset_open(struct inode *inode, struct file *file)
68{
69 unsigned minor_number = iminor(inode);
70
71 if (minor_number)
72 return -ENODEV;
73 file->private_data = NULL;
74 return 0;
75}
76
77static int
78visorchipset_release(struct inode *inode, struct file *file)
79{
80 return 0;
81}
82
Ken Cox12e364b2014-03-04 07:58:07 -060083/* When the controlvm channel is idle for at least MIN_IDLE_SECONDS,
84* we switch to slow polling mode. As soon as we get a controlvm
85* message, we switch back to fast polling mode.
86*/
87#define MIN_IDLE_SECONDS 10
Jes Sorensen52063ec2015-04-13 10:28:41 -040088static unsigned long poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
89static unsigned long most_recent_message_jiffies; /* when we got our last
Ken Coxbd5b9b32014-03-13 15:39:22 -050090 * controlvm message */
David Kershner4da33362015-05-05 18:36:39 -040091static int visorbusregistered;
Ken Cox12e364b2014-03-04 07:58:07 -060092
93#define MAX_CHIPSET_EVENTS 2
Benjamin Romerc2422332014-07-29 15:09:40 -040094static u8 chipset_events[MAX_CHIPSET_EVENTS] = { 0, 0 };
Ken Cox12e364b2014-03-04 07:58:07 -060095
Erik Arfvidson46168812015-05-05 18:36:14 -040096struct parser_context {
97 unsigned long allocbytes;
98 unsigned long param_bytes;
99 u8 *curr;
100 unsigned long bytes_remaining;
101 bool byte_stream;
102 char data[0];
103};
104
Benjamin Romer9232d2d2015-03-16 13:57:57 -0400105static struct delayed_work periodic_controlvm_work;
106static struct workqueue_struct *periodic_controlvm_workqueue;
Benjamin Romer8f1947a2015-03-16 13:57:59 -0400107static DEFINE_SEMAPHORE(notifier_lock);
Ken Cox12e364b2014-03-04 07:58:07 -0600108
Erik Arfvidsone3420ed2015-05-05 18:36:13 -0400109static struct cdev file_cdev;
110static struct visorchannel **file_controlvm_channel;
Benjamin Romerda021f02015-03-16 13:57:58 -0400111static struct controlvm_message_header g_chipset_msg_hdr;
Benjamin Romer59827f02015-03-16 13:58:00 -0400112static const uuid_le spar_diag_pool_channel_protocol_uuid =
Benjamin Romer9eee5d12014-10-23 14:29:47 -0400113 SPAR_DIAG_POOL_CHANNEL_PROTOCOL_UUID;
Ken Cox12e364b2014-03-04 07:58:07 -0600114/* 0xffffff is an invalid Bus/Device number */
Jes Sorensen52063ec2015-04-13 10:28:41 -0400115static u32 g_diagpool_bus_no = 0xffffff;
116static u32 g_diagpool_dev_no = 0xffffff;
Benjamin Romer4f44b722015-03-16 13:58:02 -0400117static struct controlvm_message_packet g_devicechangestate_packet;
Ken Cox12e364b2014-03-04 07:58:07 -0600118
Ken Cox12e364b2014-03-04 07:58:07 -0600119#define is_diagpool_channel(channel_type_guid) \
Benjamin Romer59827f02015-03-16 13:58:00 -0400120 (uuid_le_cmp(channel_type_guid,\
121 spar_diag_pool_channel_protocol_uuid) == 0)
Ken Cox12e364b2014-03-04 07:58:07 -0600122
Benjamin Romer1390b882015-03-16 13:58:03 -0400123static LIST_HEAD(bus_info_list);
124static LIST_HEAD(dev_info_list);
Ken Cox12e364b2014-03-04 07:58:07 -0600125
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400126static struct visorchannel *controlvm_channel;
Ken Cox12e364b2014-03-04 07:58:07 -0600127
Benjamin Romer84982fb2015-03-16 13:58:07 -0400128/* Manages the request payload in the controlvm channel */
Jes Sorensenc1f834e2015-04-13 10:28:39 -0400129struct visor_controlvm_payload_info {
Benjamin Romerc2422332014-07-29 15:09:40 -0400130 u8 __iomem *ptr; /* pointer to base address of payload pool */
Benjamin Romer5fc02292014-07-31 12:00:51 -0400131 u64 offset; /* offset from beginning of controlvm
Ken Cox12e364b2014-03-04 07:58:07 -0600132 * channel to beginning of payload * pool */
Benjamin Romerb3c55b12014-07-31 12:00:50 -0400133 u32 bytes; /* number of bytes in payload pool */
Jes Sorensenc1f834e2015-04-13 10:28:39 -0400134};
135
136static struct visor_controlvm_payload_info controlvm_payload_info;
Ken Cox12e364b2014-03-04 07:58:07 -0600137
Benjamin Romerea33b4ee52015-03-16 13:58:08 -0400138/* Manages the info for a CONTROLVM_DUMP_CAPTURESTATE /
139 * CONTROLVM_DUMP_GETTEXTDUMP / CONTROLVM_DUMP_COMPLETE conversation.
140 */
Jes Sorensenc1f834e2015-04-13 10:28:39 -0400141struct visor_livedump_info {
Benjamin Romerea33b4ee52015-03-16 13:58:08 -0400142 struct controlvm_message_header dumpcapture_header;
143 struct controlvm_message_header gettextdump_header;
144 struct controlvm_message_header dumpcomplete_header;
Jes Sorensenf4c11552015-04-13 10:28:40 -0400145 bool gettextdump_outstanding;
Ken Cox12e364b2014-03-04 07:58:07 -0600146 u32 crc32;
Jes Sorensen52063ec2015-04-13 10:28:41 -0400147 unsigned long length;
Ken Cox12e364b2014-03-04 07:58:07 -0600148 atomic_t buffers_in_use;
Jes Sorensen52063ec2015-04-13 10:28:41 -0400149 unsigned long destination;
Jes Sorensenc1f834e2015-04-13 10:28:39 -0400150};
151
152static struct visor_livedump_info livedump_info;
Ken Cox12e364b2014-03-04 07:58:07 -0600153
154/* The following globals are used to handle the scenario where we are unable to
155 * offload the payload from a controlvm message due to memory requirements. In
156 * this scenario, we simply stash the controlvm message, then attempt to
157 * process it again the next time controlvm_periodic_work() runs.
158 */
Benjamin Romer7166ed12015-03-16 13:58:38 -0400159static struct controlvm_message controlvm_pending_msg;
Prarit Bhargavac79b28f2015-05-05 18:36:15 -0400160static bool controlvm_pending_msg_valid;
Ken Cox12e364b2014-03-04 07:58:07 -0600161
Ken Cox12e364b2014-03-04 07:58:07 -0600162/* This identifies a data buffer that has been received via a controlvm messages
163 * in a remote --> local CONTROLVM_TRANSMIT_FILE conversation.
164 */
165struct putfile_buffer_entry {
166 struct list_head next; /* putfile_buffer_entry list */
Benjamin Romer317d9612015-03-16 13:57:51 -0400167 struct parser_context *parser_ctx; /* points to input data buffer */
Ken Cox12e364b2014-03-04 07:58:07 -0600168};
169
170/* List of struct putfile_request *, via next_putfile_request member.
171 * Each entry in this list identifies an outstanding TRANSMIT_FILE
172 * conversation.
173 */
Benjamin Romer1eee0012015-03-16 13:58:39 -0400174static LIST_HEAD(putfile_request_list);
Ken Cox12e364b2014-03-04 07:58:07 -0600175
176/* This describes a buffer and its current state of transfer (e.g., how many
177 * bytes have already been supplied as putfile data, and how many bytes are
178 * remaining) for a putfile_request.
179 */
180struct putfile_active_buffer {
181 /* a payload from a controlvm message, containing a file data buffer */
Benjamin Romer317d9612015-03-16 13:57:51 -0400182 struct parser_context *parser_ctx;
Ken Cox12e364b2014-03-04 07:58:07 -0600183 /* points within data area of parser_ctx to next byte of data */
184 u8 *pnext;
185 /* # bytes left from <pnext> to the end of this data buffer */
186 size_t bytes_remaining;
187};
188
189#define PUTFILE_REQUEST_SIG 0x0906101302281211
190/* This identifies a single remote --> local CONTROLVM_TRANSMIT_FILE
191 * conversation. Structs of this type are dynamically linked into
192 * <Putfile_request_list>.
193 */
194struct putfile_request {
195 u64 sig; /* PUTFILE_REQUEST_SIG */
196
197 /* header from original TransmitFile request */
Benjamin Romer98d7b592014-10-23 14:30:26 -0400198 struct controlvm_message_header controlvm_header;
Ken Cox12e364b2014-03-04 07:58:07 -0600199 u64 file_request_number; /* from original TransmitFile request */
200
201 /* link to next struct putfile_request */
202 struct list_head next_putfile_request;
203
204 /* most-recent sequence number supplied via a controlvm message */
205 u64 data_sequence_number;
206
207 /* head of putfile_buffer_entry list, which describes the data to be
208 * supplied as putfile data;
209 * - this list is added to when controlvm messages come in that supply
210 * file data
211 * - this list is removed from via the hotplug program that is actually
212 * consuming these buffers to write as file data */
213 struct list_head input_buffer_list;
214 spinlock_t req_list_lock; /* lock for input_buffer_list */
215
216 /* waiters for input_buffer_list to go non-empty */
217 wait_queue_head_t input_buffer_wq;
218
219 /* data not yet read within current putfile_buffer_entry */
220 struct putfile_active_buffer active_buf;
221
222 /* <0 = failed, 0 = in-progress, >0 = successful; */
223 /* note that this must be set with req_list_lock, and if you set <0, */
224 /* it is your responsibility to also free up all of the other objects */
225 /* in this struct (like input_buffer_list, active_buf.parser_ctx) */
226 /* before releasing the lock */
227 int completion_status;
228};
229
Ken Cox12e364b2014-03-04 07:58:07 -0600230struct parahotplug_request {
231 struct list_head list;
232 int id;
233 unsigned long expiration;
Benjamin Romer3ab47702014-10-23 14:30:31 -0400234 struct controlvm_message msg;
Ken Cox12e364b2014-03-04 07:58:07 -0600235};
236
Benjamin Romerddf5de52015-03-16 13:58:41 -0400237static LIST_HEAD(parahotplug_request_list);
238static DEFINE_SPINLOCK(parahotplug_request_list_lock); /* lock for above */
Ken Cox12e364b2014-03-04 07:58:07 -0600239static void parahotplug_process_list(void);
240
241/* Manages the info for a CONTROLVM_DUMP_CAPTURESTATE /
242 * CONTROLVM_REPORTEVENT.
243 */
David Kershner4da33362015-05-05 18:36:39 -0400244static struct visorchipset_busdev_notifiers busdev_notifiers;
Ken Cox12e364b2014-03-04 07:58:07 -0600245
Jes Sorensen52063ec2015-04-13 10:28:41 -0400246static void bus_create_response(u32 bus_no, int response);
247static void bus_destroy_response(u32 bus_no, int response);
248static void device_create_response(u32 bus_no, u32 dev_no, int response);
249static void device_destroy_response(u32 bus_no, u32 dev_no, int response);
250static void device_resume_response(u32 bus_no, u32 dev_no, int response);
Ken Cox12e364b2014-03-04 07:58:07 -0600251
Prarit Bhargava2ee0dee2015-05-05 18:36:16 -0400252static void visorchipset_device_pause_response(u32 bus_no, u32 dev_no,
253 int response);
254
Benjamin Romer8e3fedd2015-03-16 13:58:43 -0400255static struct visorchipset_busdev_responders busdev_responders = {
Ken Cox12e364b2014-03-04 07:58:07 -0600256 .bus_create = bus_create_response,
257 .bus_destroy = bus_destroy_response,
258 .device_create = device_create_response,
259 .device_destroy = device_destroy_response,
Ken Cox927c7922014-03-05 14:52:25 -0600260 .device_pause = visorchipset_device_pause_response,
Ken Cox12e364b2014-03-04 07:58:07 -0600261 .device_resume = device_resume_response,
262};
263
264/* info for /dev/visorchipset */
Benjamin Romer5aa8ae52015-03-16 13:58:44 -0400265static dev_t major_dev = -1; /**< indicates major num for device */
Ken Cox12e364b2014-03-04 07:58:07 -0600266
Benjamin Romer19f66342014-07-22 09:56:25 -0400267/* prototypes for attributes */
268static ssize_t toolaction_show(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400269 struct device_attribute *attr, char *buf);
Benjamin Romer19f66342014-07-22 09:56:25 -0400270static ssize_t toolaction_store(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400271 struct device_attribute *attr,
272 const char *buf, size_t count);
Benjamin Romer19f66342014-07-22 09:56:25 -0400273static DEVICE_ATTR_RW(toolaction);
274
Benjamin Romer54b31222014-07-22 09:56:26 -0400275static ssize_t boottotool_show(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400276 struct device_attribute *attr, char *buf);
Benjamin Romer54b31222014-07-22 09:56:26 -0400277static ssize_t boottotool_store(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400278 struct device_attribute *attr, const char *buf,
279 size_t count);
Benjamin Romer54b31222014-07-22 09:56:26 -0400280static DEVICE_ATTR_RW(boottotool);
281
Benjamin Romer422af172014-07-24 14:08:42 -0400282static ssize_t error_show(struct device *dev, struct device_attribute *attr,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400283 char *buf);
Benjamin Romer422af172014-07-24 14:08:42 -0400284static ssize_t error_store(struct device *dev, struct device_attribute *attr,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400285 const char *buf, size_t count);
Benjamin Romer422af172014-07-24 14:08:42 -0400286static DEVICE_ATTR_RW(error);
287
288static ssize_t textid_show(struct device *dev, struct device_attribute *attr,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400289 char *buf);
Benjamin Romer422af172014-07-24 14:08:42 -0400290static ssize_t textid_store(struct device *dev, struct device_attribute *attr,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400291 const char *buf, size_t count);
Benjamin Romer422af172014-07-24 14:08:42 -0400292static DEVICE_ATTR_RW(textid);
293
294static ssize_t remaining_steps_show(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400295 struct device_attribute *attr, char *buf);
Benjamin Romer422af172014-07-24 14:08:42 -0400296static ssize_t remaining_steps_store(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400297 struct device_attribute *attr,
298 const char *buf, size_t count);
Benjamin Romer422af172014-07-24 14:08:42 -0400299static DEVICE_ATTR_RW(remaining_steps);
300
Benjamin Romer18b87ed2014-07-24 14:08:43 -0400301static ssize_t chipsetready_store(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400302 struct device_attribute *attr,
303 const char *buf, size_t count);
Benjamin Romer18b87ed2014-07-24 14:08:43 -0400304static DEVICE_ATTR_WO(chipsetready);
305
Benjamin Romere56fa7c2014-07-29 11:11:21 -0400306static ssize_t devicedisabled_store(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400307 struct device_attribute *attr,
308 const char *buf, size_t count);
Benjamin Romere56fa7c2014-07-29 11:11:21 -0400309static DEVICE_ATTR_WO(devicedisabled);
310
311static ssize_t deviceenabled_store(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400312 struct device_attribute *attr,
313 const char *buf, size_t count);
Benjamin Romere56fa7c2014-07-29 11:11:21 -0400314static DEVICE_ATTR_WO(deviceenabled);
315
Benjamin Romer19f66342014-07-22 09:56:25 -0400316static struct attribute *visorchipset_install_attrs[] = {
317 &dev_attr_toolaction.attr,
Benjamin Romer54b31222014-07-22 09:56:26 -0400318 &dev_attr_boottotool.attr,
Benjamin Romer422af172014-07-24 14:08:42 -0400319 &dev_attr_error.attr,
320 &dev_attr_textid.attr,
321 &dev_attr_remaining_steps.attr,
Benjamin Romer19f66342014-07-22 09:56:25 -0400322 NULL
323};
324
325static struct attribute_group visorchipset_install_group = {
326 .name = "install",
327 .attrs = visorchipset_install_attrs
328};
329
Benjamin Romer18b87ed2014-07-24 14:08:43 -0400330static struct attribute *visorchipset_guest_attrs[] = {
331 &dev_attr_chipsetready.attr,
332 NULL
333};
334
335static struct attribute_group visorchipset_guest_group = {
336 .name = "guest",
337 .attrs = visorchipset_guest_attrs
338};
339
Benjamin Romere56fa7c2014-07-29 11:11:21 -0400340static struct attribute *visorchipset_parahotplug_attrs[] = {
341 &dev_attr_devicedisabled.attr,
342 &dev_attr_deviceenabled.attr,
343 NULL
344};
345
346static struct attribute_group visorchipset_parahotplug_group = {
347 .name = "parahotplug",
348 .attrs = visorchipset_parahotplug_attrs
349};
350
Benjamin Romer19f66342014-07-22 09:56:25 -0400351static const struct attribute_group *visorchipset_dev_groups[] = {
352 &visorchipset_install_group,
Benjamin Romer18b87ed2014-07-24 14:08:43 -0400353 &visorchipset_guest_group,
Benjamin Romere56fa7c2014-07-29 11:11:21 -0400354 &visorchipset_parahotplug_group,
Benjamin Romer19f66342014-07-22 09:56:25 -0400355 NULL
356};
357
Ken Cox12e364b2014-03-04 07:58:07 -0600358/* /sys/devices/platform/visorchipset */
Benjamin Romereb34e872015-03-16 13:58:45 -0400359static struct platform_device visorchipset_platform_device = {
Ken Cox12e364b2014-03-04 07:58:07 -0600360 .name = "visorchipset",
361 .id = -1,
Benjamin Romer19f66342014-07-22 09:56:25 -0400362 .dev.groups = visorchipset_dev_groups,
Ken Cox12e364b2014-03-04 07:58:07 -0600363};
364
365/* Function prototypes */
Benjamin Romerb3168c72015-03-16 13:58:46 -0400366static void controlvm_respond(struct controlvm_message_header *msg_hdr,
Benjamin Romer98d7b592014-10-23 14:30:26 -0400367 int response);
368static void controlvm_respond_chipset_init(
Benjamin Romerb3168c72015-03-16 13:58:46 -0400369 struct controlvm_message_header *msg_hdr, int response,
Benjamin Romer98d7b592014-10-23 14:30:26 -0400370 enum ultra_chipset_feature features);
371static void controlvm_respond_physdev_changestate(
Benjamin Romerb3168c72015-03-16 13:58:46 -0400372 struct controlvm_message_header *msg_hdr, int response,
Benjamin Romer98d7b592014-10-23 14:30:26 -0400373 struct spar_segment_state state);
Ken Cox12e364b2014-03-04 07:58:07 -0600374
Erik Arfvidson46168812015-05-05 18:36:14 -0400375
Prarit Bhargava2ee0dee2015-05-05 18:36:16 -0400376static void parser_done(struct parser_context *ctx);
377
Erik Arfvidson46168812015-05-05 18:36:14 -0400378static struct parser_context *
379parser_init_guts(u64 addr, u32 bytes, bool local,
380 bool standard_payload_header, bool *retry)
381{
382 int allocbytes = sizeof(struct parser_context) + bytes;
383 struct parser_context *rc = NULL;
384 struct parser_context *ctx = NULL;
Erik Arfvidson46168812015-05-05 18:36:14 -0400385 struct spar_controlvm_parameters_header *phdr = NULL;
386
387 if (retry)
388 *retry = false;
389 if (!standard_payload_header)
390 /* alloc and 0 extra byte to ensure payload is
391 * '\0'-terminated
392 */
393 allocbytes++;
394 if ((controlvm_payload_bytes_buffered + bytes)
395 > MAX_CONTROLVM_PAYLOAD_BYTES) {
396 if (retry)
397 *retry = true;
398 rc = NULL;
399 goto cleanup;
400 }
401 ctx = kzalloc(allocbytes, GFP_KERNEL|__GFP_NORETRY);
402 if (!ctx) {
403 if (retry)
404 *retry = true;
405 rc = NULL;
406 goto cleanup;
407 }
408
409 ctx->allocbytes = allocbytes;
410 ctx->param_bytes = bytes;
411 ctx->curr = NULL;
412 ctx->bytes_remaining = 0;
413 ctx->byte_stream = false;
414 if (local) {
415 void *p;
416
417 if (addr > virt_to_phys(high_memory - 1)) {
418 rc = NULL;
419 goto cleanup;
420 }
421 p = __va((unsigned long) (addr));
422 memcpy(ctx->data, p, bytes);
423 } else {
Jes Sorensendd412752015-05-05 18:36:26 -0400424 void __iomem *mapping;
Jes Sorensen712c03d2015-05-05 18:36:25 -0400425
Jes Sorensendd412752015-05-05 18:36:26 -0400426 if (!request_mem_region(addr, bytes, "visorchipset")) {
Erik Arfvidson46168812015-05-05 18:36:14 -0400427 rc = NULL;
428 goto cleanup;
429 }
Jes Sorensendd412752015-05-05 18:36:26 -0400430
431 mapping = ioremap_cache(addr, bytes);
432 if (!mapping) {
433 release_mem_region(addr, bytes);
434 rc = NULL;
435 goto cleanup;
436 }
437 memcpy_fromio(ctx->data, mapping, bytes);
438 release_mem_region(addr, bytes);
Erik Arfvidson46168812015-05-05 18:36:14 -0400439 }
440 if (!standard_payload_header) {
441 ctx->byte_stream = true;
442 rc = ctx;
443 goto cleanup;
444 }
445 phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
446 if (phdr->total_length != bytes) {
447 rc = NULL;
448 goto cleanup;
449 }
450 if (phdr->total_length < phdr->header_length) {
451 rc = NULL;
452 goto cleanup;
453 }
454 if (phdr->header_length <
455 sizeof(struct spar_controlvm_parameters_header)) {
456 rc = NULL;
457 goto cleanup;
458 }
459
460 rc = ctx;
461cleanup:
Erik Arfvidson46168812015-05-05 18:36:14 -0400462 if (rc) {
463 controlvm_payload_bytes_buffered += ctx->param_bytes;
464 } else {
465 if (ctx) {
466 parser_done(ctx);
467 ctx = NULL;
468 }
469 }
470 return rc;
471}
472
Erik Arfvidson46168812015-05-05 18:36:14 -0400473/* Call this instead of parser_init() if the payload area consists of just
474 * a sequence of bytes, rather than a struct spar_controlvm_parameters_header
475 * structures. Afterwards, you can call parser_simpleString_get() or
476 * parser_byteStream_get() to obtain the data.
477 */
Jes Sorensenfcc974d2015-05-05 18:37:11 -0400478static struct parser_context *
Erik Arfvidson46168812015-05-05 18:36:14 -0400479parser_init_byte_stream(u64 addr, u32 bytes, bool local, bool *retry)
480{
481 return parser_init_guts(addr, bytes, local, false, retry);
482}
483
Jes Sorensen464129e2015-05-05 18:37:12 -0400484static uuid_le
Erik Arfvidson46168812015-05-05 18:36:14 -0400485parser_id_get(struct parser_context *ctx)
486{
487 struct spar_controlvm_parameters_header *phdr = NULL;
488
489 if (ctx == NULL)
490 return NULL_UUID_LE;
491 phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
492 return phdr->id;
493}
494
Prarit Bhargava2ee0dee2015-05-05 18:36:16 -0400495/** Describes the state from the perspective of which controlvm messages have
496 * been received for a bus or device.
497 */
498
499enum PARSER_WHICH_STRING {
500 PARSERSTRING_INITIATOR,
501 PARSERSTRING_TARGET,
502 PARSERSTRING_CONNECTION,
503 PARSERSTRING_NAME, /* TODO: only PARSERSTRING_NAME is used ? */
504};
505
Jes Sorensen464129e2015-05-05 18:37:12 -0400506static void
Prarit Bhargava2ee0dee2015-05-05 18:36:16 -0400507parser_param_start(struct parser_context *ctx,
508 enum PARSER_WHICH_STRING which_string)
Erik Arfvidson46168812015-05-05 18:36:14 -0400509{
510 struct spar_controlvm_parameters_header *phdr = NULL;
511
512 if (ctx == NULL)
513 goto Away;
514 phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
515 switch (which_string) {
516 case PARSERSTRING_INITIATOR:
517 ctx->curr = ctx->data + phdr->initiator_offset;
518 ctx->bytes_remaining = phdr->initiator_length;
519 break;
520 case PARSERSTRING_TARGET:
521 ctx->curr = ctx->data + phdr->target_offset;
522 ctx->bytes_remaining = phdr->target_length;
523 break;
524 case PARSERSTRING_CONNECTION:
525 ctx->curr = ctx->data + phdr->connection_offset;
526 ctx->bytes_remaining = phdr->connection_length;
527 break;
528 case PARSERSTRING_NAME:
529 ctx->curr = ctx->data + phdr->name_offset;
530 ctx->bytes_remaining = phdr->name_length;
531 break;
532 default:
533 break;
534 }
535
536Away:
537 return;
538}
539
Jes Sorensen464129e2015-05-05 18:37:12 -0400540static void parser_done(struct parser_context *ctx)
Erik Arfvidson46168812015-05-05 18:36:14 -0400541{
542 if (!ctx)
543 return;
544 controlvm_payload_bytes_buffered -= ctx->param_bytes;
545 kfree(ctx);
546}
547
Jes Sorensen464129e2015-05-05 18:37:12 -0400548static void *
Erik Arfvidson46168812015-05-05 18:36:14 -0400549parser_string_get(struct parser_context *ctx)
550{
551 u8 *pscan;
552 unsigned long nscan;
553 int value_length = -1;
554 void *value = NULL;
555 int i;
556
557 if (!ctx)
558 return NULL;
559 pscan = ctx->curr;
560 nscan = ctx->bytes_remaining;
561 if (nscan == 0)
562 return NULL;
563 if (!pscan)
564 return NULL;
565 for (i = 0, value_length = -1; i < nscan; i++)
566 if (pscan[i] == '\0') {
567 value_length = i;
568 break;
569 }
570 if (value_length < 0) /* '\0' was not included in the length */
571 value_length = nscan;
572 value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY);
573 if (value == NULL)
574 return NULL;
575 if (value_length > 0)
576 memcpy(value, pscan, value_length);
577 ((u8 *) (value))[value_length] = '\0';
578 return value;
579}
580
581
Vincent Bernatd746cb52014-08-01 10:29:30 +0200582static ssize_t toolaction_show(struct device *dev,
583 struct device_attribute *attr,
584 char *buf)
Benjamin Romer19f66342014-07-22 09:56:25 -0400585{
Benjamin Romer01f4d852015-03-16 13:58:48 -0400586 u8 tool_action;
Benjamin Romer19f66342014-07-22 09:56:25 -0400587
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400588 visorchannel_read(controlvm_channel,
Benjamin Romerd19642f2014-10-23 14:30:34 -0400589 offsetof(struct spar_controlvm_channel_protocol,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400590 tool_action), &tool_action, sizeof(u8));
Benjamin Romer01f4d852015-03-16 13:58:48 -0400591 return scnprintf(buf, PAGE_SIZE, "%u\n", tool_action);
Benjamin Romer19f66342014-07-22 09:56:25 -0400592}
593
Vincent Bernatd746cb52014-08-01 10:29:30 +0200594static ssize_t toolaction_store(struct device *dev,
595 struct device_attribute *attr,
596 const char *buf, size_t count)
Benjamin Romer19f66342014-07-22 09:56:25 -0400597{
Benjamin Romer01f4d852015-03-16 13:58:48 -0400598 u8 tool_action;
Benjamin Romer66e24b72014-07-25 13:55:10 -0400599 int ret;
Benjamin Romer19f66342014-07-22 09:56:25 -0400600
Jes Sorensenebec8962015-05-05 18:35:57 -0400601 if (kstrtou8(buf, 10, &tool_action))
Benjamin Romer66e24b72014-07-25 13:55:10 -0400602 return -EINVAL;
603
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400604 ret = visorchannel_write(controlvm_channel,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400605 offsetof(struct spar_controlvm_channel_protocol,
606 tool_action),
Benjamin Romer01f4d852015-03-16 13:58:48 -0400607 &tool_action, sizeof(u8));
Benjamin Romer66e24b72014-07-25 13:55:10 -0400608
609 if (ret)
610 return ret;
Benjamin Romere22a4a02014-08-18 09:34:54 -0400611 return count;
Benjamin Romer19f66342014-07-22 09:56:25 -0400612}
613
Vincent Bernatd746cb52014-08-01 10:29:30 +0200614static ssize_t boottotool_show(struct device *dev,
615 struct device_attribute *attr,
616 char *buf)
Benjamin Romer54b31222014-07-22 09:56:26 -0400617{
Benjamin Romer365522d2015-03-16 13:58:49 -0400618 struct efi_spar_indication efi_spar_indication;
Benjamin Romer54b31222014-07-22 09:56:26 -0400619
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400620 visorchannel_read(controlvm_channel,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400621 offsetof(struct spar_controlvm_channel_protocol,
622 efi_spar_ind), &efi_spar_indication,
623 sizeof(struct efi_spar_indication));
Benjamin Romer54b31222014-07-22 09:56:26 -0400624 return scnprintf(buf, PAGE_SIZE, "%u\n",
Benjamin Romer8e76e692015-03-16 13:58:52 -0400625 efi_spar_indication.boot_to_tool);
Benjamin Romer54b31222014-07-22 09:56:26 -0400626}
627
Vincent Bernatd746cb52014-08-01 10:29:30 +0200628static ssize_t boottotool_store(struct device *dev,
629 struct device_attribute *attr,
630 const char *buf, size_t count)
Benjamin Romer54b31222014-07-22 09:56:26 -0400631{
Benjamin Romer66e24b72014-07-25 13:55:10 -0400632 int val, ret;
Benjamin Romer365522d2015-03-16 13:58:49 -0400633 struct efi_spar_indication efi_spar_indication;
Benjamin Romer54b31222014-07-22 09:56:26 -0400634
Jes Sorensenebec8962015-05-05 18:35:57 -0400635 if (kstrtoint(buf, 10, &val))
Benjamin Romer66e24b72014-07-25 13:55:10 -0400636 return -EINVAL;
637
Benjamin Romer365522d2015-03-16 13:58:49 -0400638 efi_spar_indication.boot_to_tool = val;
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400639 ret = visorchannel_write(controlvm_channel,
Benjamin Romerd19642f2014-10-23 14:30:34 -0400640 offsetof(struct spar_controlvm_channel_protocol,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400641 efi_spar_ind), &(efi_spar_indication),
642 sizeof(struct efi_spar_indication));
Benjamin Romer66e24b72014-07-25 13:55:10 -0400643
644 if (ret)
645 return ret;
Benjamin Romere22a4a02014-08-18 09:34:54 -0400646 return count;
Benjamin Romer54b31222014-07-22 09:56:26 -0400647}
Benjamin Romer422af172014-07-24 14:08:42 -0400648
649static ssize_t error_show(struct device *dev, struct device_attribute *attr,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400650 char *buf)
Benjamin Romer422af172014-07-24 14:08:42 -0400651{
652 u32 error;
653
Benjamin Romer8e76e692015-03-16 13:58:52 -0400654 visorchannel_read(controlvm_channel,
655 offsetof(struct spar_controlvm_channel_protocol,
656 installation_error),
657 &error, sizeof(u32));
Benjamin Romer422af172014-07-24 14:08:42 -0400658 return scnprintf(buf, PAGE_SIZE, "%i\n", error);
659}
660
661static ssize_t error_store(struct device *dev, struct device_attribute *attr,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400662 const char *buf, size_t count)
Benjamin Romer422af172014-07-24 14:08:42 -0400663{
664 u32 error;
Benjamin Romer66e24b72014-07-25 13:55:10 -0400665 int ret;
Benjamin Romer422af172014-07-24 14:08:42 -0400666
Jes Sorensenebec8962015-05-05 18:35:57 -0400667 if (kstrtou32(buf, 10, &error))
Benjamin Romer66e24b72014-07-25 13:55:10 -0400668 return -EINVAL;
669
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400670 ret = visorchannel_write(controlvm_channel,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400671 offsetof(struct spar_controlvm_channel_protocol,
672 installation_error),
673 &error, sizeof(u32));
Benjamin Romer66e24b72014-07-25 13:55:10 -0400674 if (ret)
675 return ret;
Benjamin Romere22a4a02014-08-18 09:34:54 -0400676 return count;
Benjamin Romer422af172014-07-24 14:08:42 -0400677}
678
679static ssize_t textid_show(struct device *dev, struct device_attribute *attr,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400680 char *buf)
Benjamin Romer422af172014-07-24 14:08:42 -0400681{
Benjamin Romer10dbf0e2015-03-16 13:58:50 -0400682 u32 text_id;
Benjamin Romer422af172014-07-24 14:08:42 -0400683
Benjamin Romer8e76e692015-03-16 13:58:52 -0400684 visorchannel_read(controlvm_channel,
685 offsetof(struct spar_controlvm_channel_protocol,
686 installation_text_id),
687 &text_id, sizeof(u32));
Benjamin Romer10dbf0e2015-03-16 13:58:50 -0400688 return scnprintf(buf, PAGE_SIZE, "%i\n", text_id);
Benjamin Romer422af172014-07-24 14:08:42 -0400689}
690
691static ssize_t textid_store(struct device *dev, struct device_attribute *attr,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400692 const char *buf, size_t count)
Benjamin Romer422af172014-07-24 14:08:42 -0400693{
Benjamin Romer10dbf0e2015-03-16 13:58:50 -0400694 u32 text_id;
Benjamin Romer66e24b72014-07-25 13:55:10 -0400695 int ret;
Benjamin Romer422af172014-07-24 14:08:42 -0400696
Jes Sorensenebec8962015-05-05 18:35:57 -0400697 if (kstrtou32(buf, 10, &text_id))
Benjamin Romer66e24b72014-07-25 13:55:10 -0400698 return -EINVAL;
699
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400700 ret = visorchannel_write(controlvm_channel,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400701 offsetof(struct spar_controlvm_channel_protocol,
702 installation_text_id),
703 &text_id, sizeof(u32));
Benjamin Romer66e24b72014-07-25 13:55:10 -0400704 if (ret)
705 return ret;
Benjamin Romere22a4a02014-08-18 09:34:54 -0400706 return count;
Benjamin Romer422af172014-07-24 14:08:42 -0400707}
708
Benjamin Romer422af172014-07-24 14:08:42 -0400709static ssize_t remaining_steps_show(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400710 struct device_attribute *attr, char *buf)
Benjamin Romer422af172014-07-24 14:08:42 -0400711{
Benjamin Romeree8da292015-03-16 13:58:51 -0400712 u16 remaining_steps;
Benjamin Romer422af172014-07-24 14:08:42 -0400713
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400714 visorchannel_read(controlvm_channel,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400715 offsetof(struct spar_controlvm_channel_protocol,
716 installation_remaining_steps),
717 &remaining_steps, sizeof(u16));
Benjamin Romeree8da292015-03-16 13:58:51 -0400718 return scnprintf(buf, PAGE_SIZE, "%hu\n", remaining_steps);
Benjamin Romer422af172014-07-24 14:08:42 -0400719}
720
721static ssize_t remaining_steps_store(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400722 struct device_attribute *attr,
723 const char *buf, size_t count)
Benjamin Romer422af172014-07-24 14:08:42 -0400724{
Benjamin Romeree8da292015-03-16 13:58:51 -0400725 u16 remaining_steps;
Benjamin Romer66e24b72014-07-25 13:55:10 -0400726 int ret;
Benjamin Romer422af172014-07-24 14:08:42 -0400727
Jes Sorensenebec8962015-05-05 18:35:57 -0400728 if (kstrtou16(buf, 10, &remaining_steps))
Benjamin Romer66e24b72014-07-25 13:55:10 -0400729 return -EINVAL;
730
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400731 ret = visorchannel_write(controlvm_channel,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400732 offsetof(struct spar_controlvm_channel_protocol,
733 installation_remaining_steps),
734 &remaining_steps, sizeof(u16));
Benjamin Romer66e24b72014-07-25 13:55:10 -0400735 if (ret)
736 return ret;
Benjamin Romere22a4a02014-08-18 09:34:54 -0400737 return count;
Benjamin Romer422af172014-07-24 14:08:42 -0400738}
739
Ken Cox12e364b2014-03-04 07:58:07 -0600740static void
Benjamin Romer9b989a982015-03-16 13:58:11 -0400741bus_info_clear(void *v)
Ken Cox12e364b2014-03-04 07:58:07 -0600742{
Jes Sorensenbbd4be32015-05-05 18:35:43 -0400743 struct visorchipset_bus_info *p = (struct visorchipset_bus_info *) v;
Ken Cox12e364b2014-03-04 07:58:07 -0600744
Ken Cox12e364b2014-03-04 07:58:07 -0600745 kfree(p->name);
Ken Cox12e364b2014-03-04 07:58:07 -0600746 kfree(p->description);
Benjamin Romer33192fa2014-10-31 09:57:27 -0400747 memset(p, 0, sizeof(struct visorchipset_bus_info));
Ken Cox12e364b2014-03-04 07:58:07 -0600748}
749
750static void
Benjamin Romer9b989a982015-03-16 13:58:11 -0400751dev_info_clear(void *v)
Ken Cox12e364b2014-03-04 07:58:07 -0600752{
Benjamin Romer246e0cd2014-10-31 09:57:24 -0400753 struct visorchipset_device_info *p =
Jes Sorensenbbd4be32015-05-05 18:35:43 -0400754 (struct visorchipset_device_info *) v;
Benjamin Romer26eb2c02014-08-18 09:34:53 -0400755
Benjamin Romer246e0cd2014-10-31 09:57:24 -0400756 memset(p, 0, sizeof(struct visorchipset_device_info));
Ken Cox12e364b2014-03-04 07:58:07 -0600757}
758
Jes Sorensen4f665202015-05-05 18:35:52 -0400759static struct visorchipset_bus_info *
760bus_find(struct list_head *list, u32 bus_no)
761{
762 struct visorchipset_bus_info *p;
763
764 list_for_each_entry(p, list, entry) {
765 if (p->bus_no == bus_no)
766 return p;
767 }
768
769 return NULL;
770}
771
Jes Sorensend480f6a2015-05-05 18:35:54 -0400772static struct visorchipset_device_info *
773device_find(struct list_head *list, u32 bus_no, u32 dev_no)
774{
775 struct visorchipset_device_info *p;
776
777 list_for_each_entry(p, list, entry) {
778 if (p->bus_no == bus_no && p->dev_no == dev_no)
779 return p;
780 }
781
782 return NULL;
783}
784
Jes Sorensen28723522015-05-05 18:35:55 -0400785static void busdevices_del(struct list_head *list, u32 bus_no)
786{
787 struct visorchipset_device_info *p, *tmp;
788
789 list_for_each_entry_safe(p, tmp, list, entry) {
790 if (p->bus_no == bus_no) {
791 list_del(&p->entry);
792 kfree(p);
793 }
794 }
795}
796
Benjamin Romerc2422332014-07-29 15:09:40 -0400797static u8
Ken Cox12e364b2014-03-04 07:58:07 -0600798check_chipset_events(void)
799{
800 int i;
Benjamin Romerc2422332014-07-29 15:09:40 -0400801 u8 send_msg = 1;
Ken Cox12e364b2014-03-04 07:58:07 -0600802 /* Check events to determine if response should be sent */
803 for (i = 0; i < MAX_CHIPSET_EVENTS; i++)
804 send_msg &= chipset_events[i];
805 return send_msg;
806}
807
808static void
809clear_chipset_events(void)
810{
811 int i;
812 /* Clear chipset_events */
813 for (i = 0; i < MAX_CHIPSET_EVENTS; i++)
814 chipset_events[i] = 0;
815}
816
817void
David Kershner4da33362015-05-05 18:36:39 -0400818visorchipset_register_busdev(
Benjamin Romerfe90d892014-10-31 09:57:32 -0400819 struct visorchipset_busdev_notifiers *notifiers,
Benjamin Romer929aa8a2014-10-31 09:57:33 -0400820 struct visorchipset_busdev_responders *responders,
Benjamin Romer1e7a59c2014-10-31 09:57:35 -0400821 struct ultra_vbus_deviceinfo *driver_info)
Ken Cox12e364b2014-03-04 07:58:07 -0600822{
Benjamin Romer8f1947a2015-03-16 13:57:59 -0400823 down(&notifier_lock);
Benjamin Romer38f736e2015-03-16 13:58:13 -0400824 if (!notifiers) {
David Kershner4da33362015-05-05 18:36:39 -0400825 memset(&busdev_notifiers, 0,
826 sizeof(busdev_notifiers));
827 visorbusregistered = 0; /* clear flag */
Ken Cox12e364b2014-03-04 07:58:07 -0600828 } else {
David Kershner4da33362015-05-05 18:36:39 -0400829 busdev_notifiers = *notifiers;
830 visorbusregistered = 1; /* set flag */
Ken Cox12e364b2014-03-04 07:58:07 -0600831 }
832 if (responders)
Benjamin Romer8e3fedd2015-03-16 13:58:43 -0400833 *responders = busdev_responders;
Benjamin Romer1e7a59c2014-10-31 09:57:35 -0400834 if (driver_info)
835 bus_device_info_init(driver_info, "chipset", "visorchipset",
Benjamin Romer8e76e692015-03-16 13:58:52 -0400836 VERSION, NULL);
Ken Cox12e364b2014-03-04 07:58:07 -0600837
Benjamin Romer8f1947a2015-03-16 13:57:59 -0400838 up(&notifier_lock);
Ken Cox12e364b2014-03-04 07:58:07 -0600839}
David Kershner4da33362015-05-05 18:36:39 -0400840EXPORT_SYMBOL_GPL(visorchipset_register_busdev);
Ken Cox12e364b2014-03-04 07:58:07 -0600841
842static void
843cleanup_controlvm_structures(void)
844{
Benjamin Romer33192fa2014-10-31 09:57:27 -0400845 struct visorchipset_bus_info *bi, *tmp_bi;
Benjamin Romer246e0cd2014-10-31 09:57:24 -0400846 struct visorchipset_device_info *di, *tmp_di;
Ken Cox12e364b2014-03-04 07:58:07 -0600847
Benjamin Romer1390b882015-03-16 13:58:03 -0400848 list_for_each_entry_safe(bi, tmp_bi, &bus_info_list, entry) {
Benjamin Romer9b989a982015-03-16 13:58:11 -0400849 bus_info_clear(bi);
Ken Cox12e364b2014-03-04 07:58:07 -0600850 list_del(&bi->entry);
851 kfree(bi);
852 }
853
Benjamin Romer1390b882015-03-16 13:58:03 -0400854 list_for_each_entry_safe(di, tmp_di, &dev_info_list, entry) {
Benjamin Romer9b989a982015-03-16 13:58:11 -0400855 dev_info_clear(di);
Ken Cox12e364b2014-03-04 07:58:07 -0600856 list_del(&di->entry);
857 kfree(di);
858 }
859}
860
861static void
Benjamin Romer3ab47702014-10-23 14:30:31 -0400862chipset_init(struct controlvm_message *inmsg)
Ken Cox12e364b2014-03-04 07:58:07 -0600863{
864 static int chipset_inited;
Benjamin Romerb9b141e2014-10-23 14:30:24 -0400865 enum ultra_chipset_feature features = 0;
Ken Cox12e364b2014-03-04 07:58:07 -0600866 int rc = CONTROLVM_RESP_SUCCESS;
867
868 POSTCODE_LINUX_2(CHIPSET_INIT_ENTRY_PC, POSTCODE_SEVERITY_INFO);
869 if (chipset_inited) {
Ken Cox22ad57b2014-03-19 13:06:25 -0500870 rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
Benjamin Romere3199b22015-03-16 13:58:14 -0400871 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -0600872 }
873 chipset_inited = 1;
874 POSTCODE_LINUX_2(CHIPSET_INIT_EXIT_PC, POSTCODE_SEVERITY_INFO);
875
876 /* Set features to indicate we support parahotplug (if Command
877 * also supports it). */
878 features =
Benjamin Romer2ea51172014-10-23 14:30:25 -0400879 inmsg->cmd.init_chipset.
Ken Cox12e364b2014-03-04 07:58:07 -0600880 features & ULTRA_CHIPSET_FEATURE_PARA_HOTPLUG;
881
882 /* Set the "reply" bit so Command knows this is a
883 * features-aware driver. */
884 features |= ULTRA_CHIPSET_FEATURE_REPLY;
885
Benjamin Romere3199b22015-03-16 13:58:14 -0400886cleanup:
Ken Cox12e364b2014-03-04 07:58:07 -0600887 if (rc < 0)
888 cleanup_controlvm_structures();
Benjamin Romer98d7b592014-10-23 14:30:26 -0400889 if (inmsg->hdr.flags.response_expected)
Ken Cox12e364b2014-03-04 07:58:07 -0600890 controlvm_respond_chipset_init(&inmsg->hdr, rc, features);
891}
892
893static void
Benjamin Romer3ab47702014-10-23 14:30:31 -0400894controlvm_init_response(struct controlvm_message *msg,
Benjamin Romerb3168c72015-03-16 13:58:46 -0400895 struct controlvm_message_header *msg_hdr, int response)
Ken Cox12e364b2014-03-04 07:58:07 -0600896{
Benjamin Romer3ab47702014-10-23 14:30:31 -0400897 memset(msg, 0, sizeof(struct controlvm_message));
Benjamin Romerb3168c72015-03-16 13:58:46 -0400898 memcpy(&msg->hdr, msg_hdr, sizeof(struct controlvm_message_header));
Benjamin Romer98d7b592014-10-23 14:30:26 -0400899 msg->hdr.payload_bytes = 0;
900 msg->hdr.payload_vm_offset = 0;
901 msg->hdr.payload_max_bytes = 0;
Ken Cox12e364b2014-03-04 07:58:07 -0600902 if (response < 0) {
Benjamin Romer98d7b592014-10-23 14:30:26 -0400903 msg->hdr.flags.failed = 1;
904 msg->hdr.completion_status = (u32) (-response);
Ken Cox12e364b2014-03-04 07:58:07 -0600905 }
906}
907
908static void
Benjamin Romerb3168c72015-03-16 13:58:46 -0400909controlvm_respond(struct controlvm_message_header *msg_hdr, int response)
Ken Cox12e364b2014-03-04 07:58:07 -0600910{
Benjamin Romer3ab47702014-10-23 14:30:31 -0400911 struct controlvm_message outmsg;
Benjamin Romer26eb2c02014-08-18 09:34:53 -0400912
Benjamin Romerb3168c72015-03-16 13:58:46 -0400913 controlvm_init_response(&outmsg, msg_hdr, response);
Ken Cox12e364b2014-03-04 07:58:07 -0600914 /* For DiagPool channel DEVICE_CHANGESTATE, we need to send
915 * back the deviceChangeState structure in the packet. */
Benjamin Romerb3168c72015-03-16 13:58:46 -0400916 if (msg_hdr->id == CONTROLVM_DEVICE_CHANGESTATE &&
Benjamin Romer0639ba62015-03-16 13:58:04 -0400917 g_devicechangestate_packet.device_change_state.bus_no ==
918 g_diagpool_bus_no &&
919 g_devicechangestate_packet.device_change_state.dev_no ==
Benjamin Romer83d48902015-03-16 13:58:01 -0400920 g_diagpool_dev_no)
Benjamin Romer4f44b722015-03-16 13:58:02 -0400921 outmsg.cmd = g_devicechangestate_packet;
Benjamin Romer2098dbd2015-03-04 12:14:22 -0500922 if (outmsg.hdr.flags.test_message == 1)
Ken Cox12e364b2014-03-04 07:58:07 -0600923 return;
Benjamin Romer2098dbd2015-03-04 12:14:22 -0500924
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400925 if (!visorchannel_signalinsert(controlvm_channel,
Ken Cox12e364b2014-03-04 07:58:07 -0600926 CONTROLVM_QUEUE_REQUEST, &outmsg)) {
Ken Cox12e364b2014-03-04 07:58:07 -0600927 return;
928 }
929}
930
931static void
Benjamin Romerb3168c72015-03-16 13:58:46 -0400932controlvm_respond_chipset_init(struct controlvm_message_header *msg_hdr,
Benjamin Romer98d7b592014-10-23 14:30:26 -0400933 int response,
Benjamin Romerb9b141e2014-10-23 14:30:24 -0400934 enum ultra_chipset_feature features)
Ken Cox12e364b2014-03-04 07:58:07 -0600935{
Benjamin Romer3ab47702014-10-23 14:30:31 -0400936 struct controlvm_message outmsg;
Benjamin Romer26eb2c02014-08-18 09:34:53 -0400937
Benjamin Romerb3168c72015-03-16 13:58:46 -0400938 controlvm_init_response(&outmsg, msg_hdr, response);
Benjamin Romer2ea51172014-10-23 14:30:25 -0400939 outmsg.cmd.init_chipset.features = features;
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400940 if (!visorchannel_signalinsert(controlvm_channel,
Ken Cox12e364b2014-03-04 07:58:07 -0600941 CONTROLVM_QUEUE_REQUEST, &outmsg)) {
Ken Cox12e364b2014-03-04 07:58:07 -0600942 return;
943 }
944}
945
Benjamin Romer98d7b592014-10-23 14:30:26 -0400946static void controlvm_respond_physdev_changestate(
Benjamin Romerb3168c72015-03-16 13:58:46 -0400947 struct controlvm_message_header *msg_hdr, int response,
Benjamin Romer98d7b592014-10-23 14:30:26 -0400948 struct spar_segment_state state)
Ken Cox12e364b2014-03-04 07:58:07 -0600949{
Benjamin Romer3ab47702014-10-23 14:30:31 -0400950 struct controlvm_message outmsg;
Benjamin Romer26eb2c02014-08-18 09:34:53 -0400951
Benjamin Romerb3168c72015-03-16 13:58:46 -0400952 controlvm_init_response(&outmsg, msg_hdr, response);
Benjamin Romer2ea51172014-10-23 14:30:25 -0400953 outmsg.cmd.device_change_state.state = state;
954 outmsg.cmd.device_change_state.flags.phys_device = 1;
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400955 if (!visorchannel_signalinsert(controlvm_channel,
Ken Cox12e364b2014-03-04 07:58:07 -0600956 CONTROLVM_QUEUE_REQUEST, &outmsg)) {
Ken Cox12e364b2014-03-04 07:58:07 -0600957 return;
958 }
959}
960
Prarit Bhargava2ee0dee2015-05-05 18:36:16 -0400961enum crash_obj_type {
962 CRASH_DEV,
963 CRASH_BUS,
964};
965
Ken Cox12e364b2014-03-04 07:58:07 -0600966void
Benjamin Romer2c683cd2014-10-31 09:57:22 -0400967visorchipset_save_message(struct controlvm_message *msg,
968 enum crash_obj_type type)
Ken Cox12e364b2014-03-04 07:58:07 -0600969{
Benjamin Romer45772252015-03-16 13:58:15 -0400970 u32 crash_msg_offset;
971 u16 crash_msg_count;
Ken Cox12e364b2014-03-04 07:58:07 -0600972
973 /* get saved message count */
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400974 if (visorchannel_read(controlvm_channel,
Benjamin Romerd19642f2014-10-23 14:30:34 -0400975 offsetof(struct spar_controlvm_channel_protocol,
976 saved_crash_message_count),
Benjamin Romer45772252015-03-16 13:58:15 -0400977 &crash_msg_count, sizeof(u16)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -0600978 POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
979 POSTCODE_SEVERITY_ERR);
980 return;
981 }
982
Benjamin Romer45772252015-03-16 13:58:15 -0400983 if (crash_msg_count != CONTROLVM_CRASHMSG_MAX) {
Ken Cox12e364b2014-03-04 07:58:07 -0600984 POSTCODE_LINUX_3(CRASH_DEV_COUNT_FAILURE_PC,
Benjamin Romer45772252015-03-16 13:58:15 -0400985 crash_msg_count,
Ken Cox12e364b2014-03-04 07:58:07 -0600986 POSTCODE_SEVERITY_ERR);
987 return;
988 }
989
990 /* get saved crash message offset */
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400991 if (visorchannel_read(controlvm_channel,
Benjamin Romerd19642f2014-10-23 14:30:34 -0400992 offsetof(struct spar_controlvm_channel_protocol,
993 saved_crash_message_offset),
Benjamin Romer45772252015-03-16 13:58:15 -0400994 &crash_msg_offset, sizeof(u32)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -0600995 POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
996 POSTCODE_SEVERITY_ERR);
997 return;
998 }
999
Benjamin Romer2c683cd2014-10-31 09:57:22 -04001000 if (type == CRASH_BUS) {
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001001 if (visorchannel_write(controlvm_channel,
Benjamin Romer45772252015-03-16 13:58:15 -04001002 crash_msg_offset,
Benjamin Romer3ab47702014-10-23 14:30:31 -04001003 msg,
1004 sizeof(struct controlvm_message)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06001005 POSTCODE_LINUX_2(SAVE_MSG_BUS_FAILURE_PC,
1006 POSTCODE_SEVERITY_ERR);
1007 return;
1008 }
Prarit Bhargava2ee0dee2015-05-05 18:36:16 -04001009 } else { /* CRASH_DEV */
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001010 if (visorchannel_write(controlvm_channel,
Benjamin Romer45772252015-03-16 13:58:15 -04001011 crash_msg_offset +
Benjamin Romer3ab47702014-10-23 14:30:31 -04001012 sizeof(struct controlvm_message), msg,
1013 sizeof(struct controlvm_message)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06001014 POSTCODE_LINUX_2(SAVE_MSG_DEV_FAILURE_PC,
1015 POSTCODE_SEVERITY_ERR);
1016 return;
1017 }
1018 }
1019}
1020EXPORT_SYMBOL_GPL(visorchipset_save_message);
1021
1022static void
Jes Sorensen52063ec2015-04-13 10:28:41 -04001023bus_responder(enum controlvm_id cmd_id, u32 bus_no, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06001024{
Jes Sorensene82ba622015-05-05 18:35:45 -04001025 struct visorchipset_bus_info *p;
Jes Sorensenf4c11552015-04-13 10:28:40 -04001026 bool need_clear = false;
Ken Cox12e364b2014-03-04 07:58:07 -06001027
Jes Sorensen4f665202015-05-05 18:35:52 -04001028 p = bus_find(&bus_info_list, bus_no);
Benjamin Romer0aca78442015-03-04 12:14:25 -05001029 if (!p)
Ken Cox12e364b2014-03-04 07:58:07 -06001030 return;
Benjamin Romer0aca78442015-03-04 12:14:25 -05001031
Ken Cox12e364b2014-03-04 07:58:07 -06001032 if (response < 0) {
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001033 if ((cmd_id == CONTROLVM_BUS_CREATE) &&
Ken Cox12e364b2014-03-04 07:58:07 -06001034 (response != (-CONTROLVM_RESP_ERROR_ALREADY_DONE)))
1035 /* undo the row we just created... */
Jes Sorensen28723522015-05-05 18:35:55 -04001036 busdevices_del(&dev_info_list, bus_no);
Ken Cox12e364b2014-03-04 07:58:07 -06001037 } else {
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001038 if (cmd_id == CONTROLVM_BUS_CREATE)
Ken Cox12e364b2014-03-04 07:58:07 -06001039 p->state.created = 1;
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001040 if (cmd_id == CONTROLVM_BUS_DESTROY)
Jes Sorensenf4c11552015-04-13 10:28:40 -04001041 need_clear = true;
Ken Cox12e364b2014-03-04 07:58:07 -06001042 }
1043
Benjamin Romer0aca78442015-03-04 12:14:25 -05001044 if (p->pending_msg_hdr.id == CONTROLVM_INVALID)
Ken Cox12e364b2014-03-04 07:58:07 -06001045 return; /* no controlvm response needed */
Benjamin Romer6b59b312015-03-16 13:58:18 -04001046 if (p->pending_msg_hdr.id != (u32)cmd_id)
Ken Cox12e364b2014-03-04 07:58:07 -06001047 return;
Benjamin Romer33192fa2014-10-31 09:57:27 -04001048 controlvm_respond(&p->pending_msg_hdr, response);
1049 p->pending_msg_hdr.id = CONTROLVM_INVALID;
Ken Cox12e364b2014-03-04 07:58:07 -06001050 if (need_clear) {
Benjamin Romer9b989a982015-03-16 13:58:11 -04001051 bus_info_clear(p);
Jes Sorensen28723522015-05-05 18:35:55 -04001052 busdevices_del(&dev_info_list, bus_no);
Ken Cox12e364b2014-03-04 07:58:07 -06001053 }
1054}
1055
1056static void
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001057device_changestate_responder(enum controlvm_id cmd_id,
Jes Sorensen52063ec2015-04-13 10:28:41 -04001058 u32 bus_no, u32 dev_no, int response,
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001059 struct spar_segment_state response_state)
Ken Cox12e364b2014-03-04 07:58:07 -06001060{
Jes Sorensene82ba622015-05-05 18:35:45 -04001061 struct visorchipset_device_info *p;
Benjamin Romer3ab47702014-10-23 14:30:31 -04001062 struct controlvm_message outmsg;
Ken Cox12e364b2014-03-04 07:58:07 -06001063
Jes Sorensend480f6a2015-05-05 18:35:54 -04001064 p = device_find(&dev_info_list, bus_no, dev_no);
Benjamin Romer0aca78442015-03-04 12:14:25 -05001065 if (!p)
Ken Cox12e364b2014-03-04 07:58:07 -06001066 return;
Benjamin Romer0aca78442015-03-04 12:14:25 -05001067 if (p->pending_msg_hdr.id == CONTROLVM_INVALID)
Ken Cox12e364b2014-03-04 07:58:07 -06001068 return; /* no controlvm response needed */
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001069 if (p->pending_msg_hdr.id != cmd_id)
Ken Cox12e364b2014-03-04 07:58:07 -06001070 return;
Ken Cox12e364b2014-03-04 07:58:07 -06001071
Benjamin Romer246e0cd2014-10-31 09:57:24 -04001072 controlvm_init_response(&outmsg, &p->pending_msg_hdr, response);
Ken Cox12e364b2014-03-04 07:58:07 -06001073
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001074 outmsg.cmd.device_change_state.bus_no = bus_no;
1075 outmsg.cmd.device_change_state.dev_no = dev_no;
1076 outmsg.cmd.device_change_state.state = response_state;
Ken Cox12e364b2014-03-04 07:58:07 -06001077
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001078 if (!visorchannel_signalinsert(controlvm_channel,
Benjamin Romer0aca78442015-03-04 12:14:25 -05001079 CONTROLVM_QUEUE_REQUEST, &outmsg))
Ken Cox12e364b2014-03-04 07:58:07 -06001080 return;
Ken Cox12e364b2014-03-04 07:58:07 -06001081
Benjamin Romer246e0cd2014-10-31 09:57:24 -04001082 p->pending_msg_hdr.id = CONTROLVM_INVALID;
Ken Cox12e364b2014-03-04 07:58:07 -06001083}
1084
1085static void
Jes Sorensen52063ec2015-04-13 10:28:41 -04001086device_responder(enum controlvm_id cmd_id, u32 bus_no, u32 dev_no, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06001087{
Jes Sorensene82ba622015-05-05 18:35:45 -04001088 struct visorchipset_device_info *p;
Jes Sorensenf4c11552015-04-13 10:28:40 -04001089 bool need_clear = false;
Ken Cox12e364b2014-03-04 07:58:07 -06001090
Jes Sorensend480f6a2015-05-05 18:35:54 -04001091 p = device_find(&dev_info_list, bus_no, dev_no);
Benjamin Romer0aca78442015-03-04 12:14:25 -05001092 if (!p)
Ken Cox12e364b2014-03-04 07:58:07 -06001093 return;
Ken Cox12e364b2014-03-04 07:58:07 -06001094 if (response >= 0) {
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001095 if (cmd_id == CONTROLVM_DEVICE_CREATE)
Ken Cox12e364b2014-03-04 07:58:07 -06001096 p->state.created = 1;
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001097 if (cmd_id == CONTROLVM_DEVICE_DESTROY)
Jes Sorensenf4c11552015-04-13 10:28:40 -04001098 need_clear = true;
Ken Cox12e364b2014-03-04 07:58:07 -06001099 }
1100
Benjamin Romer0aca78442015-03-04 12:14:25 -05001101 if (p->pending_msg_hdr.id == CONTROLVM_INVALID)
Ken Cox12e364b2014-03-04 07:58:07 -06001102 return; /* no controlvm response needed */
Benjamin Romer0aca78442015-03-04 12:14:25 -05001103
Benjamin Romer6b59b312015-03-16 13:58:18 -04001104 if (p->pending_msg_hdr.id != (u32)cmd_id)
Ken Cox12e364b2014-03-04 07:58:07 -06001105 return;
Benjamin Romer0aca78442015-03-04 12:14:25 -05001106
Benjamin Romer246e0cd2014-10-31 09:57:24 -04001107 controlvm_respond(&p->pending_msg_hdr, response);
1108 p->pending_msg_hdr.id = CONTROLVM_INVALID;
Ken Cox12e364b2014-03-04 07:58:07 -06001109 if (need_clear)
Benjamin Romer9b989a982015-03-16 13:58:11 -04001110 dev_info_clear(p);
Ken Cox12e364b2014-03-04 07:58:07 -06001111}
1112
1113static void
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001114bus_epilog(u32 bus_no,
1115 u32 cmd, struct controlvm_message_header *msg_hdr,
Jes Sorensenf4c11552015-04-13 10:28:40 -04001116 int response, bool need_response)
Ken Cox12e364b2014-03-04 07:58:07 -06001117{
Jes Sorensen4f665202015-05-05 18:35:52 -04001118 struct visorchipset_bus_info *bus_info;
Jes Sorensenf4c11552015-04-13 10:28:40 -04001119 bool notified = false;
Ken Cox12e364b2014-03-04 07:58:07 -06001120
Jes Sorensen4f665202015-05-05 18:35:52 -04001121 bus_info = bus_find(&bus_info_list, bus_no);
Ken Cox12e364b2014-03-04 07:58:07 -06001122
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001123 if (!bus_info)
Ken Cox12e364b2014-03-04 07:58:07 -06001124 return;
Benjamin Romer0aca78442015-03-04 12:14:25 -05001125
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001126 if (need_response) {
1127 memcpy(&bus_info->pending_msg_hdr, msg_hdr,
Benjamin Romer98d7b592014-10-23 14:30:26 -04001128 sizeof(struct controlvm_message_header));
Benjamin Romer75c1f8b2015-03-16 13:58:19 -04001129 } else {
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001130 bus_info->pending_msg_hdr.id = CONTROLVM_INVALID;
Benjamin Romer75c1f8b2015-03-16 13:58:19 -04001131 }
Ken Cox12e364b2014-03-04 07:58:07 -06001132
Benjamin Romer8f1947a2015-03-16 13:57:59 -04001133 down(&notifier_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001134 if (response == CONTROLVM_RESP_SUCCESS) {
1135 switch (cmd) {
1136 case CONTROLVM_BUS_CREATE:
David Kershner4da33362015-05-05 18:36:39 -04001137 if (busdev_notifiers.bus_create) {
1138 (*busdev_notifiers.bus_create) (bus_no);
Jes Sorensenf4c11552015-04-13 10:28:40 -04001139 notified = true;
Ken Cox12e364b2014-03-04 07:58:07 -06001140 }
1141 break;
1142 case CONTROLVM_BUS_DESTROY:
David Kershner4da33362015-05-05 18:36:39 -04001143 if (busdev_notifiers.bus_destroy) {
1144 (*busdev_notifiers.bus_destroy) (bus_no);
Jes Sorensenf4c11552015-04-13 10:28:40 -04001145 notified = true;
Ken Cox12e364b2014-03-04 07:58:07 -06001146 }
1147 break;
1148 }
1149 }
1150 if (notified)
1151 /* The callback function just called above is responsible
Benjamin Romer929aa8a2014-10-31 09:57:33 -04001152 * for calling the appropriate visorchipset_busdev_responders
Ken Cox12e364b2014-03-04 07:58:07 -06001153 * function, which will call bus_responder()
1154 */
1155 ;
1156 else
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001157 bus_responder(cmd, bus_no, response);
Benjamin Romer8f1947a2015-03-16 13:57:59 -04001158 up(&notifier_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001159}
1160
1161static void
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001162device_epilog(u32 bus_no, u32 dev_no, struct spar_segment_state state, u32 cmd,
1163 struct controlvm_message_header *msg_hdr, int response,
Jes Sorensenf4c11552015-04-13 10:28:40 -04001164 bool need_response, bool for_visorbus)
Ken Cox12e364b2014-03-04 07:58:07 -06001165{
Jes Sorensene82ba622015-05-05 18:35:45 -04001166 struct visorchipset_busdev_notifiers *notifiers;
Jes Sorensenf4c11552015-04-13 10:28:40 -04001167 bool notified = false;
Ken Cox12e364b2014-03-04 07:58:07 -06001168
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001169 struct visorchipset_device_info *dev_info =
Jes Sorensend480f6a2015-05-05 18:35:54 -04001170 device_find(&dev_info_list, bus_no, dev_no);
Ken Cox12e364b2014-03-04 07:58:07 -06001171 char *envp[] = {
1172 "SPARSP_DIAGPOOL_PAUSED_STATE = 1",
1173 NULL
1174 };
1175
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001176 if (!dev_info)
Ken Cox12e364b2014-03-04 07:58:07 -06001177 return;
Benjamin Romer0aca78442015-03-04 12:14:25 -05001178
David Kershner4da33362015-05-05 18:36:39 -04001179 notifiers = &busdev_notifiers;
1180
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001181 if (need_response) {
1182 memcpy(&dev_info->pending_msg_hdr, msg_hdr,
Benjamin Romer98d7b592014-10-23 14:30:26 -04001183 sizeof(struct controlvm_message_header));
Benjamin Romer75c1f8b2015-03-16 13:58:19 -04001184 } else {
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001185 dev_info->pending_msg_hdr.id = CONTROLVM_INVALID;
Benjamin Romer75c1f8b2015-03-16 13:58:19 -04001186 }
Ken Cox12e364b2014-03-04 07:58:07 -06001187
Benjamin Romer8f1947a2015-03-16 13:57:59 -04001188 down(&notifier_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001189 if (response >= 0) {
1190 switch (cmd) {
1191 case CONTROLVM_DEVICE_CREATE:
1192 if (notifiers->device_create) {
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001193 (*notifiers->device_create) (bus_no, dev_no);
Jes Sorensenf4c11552015-04-13 10:28:40 -04001194 notified = true;
Ken Cox12e364b2014-03-04 07:58:07 -06001195 }
1196 break;
1197 case CONTROLVM_DEVICE_CHANGESTATE:
1198 /* ServerReady / ServerRunning / SegmentStateRunning */
Benjamin Romerbd0d2dc2014-10-23 14:30:13 -04001199 if (state.alive == segment_state_running.alive &&
1200 state.operating ==
1201 segment_state_running.operating) {
Ken Cox12e364b2014-03-04 07:58:07 -06001202 if (notifiers->device_resume) {
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001203 (*notifiers->device_resume) (bus_no,
1204 dev_no);
Jes Sorensenf4c11552015-04-13 10:28:40 -04001205 notified = true;
Ken Cox12e364b2014-03-04 07:58:07 -06001206 }
1207 }
1208 /* ServerNotReady / ServerLost / SegmentStateStandby */
Benjamin Romerbd0d2dc2014-10-23 14:30:13 -04001209 else if (state.alive == segment_state_standby.alive &&
Benjamin Romer3f833b52014-10-23 14:30:12 -04001210 state.operating ==
Benjamin Romerbd0d2dc2014-10-23 14:30:13 -04001211 segment_state_standby.operating) {
Ken Cox12e364b2014-03-04 07:58:07 -06001212 /* technically this is standby case
1213 * where server is lost
1214 */
1215 if (notifiers->device_pause) {
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001216 (*notifiers->device_pause) (bus_no,
1217 dev_no);
Jes Sorensenf4c11552015-04-13 10:28:40 -04001218 notified = true;
Ken Cox12e364b2014-03-04 07:58:07 -06001219 }
Benjamin Romerbd0d2dc2014-10-23 14:30:13 -04001220 } else if (state.alive == segment_state_paused.alive &&
Benjamin Romer3f833b52014-10-23 14:30:12 -04001221 state.operating ==
Benjamin Romerbd0d2dc2014-10-23 14:30:13 -04001222 segment_state_paused.operating) {
Ken Cox12e364b2014-03-04 07:58:07 -06001223 /* this is lite pause where channel is
1224 * still valid just 'pause' of it
1225 */
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001226 if (bus_no == g_diagpool_bus_no &&
1227 dev_no == g_diagpool_dev_no) {
Ken Cox12e364b2014-03-04 07:58:07 -06001228 /* this will trigger the
1229 * diag_shutdown.sh script in
1230 * the visorchipset hotplug */
1231 kobject_uevent_env
Benjamin Romereb34e872015-03-16 13:58:45 -04001232 (&visorchipset_platform_device.dev.
Ken Cox12e364b2014-03-04 07:58:07 -06001233 kobj, KOBJ_ONLINE, envp);
1234 }
1235 }
1236 break;
1237 case CONTROLVM_DEVICE_DESTROY:
1238 if (notifiers->device_destroy) {
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001239 (*notifiers->device_destroy) (bus_no, dev_no);
Jes Sorensenf4c11552015-04-13 10:28:40 -04001240 notified = true;
Ken Cox12e364b2014-03-04 07:58:07 -06001241 }
1242 break;
1243 }
1244 }
1245 if (notified)
1246 /* The callback function just called above is responsible
Benjamin Romer929aa8a2014-10-31 09:57:33 -04001247 * for calling the appropriate visorchipset_busdev_responders
Ken Cox12e364b2014-03-04 07:58:07 -06001248 * function, which will call device_responder()
1249 */
1250 ;
1251 else
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001252 device_responder(cmd, bus_no, dev_no, response);
Benjamin Romer8f1947a2015-03-16 13:57:59 -04001253 up(&notifier_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001254}
1255
1256static void
Benjamin Romer3ab47702014-10-23 14:30:31 -04001257bus_create(struct controlvm_message *inmsg)
Ken Cox12e364b2014-03-04 07:58:07 -06001258{
Benjamin Romer2ea51172014-10-23 14:30:25 -04001259 struct controlvm_message_packet *cmd = &inmsg->cmd;
Jes Sorensen52063ec2015-04-13 10:28:41 -04001260 u32 bus_no = cmd->create_bus.bus_no;
Ken Cox12e364b2014-03-04 07:58:07 -06001261 int rc = CONTROLVM_RESP_SUCCESS;
Jes Sorensene82ba622015-05-05 18:35:45 -04001262 struct visorchipset_bus_info *bus_info;
Ken Cox12e364b2014-03-04 07:58:07 -06001263
Jes Sorensen4f665202015-05-05 18:35:52 -04001264 bus_info = bus_find(&bus_info_list, bus_no);
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001265 if (bus_info && (bus_info->state.created == 1)) {
1266 POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001267 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001268 rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001269 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001270 }
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001271 bus_info = kzalloc(sizeof(*bus_info), GFP_KERNEL);
1272 if (!bus_info) {
1273 POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001274 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001275 rc = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001276 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001277 }
1278
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001279 INIT_LIST_HEAD(&bus_info->entry);
1280 bus_info->bus_no = bus_no;
Ken Cox12e364b2014-03-04 07:58:07 -06001281
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001282 POSTCODE_LINUX_3(BUS_CREATE_ENTRY_PC, bus_no, POSTCODE_SEVERITY_INFO);
Ken Cox12e364b2014-03-04 07:58:07 -06001283
Benjamin Romer98d7b592014-10-23 14:30:26 -04001284 if (inmsg->hdr.flags.test_message == 1)
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001285 bus_info->chan_info.addr_type = ADDRTYPE_LOCALTEST;
Ken Cox12e364b2014-03-04 07:58:07 -06001286 else
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001287 bus_info->chan_info.addr_type = ADDRTYPE_LOCALPHYSICAL;
Ken Cox12e364b2014-03-04 07:58:07 -06001288
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001289 bus_info->flags.server = inmsg->hdr.flags.server;
1290 bus_info->chan_info.channel_addr = cmd->create_bus.channel_addr;
1291 bus_info->chan_info.n_channel_bytes = cmd->create_bus.channel_bytes;
1292 bus_info->chan_info.channel_type_uuid =
Benjamin Romer9b1caee2014-10-31 09:57:23 -04001293 cmd->create_bus.bus_data_type_uuid;
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001294 bus_info->chan_info.channel_inst_uuid = cmd->create_bus.bus_inst_uuid;
Ken Cox12e364b2014-03-04 07:58:07 -06001295
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001296 list_add(&bus_info->entry, &bus_info_list);
Ken Cox12e364b2014-03-04 07:58:07 -06001297
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001298 POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, bus_no, POSTCODE_SEVERITY_INFO);
Ken Cox12e364b2014-03-04 07:58:07 -06001299
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001300cleanup:
1301 bus_epilog(bus_no, CONTROLVM_BUS_CREATE, &inmsg->hdr,
Benjamin Romer98d7b592014-10-23 14:30:26 -04001302 rc, inmsg->hdr.flags.response_expected == 1);
Ken Cox12e364b2014-03-04 07:58:07 -06001303}
1304
1305static void
Benjamin Romer3ab47702014-10-23 14:30:31 -04001306bus_destroy(struct controlvm_message *inmsg)
Ken Cox12e364b2014-03-04 07:58:07 -06001307{
Benjamin Romer2ea51172014-10-23 14:30:25 -04001308 struct controlvm_message_packet *cmd = &inmsg->cmd;
Jes Sorensen52063ec2015-04-13 10:28:41 -04001309 u32 bus_no = cmd->destroy_bus.bus_no;
Benjamin Romerdff54cd2015-03-16 13:58:21 -04001310 struct visorchipset_bus_info *bus_info;
Ken Cox12e364b2014-03-04 07:58:07 -06001311 int rc = CONTROLVM_RESP_SUCCESS;
1312
Jes Sorensen4f665202015-05-05 18:35:52 -04001313 bus_info = bus_find(&bus_info_list, bus_no);
Benjamin Romerdff54cd2015-03-16 13:58:21 -04001314 if (!bus_info)
Ken Cox22ad57b2014-03-19 13:06:25 -05001315 rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
Benjamin Romerdff54cd2015-03-16 13:58:21 -04001316 else if (bus_info->state.created == 0)
Ken Cox22ad57b2014-03-19 13:06:25 -05001317 rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
Ken Cox12e364b2014-03-04 07:58:07 -06001318
Benjamin Romerdff54cd2015-03-16 13:58:21 -04001319 bus_epilog(bus_no, CONTROLVM_BUS_DESTROY, &inmsg->hdr,
Benjamin Romer98d7b592014-10-23 14:30:26 -04001320 rc, inmsg->hdr.flags.response_expected == 1);
Ken Cox12e364b2014-03-04 07:58:07 -06001321}
1322
1323static void
Benjamin Romer317d9612015-03-16 13:57:51 -04001324bus_configure(struct controlvm_message *inmsg,
1325 struct parser_context *parser_ctx)
Ken Cox12e364b2014-03-04 07:58:07 -06001326{
Benjamin Romer2ea51172014-10-23 14:30:25 -04001327 struct controlvm_message_packet *cmd = &inmsg->cmd;
Jes Sorensene82ba622015-05-05 18:35:45 -04001328 u32 bus_no;
1329 struct visorchipset_bus_info *bus_info;
Ken Cox12e364b2014-03-04 07:58:07 -06001330 int rc = CONTROLVM_RESP_SUCCESS;
1331 char s[99];
1332
Benjamin Romer654bada2015-03-16 13:58:22 -04001333 bus_no = cmd->configure_bus.bus_no;
1334 POSTCODE_LINUX_3(BUS_CONFIGURE_ENTRY_PC, bus_no,
1335 POSTCODE_SEVERITY_INFO);
Ken Cox12e364b2014-03-04 07:58:07 -06001336
Jes Sorensen4f665202015-05-05 18:35:52 -04001337 bus_info = bus_find(&bus_info_list, bus_no);
Benjamin Romer654bada2015-03-16 13:58:22 -04001338 if (!bus_info) {
1339 POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001340 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001341 rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
Benjamin Romer654bada2015-03-16 13:58:22 -04001342 } else if (bus_info->state.created == 0) {
1343 POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001344 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001345 rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
Benjamin Romer654bada2015-03-16 13:58:22 -04001346 } else if (bus_info->pending_msg_hdr.id != CONTROLVM_INVALID) {
1347 POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001348 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001349 rc = -CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT;
Benjamin Romer654bada2015-03-16 13:58:22 -04001350 } else {
1351 bus_info->partition_handle = cmd->configure_bus.guest_handle;
1352 bus_info->partition_uuid = parser_id_get(parser_ctx);
1353 parser_param_start(parser_ctx, PARSERSTRING_NAME);
1354 bus_info->name = parser_string_get(parser_ctx);
1355
1356 visorchannel_uuid_id(&bus_info->partition_uuid, s);
1357 POSTCODE_LINUX_3(BUS_CONFIGURE_EXIT_PC, bus_no,
1358 POSTCODE_SEVERITY_INFO);
Ken Cox12e364b2014-03-04 07:58:07 -06001359 }
Benjamin Romer654bada2015-03-16 13:58:22 -04001360 bus_epilog(bus_no, CONTROLVM_BUS_CONFIGURE, &inmsg->hdr,
Benjamin Romer98d7b592014-10-23 14:30:26 -04001361 rc, inmsg->hdr.flags.response_expected == 1);
Ken Cox12e364b2014-03-04 07:58:07 -06001362}
1363
1364static void
Benjamin Romer3ab47702014-10-23 14:30:31 -04001365my_device_create(struct controlvm_message *inmsg)
Ken Cox12e364b2014-03-04 07:58:07 -06001366{
Benjamin Romer2ea51172014-10-23 14:30:25 -04001367 struct controlvm_message_packet *cmd = &inmsg->cmd;
Jes Sorensen52063ec2015-04-13 10:28:41 -04001368 u32 bus_no = cmd->create_device.bus_no;
1369 u32 dev_no = cmd->create_device.dev_no;
Jes Sorensene82ba622015-05-05 18:35:45 -04001370 struct visorchipset_device_info *dev_info;
1371 struct visorchipset_bus_info *bus_info;
Ken Cox12e364b2014-03-04 07:58:07 -06001372 int rc = CONTROLVM_RESP_SUCCESS;
1373
Jes Sorensend480f6a2015-05-05 18:35:54 -04001374 dev_info = device_find(&dev_info_list, bus_no, dev_no);
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001375 if (dev_info && (dev_info->state.created == 1)) {
1376 POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001377 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001378 rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001379 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001380 }
Jes Sorensen4f665202015-05-05 18:35:52 -04001381 bus_info = bus_find(&bus_info_list, bus_no);
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001382 if (!bus_info) {
1383 POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001384 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001385 rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001386 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001387 }
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001388 if (bus_info->state.created == 0) {
1389 POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001390 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001391 rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001392 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001393 }
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001394 dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL);
1395 if (!dev_info) {
1396 POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001397 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001398 rc = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001399 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001400 }
Andreea-Cristina Bernat97a84f12014-03-14 04:20:06 +02001401
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001402 INIT_LIST_HEAD(&dev_info->entry);
1403 dev_info->bus_no = bus_no;
1404 dev_info->dev_no = dev_no;
1405 dev_info->dev_inst_uuid = cmd->create_device.dev_inst_uuid;
1406 POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, dev_no, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001407 POSTCODE_SEVERITY_INFO);
1408
Benjamin Romer98d7b592014-10-23 14:30:26 -04001409 if (inmsg->hdr.flags.test_message == 1)
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001410 dev_info->chan_info.addr_type = ADDRTYPE_LOCALTEST;
Ken Cox12e364b2014-03-04 07:58:07 -06001411 else
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001412 dev_info->chan_info.addr_type = ADDRTYPE_LOCALPHYSICAL;
1413 dev_info->chan_info.channel_addr = cmd->create_device.channel_addr;
1414 dev_info->chan_info.n_channel_bytes = cmd->create_device.channel_bytes;
1415 dev_info->chan_info.channel_type_uuid =
Benjamin Romer9b1caee2014-10-31 09:57:23 -04001416 cmd->create_device.data_type_uuid;
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001417 dev_info->chan_info.intr = cmd->create_device.intr;
1418 list_add(&dev_info->entry, &dev_info_list);
1419 POSTCODE_LINUX_4(DEVICE_CREATE_EXIT_PC, dev_no, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001420 POSTCODE_SEVERITY_INFO);
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001421cleanup:
Ken Cox12e364b2014-03-04 07:58:07 -06001422 /* get the bus and devNo for DiagPool channel */
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001423 if (dev_info &&
1424 is_diagpool_channel(dev_info->chan_info.channel_type_uuid)) {
1425 g_diagpool_bus_no = bus_no;
1426 g_diagpool_dev_no = dev_no;
Ken Cox12e364b2014-03-04 07:58:07 -06001427 }
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001428 device_epilog(bus_no, dev_no, segment_state_running,
Ken Cox12e364b2014-03-04 07:58:07 -06001429 CONTROLVM_DEVICE_CREATE, &inmsg->hdr, rc,
David Kershner4da33362015-05-05 18:36:39 -04001430 inmsg->hdr.flags.response_expected == 1, 1);
Ken Cox12e364b2014-03-04 07:58:07 -06001431}
1432
1433static void
Benjamin Romer3ab47702014-10-23 14:30:31 -04001434my_device_changestate(struct controlvm_message *inmsg)
Ken Cox12e364b2014-03-04 07:58:07 -06001435{
Benjamin Romer2ea51172014-10-23 14:30:25 -04001436 struct controlvm_message_packet *cmd = &inmsg->cmd;
Jes Sorensen52063ec2015-04-13 10:28:41 -04001437 u32 bus_no = cmd->device_change_state.bus_no;
1438 u32 dev_no = cmd->device_change_state.dev_no;
Benjamin Romer2ea51172014-10-23 14:30:25 -04001439 struct spar_segment_state state = cmd->device_change_state.state;
Jes Sorensene82ba622015-05-05 18:35:45 -04001440 struct visorchipset_device_info *dev_info;
Ken Cox12e364b2014-03-04 07:58:07 -06001441 int rc = CONTROLVM_RESP_SUCCESS;
1442
Jes Sorensend480f6a2015-05-05 18:35:54 -04001443 dev_info = device_find(&dev_info_list, bus_no, dev_no);
Benjamin Romer0278a902015-03-16 13:58:24 -04001444 if (!dev_info) {
1445 POSTCODE_LINUX_4(DEVICE_CHANGESTATE_FAILURE_PC, dev_no, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001446 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001447 rc = -CONTROLVM_RESP_ERROR_DEVICE_INVALID;
Benjamin Romer0278a902015-03-16 13:58:24 -04001448 } else if (dev_info->state.created == 0) {
1449 POSTCODE_LINUX_4(DEVICE_CHANGESTATE_FAILURE_PC, dev_no, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001450 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001451 rc = -CONTROLVM_RESP_ERROR_DEVICE_INVALID;
Ken Cox12e364b2014-03-04 07:58:07 -06001452 }
Benjamin Romer0278a902015-03-16 13:58:24 -04001453 if ((rc >= CONTROLVM_RESP_SUCCESS) && dev_info)
1454 device_epilog(bus_no, dev_no, state,
1455 CONTROLVM_DEVICE_CHANGESTATE, &inmsg->hdr, rc,
David Kershner4da33362015-05-05 18:36:39 -04001456 inmsg->hdr.flags.response_expected == 1, 1);
Ken Cox12e364b2014-03-04 07:58:07 -06001457}
1458
1459static void
Benjamin Romer3ab47702014-10-23 14:30:31 -04001460my_device_destroy(struct controlvm_message *inmsg)
Ken Cox12e364b2014-03-04 07:58:07 -06001461{
Benjamin Romer2ea51172014-10-23 14:30:25 -04001462 struct controlvm_message_packet *cmd = &inmsg->cmd;
Jes Sorensen52063ec2015-04-13 10:28:41 -04001463 u32 bus_no = cmd->destroy_device.bus_no;
1464 u32 dev_no = cmd->destroy_device.dev_no;
Jes Sorensene82ba622015-05-05 18:35:45 -04001465 struct visorchipset_device_info *dev_info;
Ken Cox12e364b2014-03-04 07:58:07 -06001466 int rc = CONTROLVM_RESP_SUCCESS;
1467
Jes Sorensend480f6a2015-05-05 18:35:54 -04001468 dev_info = device_find(&dev_info_list, bus_no, dev_no);
Benjamin Romer61715c82015-03-16 13:58:25 -04001469 if (!dev_info)
Ken Cox22ad57b2014-03-19 13:06:25 -05001470 rc = -CONTROLVM_RESP_ERROR_DEVICE_INVALID;
Benjamin Romer61715c82015-03-16 13:58:25 -04001471 else if (dev_info->state.created == 0)
Ken Cox22ad57b2014-03-19 13:06:25 -05001472 rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
Ken Cox12e364b2014-03-04 07:58:07 -06001473
Benjamin Romer61715c82015-03-16 13:58:25 -04001474 if ((rc >= CONTROLVM_RESP_SUCCESS) && dev_info)
1475 device_epilog(bus_no, dev_no, segment_state_running,
Ken Cox12e364b2014-03-04 07:58:07 -06001476 CONTROLVM_DEVICE_DESTROY, &inmsg->hdr, rc,
David Kershner4da33362015-05-05 18:36:39 -04001477 inmsg->hdr.flags.response_expected == 1, 1);
Ken Cox12e364b2014-03-04 07:58:07 -06001478}
1479
1480/* When provided with the physical address of the controlvm channel
1481 * (phys_addr), the offset to the payload area we need to manage
1482 * (offset), and the size of this payload area (bytes), fills in the
Jes Sorensenf4c11552015-04-13 10:28:40 -04001483 * controlvm_payload_info struct. Returns true for success or false
Ken Cox12e364b2014-03-04 07:58:07 -06001484 * for failure.
1485 */
1486static int
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -04001487initialize_controlvm_payload_info(u64 phys_addr, u64 offset, u32 bytes,
Jes Sorensenc1f834e2015-04-13 10:28:39 -04001488 struct visor_controlvm_payload_info *info)
Ken Cox12e364b2014-03-04 07:58:07 -06001489{
Benjamin Romerc2422332014-07-29 15:09:40 -04001490 u8 __iomem *payload = NULL;
Ken Cox12e364b2014-03-04 07:58:07 -06001491 int rc = CONTROLVM_RESP_SUCCESS;
1492
Benjamin Romer38f736e2015-03-16 13:58:13 -04001493 if (!info) {
Ken Cox22ad57b2014-03-19 13:06:25 -05001494 rc = -CONTROLVM_RESP_ERROR_PAYLOAD_INVALID;
Benjamin Romerf118a392015-03-16 13:58:26 -04001495 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001496 }
Jes Sorensenc1f834e2015-04-13 10:28:39 -04001497 memset(info, 0, sizeof(struct visor_controlvm_payload_info));
Ken Cox12e364b2014-03-04 07:58:07 -06001498 if ((offset == 0) || (bytes == 0)) {
Ken Cox22ad57b2014-03-19 13:06:25 -05001499 rc = -CONTROLVM_RESP_ERROR_PAYLOAD_INVALID;
Benjamin Romerf118a392015-03-16 13:58:26 -04001500 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001501 }
1502 payload = ioremap_cache(phys_addr + offset, bytes);
Benjamin Romer38f736e2015-03-16 13:58:13 -04001503 if (!payload) {
Ken Cox22ad57b2014-03-19 13:06:25 -05001504 rc = -CONTROLVM_RESP_ERROR_IOREMAP_FAILED;
Benjamin Romerf118a392015-03-16 13:58:26 -04001505 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001506 }
1507
1508 info->offset = offset;
1509 info->bytes = bytes;
1510 info->ptr = payload;
Ken Cox12e364b2014-03-04 07:58:07 -06001511
Benjamin Romerf118a392015-03-16 13:58:26 -04001512cleanup:
Ken Cox12e364b2014-03-04 07:58:07 -06001513 if (rc < 0) {
Benjamin Romerf118a392015-03-16 13:58:26 -04001514 if (payload) {
Ken Cox12e364b2014-03-04 07:58:07 -06001515 iounmap(payload);
1516 payload = NULL;
1517 }
1518 }
1519 return rc;
1520}
1521
1522static void
Jes Sorensenc1f834e2015-04-13 10:28:39 -04001523destroy_controlvm_payload_info(struct visor_controlvm_payload_info *info)
Ken Cox12e364b2014-03-04 07:58:07 -06001524{
Benjamin Romer597c3382015-03-16 13:58:27 -04001525 if (info->ptr) {
Ken Cox12e364b2014-03-04 07:58:07 -06001526 iounmap(info->ptr);
1527 info->ptr = NULL;
1528 }
Jes Sorensenc1f834e2015-04-13 10:28:39 -04001529 memset(info, 0, sizeof(struct visor_controlvm_payload_info));
Ken Cox12e364b2014-03-04 07:58:07 -06001530}
1531
1532static void
1533initialize_controlvm_payload(void)
1534{
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -04001535 u64 phys_addr = visorchannel_get_physaddr(controlvm_channel);
Benjamin Romercafefc02015-03-16 13:58:28 -04001536 u64 payload_offset = 0;
1537 u32 payload_bytes = 0;
Benjamin Romer26eb2c02014-08-18 09:34:53 -04001538
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001539 if (visorchannel_read(controlvm_channel,
Benjamin Romerd19642f2014-10-23 14:30:34 -04001540 offsetof(struct spar_controlvm_channel_protocol,
1541 request_payload_offset),
Benjamin Romercafefc02015-03-16 13:58:28 -04001542 &payload_offset, sizeof(payload_offset)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06001543 POSTCODE_LINUX_2(CONTROLVM_INIT_FAILURE_PC,
1544 POSTCODE_SEVERITY_ERR);
1545 return;
1546 }
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001547 if (visorchannel_read(controlvm_channel,
Benjamin Romerd19642f2014-10-23 14:30:34 -04001548 offsetof(struct spar_controlvm_channel_protocol,
1549 request_payload_bytes),
Benjamin Romercafefc02015-03-16 13:58:28 -04001550 &payload_bytes, sizeof(payload_bytes)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06001551 POSTCODE_LINUX_2(CONTROLVM_INIT_FAILURE_PC,
1552 POSTCODE_SEVERITY_ERR);
1553 return;
1554 }
1555 initialize_controlvm_payload_info(phys_addr,
Benjamin Romercafefc02015-03-16 13:58:28 -04001556 payload_offset, payload_bytes,
Benjamin Romer84982fb2015-03-16 13:58:07 -04001557 &controlvm_payload_info);
Ken Cox12e364b2014-03-04 07:58:07 -06001558}
1559
1560/* Send ACTION=online for DEVPATH=/sys/devices/platform/visorchipset.
1561 * Returns CONTROLVM_RESP_xxx code.
1562 */
1563int
1564visorchipset_chipset_ready(void)
1565{
Benjamin Romereb34e872015-03-16 13:58:45 -04001566 kobject_uevent(&visorchipset_platform_device.dev.kobj, KOBJ_ONLINE);
Ken Cox12e364b2014-03-04 07:58:07 -06001567 return CONTROLVM_RESP_SUCCESS;
1568}
1569EXPORT_SYMBOL_GPL(visorchipset_chipset_ready);
1570
1571int
1572visorchipset_chipset_selftest(void)
1573{
1574 char env_selftest[20];
1575 char *envp[] = { env_selftest, NULL };
Benjamin Romer26eb2c02014-08-18 09:34:53 -04001576
Ken Cox12e364b2014-03-04 07:58:07 -06001577 sprintf(env_selftest, "SPARSP_SELFTEST=%d", 1);
Benjamin Romereb34e872015-03-16 13:58:45 -04001578 kobject_uevent_env(&visorchipset_platform_device.dev.kobj, KOBJ_CHANGE,
Ken Cox12e364b2014-03-04 07:58:07 -06001579 envp);
1580 return CONTROLVM_RESP_SUCCESS;
1581}
1582EXPORT_SYMBOL_GPL(visorchipset_chipset_selftest);
1583
1584/* Send ACTION=offline for DEVPATH=/sys/devices/platform/visorchipset.
1585 * Returns CONTROLVM_RESP_xxx code.
1586 */
1587int
1588visorchipset_chipset_notready(void)
1589{
Benjamin Romereb34e872015-03-16 13:58:45 -04001590 kobject_uevent(&visorchipset_platform_device.dev.kobj, KOBJ_OFFLINE);
Ken Cox12e364b2014-03-04 07:58:07 -06001591 return CONTROLVM_RESP_SUCCESS;
1592}
1593EXPORT_SYMBOL_GPL(visorchipset_chipset_notready);
1594
1595static void
Benjamin Romer77a04492015-03-16 13:58:47 -04001596chipset_ready(struct controlvm_message_header *msg_hdr)
Ken Cox12e364b2014-03-04 07:58:07 -06001597{
1598 int rc = visorchipset_chipset_ready();
Benjamin Romer26eb2c02014-08-18 09:34:53 -04001599
Ken Cox12e364b2014-03-04 07:58:07 -06001600 if (rc != CONTROLVM_RESP_SUCCESS)
1601 rc = -rc;
Benjamin Romer77a04492015-03-16 13:58:47 -04001602 if (msg_hdr->flags.response_expected && !visorchipset_holdchipsetready)
1603 controlvm_respond(msg_hdr, rc);
1604 if (msg_hdr->flags.response_expected && visorchipset_holdchipsetready) {
Ken Cox12e364b2014-03-04 07:58:07 -06001605 /* Send CHIPSET_READY response when all modules have been loaded
1606 * and disks mounted for the partition
1607 */
Benjamin Romer77a04492015-03-16 13:58:47 -04001608 g_chipset_msg_hdr = *msg_hdr;
Ken Cox12e364b2014-03-04 07:58:07 -06001609 }
1610}
1611
1612static void
Benjamin Romer77a04492015-03-16 13:58:47 -04001613chipset_selftest(struct controlvm_message_header *msg_hdr)
Ken Cox12e364b2014-03-04 07:58:07 -06001614{
1615 int rc = visorchipset_chipset_selftest();
Benjamin Romer26eb2c02014-08-18 09:34:53 -04001616
Ken Cox12e364b2014-03-04 07:58:07 -06001617 if (rc != CONTROLVM_RESP_SUCCESS)
1618 rc = -rc;
Benjamin Romer77a04492015-03-16 13:58:47 -04001619 if (msg_hdr->flags.response_expected)
1620 controlvm_respond(msg_hdr, rc);
Ken Cox12e364b2014-03-04 07:58:07 -06001621}
1622
1623static void
Benjamin Romer77a04492015-03-16 13:58:47 -04001624chipset_notready(struct controlvm_message_header *msg_hdr)
Ken Cox12e364b2014-03-04 07:58:07 -06001625{
1626 int rc = visorchipset_chipset_notready();
Benjamin Romer26eb2c02014-08-18 09:34:53 -04001627
Ken Cox12e364b2014-03-04 07:58:07 -06001628 if (rc != CONTROLVM_RESP_SUCCESS)
1629 rc = -rc;
Benjamin Romer77a04492015-03-16 13:58:47 -04001630 if (msg_hdr->flags.response_expected)
1631 controlvm_respond(msg_hdr, rc);
Ken Cox12e364b2014-03-04 07:58:07 -06001632}
1633
1634/* This is your "one-stop" shop for grabbing the next message from the
1635 * CONTROLVM_QUEUE_EVENT queue in the controlvm channel.
1636 */
Jes Sorensenf4c11552015-04-13 10:28:40 -04001637static bool
Benjamin Romer3ab47702014-10-23 14:30:31 -04001638read_controlvm_event(struct controlvm_message *msg)
Ken Cox12e364b2014-03-04 07:58:07 -06001639{
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001640 if (visorchannel_signalremove(controlvm_channel,
Ken Cox12e364b2014-03-04 07:58:07 -06001641 CONTROLVM_QUEUE_EVENT, msg)) {
1642 /* got a message */
Benjamin Romer0aca78442015-03-04 12:14:25 -05001643 if (msg->hdr.flags.test_message == 1)
Jes Sorensenf4c11552015-04-13 10:28:40 -04001644 return false;
1645 return true;
Ken Cox12e364b2014-03-04 07:58:07 -06001646 }
Jes Sorensenf4c11552015-04-13 10:28:40 -04001647 return false;
Ken Cox12e364b2014-03-04 07:58:07 -06001648}
1649
1650/*
1651 * The general parahotplug flow works as follows. The visorchipset
1652 * driver receives a DEVICE_CHANGESTATE message from Command
1653 * specifying a physical device to enable or disable. The CONTROLVM
1654 * message handler calls parahotplug_process_message, which then adds
1655 * the message to a global list and kicks off a udev event which
1656 * causes a user level script to enable or disable the specified
1657 * device. The udev script then writes to
1658 * /proc/visorchipset/parahotplug, which causes parahotplug_proc_write
1659 * to get called, at which point the appropriate CONTROLVM message is
1660 * retrieved from the list and responded to.
1661 */
1662
1663#define PARAHOTPLUG_TIMEOUT_MS 2000
1664
1665/*
1666 * Generate unique int to match an outstanding CONTROLVM message with a
1667 * udev script /proc response
1668 */
1669static int
1670parahotplug_next_id(void)
1671{
1672 static atomic_t id = ATOMIC_INIT(0);
Benjamin Romer26eb2c02014-08-18 09:34:53 -04001673
Ken Cox12e364b2014-03-04 07:58:07 -06001674 return atomic_inc_return(&id);
1675}
1676
1677/*
1678 * Returns the time (in jiffies) when a CONTROLVM message on the list
1679 * should expire -- PARAHOTPLUG_TIMEOUT_MS in the future
1680 */
1681static unsigned long
1682parahotplug_next_expiration(void)
1683{
Nicholas Mc Guire2cc1a1b2015-01-31 12:02:08 +01001684 return jiffies + msecs_to_jiffies(PARAHOTPLUG_TIMEOUT_MS);
Ken Cox12e364b2014-03-04 07:58:07 -06001685}
1686
1687/*
1688 * Create a parahotplug_request, which is basically a wrapper for a
1689 * CONTROLVM_MESSAGE that we can stick on a list
1690 */
1691static struct parahotplug_request *
Benjamin Romer3ab47702014-10-23 14:30:31 -04001692parahotplug_request_create(struct controlvm_message *msg)
Ken Cox12e364b2014-03-04 07:58:07 -06001693{
Quentin Lambertea0dcfc2015-02-10 15:12:07 +01001694 struct parahotplug_request *req;
1695
Benjamin Romer6a55e3c2015-03-16 13:58:30 -04001696 req = kmalloc(sizeof(*req), GFP_KERNEL | __GFP_NORETRY);
Benjamin Romer38f736e2015-03-16 13:58:13 -04001697 if (!req)
Ken Cox12e364b2014-03-04 07:58:07 -06001698 return NULL;
1699
1700 req->id = parahotplug_next_id();
1701 req->expiration = parahotplug_next_expiration();
1702 req->msg = *msg;
1703
1704 return req;
1705}
1706
1707/*
1708 * Free a parahotplug_request.
1709 */
1710static void
1711parahotplug_request_destroy(struct parahotplug_request *req)
1712{
1713 kfree(req);
1714}
1715
1716/*
1717 * Cause uevent to run the user level script to do the disable/enable
1718 * specified in (the CONTROLVM message in) the specified
1719 * parahotplug_request
1720 */
1721static void
1722parahotplug_request_kickoff(struct parahotplug_request *req)
1723{
Benjamin Romer2ea51172014-10-23 14:30:25 -04001724 struct controlvm_message_packet *cmd = &req->msg.cmd;
Ken Cox12e364b2014-03-04 07:58:07 -06001725 char env_cmd[40], env_id[40], env_state[40], env_bus[40], env_dev[40],
1726 env_func[40];
1727 char *envp[] = {
1728 env_cmd, env_id, env_state, env_bus, env_dev, env_func, NULL
1729 };
1730
1731 sprintf(env_cmd, "SPAR_PARAHOTPLUG=1");
1732 sprintf(env_id, "SPAR_PARAHOTPLUG_ID=%d", req->id);
1733 sprintf(env_state, "SPAR_PARAHOTPLUG_STATE=%d",
Benjamin Romer2ea51172014-10-23 14:30:25 -04001734 cmd->device_change_state.state.active);
Ken Cox12e364b2014-03-04 07:58:07 -06001735 sprintf(env_bus, "SPAR_PARAHOTPLUG_BUS=%d",
Benjamin Romer2ea51172014-10-23 14:30:25 -04001736 cmd->device_change_state.bus_no);
Ken Cox12e364b2014-03-04 07:58:07 -06001737 sprintf(env_dev, "SPAR_PARAHOTPLUG_DEVICE=%d",
Benjamin Romer2ea51172014-10-23 14:30:25 -04001738 cmd->device_change_state.dev_no >> 3);
Ken Cox12e364b2014-03-04 07:58:07 -06001739 sprintf(env_func, "SPAR_PARAHOTPLUG_FUNCTION=%d",
Benjamin Romer2ea51172014-10-23 14:30:25 -04001740 cmd->device_change_state.dev_no & 0x7);
Ken Cox12e364b2014-03-04 07:58:07 -06001741
Benjamin Romereb34e872015-03-16 13:58:45 -04001742 kobject_uevent_env(&visorchipset_platform_device.dev.kobj, KOBJ_CHANGE,
Ken Cox12e364b2014-03-04 07:58:07 -06001743 envp);
1744}
1745
1746/*
1747 * Remove any request from the list that's been on there too long and
1748 * respond with an error.
1749 */
1750static void
1751parahotplug_process_list(void)
1752{
Jes Sorensene82ba622015-05-05 18:35:45 -04001753 struct list_head *pos;
1754 struct list_head *tmp;
Ken Cox12e364b2014-03-04 07:58:07 -06001755
Benjamin Romerddf5de52015-03-16 13:58:41 -04001756 spin_lock(&parahotplug_request_list_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001757
Benjamin Romerddf5de52015-03-16 13:58:41 -04001758 list_for_each_safe(pos, tmp, &parahotplug_request_list) {
Ken Cox12e364b2014-03-04 07:58:07 -06001759 struct parahotplug_request *req =
1760 list_entry(pos, struct parahotplug_request, list);
Benjamin Romer55b33412015-03-16 13:58:29 -04001761
1762 if (!time_after_eq(jiffies, req->expiration))
1763 continue;
1764
1765 list_del(pos);
1766 if (req->msg.hdr.flags.response_expected)
1767 controlvm_respond_physdev_changestate(
1768 &req->msg.hdr,
1769 CONTROLVM_RESP_ERROR_DEVICE_UDEV_TIMEOUT,
1770 req->msg.cmd.device_change_state.state);
1771 parahotplug_request_destroy(req);
Ken Cox12e364b2014-03-04 07:58:07 -06001772 }
1773
Benjamin Romerddf5de52015-03-16 13:58:41 -04001774 spin_unlock(&parahotplug_request_list_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001775}
1776
1777/*
1778 * Called from the /proc handler, which means the user script has
1779 * finished the enable/disable. Find the matching identifier, and
1780 * respond to the CONTROLVM message with success.
1781 */
1782static int
Benjamin Romerb06bdf72014-07-31 12:00:49 -04001783parahotplug_request_complete(int id, u16 active)
Ken Cox12e364b2014-03-04 07:58:07 -06001784{
Jes Sorensene82ba622015-05-05 18:35:45 -04001785 struct list_head *pos;
1786 struct list_head *tmp;
Ken Cox12e364b2014-03-04 07:58:07 -06001787
Benjamin Romerddf5de52015-03-16 13:58:41 -04001788 spin_lock(&parahotplug_request_list_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001789
1790 /* Look for a request matching "id". */
Benjamin Romerddf5de52015-03-16 13:58:41 -04001791 list_for_each_safe(pos, tmp, &parahotplug_request_list) {
Ken Cox12e364b2014-03-04 07:58:07 -06001792 struct parahotplug_request *req =
1793 list_entry(pos, struct parahotplug_request, list);
1794 if (req->id == id) {
1795 /* Found a match. Remove it from the list and
1796 * respond.
1797 */
1798 list_del(pos);
Benjamin Romerddf5de52015-03-16 13:58:41 -04001799 spin_unlock(&parahotplug_request_list_lock);
Benjamin Romer2ea51172014-10-23 14:30:25 -04001800 req->msg.cmd.device_change_state.state.active = active;
Benjamin Romer98d7b592014-10-23 14:30:26 -04001801 if (req->msg.hdr.flags.response_expected)
Ken Cox12e364b2014-03-04 07:58:07 -06001802 controlvm_respond_physdev_changestate(
1803 &req->msg.hdr, CONTROLVM_RESP_SUCCESS,
Benjamin Romer2ea51172014-10-23 14:30:25 -04001804 req->msg.cmd.device_change_state.state);
Ken Cox12e364b2014-03-04 07:58:07 -06001805 parahotplug_request_destroy(req);
1806 return 0;
1807 }
1808 }
1809
Benjamin Romerddf5de52015-03-16 13:58:41 -04001810 spin_unlock(&parahotplug_request_list_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001811 return -1;
1812}
1813
1814/*
1815 * Enables or disables a PCI device by kicking off a udev script
1816 */
Ken Coxbd5b9b32014-03-13 15:39:22 -05001817static void
Benjamin Romer3ab47702014-10-23 14:30:31 -04001818parahotplug_process_message(struct controlvm_message *inmsg)
Ken Cox12e364b2014-03-04 07:58:07 -06001819{
1820 struct parahotplug_request *req;
1821
1822 req = parahotplug_request_create(inmsg);
1823
Benjamin Romer38f736e2015-03-16 13:58:13 -04001824 if (!req)
Ken Cox12e364b2014-03-04 07:58:07 -06001825 return;
Ken Cox12e364b2014-03-04 07:58:07 -06001826
Benjamin Romer2ea51172014-10-23 14:30:25 -04001827 if (inmsg->cmd.device_change_state.state.active) {
Ken Cox12e364b2014-03-04 07:58:07 -06001828 /* For enable messages, just respond with success
1829 * right away. This is a bit of a hack, but there are
1830 * issues with the early enable messages we get (with
1831 * either the udev script not detecting that the device
1832 * is up, or not getting called at all). Fortunately
1833 * the messages that get lost don't matter anyway, as
1834 * devices are automatically enabled at
1835 * initialization.
1836 */
1837 parahotplug_request_kickoff(req);
1838 controlvm_respond_physdev_changestate(&inmsg->hdr,
Benjamin Romer8e76e692015-03-16 13:58:52 -04001839 CONTROLVM_RESP_SUCCESS,
1840 inmsg->cmd.device_change_state.state);
Ken Cox12e364b2014-03-04 07:58:07 -06001841 parahotplug_request_destroy(req);
1842 } else {
1843 /* For disable messages, add the request to the
1844 * request list before kicking off the udev script. It
1845 * won't get responded to until the script has
1846 * indicated it's done.
1847 */
Benjamin Romerddf5de52015-03-16 13:58:41 -04001848 spin_lock(&parahotplug_request_list_lock);
1849 list_add_tail(&req->list, &parahotplug_request_list);
1850 spin_unlock(&parahotplug_request_list_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001851
1852 parahotplug_request_kickoff(req);
1853 }
1854}
1855
Ken Cox12e364b2014-03-04 07:58:07 -06001856/* Process a controlvm message.
1857 * Return result:
Prarit Bhargava779d0752015-05-05 18:37:01 -04001858 * false - this function will return false only in the case where the
Ken Cox12e364b2014-03-04 07:58:07 -06001859 * controlvm message was NOT processed, but processing must be
1860 * retried before reading the next controlvm message; a
1861 * scenario where this can occur is when we need to throttle
1862 * the allocation of memory in which to copy out controlvm
1863 * payload data
Jes Sorensenf4c11552015-04-13 10:28:40 -04001864 * true - processing of the controlvm message completed,
Ken Cox12e364b2014-03-04 07:58:07 -06001865 * either successfully or with an error.
1866 */
Jes Sorensenf4c11552015-04-13 10:28:40 -04001867static bool
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -04001868handle_command(struct controlvm_message inmsg, u64 channel_addr)
Ken Cox12e364b2014-03-04 07:58:07 -06001869{
Benjamin Romer2ea51172014-10-23 14:30:25 -04001870 struct controlvm_message_packet *cmd = &inmsg.cmd;
Jes Sorensene82ba622015-05-05 18:35:45 -04001871 u64 parm_addr;
1872 u32 parm_bytes;
Benjamin Romer317d9612015-03-16 13:57:51 -04001873 struct parser_context *parser_ctx = NULL;
Jes Sorensene82ba622015-05-05 18:35:45 -04001874 bool local_addr;
Benjamin Romer3ab47702014-10-23 14:30:31 -04001875 struct controlvm_message ackmsg;
Ken Cox12e364b2014-03-04 07:58:07 -06001876
1877 /* create parsing context if necessary */
Benjamin Romer818352a2015-03-16 13:58:31 -04001878 local_addr = (inmsg.hdr.flags.test_message == 1);
Benjamin Romer0aca78442015-03-04 12:14:25 -05001879 if (channel_addr == 0)
Jes Sorensenf4c11552015-04-13 10:28:40 -04001880 return true;
Benjamin Romer818352a2015-03-16 13:58:31 -04001881 parm_addr = channel_addr + inmsg.hdr.payload_vm_offset;
1882 parm_bytes = inmsg.hdr.payload_bytes;
Ken Cox12e364b2014-03-04 07:58:07 -06001883
1884 /* Parameter and channel addresses within test messages actually lie
1885 * within our OS-controlled memory. We need to know that, because it
1886 * makes a difference in how we compute the virtual address.
1887 */
Jes Sorensenebec8962015-05-05 18:35:57 -04001888 if (parm_addr && parm_bytes) {
Jes Sorensenf4c11552015-04-13 10:28:40 -04001889 bool retry = false;
Benjamin Romer26eb2c02014-08-18 09:34:53 -04001890
Ken Cox12e364b2014-03-04 07:58:07 -06001891 parser_ctx =
Benjamin Romer818352a2015-03-16 13:58:31 -04001892 parser_init_byte_stream(parm_addr, parm_bytes,
1893 local_addr, &retry);
Benjamin Romer1b088722015-03-04 12:14:26 -05001894 if (!parser_ctx && retry)
Jes Sorensenf4c11552015-04-13 10:28:40 -04001895 return false;
Ken Cox12e364b2014-03-04 07:58:07 -06001896 }
1897
Benjamin Romer818352a2015-03-16 13:58:31 -04001898 if (!local_addr) {
Ken Cox12e364b2014-03-04 07:58:07 -06001899 controlvm_init_response(&ackmsg, &inmsg.hdr,
1900 CONTROLVM_RESP_SUCCESS);
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001901 if (controlvm_channel)
1902 visorchannel_signalinsert(controlvm_channel,
Benjamin Romer1b088722015-03-04 12:14:26 -05001903 CONTROLVM_QUEUE_ACK,
1904 &ackmsg);
Ken Cox12e364b2014-03-04 07:58:07 -06001905 }
Benjamin Romer98d7b592014-10-23 14:30:26 -04001906 switch (inmsg.hdr.id) {
Ken Cox12e364b2014-03-04 07:58:07 -06001907 case CONTROLVM_CHIPSET_INIT:
Ken Cox12e364b2014-03-04 07:58:07 -06001908 chipset_init(&inmsg);
1909 break;
1910 case CONTROLVM_BUS_CREATE:
Ken Cox12e364b2014-03-04 07:58:07 -06001911 bus_create(&inmsg);
1912 break;
1913 case CONTROLVM_BUS_DESTROY:
Ken Cox12e364b2014-03-04 07:58:07 -06001914 bus_destroy(&inmsg);
1915 break;
1916 case CONTROLVM_BUS_CONFIGURE:
Ken Cox12e364b2014-03-04 07:58:07 -06001917 bus_configure(&inmsg, parser_ctx);
1918 break;
1919 case CONTROLVM_DEVICE_CREATE:
Ken Cox12e364b2014-03-04 07:58:07 -06001920 my_device_create(&inmsg);
1921 break;
1922 case CONTROLVM_DEVICE_CHANGESTATE:
Benjamin Romer2ea51172014-10-23 14:30:25 -04001923 if (cmd->device_change_state.flags.phys_device) {
Ken Cox12e364b2014-03-04 07:58:07 -06001924 parahotplug_process_message(&inmsg);
1925 } else {
Ken Cox12e364b2014-03-04 07:58:07 -06001926 /* save the hdr and cmd structures for later use */
1927 /* when sending back the response to Command */
1928 my_device_changestate(&inmsg);
Benjamin Romer4f44b722015-03-16 13:58:02 -04001929 g_devicechangestate_packet = inmsg.cmd;
Ken Cox12e364b2014-03-04 07:58:07 -06001930 break;
1931 }
1932 break;
1933 case CONTROLVM_DEVICE_DESTROY:
Ken Cox12e364b2014-03-04 07:58:07 -06001934 my_device_destroy(&inmsg);
1935 break;
1936 case CONTROLVM_DEVICE_CONFIGURE:
Ken Cox12e364b2014-03-04 07:58:07 -06001937 /* no op for now, just send a respond that we passed */
Benjamin Romer98d7b592014-10-23 14:30:26 -04001938 if (inmsg.hdr.flags.response_expected)
Ken Cox12e364b2014-03-04 07:58:07 -06001939 controlvm_respond(&inmsg.hdr, CONTROLVM_RESP_SUCCESS);
1940 break;
1941 case CONTROLVM_CHIPSET_READY:
Ken Cox12e364b2014-03-04 07:58:07 -06001942 chipset_ready(&inmsg.hdr);
1943 break;
1944 case CONTROLVM_CHIPSET_SELFTEST:
Ken Cox12e364b2014-03-04 07:58:07 -06001945 chipset_selftest(&inmsg.hdr);
1946 break;
1947 case CONTROLVM_CHIPSET_STOP:
Ken Cox12e364b2014-03-04 07:58:07 -06001948 chipset_notready(&inmsg.hdr);
1949 break;
1950 default:
Benjamin Romer98d7b592014-10-23 14:30:26 -04001951 if (inmsg.hdr.flags.response_expected)
Ken Cox12e364b2014-03-04 07:58:07 -06001952 controlvm_respond(&inmsg.hdr,
Benjamin Romer818352a2015-03-16 13:58:31 -04001953 -CONTROLVM_RESP_ERROR_MESSAGE_ID_UNKNOWN);
Ken Cox12e364b2014-03-04 07:58:07 -06001954 break;
1955 }
1956
Benjamin Romer38f736e2015-03-16 13:58:13 -04001957 if (parser_ctx) {
Ken Cox12e364b2014-03-04 07:58:07 -06001958 parser_done(parser_ctx);
1959 parser_ctx = NULL;
1960 }
Jes Sorensenf4c11552015-04-13 10:28:40 -04001961 return true;
Ken Cox12e364b2014-03-04 07:58:07 -06001962}
1963
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -04001964static u64 controlvm_get_channel_address(void)
Benjamin Romer524b0b62014-07-17 12:39:57 -04001965{
Benjamin Romer5fc02292014-07-31 12:00:51 -04001966 u64 addr = 0;
Benjamin Romerb3c55b12014-07-31 12:00:50 -04001967 u32 size = 0;
Benjamin Romer524b0b62014-07-17 12:39:57 -04001968
Benjamin Romer0aca78442015-03-04 12:14:25 -05001969 if (!VMCALL_SUCCESSFUL(issue_vmcall_io_controlvm_addr(&addr, &size)))
Benjamin Romer524b0b62014-07-17 12:39:57 -04001970 return 0;
Benjamin Romer0aca78442015-03-04 12:14:25 -05001971
Benjamin Romer524b0b62014-07-17 12:39:57 -04001972 return addr;
1973}
1974
Ken Cox12e364b2014-03-04 07:58:07 -06001975static void
1976controlvm_periodic_work(struct work_struct *work)
1977{
Benjamin Romer3ab47702014-10-23 14:30:31 -04001978 struct controlvm_message inmsg;
Jes Sorensenf4c11552015-04-13 10:28:40 -04001979 bool got_command = false;
1980 bool handle_command_failed = false;
Benjamin Romer1c1ed292015-03-16 13:58:32 -04001981 static u64 poll_count;
Ken Cox12e364b2014-03-04 07:58:07 -06001982
1983 /* make sure visorbus server is registered for controlvm callbacks */
David Kershner4da33362015-05-05 18:36:39 -04001984 if (visorchipset_visorbusregwait && !visorbusregistered)
Benjamin Romer1c1ed292015-03-16 13:58:32 -04001985 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001986
Benjamin Romer1c1ed292015-03-16 13:58:32 -04001987 poll_count++;
1988 if (poll_count >= 250)
Ken Cox12e364b2014-03-04 07:58:07 -06001989 ; /* keep going */
1990 else
Benjamin Romer1c1ed292015-03-16 13:58:32 -04001991 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001992
1993 /* Check events to determine if response to CHIPSET_READY
1994 * should be sent
1995 */
Benjamin Romer0639ba62015-03-16 13:58:04 -04001996 if (visorchipset_holdchipsetready &&
1997 (g_chipset_msg_hdr.id != CONTROLVM_INVALID)) {
Ken Cox12e364b2014-03-04 07:58:07 -06001998 if (check_chipset_events() == 1) {
Benjamin Romerda021f02015-03-16 13:57:58 -04001999 controlvm_respond(&g_chipset_msg_hdr, 0);
Ken Cox12e364b2014-03-04 07:58:07 -06002000 clear_chipset_events();
Benjamin Romerda021f02015-03-16 13:57:58 -04002001 memset(&g_chipset_msg_hdr, 0,
Benjamin Romer98d7b592014-10-23 14:30:26 -04002002 sizeof(struct controlvm_message_header));
Ken Cox12e364b2014-03-04 07:58:07 -06002003 }
2004 }
2005
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002006 while (visorchannel_signalremove(controlvm_channel,
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002007 CONTROLVM_QUEUE_RESPONSE,
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002008 &inmsg))
2009 ;
Benjamin Romer1c1ed292015-03-16 13:58:32 -04002010 if (!got_command) {
Benjamin Romer7166ed12015-03-16 13:58:38 -04002011 if (controlvm_pending_msg_valid) {
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002012 /* we throttled processing of a prior
2013 * msg, so try to process it again
2014 * rather than reading a new one
2015 */
Benjamin Romer7166ed12015-03-16 13:58:38 -04002016 inmsg = controlvm_pending_msg;
Jes Sorensenf4c11552015-04-13 10:28:40 -04002017 controlvm_pending_msg_valid = false;
Benjamin Romer1c1ed292015-03-16 13:58:32 -04002018 got_command = true;
Benjamin Romer75c1f8b2015-03-16 13:58:19 -04002019 } else {
Benjamin Romer1c1ed292015-03-16 13:58:32 -04002020 got_command = read_controlvm_event(&inmsg);
Benjamin Romer75c1f8b2015-03-16 13:58:19 -04002021 }
Ken Cox12e364b2014-03-04 07:58:07 -06002022 }
2023
Jes Sorensenf4c11552015-04-13 10:28:40 -04002024 handle_command_failed = false;
Benjamin Romer1c1ed292015-03-16 13:58:32 -04002025 while (got_command && (!handle_command_failed)) {
Benjamin Romerb53e0e92015-03-16 13:57:56 -04002026 most_recent_message_jiffies = jiffies;
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002027 if (handle_command(inmsg,
2028 visorchannel_get_physaddr
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002029 (controlvm_channel)))
Benjamin Romer1c1ed292015-03-16 13:58:32 -04002030 got_command = read_controlvm_event(&inmsg);
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002031 else {
2032 /* this is a scenario where throttling
2033 * is required, but probably NOT an
2034 * error...; we stash the current
2035 * controlvm msg so we will attempt to
2036 * reprocess it on our next loop
2037 */
Jes Sorensenf4c11552015-04-13 10:28:40 -04002038 handle_command_failed = true;
Benjamin Romer7166ed12015-03-16 13:58:38 -04002039 controlvm_pending_msg = inmsg;
Jes Sorensenf4c11552015-04-13 10:28:40 -04002040 controlvm_pending_msg_valid = true;
Ken Cox12e364b2014-03-04 07:58:07 -06002041 }
2042 }
2043
2044 /* parahotplug_worker */
2045 parahotplug_process_list();
2046
Benjamin Romer1c1ed292015-03-16 13:58:32 -04002047cleanup:
Ken Cox12e364b2014-03-04 07:58:07 -06002048
2049 if (time_after(jiffies,
Benjamin Romerb53e0e92015-03-16 13:57:56 -04002050 most_recent_message_jiffies + (HZ * MIN_IDLE_SECONDS))) {
Ken Cox12e364b2014-03-04 07:58:07 -06002051 /* it's been longer than MIN_IDLE_SECONDS since we
2052 * processed our last controlvm message; slow down the
2053 * polling
2054 */
Benjamin Romer911e2132015-03-16 13:57:47 -04002055 if (poll_jiffies != POLLJIFFIES_CONTROLVMCHANNEL_SLOW)
2056 poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_SLOW;
Ken Cox12e364b2014-03-04 07:58:07 -06002057 } else {
Benjamin Romer911e2132015-03-16 13:57:47 -04002058 if (poll_jiffies != POLLJIFFIES_CONTROLVMCHANNEL_FAST)
2059 poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
Ken Cox12e364b2014-03-04 07:58:07 -06002060 }
2061
Benjamin Romer9232d2d2015-03-16 13:57:57 -04002062 queue_delayed_work(periodic_controlvm_workqueue,
2063 &periodic_controlvm_work, poll_jiffies);
Ken Cox12e364b2014-03-04 07:58:07 -06002064}
2065
2066static void
2067setup_crash_devices_work_queue(struct work_struct *work)
2068{
Benjamin Romere6bdb902015-03-16 13:58:33 -04002069 struct controlvm_message local_crash_bus_msg;
2070 struct controlvm_message local_crash_dev_msg;
Benjamin Romer3ab47702014-10-23 14:30:31 -04002071 struct controlvm_message msg;
Benjamin Romere6bdb902015-03-16 13:58:33 -04002072 u32 local_crash_msg_offset;
2073 u16 local_crash_msg_count;
Ken Cox12e364b2014-03-04 07:58:07 -06002074
David Kershner4da33362015-05-05 18:36:39 -04002075 /* make sure visorbus is registered for controlvm callbacks */
2076 if (visorchipset_visorbusregwait && !visorbusregistered)
Benjamin Romere6bdb902015-03-16 13:58:33 -04002077 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06002078
2079 POSTCODE_LINUX_2(CRASH_DEV_ENTRY_PC, POSTCODE_SEVERITY_INFO);
2080
2081 /* send init chipset msg */
Benjamin Romer98d7b592014-10-23 14:30:26 -04002082 msg.hdr.id = CONTROLVM_CHIPSET_INIT;
Benjamin Romer2ea51172014-10-23 14:30:25 -04002083 msg.cmd.init_chipset.bus_count = 23;
2084 msg.cmd.init_chipset.switch_count = 0;
Ken Cox12e364b2014-03-04 07:58:07 -06002085
2086 chipset_init(&msg);
2087
Ken Cox12e364b2014-03-04 07:58:07 -06002088 /* get saved message count */
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002089 if (visorchannel_read(controlvm_channel,
Benjamin Romerd19642f2014-10-23 14:30:34 -04002090 offsetof(struct spar_controlvm_channel_protocol,
2091 saved_crash_message_count),
Benjamin Romere6bdb902015-03-16 13:58:33 -04002092 &local_crash_msg_count, sizeof(u16)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06002093 POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
2094 POSTCODE_SEVERITY_ERR);
2095 return;
2096 }
2097
Benjamin Romere6bdb902015-03-16 13:58:33 -04002098 if (local_crash_msg_count != CONTROLVM_CRASHMSG_MAX) {
Ken Cox12e364b2014-03-04 07:58:07 -06002099 POSTCODE_LINUX_3(CRASH_DEV_COUNT_FAILURE_PC,
Benjamin Romere6bdb902015-03-16 13:58:33 -04002100 local_crash_msg_count,
Ken Cox12e364b2014-03-04 07:58:07 -06002101 POSTCODE_SEVERITY_ERR);
2102 return;
2103 }
2104
2105 /* get saved crash message offset */
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002106 if (visorchannel_read(controlvm_channel,
Benjamin Romerd19642f2014-10-23 14:30:34 -04002107 offsetof(struct spar_controlvm_channel_protocol,
2108 saved_crash_message_offset),
Benjamin Romere6bdb902015-03-16 13:58:33 -04002109 &local_crash_msg_offset, sizeof(u32)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06002110 POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
2111 POSTCODE_SEVERITY_ERR);
2112 return;
2113 }
2114
2115 /* read create device message for storage bus offset */
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002116 if (visorchannel_read(controlvm_channel,
Benjamin Romere6bdb902015-03-16 13:58:33 -04002117 local_crash_msg_offset,
2118 &local_crash_bus_msg,
Benjamin Romer3ab47702014-10-23 14:30:31 -04002119 sizeof(struct controlvm_message)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06002120 POSTCODE_LINUX_2(CRASH_DEV_RD_BUS_FAIULRE_PC,
2121 POSTCODE_SEVERITY_ERR);
2122 return;
2123 }
2124
2125 /* read create device message for storage device */
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002126 if (visorchannel_read(controlvm_channel,
Benjamin Romere6bdb902015-03-16 13:58:33 -04002127 local_crash_msg_offset +
Benjamin Romer3ab47702014-10-23 14:30:31 -04002128 sizeof(struct controlvm_message),
Benjamin Romere6bdb902015-03-16 13:58:33 -04002129 &local_crash_dev_msg,
Benjamin Romer3ab47702014-10-23 14:30:31 -04002130 sizeof(struct controlvm_message)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06002131 POSTCODE_LINUX_2(CRASH_DEV_RD_DEV_FAIULRE_PC,
2132 POSTCODE_SEVERITY_ERR);
2133 return;
2134 }
2135
2136 /* reuse IOVM create bus message */
Jes Sorensenebec8962015-05-05 18:35:57 -04002137 if (local_crash_bus_msg.cmd.create_bus.channel_addr) {
Benjamin Romere6bdb902015-03-16 13:58:33 -04002138 bus_create(&local_crash_bus_msg);
Benjamin Romer75c1f8b2015-03-16 13:58:19 -04002139 } else {
Ken Cox12e364b2014-03-04 07:58:07 -06002140 POSTCODE_LINUX_2(CRASH_DEV_BUS_NULL_FAILURE_PC,
2141 POSTCODE_SEVERITY_ERR);
2142 return;
2143 }
2144
2145 /* reuse create device message for storage device */
Jes Sorensenebec8962015-05-05 18:35:57 -04002146 if (local_crash_dev_msg.cmd.create_device.channel_addr) {
Benjamin Romere6bdb902015-03-16 13:58:33 -04002147 my_device_create(&local_crash_dev_msg);
Benjamin Romer75c1f8b2015-03-16 13:58:19 -04002148 } else {
Ken Cox12e364b2014-03-04 07:58:07 -06002149 POSTCODE_LINUX_2(CRASH_DEV_DEV_NULL_FAILURE_PC,
2150 POSTCODE_SEVERITY_ERR);
2151 return;
2152 }
Ken Cox12e364b2014-03-04 07:58:07 -06002153 POSTCODE_LINUX_2(CRASH_DEV_EXIT_PC, POSTCODE_SEVERITY_INFO);
2154 return;
2155
Benjamin Romere6bdb902015-03-16 13:58:33 -04002156cleanup:
Ken Cox12e364b2014-03-04 07:58:07 -06002157
Benjamin Romer911e2132015-03-16 13:57:47 -04002158 poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_SLOW;
Ken Cox12e364b2014-03-04 07:58:07 -06002159
Benjamin Romer9232d2d2015-03-16 13:57:57 -04002160 queue_delayed_work(periodic_controlvm_workqueue,
2161 &periodic_controlvm_work, poll_jiffies);
Ken Cox12e364b2014-03-04 07:58:07 -06002162}
2163
2164static void
Jes Sorensen52063ec2015-04-13 10:28:41 -04002165bus_create_response(u32 bus_no, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06002166{
Benjamin Romer8e3fedd2015-03-16 13:58:43 -04002167 bus_responder(CONTROLVM_BUS_CREATE, bus_no, response);
Ken Cox12e364b2014-03-04 07:58:07 -06002168}
2169
2170static void
Jes Sorensen52063ec2015-04-13 10:28:41 -04002171bus_destroy_response(u32 bus_no, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06002172{
Benjamin Romer8e3fedd2015-03-16 13:58:43 -04002173 bus_responder(CONTROLVM_BUS_DESTROY, bus_no, response);
Ken Cox12e364b2014-03-04 07:58:07 -06002174}
2175
2176static void
Jes Sorensen52063ec2015-04-13 10:28:41 -04002177device_create_response(u32 bus_no, u32 dev_no, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06002178{
Benjamin Romer8e3fedd2015-03-16 13:58:43 -04002179 device_responder(CONTROLVM_DEVICE_CREATE, bus_no, dev_no, response);
Ken Cox12e364b2014-03-04 07:58:07 -06002180}
2181
2182static void
Jes Sorensen52063ec2015-04-13 10:28:41 -04002183device_destroy_response(u32 bus_no, u32 dev_no, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06002184{
Benjamin Romer8e3fedd2015-03-16 13:58:43 -04002185 device_responder(CONTROLVM_DEVICE_DESTROY, bus_no, dev_no, response);
Ken Cox12e364b2014-03-04 07:58:07 -06002186}
2187
2188void
Jes Sorensen52063ec2015-04-13 10:28:41 -04002189visorchipset_device_pause_response(u32 bus_no, u32 dev_no, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06002190{
Ken Cox12e364b2014-03-04 07:58:07 -06002191 device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE,
Benjamin Romer8420f412014-10-31 09:57:36 -04002192 bus_no, dev_no, response,
Benjamin Romerbd0d2dc2014-10-23 14:30:13 -04002193 segment_state_standby);
Ken Cox12e364b2014-03-04 07:58:07 -06002194}
Ken Cox927c7922014-03-05 14:52:25 -06002195EXPORT_SYMBOL_GPL(visorchipset_device_pause_response);
Ken Cox12e364b2014-03-04 07:58:07 -06002196
2197static void
Jes Sorensen52063ec2015-04-13 10:28:41 -04002198device_resume_response(u32 bus_no, u32 dev_no, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06002199{
2200 device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE,
Benjamin Romer8e3fedd2015-03-16 13:58:43 -04002201 bus_no, dev_no, response,
Benjamin Romerbd0d2dc2014-10-23 14:30:13 -04002202 segment_state_running);
Ken Cox12e364b2014-03-04 07:58:07 -06002203}
2204
Jes Sorensenf4c11552015-04-13 10:28:40 -04002205bool
Jes Sorensen52063ec2015-04-13 10:28:41 -04002206visorchipset_get_bus_info(u32 bus_no, struct visorchipset_bus_info *bus_info)
Ken Cox12e364b2014-03-04 07:58:07 -06002207{
Jes Sorensen4f665202015-05-05 18:35:52 -04002208 void *p = bus_find(&bus_info_list, bus_no);
Benjamin Romer26eb2c02014-08-18 09:34:53 -04002209
Benjamin Romer0aca78442015-03-04 12:14:25 -05002210 if (!p)
Jes Sorensenf4c11552015-04-13 10:28:40 -04002211 return false;
Benjamin Romer77db7122014-10-31 09:57:37 -04002212 memcpy(bus_info, p, sizeof(struct visorchipset_bus_info));
Jes Sorensenf4c11552015-04-13 10:28:40 -04002213 return true;
Ken Cox12e364b2014-03-04 07:58:07 -06002214}
2215EXPORT_SYMBOL_GPL(visorchipset_get_bus_info);
2216
Jes Sorensenf4c11552015-04-13 10:28:40 -04002217bool
Jes Sorensen52063ec2015-04-13 10:28:41 -04002218visorchipset_set_bus_context(u32 bus_no, void *context)
Ken Cox12e364b2014-03-04 07:58:07 -06002219{
Jes Sorensen4f665202015-05-05 18:35:52 -04002220 struct visorchipset_bus_info *p = bus_find(&bus_info_list, bus_no);
Benjamin Romer26eb2c02014-08-18 09:34:53 -04002221
Benjamin Romer0aca78442015-03-04 12:14:25 -05002222 if (!p)
Jes Sorensenf4c11552015-04-13 10:28:40 -04002223 return false;
Ken Cox12e364b2014-03-04 07:58:07 -06002224 p->bus_driver_context = context;
Jes Sorensenf4c11552015-04-13 10:28:40 -04002225 return true;
Ken Cox12e364b2014-03-04 07:58:07 -06002226}
2227EXPORT_SYMBOL_GPL(visorchipset_set_bus_context);
2228
Jes Sorensenf4c11552015-04-13 10:28:40 -04002229bool
Jes Sorensen52063ec2015-04-13 10:28:41 -04002230visorchipset_get_device_info(u32 bus_no, u32 dev_no,
Benjamin Romerb486df12014-10-31 09:57:38 -04002231 struct visorchipset_device_info *dev_info)
Ken Cox12e364b2014-03-04 07:58:07 -06002232{
Jes Sorensend480f6a2015-05-05 18:35:54 -04002233 void *p = device_find(&dev_info_list, bus_no, dev_no);
Benjamin Romer26eb2c02014-08-18 09:34:53 -04002234
Benjamin Romer0aca78442015-03-04 12:14:25 -05002235 if (!p)
Jes Sorensenf4c11552015-04-13 10:28:40 -04002236 return false;
Benjamin Romerb486df12014-10-31 09:57:38 -04002237 memcpy(dev_info, p, sizeof(struct visorchipset_device_info));
Jes Sorensenf4c11552015-04-13 10:28:40 -04002238 return true;
Ken Cox12e364b2014-03-04 07:58:07 -06002239}
2240EXPORT_SYMBOL_GPL(visorchipset_get_device_info);
2241
Jes Sorensenf4c11552015-04-13 10:28:40 -04002242bool
Jes Sorensen52063ec2015-04-13 10:28:41 -04002243visorchipset_set_device_context(u32 bus_no, u32 dev_no, void *context)
Ken Cox12e364b2014-03-04 07:58:07 -06002244{
Jes Sorensend480f6a2015-05-05 18:35:54 -04002245 struct visorchipset_device_info *p;
2246
2247 p = device_find(&dev_info_list, bus_no, dev_no);
Benjamin Romer26eb2c02014-08-18 09:34:53 -04002248
Benjamin Romer0aca78442015-03-04 12:14:25 -05002249 if (!p)
Jes Sorensenf4c11552015-04-13 10:28:40 -04002250 return false;
Ken Cox12e364b2014-03-04 07:58:07 -06002251 p->bus_driver_context = context;
Jes Sorensenf4c11552015-04-13 10:28:40 -04002252 return true;
Ken Cox12e364b2014-03-04 07:58:07 -06002253}
2254EXPORT_SYMBOL_GPL(visorchipset_set_device_context);
2255
2256/* Generic wrapper function for allocating memory from a kmem_cache pool.
2257 */
2258void *
Jes Sorensenf4c11552015-04-13 10:28:40 -04002259visorchipset_cache_alloc(struct kmem_cache *pool, bool ok_to_block,
Ken Cox12e364b2014-03-04 07:58:07 -06002260 char *fn, int ln)
2261{
2262 gfp_t gfp;
2263 void *p;
2264
2265 if (ok_to_block)
2266 gfp = GFP_KERNEL;
2267 else
2268 gfp = GFP_ATOMIC;
2269 /* __GFP_NORETRY means "ok to fail", meaning
2270 * kmem_cache_alloc() can return NULL, implying the caller CAN
2271 * cope with failure. If you do NOT specify __GFP_NORETRY,
2272 * Linux will go to extreme measures to get memory for you
2273 * (like, invoke oom killer), which will probably cripple the
2274 * system.
2275 */
2276 gfp |= __GFP_NORETRY;
2277 p = kmem_cache_alloc(pool, gfp);
Benjamin Romer0aca78442015-03-04 12:14:25 -05002278 if (!p)
Ken Cox12e364b2014-03-04 07:58:07 -06002279 return NULL;
Benjamin Romer0aca78442015-03-04 12:14:25 -05002280
Ken Cox12e364b2014-03-04 07:58:07 -06002281 return p;
2282}
2283
2284/* Generic wrapper function for freeing memory from a kmem_cache pool.
2285 */
2286void
2287visorchipset_cache_free(struct kmem_cache *pool, void *p, char *fn, int ln)
2288{
Benjamin Romer0aca78442015-03-04 12:14:25 -05002289 if (!p)
Ken Cox12e364b2014-03-04 07:58:07 -06002290 return;
Benjamin Romer0aca78442015-03-04 12:14:25 -05002291
Ken Cox12e364b2014-03-04 07:58:07 -06002292 kmem_cache_free(pool, p);
2293}
2294
Benjamin Romer18b87ed2014-07-24 14:08:43 -04002295static ssize_t chipsetready_store(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -04002296 struct device_attribute *attr,
2297 const char *buf, size_t count)
Ken Cox12e364b2014-03-04 07:58:07 -06002298{
Benjamin Romer18b87ed2014-07-24 14:08:43 -04002299 char msgtype[64];
Ken Cox12e364b2014-03-04 07:58:07 -06002300
Benjamin Romer66e24b72014-07-25 13:55:10 -04002301 if (sscanf(buf, "%63s", msgtype) != 1)
Ken Cox12e364b2014-03-04 07:58:07 -06002302 return -EINVAL;
Benjamin Romer66e24b72014-07-25 13:55:10 -04002303
Jes Sorensenebec8962015-05-05 18:35:57 -04002304 if (!strcmp(msgtype, "CALLHOMEDISK_MOUNTED")) {
Benjamin Romer66e24b72014-07-25 13:55:10 -04002305 chipset_events[0] = 1;
2306 return count;
Jes Sorensenebec8962015-05-05 18:35:57 -04002307 } else if (!strcmp(msgtype, "MODULES_LOADED")) {
Benjamin Romer66e24b72014-07-25 13:55:10 -04002308 chipset_events[1] = 1;
2309 return count;
Benjamin Romere22a4a02014-08-18 09:34:54 -04002310 }
2311 return -EINVAL;
Ken Cox12e364b2014-03-04 07:58:07 -06002312}
2313
Benjamin Romere56fa7c2014-07-29 11:11:21 -04002314/* The parahotplug/devicedisabled interface gets called by our support script
2315 * when an SR-IOV device has been shut down. The ID is passed to the script
2316 * and then passed back when the device has been removed.
2317 */
2318static ssize_t devicedisabled_store(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -04002319 struct device_attribute *attr,
2320 const char *buf, size_t count)
Benjamin Romere56fa7c2014-07-29 11:11:21 -04002321{
Jes Sorensen94217362015-05-05 18:35:46 -04002322 unsigned int id;
Benjamin Romere56fa7c2014-07-29 11:11:21 -04002323
Jes Sorensenebec8962015-05-05 18:35:57 -04002324 if (kstrtouint(buf, 10, &id))
Benjamin Romere56fa7c2014-07-29 11:11:21 -04002325 return -EINVAL;
2326
2327 parahotplug_request_complete(id, 0);
2328 return count;
2329}
2330
2331/* The parahotplug/deviceenabled interface gets called by our support script
2332 * when an SR-IOV device has been recovered. The ID is passed to the script
2333 * and then passed back when the device has been brought back up.
2334 */
2335static ssize_t deviceenabled_store(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -04002336 struct device_attribute *attr,
2337 const char *buf, size_t count)
Benjamin Romere56fa7c2014-07-29 11:11:21 -04002338{
Jes Sorensen94217362015-05-05 18:35:46 -04002339 unsigned int id;
Benjamin Romere56fa7c2014-07-29 11:11:21 -04002340
Jes Sorensenebec8962015-05-05 18:35:57 -04002341 if (kstrtouint(buf, 10, &id))
Benjamin Romere56fa7c2014-07-29 11:11:21 -04002342 return -EINVAL;
2343
2344 parahotplug_request_complete(id, 1);
2345 return count;
2346}
2347
Erik Arfvidsone3420ed2015-05-05 18:36:13 -04002348static int
2349visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
2350{
2351 unsigned long physaddr = 0;
2352 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
Erik Arfvidson780fcad2015-05-05 18:36:35 -04002353 u64 addr = 0;
Erik Arfvidsone3420ed2015-05-05 18:36:13 -04002354
2355 /* sv_enable_dfp(); */
2356 if (offset & (PAGE_SIZE - 1))
2357 return -ENXIO; /* need aligned offsets */
2358
2359 switch (offset) {
2360 case VISORCHIPSET_MMAP_CONTROLCHANOFFSET:
2361 vma->vm_flags |= VM_IO;
2362 if (!*file_controlvm_channel)
2363 return -ENXIO;
2364
2365 visorchannel_read(*file_controlvm_channel,
2366 offsetof(struct spar_controlvm_channel_protocol,
2367 gp_control_channel),
2368 &addr, sizeof(addr));
2369 if (!addr)
2370 return -ENXIO;
2371
2372 physaddr = (unsigned long)addr;
2373 if (remap_pfn_range(vma, vma->vm_start,
2374 physaddr >> PAGE_SHIFT,
2375 vma->vm_end - vma->vm_start,
2376 /*pgprot_noncached */
2377 (vma->vm_page_prot))) {
2378 return -EAGAIN;
2379 }
2380 break;
2381 default:
2382 return -ENXIO;
2383 }
2384 return 0;
2385}
2386
2387static long visorchipset_ioctl(struct file *file, unsigned int cmd,
2388 unsigned long arg)
2389{
2390 s64 adjustment;
2391 s64 vrtc_offset;
2392
2393 switch (cmd) {
2394 case VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET:
2395 /* get the physical rtc offset */
2396 vrtc_offset = issue_vmcall_query_guest_virtual_time_offset();
2397 if (copy_to_user((void __user *)arg, &vrtc_offset,
2398 sizeof(vrtc_offset))) {
2399 return -EFAULT;
2400 }
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -04002401 return 0;
Erik Arfvidsone3420ed2015-05-05 18:36:13 -04002402 case VMCALL_UPDATE_PHYSICAL_TIME:
2403 if (copy_from_user(&adjustment, (void __user *)arg,
2404 sizeof(adjustment))) {
2405 return -EFAULT;
2406 }
2407 return issue_vmcall_update_physical_time(adjustment);
2408 default:
2409 return -EFAULT;
2410 }
2411}
2412
2413static const struct file_operations visorchipset_fops = {
2414 .owner = THIS_MODULE,
2415 .open = visorchipset_open,
2416 .read = NULL,
2417 .write = NULL,
2418 .unlocked_ioctl = visorchipset_ioctl,
2419 .release = visorchipset_release,
2420 .mmap = visorchipset_mmap,
2421};
2422
2423int
2424visorchipset_file_init(dev_t major_dev, struct visorchannel **controlvm_channel)
2425{
2426 int rc = 0;
2427
2428 file_controlvm_channel = controlvm_channel;
2429 cdev_init(&file_cdev, &visorchipset_fops);
2430 file_cdev.owner = THIS_MODULE;
2431 if (MAJOR(major_dev) == 0) {
Erik Arfvidson46168812015-05-05 18:36:14 -04002432 rc = alloc_chrdev_region(&major_dev, 0, 1, "visorchipset");
Erik Arfvidsone3420ed2015-05-05 18:36:13 -04002433 /* dynamic major device number registration required */
2434 if (rc < 0)
2435 return rc;
2436 } else {
2437 /* static major device number registration required */
Erik Arfvidson46168812015-05-05 18:36:14 -04002438 rc = register_chrdev_region(major_dev, 1, "visorchipset");
Erik Arfvidsone3420ed2015-05-05 18:36:13 -04002439 if (rc < 0)
2440 return rc;
2441 }
2442 rc = cdev_add(&file_cdev, MKDEV(MAJOR(major_dev), 0), 1);
2443 if (rc < 0) {
2444 unregister_chrdev_region(major_dev, 1);
2445 return rc;
2446 }
2447 return 0;
2448}
2449
Prarit Bhargava55c67dc2015-05-05 18:37:02 -04002450static int
2451visorchipset_init(struct acpi_device *acpi_device)
Ken Cox12e364b2014-03-04 07:58:07 -06002452{
David Kershner33078252015-05-05 18:36:48 -04002453 int rc = 0;
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -04002454 u64 addr;
Ken Cox12e364b2014-03-04 07:58:07 -06002455
David Kershner4da33362015-05-05 18:36:39 -04002456 memset(&busdev_notifiers, 0, sizeof(busdev_notifiers));
Benjamin Romer84982fb2015-03-16 13:58:07 -04002457 memset(&controlvm_payload_info, 0, sizeof(controlvm_payload_info));
Benjamin Romerea33b4ee52015-03-16 13:58:08 -04002458 memset(&livedump_info, 0, sizeof(livedump_info));
2459 atomic_set(&livedump_info.buffers_in_use, 0);
Ken Cox12e364b2014-03-04 07:58:07 -06002460
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002461 addr = controlvm_get_channel_address();
Jes Sorensenebec8962015-05-05 18:35:57 -04002462 if (addr) {
Jes Sorensendf942472015-05-05 18:37:10 -04002463 int tmp_sz = sizeof(struct spar_controlvm_channel_protocol);
2464 uuid_le uuid = SPAR_CONTROLVM_CHANNEL_PROTOCOL_UUID;
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002465 controlvm_channel =
Jes Sorensendf942472015-05-05 18:37:10 -04002466 visorchannel_create_with_lock(addr, tmp_sz,
2467 GFP_KERNEL, uuid);
Benjamin Romer93a84562014-10-23 14:30:05 -04002468 if (SPAR_CONTROLVM_CHANNEL_OK_CLIENT(
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002469 visorchannel_get_header(controlvm_channel))) {
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002470 initialize_controlvm_payload();
2471 } else {
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002472 visorchannel_destroy(controlvm_channel);
2473 controlvm_channel = NULL;
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002474 return -ENODEV;
2475 }
2476 } else {
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002477 return -ENODEV;
2478 }
2479
Benjamin Romer5aa8ae52015-03-16 13:58:44 -04002480 major_dev = MKDEV(visorchipset_major, 0);
2481 rc = visorchipset_file_init(major_dev, &controlvm_channel);
Ken Cox4cb005a2014-03-19 13:06:20 -05002482 if (rc < 0) {
Ken Cox4cb005a2014-03-19 13:06:20 -05002483 POSTCODE_LINUX_2(CHIPSET_INIT_FAILURE_PC, DIAG_SEVERITY_ERR);
Benjamin Romera6a39892015-03-16 13:58:34 -04002484 goto cleanup;
Ken Cox4cb005a2014-03-19 13:06:20 -05002485 }
Ken Cox9f8d0e82014-03-19 13:06:19 -05002486
Benjamin Romerda021f02015-03-16 13:57:58 -04002487 memset(&g_chipset_msg_hdr, 0, sizeof(struct controlvm_message_header));
Ken Cox12e364b2014-03-04 07:58:07 -06002488
David Kershner4da33362015-05-05 18:36:39 -04002489 /* if booting in a crash kernel */
2490 if (is_kdump_kernel())
2491 INIT_DELAYED_WORK(&periodic_controlvm_work,
2492 setup_crash_devices_work_queue);
2493 else
2494 INIT_DELAYED_WORK(&periodic_controlvm_work,
2495 controlvm_periodic_work);
2496 periodic_controlvm_workqueue =
2497 create_singlethread_workqueue("visorchipset_controlvm");
Ken Cox12e364b2014-03-04 07:58:07 -06002498
David Kershner4da33362015-05-05 18:36:39 -04002499 if (!periodic_controlvm_workqueue) {
2500 POSTCODE_LINUX_2(CREATE_WORKQUEUE_FAILED_PC,
2501 DIAG_SEVERITY_ERR);
2502 rc = -ENOMEM;
2503 goto cleanup;
2504 }
2505 most_recent_message_jiffies = jiffies;
2506 poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
2507 rc = queue_delayed_work(periodic_controlvm_workqueue,
2508 &periodic_controlvm_work, poll_jiffies);
2509 if (rc < 0) {
2510 POSTCODE_LINUX_2(QUEUE_DELAYED_WORK_PC,
2511 DIAG_SEVERITY_ERR);
2512 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06002513 }
2514
Benjamin Romereb34e872015-03-16 13:58:45 -04002515 visorchipset_platform_device.dev.devt = major_dev;
2516 if (platform_device_register(&visorchipset_platform_device) < 0) {
Ken Cox4cb005a2014-03-19 13:06:20 -05002517 POSTCODE_LINUX_2(DEVICE_REGISTER_FAILURE_PC, DIAG_SEVERITY_ERR);
2518 rc = -1;
Benjamin Romera6a39892015-03-16 13:58:34 -04002519 goto cleanup;
Ken Cox4cb005a2014-03-19 13:06:20 -05002520 }
Ken Cox12e364b2014-03-04 07:58:07 -06002521 POSTCODE_LINUX_2(CHIPSET_INIT_SUCCESS_PC, POSTCODE_SEVERITY_INFO);
Prarit Bhargavac79b28f2015-05-05 18:36:15 -04002522
2523 rc = visorbus_init();
Benjamin Romera6a39892015-03-16 13:58:34 -04002524cleanup:
Ken Cox12e364b2014-03-04 07:58:07 -06002525 if (rc) {
Ken Cox12e364b2014-03-04 07:58:07 -06002526 POSTCODE_LINUX_3(CHIPSET_INIT_FAILURE_PC, rc,
2527 POSTCODE_SEVERITY_ERR);
2528 }
2529 return rc;
2530}
2531
Erik Arfvidsone3420ed2015-05-05 18:36:13 -04002532void
2533visorchipset_file_cleanup(dev_t major_dev)
2534{
2535 if (file_cdev.ops)
2536 cdev_del(&file_cdev);
2537 file_cdev.ops = NULL;
2538 unregister_chrdev_region(major_dev, 1);
2539}
2540
Prarit Bhargava55c67dc2015-05-05 18:37:02 -04002541static int
2542visorchipset_exit(struct acpi_device *acpi_device)
Ken Cox12e364b2014-03-04 07:58:07 -06002543{
Ken Cox12e364b2014-03-04 07:58:07 -06002544 POSTCODE_LINUX_2(DRIVER_EXIT_PC, POSTCODE_SEVERITY_INFO);
2545
Prarit Bhargavac79b28f2015-05-05 18:36:15 -04002546 visorbus_exit();
2547
David Kershner4da33362015-05-05 18:36:39 -04002548 cancel_delayed_work(&periodic_controlvm_work);
2549 flush_workqueue(periodic_controlvm_workqueue);
2550 destroy_workqueue(periodic_controlvm_workqueue);
2551 periodic_controlvm_workqueue = NULL;
2552 destroy_controlvm_payload_info(&controlvm_payload_info);
Benjamin Romer17833192014-07-15 13:30:41 -04002553
Ken Cox12e364b2014-03-04 07:58:07 -06002554 cleanup_controlvm_structures();
2555
Benjamin Romerda021f02015-03-16 13:57:58 -04002556 memset(&g_chipset_msg_hdr, 0, sizeof(struct controlvm_message_header));
Ken Cox12e364b2014-03-04 07:58:07 -06002557
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002558 visorchannel_destroy(controlvm_channel);
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002559
Sudip Mukherjeeaddceb12015-03-24 20:47:28 +05302560 visorchipset_file_cleanup(visorchipset_platform_device.dev.devt);
Ken Cox12e364b2014-03-04 07:58:07 -06002561 POSTCODE_LINUX_2(DRIVER_EXIT_PC, POSTCODE_SEVERITY_INFO);
Prarit Bhargava55c67dc2015-05-05 18:37:02 -04002562
2563 return 0;
2564}
2565
2566static const struct acpi_device_id unisys_device_ids[] = {
2567 {"PNP0A07", 0},
2568 {"", 0},
2569};
Prarit Bhargava55c67dc2015-05-05 18:37:02 -04002570
2571static struct acpi_driver unisys_acpi_driver = {
2572 .name = "unisys_acpi",
2573 .class = "unisys_acpi_class",
2574 .owner = THIS_MODULE,
2575 .ids = unisys_device_ids,
2576 .ops = {
2577 .add = visorchipset_init,
2578 .remove = visorchipset_exit,
2579 },
2580};
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -04002581static __init uint32_t visorutil_spar_detect(void)
2582{
2583 unsigned int eax, ebx, ecx, edx;
2584
2585 if (cpu_has_hypervisor) {
2586 /* check the ID */
2587 cpuid(UNISYS_SPAR_LEAF_ID, &eax, &ebx, &ecx, &edx);
2588 return (ebx == UNISYS_SPAR_ID_EBX) &&
2589 (ecx == UNISYS_SPAR_ID_ECX) &&
2590 (edx == UNISYS_SPAR_ID_EDX);
2591 } else {
2592 return 0;
2593 }
2594}
Prarit Bhargava55c67dc2015-05-05 18:37:02 -04002595
2596static int init_unisys(void)
2597{
2598 int result;
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -04002599 if (!visorutil_spar_detect())
Prarit Bhargava55c67dc2015-05-05 18:37:02 -04002600 return -ENODEV;
2601
2602 result = acpi_bus_register_driver(&unisys_acpi_driver);
2603 if (result)
2604 return -ENODEV;
2605
2606 pr_info("Unisys Visorchipset Driver Loaded.\n");
2607 return 0;
2608};
2609
2610static void exit_unisys(void)
2611{
2612 acpi_bus_unregister_driver(&unisys_acpi_driver);
Ken Cox12e364b2014-03-04 07:58:07 -06002613}
2614
Ken Cox12e364b2014-03-04 07:58:07 -06002615module_param_named(major, visorchipset_major, int, S_IRUGO);
Jes Sorensenb615d622015-05-05 18:35:38 -04002616MODULE_PARM_DESC(visorchipset_major,
2617 "major device number to use for the device node");
David Kershner4da33362015-05-05 18:36:39 -04002618module_param_named(visorbusregwait, visorchipset_visorbusregwait, int, S_IRUGO);
2619MODULE_PARM_DESC(visorchipset_visorbusreqwait,
Ken Cox12e364b2014-03-04 07:58:07 -06002620 "1 to have the module wait for the visor bus to register");
Ken Cox12e364b2014-03-04 07:58:07 -06002621module_param_named(holdchipsetready, visorchipset_holdchipsetready,
2622 int, S_IRUGO);
2623MODULE_PARM_DESC(visorchipset_holdchipsetready,
2624 "1 to hold response to CHIPSET_READY");
Jes Sorensenb615d622015-05-05 18:35:38 -04002625
Prarit Bhargava55c67dc2015-05-05 18:37:02 -04002626module_init(init_unisys);
2627module_exit(exit_unisys);
Ken Cox12e364b2014-03-04 07:58:07 -06002628
2629MODULE_AUTHOR("Unisys");
2630MODULE_LICENSE("GPL");
2631MODULE_DESCRIPTION("Supervisor chipset driver for service partition: ver "
2632 VERSION);
2633MODULE_VERSION(VERSION);