blob: e61ec342c2ea3b68436e36cd92e82538d94c78d7 [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
473struct parser_context *
474parser_init(u64 addr, u32 bytes, bool local, bool *retry)
475{
476 return parser_init_guts(addr, bytes, local, true, retry);
477}
478
479/* Call this instead of parser_init() if the payload area consists of just
480 * a sequence of bytes, rather than a struct spar_controlvm_parameters_header
481 * structures. Afterwards, you can call parser_simpleString_get() or
482 * parser_byteStream_get() to obtain the data.
483 */
484struct parser_context *
485parser_init_byte_stream(u64 addr, u32 bytes, bool local, bool *retry)
486{
487 return parser_init_guts(addr, bytes, local, false, retry);
488}
489
490/* Obtain '\0'-terminated copy of string in payload area.
491 */
492char *
493parser_simpleString_get(struct parser_context *ctx)
494{
495 if (!ctx->byte_stream)
496 return NULL;
497 return ctx->data; /* note this IS '\0'-terminated, because of
498 * the num of bytes we alloc+clear in
499 * parser_init_byteStream() */
500}
501
502/* Obtain a copy of the buffer in the payload area.
503 */
504void *parser_byte_stream_get(struct parser_context *ctx, unsigned long *nbytes)
505{
506 if (!ctx->byte_stream)
507 return NULL;
508 if (nbytes)
509 *nbytes = ctx->param_bytes;
510 return (void *)ctx->data;
511}
512
513uuid_le
514parser_id_get(struct parser_context *ctx)
515{
516 struct spar_controlvm_parameters_header *phdr = NULL;
517
518 if (ctx == NULL)
519 return NULL_UUID_LE;
520 phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
521 return phdr->id;
522}
523
Prarit Bhargava2ee0dee2015-05-05 18:36:16 -0400524/** Describes the state from the perspective of which controlvm messages have
525 * been received for a bus or device.
526 */
527
528enum PARSER_WHICH_STRING {
529 PARSERSTRING_INITIATOR,
530 PARSERSTRING_TARGET,
531 PARSERSTRING_CONNECTION,
532 PARSERSTRING_NAME, /* TODO: only PARSERSTRING_NAME is used ? */
533};
534
Erik Arfvidson46168812015-05-05 18:36:14 -0400535void
Prarit Bhargava2ee0dee2015-05-05 18:36:16 -0400536parser_param_start(struct parser_context *ctx,
537 enum PARSER_WHICH_STRING which_string)
Erik Arfvidson46168812015-05-05 18:36:14 -0400538{
539 struct spar_controlvm_parameters_header *phdr = NULL;
540
541 if (ctx == NULL)
542 goto Away;
543 phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
544 switch (which_string) {
545 case PARSERSTRING_INITIATOR:
546 ctx->curr = ctx->data + phdr->initiator_offset;
547 ctx->bytes_remaining = phdr->initiator_length;
548 break;
549 case PARSERSTRING_TARGET:
550 ctx->curr = ctx->data + phdr->target_offset;
551 ctx->bytes_remaining = phdr->target_length;
552 break;
553 case PARSERSTRING_CONNECTION:
554 ctx->curr = ctx->data + phdr->connection_offset;
555 ctx->bytes_remaining = phdr->connection_length;
556 break;
557 case PARSERSTRING_NAME:
558 ctx->curr = ctx->data + phdr->name_offset;
559 ctx->bytes_remaining = phdr->name_length;
560 break;
561 default:
562 break;
563 }
564
565Away:
566 return;
567}
568
569void
570parser_done(struct parser_context *ctx)
571{
572 if (!ctx)
573 return;
574 controlvm_payload_bytes_buffered -= ctx->param_bytes;
575 kfree(ctx);
576}
577
578/** Return length of string not counting trailing spaces. */
579static int
580string_length_no_trail(char *s, int len)
581{
582 int i = len - 1;
583
584 while (i >= 0) {
585 if (!isspace(s[i]))
586 return i + 1;
587 i--;
588 }
589 return 0;
590}
591
592/** Grab the next name and value out of the parameter buffer.
593 * The entire parameter buffer looks like this:
594 * <name>=<value>\0
595 * <name>=<value>\0
596 * ...
597 * \0
598 * If successful, the next <name> value is returned within the supplied
599 * <nam> buffer (the value is always upper-cased), and the corresponding
600 * <value> is returned within a kmalloc()ed buffer, whose pointer is
601 * provided as the return value of this function.
602 * (The total number of bytes allocated is strlen(<value>)+1.)
603 *
604 * NULL is returned to indicate failure, which can occur for several reasons:
605 * - all <name>=<value> pairs have already been processed
606 * - bad parameter
607 * - parameter buffer ends prematurely (couldn't find an '=' or '\0' within
608 * the confines of the parameter buffer)
609 * - the <nam> buffer is not large enough to hold the <name> of the next
610 * parameter
611 */
612void *
613parser_param_get(struct parser_context *ctx, char *nam, int namesize)
614{
615 u8 *pscan, *pnam = nam;
616 unsigned long nscan;
617 int value_length = -1, orig_value_length = -1;
618 void *value = NULL;
619 int i;
620 int closing_quote = 0;
621
622 if (!ctx)
623 return NULL;
624 pscan = ctx->curr;
625 nscan = ctx->bytes_remaining;
626 if (nscan == 0)
627 return NULL;
628 if (*pscan == '\0')
629 /* This is the normal return point after you have processed
630 * all of the <name>=<value> pairs in a syntactically-valid
631 * parameter buffer.
632 */
633 return NULL;
634
635 /* skip whitespace */
636 while (isspace(*pscan)) {
637 pscan++;
638 nscan--;
639 if (nscan == 0)
640 return NULL;
641 }
642
643 while (*pscan != ':') {
644 if (namesize <= 0)
645 return NULL;
646 *pnam = toupper(*pscan);
647 pnam++;
648 namesize--;
649 pscan++;
650 nscan--;
651 if (nscan == 0)
652 return NULL;
653 }
654 if (namesize <= 0)
655 return NULL;
656 *pnam = '\0';
657 nam[string_length_no_trail(nam, strlen(nam))] = '\0';
658
659 /* point to char immediately after ":" in "<name>:<value>" */
660 pscan++;
661 nscan--;
662 /* skip whitespace */
663 while (isspace(*pscan)) {
664 pscan++;
665 nscan--;
666 if (nscan == 0)
667 return NULL;
668 }
669 if (nscan == 0)
670 return NULL;
671 if (*pscan == '\'' || *pscan == '"') {
672 closing_quote = *pscan;
673 pscan++;
674 nscan--;
675 if (nscan == 0)
676 return NULL;
677 }
678
679 /* look for a separator character, terminator character, or
680 * end of data
681 */
682 for (i = 0, value_length = -1; i < nscan; i++) {
683 if (closing_quote) {
684 if (pscan[i] == '\0')
685 return NULL;
686 if (pscan[i] == closing_quote) {
687 value_length = i;
688 break;
689 }
690 } else
691 if (pscan[i] == ',' || pscan[i] == ';'
692 || pscan[i] == '\0') {
693 value_length = i;
694 break;
695 }
696 }
697 if (value_length < 0) {
698 if (closing_quote)
699 return NULL;
700 value_length = nscan;
701 }
702 orig_value_length = value_length;
703 if (closing_quote == 0)
704 value_length = string_length_no_trail(pscan, orig_value_length);
705 value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY);
706 if (value == NULL)
707 return NULL;
708 memcpy(value, pscan, value_length);
709 ((u8 *) (value))[value_length] = '\0';
710
711 pscan += orig_value_length;
712 nscan -= orig_value_length;
713
714 /* skip past separator or closing quote */
715 if (nscan > 0) {
716 if (*pscan != '\0') {
717 pscan++;
718 nscan--;
719 }
720 }
721
722 if (closing_quote && (nscan > 0)) {
723 /* we still need to skip around the real separator if present */
724 /* first, skip whitespace */
725 while (isspace(*pscan)) {
726 pscan++;
727 nscan--;
728 if (nscan == 0)
729 break;
730 }
731 if (nscan > 0) {
732 if (*pscan == ',' || *pscan == ';') {
733 pscan++;
734 nscan--;
735 } else if (*pscan != '\0') {
736 kfree(value);
737 value = NULL;
738 return NULL;
739 }
740 }
741 }
742 ctx->curr = pscan;
743 ctx->bytes_remaining = nscan;
744 return value;
745}
746
747void *
748parser_string_get(struct parser_context *ctx)
749{
750 u8 *pscan;
751 unsigned long nscan;
752 int value_length = -1;
753 void *value = NULL;
754 int i;
755
756 if (!ctx)
757 return NULL;
758 pscan = ctx->curr;
759 nscan = ctx->bytes_remaining;
760 if (nscan == 0)
761 return NULL;
762 if (!pscan)
763 return NULL;
764 for (i = 0, value_length = -1; i < nscan; i++)
765 if (pscan[i] == '\0') {
766 value_length = i;
767 break;
768 }
769 if (value_length < 0) /* '\0' was not included in the length */
770 value_length = nscan;
771 value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY);
772 if (value == NULL)
773 return NULL;
774 if (value_length > 0)
775 memcpy(value, pscan, value_length);
776 ((u8 *) (value))[value_length] = '\0';
777 return value;
778}
779
780
Vincent Bernatd746cb52014-08-01 10:29:30 +0200781static ssize_t toolaction_show(struct device *dev,
782 struct device_attribute *attr,
783 char *buf)
Benjamin Romer19f66342014-07-22 09:56:25 -0400784{
Benjamin Romer01f4d852015-03-16 13:58:48 -0400785 u8 tool_action;
Benjamin Romer19f66342014-07-22 09:56:25 -0400786
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400787 visorchannel_read(controlvm_channel,
Benjamin Romerd19642f2014-10-23 14:30:34 -0400788 offsetof(struct spar_controlvm_channel_protocol,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400789 tool_action), &tool_action, sizeof(u8));
Benjamin Romer01f4d852015-03-16 13:58:48 -0400790 return scnprintf(buf, PAGE_SIZE, "%u\n", tool_action);
Benjamin Romer19f66342014-07-22 09:56:25 -0400791}
792
Vincent Bernatd746cb52014-08-01 10:29:30 +0200793static ssize_t toolaction_store(struct device *dev,
794 struct device_attribute *attr,
795 const char *buf, size_t count)
Benjamin Romer19f66342014-07-22 09:56:25 -0400796{
Benjamin Romer01f4d852015-03-16 13:58:48 -0400797 u8 tool_action;
Benjamin Romer66e24b72014-07-25 13:55:10 -0400798 int ret;
Benjamin Romer19f66342014-07-22 09:56:25 -0400799
Jes Sorensenebec8962015-05-05 18:35:57 -0400800 if (kstrtou8(buf, 10, &tool_action))
Benjamin Romer66e24b72014-07-25 13:55:10 -0400801 return -EINVAL;
802
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400803 ret = visorchannel_write(controlvm_channel,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400804 offsetof(struct spar_controlvm_channel_protocol,
805 tool_action),
Benjamin Romer01f4d852015-03-16 13:58:48 -0400806 &tool_action, sizeof(u8));
Benjamin Romer66e24b72014-07-25 13:55:10 -0400807
808 if (ret)
809 return ret;
Benjamin Romere22a4a02014-08-18 09:34:54 -0400810 return count;
Benjamin Romer19f66342014-07-22 09:56:25 -0400811}
812
Vincent Bernatd746cb52014-08-01 10:29:30 +0200813static ssize_t boottotool_show(struct device *dev,
814 struct device_attribute *attr,
815 char *buf)
Benjamin Romer54b31222014-07-22 09:56:26 -0400816{
Benjamin Romer365522d2015-03-16 13:58:49 -0400817 struct efi_spar_indication efi_spar_indication;
Benjamin Romer54b31222014-07-22 09:56:26 -0400818
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400819 visorchannel_read(controlvm_channel,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400820 offsetof(struct spar_controlvm_channel_protocol,
821 efi_spar_ind), &efi_spar_indication,
822 sizeof(struct efi_spar_indication));
Benjamin Romer54b31222014-07-22 09:56:26 -0400823 return scnprintf(buf, PAGE_SIZE, "%u\n",
Benjamin Romer8e76e692015-03-16 13:58:52 -0400824 efi_spar_indication.boot_to_tool);
Benjamin Romer54b31222014-07-22 09:56:26 -0400825}
826
Vincent Bernatd746cb52014-08-01 10:29:30 +0200827static ssize_t boottotool_store(struct device *dev,
828 struct device_attribute *attr,
829 const char *buf, size_t count)
Benjamin Romer54b31222014-07-22 09:56:26 -0400830{
Benjamin Romer66e24b72014-07-25 13:55:10 -0400831 int val, ret;
Benjamin Romer365522d2015-03-16 13:58:49 -0400832 struct efi_spar_indication efi_spar_indication;
Benjamin Romer54b31222014-07-22 09:56:26 -0400833
Jes Sorensenebec8962015-05-05 18:35:57 -0400834 if (kstrtoint(buf, 10, &val))
Benjamin Romer66e24b72014-07-25 13:55:10 -0400835 return -EINVAL;
836
Benjamin Romer365522d2015-03-16 13:58:49 -0400837 efi_spar_indication.boot_to_tool = val;
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400838 ret = visorchannel_write(controlvm_channel,
Benjamin Romerd19642f2014-10-23 14:30:34 -0400839 offsetof(struct spar_controlvm_channel_protocol,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400840 efi_spar_ind), &(efi_spar_indication),
841 sizeof(struct efi_spar_indication));
Benjamin Romer66e24b72014-07-25 13:55:10 -0400842
843 if (ret)
844 return ret;
Benjamin Romere22a4a02014-08-18 09:34:54 -0400845 return count;
Benjamin Romer54b31222014-07-22 09:56:26 -0400846}
Benjamin Romer422af172014-07-24 14:08:42 -0400847
848static ssize_t error_show(struct device *dev, struct device_attribute *attr,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400849 char *buf)
Benjamin Romer422af172014-07-24 14:08:42 -0400850{
851 u32 error;
852
Benjamin Romer8e76e692015-03-16 13:58:52 -0400853 visorchannel_read(controlvm_channel,
854 offsetof(struct spar_controlvm_channel_protocol,
855 installation_error),
856 &error, sizeof(u32));
Benjamin Romer422af172014-07-24 14:08:42 -0400857 return scnprintf(buf, PAGE_SIZE, "%i\n", error);
858}
859
860static ssize_t error_store(struct device *dev, struct device_attribute *attr,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400861 const char *buf, size_t count)
Benjamin Romer422af172014-07-24 14:08:42 -0400862{
863 u32 error;
Benjamin Romer66e24b72014-07-25 13:55:10 -0400864 int ret;
Benjamin Romer422af172014-07-24 14:08:42 -0400865
Jes Sorensenebec8962015-05-05 18:35:57 -0400866 if (kstrtou32(buf, 10, &error))
Benjamin Romer66e24b72014-07-25 13:55:10 -0400867 return -EINVAL;
868
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400869 ret = visorchannel_write(controlvm_channel,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400870 offsetof(struct spar_controlvm_channel_protocol,
871 installation_error),
872 &error, sizeof(u32));
Benjamin Romer66e24b72014-07-25 13:55:10 -0400873 if (ret)
874 return ret;
Benjamin Romere22a4a02014-08-18 09:34:54 -0400875 return count;
Benjamin Romer422af172014-07-24 14:08:42 -0400876}
877
878static ssize_t textid_show(struct device *dev, struct device_attribute *attr,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400879 char *buf)
Benjamin Romer422af172014-07-24 14:08:42 -0400880{
Benjamin Romer10dbf0e2015-03-16 13:58:50 -0400881 u32 text_id;
Benjamin Romer422af172014-07-24 14:08:42 -0400882
Benjamin Romer8e76e692015-03-16 13:58:52 -0400883 visorchannel_read(controlvm_channel,
884 offsetof(struct spar_controlvm_channel_protocol,
885 installation_text_id),
886 &text_id, sizeof(u32));
Benjamin Romer10dbf0e2015-03-16 13:58:50 -0400887 return scnprintf(buf, PAGE_SIZE, "%i\n", text_id);
Benjamin Romer422af172014-07-24 14:08:42 -0400888}
889
890static ssize_t textid_store(struct device *dev, struct device_attribute *attr,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400891 const char *buf, size_t count)
Benjamin Romer422af172014-07-24 14:08:42 -0400892{
Benjamin Romer10dbf0e2015-03-16 13:58:50 -0400893 u32 text_id;
Benjamin Romer66e24b72014-07-25 13:55:10 -0400894 int ret;
Benjamin Romer422af172014-07-24 14:08:42 -0400895
Jes Sorensenebec8962015-05-05 18:35:57 -0400896 if (kstrtou32(buf, 10, &text_id))
Benjamin Romer66e24b72014-07-25 13:55:10 -0400897 return -EINVAL;
898
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400899 ret = visorchannel_write(controlvm_channel,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400900 offsetof(struct spar_controlvm_channel_protocol,
901 installation_text_id),
902 &text_id, sizeof(u32));
Benjamin Romer66e24b72014-07-25 13:55:10 -0400903 if (ret)
904 return ret;
Benjamin Romere22a4a02014-08-18 09:34:54 -0400905 return count;
Benjamin Romer422af172014-07-24 14:08:42 -0400906}
907
Benjamin Romer422af172014-07-24 14:08:42 -0400908static ssize_t remaining_steps_show(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400909 struct device_attribute *attr, char *buf)
Benjamin Romer422af172014-07-24 14:08:42 -0400910{
Benjamin Romeree8da292015-03-16 13:58:51 -0400911 u16 remaining_steps;
Benjamin Romer422af172014-07-24 14:08:42 -0400912
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400913 visorchannel_read(controlvm_channel,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400914 offsetof(struct spar_controlvm_channel_protocol,
915 installation_remaining_steps),
916 &remaining_steps, sizeof(u16));
Benjamin Romeree8da292015-03-16 13:58:51 -0400917 return scnprintf(buf, PAGE_SIZE, "%hu\n", remaining_steps);
Benjamin Romer422af172014-07-24 14:08:42 -0400918}
919
920static ssize_t remaining_steps_store(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400921 struct device_attribute *attr,
922 const char *buf, size_t count)
Benjamin Romer422af172014-07-24 14:08:42 -0400923{
Benjamin Romeree8da292015-03-16 13:58:51 -0400924 u16 remaining_steps;
Benjamin Romer66e24b72014-07-25 13:55:10 -0400925 int ret;
Benjamin Romer422af172014-07-24 14:08:42 -0400926
Jes Sorensenebec8962015-05-05 18:35:57 -0400927 if (kstrtou16(buf, 10, &remaining_steps))
Benjamin Romer66e24b72014-07-25 13:55:10 -0400928 return -EINVAL;
929
Benjamin Romerc3d9a222015-03-16 13:58:05 -0400930 ret = visorchannel_write(controlvm_channel,
Benjamin Romer8e76e692015-03-16 13:58:52 -0400931 offsetof(struct spar_controlvm_channel_protocol,
932 installation_remaining_steps),
933 &remaining_steps, sizeof(u16));
Benjamin Romer66e24b72014-07-25 13:55:10 -0400934 if (ret)
935 return ret;
Benjamin Romere22a4a02014-08-18 09:34:54 -0400936 return count;
Benjamin Romer422af172014-07-24 14:08:42 -0400937}
938
Ken Cox12e364b2014-03-04 07:58:07 -0600939static void
Benjamin Romer9b989a982015-03-16 13:58:11 -0400940bus_info_clear(void *v)
Ken Cox12e364b2014-03-04 07:58:07 -0600941{
Jes Sorensenbbd4be32015-05-05 18:35:43 -0400942 struct visorchipset_bus_info *p = (struct visorchipset_bus_info *) v;
Ken Cox12e364b2014-03-04 07:58:07 -0600943
Ken Cox12e364b2014-03-04 07:58:07 -0600944 kfree(p->name);
Ken Cox12e364b2014-03-04 07:58:07 -0600945 kfree(p->description);
Benjamin Romer33192fa2014-10-31 09:57:27 -0400946 memset(p, 0, sizeof(struct visorchipset_bus_info));
Ken Cox12e364b2014-03-04 07:58:07 -0600947}
948
949static void
Benjamin Romer9b989a982015-03-16 13:58:11 -0400950dev_info_clear(void *v)
Ken Cox12e364b2014-03-04 07:58:07 -0600951{
Benjamin Romer246e0cd2014-10-31 09:57:24 -0400952 struct visorchipset_device_info *p =
Jes Sorensenbbd4be32015-05-05 18:35:43 -0400953 (struct visorchipset_device_info *) v;
Benjamin Romer26eb2c02014-08-18 09:34:53 -0400954
Benjamin Romer246e0cd2014-10-31 09:57:24 -0400955 memset(p, 0, sizeof(struct visorchipset_device_info));
Ken Cox12e364b2014-03-04 07:58:07 -0600956}
957
Jes Sorensen4f665202015-05-05 18:35:52 -0400958static struct visorchipset_bus_info *
959bus_find(struct list_head *list, u32 bus_no)
960{
961 struct visorchipset_bus_info *p;
962
963 list_for_each_entry(p, list, entry) {
964 if (p->bus_no == bus_no)
965 return p;
966 }
967
968 return NULL;
969}
970
Jes Sorensend480f6a2015-05-05 18:35:54 -0400971static struct visorchipset_device_info *
972device_find(struct list_head *list, u32 bus_no, u32 dev_no)
973{
974 struct visorchipset_device_info *p;
975
976 list_for_each_entry(p, list, entry) {
977 if (p->bus_no == bus_no && p->dev_no == dev_no)
978 return p;
979 }
980
981 return NULL;
982}
983
Jes Sorensen28723522015-05-05 18:35:55 -0400984static void busdevices_del(struct list_head *list, u32 bus_no)
985{
986 struct visorchipset_device_info *p, *tmp;
987
988 list_for_each_entry_safe(p, tmp, list, entry) {
989 if (p->bus_no == bus_no) {
990 list_del(&p->entry);
991 kfree(p);
992 }
993 }
994}
995
Benjamin Romerc2422332014-07-29 15:09:40 -0400996static u8
Ken Cox12e364b2014-03-04 07:58:07 -0600997check_chipset_events(void)
998{
999 int i;
Benjamin Romerc2422332014-07-29 15:09:40 -04001000 u8 send_msg = 1;
Ken Cox12e364b2014-03-04 07:58:07 -06001001 /* Check events to determine if response should be sent */
1002 for (i = 0; i < MAX_CHIPSET_EVENTS; i++)
1003 send_msg &= chipset_events[i];
1004 return send_msg;
1005}
1006
1007static void
1008clear_chipset_events(void)
1009{
1010 int i;
1011 /* Clear chipset_events */
1012 for (i = 0; i < MAX_CHIPSET_EVENTS; i++)
1013 chipset_events[i] = 0;
1014}
1015
1016void
David Kershner4da33362015-05-05 18:36:39 -04001017visorchipset_register_busdev(
Benjamin Romerfe90d892014-10-31 09:57:32 -04001018 struct visorchipset_busdev_notifiers *notifiers,
Benjamin Romer929aa8a2014-10-31 09:57:33 -04001019 struct visorchipset_busdev_responders *responders,
Benjamin Romer1e7a59c2014-10-31 09:57:35 -04001020 struct ultra_vbus_deviceinfo *driver_info)
Ken Cox12e364b2014-03-04 07:58:07 -06001021{
Benjamin Romer8f1947a2015-03-16 13:57:59 -04001022 down(&notifier_lock);
Benjamin Romer38f736e2015-03-16 13:58:13 -04001023 if (!notifiers) {
David Kershner4da33362015-05-05 18:36:39 -04001024 memset(&busdev_notifiers, 0,
1025 sizeof(busdev_notifiers));
1026 visorbusregistered = 0; /* clear flag */
Ken Cox12e364b2014-03-04 07:58:07 -06001027 } else {
David Kershner4da33362015-05-05 18:36:39 -04001028 busdev_notifiers = *notifiers;
1029 visorbusregistered = 1; /* set flag */
Ken Cox12e364b2014-03-04 07:58:07 -06001030 }
1031 if (responders)
Benjamin Romer8e3fedd2015-03-16 13:58:43 -04001032 *responders = busdev_responders;
Benjamin Romer1e7a59c2014-10-31 09:57:35 -04001033 if (driver_info)
1034 bus_device_info_init(driver_info, "chipset", "visorchipset",
Benjamin Romer8e76e692015-03-16 13:58:52 -04001035 VERSION, NULL);
Ken Cox12e364b2014-03-04 07:58:07 -06001036
Benjamin Romer8f1947a2015-03-16 13:57:59 -04001037 up(&notifier_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001038}
David Kershner4da33362015-05-05 18:36:39 -04001039EXPORT_SYMBOL_GPL(visorchipset_register_busdev);
Ken Cox12e364b2014-03-04 07:58:07 -06001040
1041static void
1042cleanup_controlvm_structures(void)
1043{
Benjamin Romer33192fa2014-10-31 09:57:27 -04001044 struct visorchipset_bus_info *bi, *tmp_bi;
Benjamin Romer246e0cd2014-10-31 09:57:24 -04001045 struct visorchipset_device_info *di, *tmp_di;
Ken Cox12e364b2014-03-04 07:58:07 -06001046
Benjamin Romer1390b882015-03-16 13:58:03 -04001047 list_for_each_entry_safe(bi, tmp_bi, &bus_info_list, entry) {
Benjamin Romer9b989a982015-03-16 13:58:11 -04001048 bus_info_clear(bi);
Ken Cox12e364b2014-03-04 07:58:07 -06001049 list_del(&bi->entry);
1050 kfree(bi);
1051 }
1052
Benjamin Romer1390b882015-03-16 13:58:03 -04001053 list_for_each_entry_safe(di, tmp_di, &dev_info_list, entry) {
Benjamin Romer9b989a982015-03-16 13:58:11 -04001054 dev_info_clear(di);
Ken Cox12e364b2014-03-04 07:58:07 -06001055 list_del(&di->entry);
1056 kfree(di);
1057 }
1058}
1059
1060static void
Benjamin Romer3ab47702014-10-23 14:30:31 -04001061chipset_init(struct controlvm_message *inmsg)
Ken Cox12e364b2014-03-04 07:58:07 -06001062{
1063 static int chipset_inited;
Benjamin Romerb9b141e2014-10-23 14:30:24 -04001064 enum ultra_chipset_feature features = 0;
Ken Cox12e364b2014-03-04 07:58:07 -06001065 int rc = CONTROLVM_RESP_SUCCESS;
1066
1067 POSTCODE_LINUX_2(CHIPSET_INIT_ENTRY_PC, POSTCODE_SEVERITY_INFO);
1068 if (chipset_inited) {
Ken Cox22ad57b2014-03-19 13:06:25 -05001069 rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
Benjamin Romere3199b22015-03-16 13:58:14 -04001070 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001071 }
1072 chipset_inited = 1;
1073 POSTCODE_LINUX_2(CHIPSET_INIT_EXIT_PC, POSTCODE_SEVERITY_INFO);
1074
1075 /* Set features to indicate we support parahotplug (if Command
1076 * also supports it). */
1077 features =
Benjamin Romer2ea51172014-10-23 14:30:25 -04001078 inmsg->cmd.init_chipset.
Ken Cox12e364b2014-03-04 07:58:07 -06001079 features & ULTRA_CHIPSET_FEATURE_PARA_HOTPLUG;
1080
1081 /* Set the "reply" bit so Command knows this is a
1082 * features-aware driver. */
1083 features |= ULTRA_CHIPSET_FEATURE_REPLY;
1084
Benjamin Romere3199b22015-03-16 13:58:14 -04001085cleanup:
Ken Cox12e364b2014-03-04 07:58:07 -06001086 if (rc < 0)
1087 cleanup_controlvm_structures();
Benjamin Romer98d7b592014-10-23 14:30:26 -04001088 if (inmsg->hdr.flags.response_expected)
Ken Cox12e364b2014-03-04 07:58:07 -06001089 controlvm_respond_chipset_init(&inmsg->hdr, rc, features);
1090}
1091
1092static void
Benjamin Romer3ab47702014-10-23 14:30:31 -04001093controlvm_init_response(struct controlvm_message *msg,
Benjamin Romerb3168c72015-03-16 13:58:46 -04001094 struct controlvm_message_header *msg_hdr, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06001095{
Benjamin Romer3ab47702014-10-23 14:30:31 -04001096 memset(msg, 0, sizeof(struct controlvm_message));
Benjamin Romerb3168c72015-03-16 13:58:46 -04001097 memcpy(&msg->hdr, msg_hdr, sizeof(struct controlvm_message_header));
Benjamin Romer98d7b592014-10-23 14:30:26 -04001098 msg->hdr.payload_bytes = 0;
1099 msg->hdr.payload_vm_offset = 0;
1100 msg->hdr.payload_max_bytes = 0;
Ken Cox12e364b2014-03-04 07:58:07 -06001101 if (response < 0) {
Benjamin Romer98d7b592014-10-23 14:30:26 -04001102 msg->hdr.flags.failed = 1;
1103 msg->hdr.completion_status = (u32) (-response);
Ken Cox12e364b2014-03-04 07:58:07 -06001104 }
1105}
1106
1107static void
Benjamin Romerb3168c72015-03-16 13:58:46 -04001108controlvm_respond(struct controlvm_message_header *msg_hdr, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06001109{
Benjamin Romer3ab47702014-10-23 14:30:31 -04001110 struct controlvm_message outmsg;
Benjamin Romer26eb2c02014-08-18 09:34:53 -04001111
Benjamin Romerb3168c72015-03-16 13:58:46 -04001112 controlvm_init_response(&outmsg, msg_hdr, response);
Ken Cox12e364b2014-03-04 07:58:07 -06001113 /* For DiagPool channel DEVICE_CHANGESTATE, we need to send
1114 * back the deviceChangeState structure in the packet. */
Benjamin Romerb3168c72015-03-16 13:58:46 -04001115 if (msg_hdr->id == CONTROLVM_DEVICE_CHANGESTATE &&
Benjamin Romer0639ba62015-03-16 13:58:04 -04001116 g_devicechangestate_packet.device_change_state.bus_no ==
1117 g_diagpool_bus_no &&
1118 g_devicechangestate_packet.device_change_state.dev_no ==
Benjamin Romer83d48902015-03-16 13:58:01 -04001119 g_diagpool_dev_no)
Benjamin Romer4f44b722015-03-16 13:58:02 -04001120 outmsg.cmd = g_devicechangestate_packet;
Benjamin Romer2098dbd2015-03-04 12:14:22 -05001121 if (outmsg.hdr.flags.test_message == 1)
Ken Cox12e364b2014-03-04 07:58:07 -06001122 return;
Benjamin Romer2098dbd2015-03-04 12:14:22 -05001123
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001124 if (!visorchannel_signalinsert(controlvm_channel,
Ken Cox12e364b2014-03-04 07:58:07 -06001125 CONTROLVM_QUEUE_REQUEST, &outmsg)) {
Ken Cox12e364b2014-03-04 07:58:07 -06001126 return;
1127 }
1128}
1129
1130static void
Benjamin Romerb3168c72015-03-16 13:58:46 -04001131controlvm_respond_chipset_init(struct controlvm_message_header *msg_hdr,
Benjamin Romer98d7b592014-10-23 14:30:26 -04001132 int response,
Benjamin Romerb9b141e2014-10-23 14:30:24 -04001133 enum ultra_chipset_feature features)
Ken Cox12e364b2014-03-04 07:58:07 -06001134{
Benjamin Romer3ab47702014-10-23 14:30:31 -04001135 struct controlvm_message outmsg;
Benjamin Romer26eb2c02014-08-18 09:34:53 -04001136
Benjamin Romerb3168c72015-03-16 13:58:46 -04001137 controlvm_init_response(&outmsg, msg_hdr, response);
Benjamin Romer2ea51172014-10-23 14:30:25 -04001138 outmsg.cmd.init_chipset.features = features;
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001139 if (!visorchannel_signalinsert(controlvm_channel,
Ken Cox12e364b2014-03-04 07:58:07 -06001140 CONTROLVM_QUEUE_REQUEST, &outmsg)) {
Ken Cox12e364b2014-03-04 07:58:07 -06001141 return;
1142 }
1143}
1144
Benjamin Romer98d7b592014-10-23 14:30:26 -04001145static void controlvm_respond_physdev_changestate(
Benjamin Romerb3168c72015-03-16 13:58:46 -04001146 struct controlvm_message_header *msg_hdr, int response,
Benjamin Romer98d7b592014-10-23 14:30:26 -04001147 struct spar_segment_state state)
Ken Cox12e364b2014-03-04 07:58:07 -06001148{
Benjamin Romer3ab47702014-10-23 14:30:31 -04001149 struct controlvm_message outmsg;
Benjamin Romer26eb2c02014-08-18 09:34:53 -04001150
Benjamin Romerb3168c72015-03-16 13:58:46 -04001151 controlvm_init_response(&outmsg, msg_hdr, response);
Benjamin Romer2ea51172014-10-23 14:30:25 -04001152 outmsg.cmd.device_change_state.state = state;
1153 outmsg.cmd.device_change_state.flags.phys_device = 1;
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001154 if (!visorchannel_signalinsert(controlvm_channel,
Ken Cox12e364b2014-03-04 07:58:07 -06001155 CONTROLVM_QUEUE_REQUEST, &outmsg)) {
Ken Cox12e364b2014-03-04 07:58:07 -06001156 return;
1157 }
1158}
1159
Prarit Bhargava2ee0dee2015-05-05 18:36:16 -04001160enum crash_obj_type {
1161 CRASH_DEV,
1162 CRASH_BUS,
1163};
1164
Ken Cox12e364b2014-03-04 07:58:07 -06001165void
Benjamin Romer2c683cd2014-10-31 09:57:22 -04001166visorchipset_save_message(struct controlvm_message *msg,
1167 enum crash_obj_type type)
Ken Cox12e364b2014-03-04 07:58:07 -06001168{
Benjamin Romer45772252015-03-16 13:58:15 -04001169 u32 crash_msg_offset;
1170 u16 crash_msg_count;
Ken Cox12e364b2014-03-04 07:58:07 -06001171
1172 /* get saved message count */
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001173 if (visorchannel_read(controlvm_channel,
Benjamin Romerd19642f2014-10-23 14:30:34 -04001174 offsetof(struct spar_controlvm_channel_protocol,
1175 saved_crash_message_count),
Benjamin Romer45772252015-03-16 13:58:15 -04001176 &crash_msg_count, sizeof(u16)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06001177 POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
1178 POSTCODE_SEVERITY_ERR);
1179 return;
1180 }
1181
Benjamin Romer45772252015-03-16 13:58:15 -04001182 if (crash_msg_count != CONTROLVM_CRASHMSG_MAX) {
Ken Cox12e364b2014-03-04 07:58:07 -06001183 POSTCODE_LINUX_3(CRASH_DEV_COUNT_FAILURE_PC,
Benjamin Romer45772252015-03-16 13:58:15 -04001184 crash_msg_count,
Ken Cox12e364b2014-03-04 07:58:07 -06001185 POSTCODE_SEVERITY_ERR);
1186 return;
1187 }
1188
1189 /* get saved crash message offset */
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001190 if (visorchannel_read(controlvm_channel,
Benjamin Romerd19642f2014-10-23 14:30:34 -04001191 offsetof(struct spar_controlvm_channel_protocol,
1192 saved_crash_message_offset),
Benjamin Romer45772252015-03-16 13:58:15 -04001193 &crash_msg_offset, sizeof(u32)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06001194 POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
1195 POSTCODE_SEVERITY_ERR);
1196 return;
1197 }
1198
Benjamin Romer2c683cd2014-10-31 09:57:22 -04001199 if (type == CRASH_BUS) {
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001200 if (visorchannel_write(controlvm_channel,
Benjamin Romer45772252015-03-16 13:58:15 -04001201 crash_msg_offset,
Benjamin Romer3ab47702014-10-23 14:30:31 -04001202 msg,
1203 sizeof(struct controlvm_message)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06001204 POSTCODE_LINUX_2(SAVE_MSG_BUS_FAILURE_PC,
1205 POSTCODE_SEVERITY_ERR);
1206 return;
1207 }
Prarit Bhargava2ee0dee2015-05-05 18:36:16 -04001208 } else { /* CRASH_DEV */
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001209 if (visorchannel_write(controlvm_channel,
Benjamin Romer45772252015-03-16 13:58:15 -04001210 crash_msg_offset +
Benjamin Romer3ab47702014-10-23 14:30:31 -04001211 sizeof(struct controlvm_message), msg,
1212 sizeof(struct controlvm_message)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06001213 POSTCODE_LINUX_2(SAVE_MSG_DEV_FAILURE_PC,
1214 POSTCODE_SEVERITY_ERR);
1215 return;
1216 }
1217 }
1218}
1219EXPORT_SYMBOL_GPL(visorchipset_save_message);
1220
1221static void
Jes Sorensen52063ec2015-04-13 10:28:41 -04001222bus_responder(enum controlvm_id cmd_id, u32 bus_no, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06001223{
Jes Sorensene82ba622015-05-05 18:35:45 -04001224 struct visorchipset_bus_info *p;
Jes Sorensenf4c11552015-04-13 10:28:40 -04001225 bool need_clear = false;
Ken Cox12e364b2014-03-04 07:58:07 -06001226
Jes Sorensen4f665202015-05-05 18:35:52 -04001227 p = bus_find(&bus_info_list, bus_no);
Benjamin Romer0aca78442015-03-04 12:14:25 -05001228 if (!p)
Ken Cox12e364b2014-03-04 07:58:07 -06001229 return;
Benjamin Romer0aca78442015-03-04 12:14:25 -05001230
Ken Cox12e364b2014-03-04 07:58:07 -06001231 if (response < 0) {
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001232 if ((cmd_id == CONTROLVM_BUS_CREATE) &&
Ken Cox12e364b2014-03-04 07:58:07 -06001233 (response != (-CONTROLVM_RESP_ERROR_ALREADY_DONE)))
1234 /* undo the row we just created... */
Jes Sorensen28723522015-05-05 18:35:55 -04001235 busdevices_del(&dev_info_list, bus_no);
Ken Cox12e364b2014-03-04 07:58:07 -06001236 } else {
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001237 if (cmd_id == CONTROLVM_BUS_CREATE)
Ken Cox12e364b2014-03-04 07:58:07 -06001238 p->state.created = 1;
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001239 if (cmd_id == CONTROLVM_BUS_DESTROY)
Jes Sorensenf4c11552015-04-13 10:28:40 -04001240 need_clear = true;
Ken Cox12e364b2014-03-04 07:58:07 -06001241 }
1242
Benjamin Romer0aca78442015-03-04 12:14:25 -05001243 if (p->pending_msg_hdr.id == CONTROLVM_INVALID)
Ken Cox12e364b2014-03-04 07:58:07 -06001244 return; /* no controlvm response needed */
Benjamin Romer6b59b312015-03-16 13:58:18 -04001245 if (p->pending_msg_hdr.id != (u32)cmd_id)
Ken Cox12e364b2014-03-04 07:58:07 -06001246 return;
Benjamin Romer33192fa2014-10-31 09:57:27 -04001247 controlvm_respond(&p->pending_msg_hdr, response);
1248 p->pending_msg_hdr.id = CONTROLVM_INVALID;
Ken Cox12e364b2014-03-04 07:58:07 -06001249 if (need_clear) {
Benjamin Romer9b989a982015-03-16 13:58:11 -04001250 bus_info_clear(p);
Jes Sorensen28723522015-05-05 18:35:55 -04001251 busdevices_del(&dev_info_list, bus_no);
Ken Cox12e364b2014-03-04 07:58:07 -06001252 }
1253}
1254
1255static void
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001256device_changestate_responder(enum controlvm_id cmd_id,
Jes Sorensen52063ec2015-04-13 10:28:41 -04001257 u32 bus_no, u32 dev_no, int response,
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001258 struct spar_segment_state response_state)
Ken Cox12e364b2014-03-04 07:58:07 -06001259{
Jes Sorensene82ba622015-05-05 18:35:45 -04001260 struct visorchipset_device_info *p;
Benjamin Romer3ab47702014-10-23 14:30:31 -04001261 struct controlvm_message outmsg;
Ken Cox12e364b2014-03-04 07:58:07 -06001262
Jes Sorensend480f6a2015-05-05 18:35:54 -04001263 p = device_find(&dev_info_list, bus_no, dev_no);
Benjamin Romer0aca78442015-03-04 12:14:25 -05001264 if (!p)
Ken Cox12e364b2014-03-04 07:58:07 -06001265 return;
Benjamin Romer0aca78442015-03-04 12:14:25 -05001266 if (p->pending_msg_hdr.id == CONTROLVM_INVALID)
Ken Cox12e364b2014-03-04 07:58:07 -06001267 return; /* no controlvm response needed */
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001268 if (p->pending_msg_hdr.id != cmd_id)
Ken Cox12e364b2014-03-04 07:58:07 -06001269 return;
Ken Cox12e364b2014-03-04 07:58:07 -06001270
Benjamin Romer246e0cd2014-10-31 09:57:24 -04001271 controlvm_init_response(&outmsg, &p->pending_msg_hdr, response);
Ken Cox12e364b2014-03-04 07:58:07 -06001272
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001273 outmsg.cmd.device_change_state.bus_no = bus_no;
1274 outmsg.cmd.device_change_state.dev_no = dev_no;
1275 outmsg.cmd.device_change_state.state = response_state;
Ken Cox12e364b2014-03-04 07:58:07 -06001276
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001277 if (!visorchannel_signalinsert(controlvm_channel,
Benjamin Romer0aca78442015-03-04 12:14:25 -05001278 CONTROLVM_QUEUE_REQUEST, &outmsg))
Ken Cox12e364b2014-03-04 07:58:07 -06001279 return;
Ken Cox12e364b2014-03-04 07:58:07 -06001280
Benjamin Romer246e0cd2014-10-31 09:57:24 -04001281 p->pending_msg_hdr.id = CONTROLVM_INVALID;
Ken Cox12e364b2014-03-04 07:58:07 -06001282}
1283
1284static void
Jes Sorensen52063ec2015-04-13 10:28:41 -04001285device_responder(enum controlvm_id cmd_id, u32 bus_no, u32 dev_no, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06001286{
Jes Sorensene82ba622015-05-05 18:35:45 -04001287 struct visorchipset_device_info *p;
Jes Sorensenf4c11552015-04-13 10:28:40 -04001288 bool need_clear = false;
Ken Cox12e364b2014-03-04 07:58:07 -06001289
Jes Sorensend480f6a2015-05-05 18:35:54 -04001290 p = device_find(&dev_info_list, bus_no, dev_no);
Benjamin Romer0aca78442015-03-04 12:14:25 -05001291 if (!p)
Ken Cox12e364b2014-03-04 07:58:07 -06001292 return;
Ken Cox12e364b2014-03-04 07:58:07 -06001293 if (response >= 0) {
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001294 if (cmd_id == CONTROLVM_DEVICE_CREATE)
Ken Cox12e364b2014-03-04 07:58:07 -06001295 p->state.created = 1;
Benjamin Romerfbb31f42015-03-16 13:58:16 -04001296 if (cmd_id == CONTROLVM_DEVICE_DESTROY)
Jes Sorensenf4c11552015-04-13 10:28:40 -04001297 need_clear = true;
Ken Cox12e364b2014-03-04 07:58:07 -06001298 }
1299
Benjamin Romer0aca78442015-03-04 12:14:25 -05001300 if (p->pending_msg_hdr.id == CONTROLVM_INVALID)
Ken Cox12e364b2014-03-04 07:58:07 -06001301 return; /* no controlvm response needed */
Benjamin Romer0aca78442015-03-04 12:14:25 -05001302
Benjamin Romer6b59b312015-03-16 13:58:18 -04001303 if (p->pending_msg_hdr.id != (u32)cmd_id)
Ken Cox12e364b2014-03-04 07:58:07 -06001304 return;
Benjamin Romer0aca78442015-03-04 12:14:25 -05001305
Benjamin Romer246e0cd2014-10-31 09:57:24 -04001306 controlvm_respond(&p->pending_msg_hdr, response);
1307 p->pending_msg_hdr.id = CONTROLVM_INVALID;
Ken Cox12e364b2014-03-04 07:58:07 -06001308 if (need_clear)
Benjamin Romer9b989a982015-03-16 13:58:11 -04001309 dev_info_clear(p);
Ken Cox12e364b2014-03-04 07:58:07 -06001310}
1311
1312static void
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001313bus_epilog(u32 bus_no,
1314 u32 cmd, struct controlvm_message_header *msg_hdr,
Jes Sorensenf4c11552015-04-13 10:28:40 -04001315 int response, bool need_response)
Ken Cox12e364b2014-03-04 07:58:07 -06001316{
Jes Sorensen4f665202015-05-05 18:35:52 -04001317 struct visorchipset_bus_info *bus_info;
Jes Sorensenf4c11552015-04-13 10:28:40 -04001318 bool notified = false;
Ken Cox12e364b2014-03-04 07:58:07 -06001319
Jes Sorensen4f665202015-05-05 18:35:52 -04001320 bus_info = bus_find(&bus_info_list, bus_no);
Ken Cox12e364b2014-03-04 07:58:07 -06001321
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001322 if (!bus_info)
Ken Cox12e364b2014-03-04 07:58:07 -06001323 return;
Benjamin Romer0aca78442015-03-04 12:14:25 -05001324
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001325 if (need_response) {
1326 memcpy(&bus_info->pending_msg_hdr, msg_hdr,
Benjamin Romer98d7b592014-10-23 14:30:26 -04001327 sizeof(struct controlvm_message_header));
Benjamin Romer75c1f8b2015-03-16 13:58:19 -04001328 } else {
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001329 bus_info->pending_msg_hdr.id = CONTROLVM_INVALID;
Benjamin Romer75c1f8b2015-03-16 13:58:19 -04001330 }
Ken Cox12e364b2014-03-04 07:58:07 -06001331
Benjamin Romer8f1947a2015-03-16 13:57:59 -04001332 down(&notifier_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001333 if (response == CONTROLVM_RESP_SUCCESS) {
1334 switch (cmd) {
1335 case CONTROLVM_BUS_CREATE:
David Kershner4da33362015-05-05 18:36:39 -04001336 if (busdev_notifiers.bus_create) {
1337 (*busdev_notifiers.bus_create) (bus_no);
Jes Sorensenf4c11552015-04-13 10:28:40 -04001338 notified = true;
Ken Cox12e364b2014-03-04 07:58:07 -06001339 }
1340 break;
1341 case CONTROLVM_BUS_DESTROY:
David Kershner4da33362015-05-05 18:36:39 -04001342 if (busdev_notifiers.bus_destroy) {
1343 (*busdev_notifiers.bus_destroy) (bus_no);
Jes Sorensenf4c11552015-04-13 10:28:40 -04001344 notified = true;
Ken Cox12e364b2014-03-04 07:58:07 -06001345 }
1346 break;
1347 }
1348 }
1349 if (notified)
1350 /* The callback function just called above is responsible
Benjamin Romer929aa8a2014-10-31 09:57:33 -04001351 * for calling the appropriate visorchipset_busdev_responders
Ken Cox12e364b2014-03-04 07:58:07 -06001352 * function, which will call bus_responder()
1353 */
1354 ;
1355 else
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001356 bus_responder(cmd, bus_no, response);
Benjamin Romer8f1947a2015-03-16 13:57:59 -04001357 up(&notifier_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001358}
1359
1360static void
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001361device_epilog(u32 bus_no, u32 dev_no, struct spar_segment_state state, u32 cmd,
1362 struct controlvm_message_header *msg_hdr, int response,
Jes Sorensenf4c11552015-04-13 10:28:40 -04001363 bool need_response, bool for_visorbus)
Ken Cox12e364b2014-03-04 07:58:07 -06001364{
Jes Sorensene82ba622015-05-05 18:35:45 -04001365 struct visorchipset_busdev_notifiers *notifiers;
Jes Sorensenf4c11552015-04-13 10:28:40 -04001366 bool notified = false;
Ken Cox12e364b2014-03-04 07:58:07 -06001367
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001368 struct visorchipset_device_info *dev_info =
Jes Sorensend480f6a2015-05-05 18:35:54 -04001369 device_find(&dev_info_list, bus_no, dev_no);
Ken Cox12e364b2014-03-04 07:58:07 -06001370 char *envp[] = {
1371 "SPARSP_DIAGPOOL_PAUSED_STATE = 1",
1372 NULL
1373 };
1374
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001375 if (!dev_info)
Ken Cox12e364b2014-03-04 07:58:07 -06001376 return;
Benjamin Romer0aca78442015-03-04 12:14:25 -05001377
David Kershner4da33362015-05-05 18:36:39 -04001378 notifiers = &busdev_notifiers;
1379
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001380 if (need_response) {
1381 memcpy(&dev_info->pending_msg_hdr, msg_hdr,
Benjamin Romer98d7b592014-10-23 14:30:26 -04001382 sizeof(struct controlvm_message_header));
Benjamin Romer75c1f8b2015-03-16 13:58:19 -04001383 } else {
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001384 dev_info->pending_msg_hdr.id = CONTROLVM_INVALID;
Benjamin Romer75c1f8b2015-03-16 13:58:19 -04001385 }
Ken Cox12e364b2014-03-04 07:58:07 -06001386
Benjamin Romer8f1947a2015-03-16 13:57:59 -04001387 down(&notifier_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001388 if (response >= 0) {
1389 switch (cmd) {
1390 case CONTROLVM_DEVICE_CREATE:
1391 if (notifiers->device_create) {
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001392 (*notifiers->device_create) (bus_no, dev_no);
Jes Sorensenf4c11552015-04-13 10:28:40 -04001393 notified = true;
Ken Cox12e364b2014-03-04 07:58:07 -06001394 }
1395 break;
1396 case CONTROLVM_DEVICE_CHANGESTATE:
1397 /* ServerReady / ServerRunning / SegmentStateRunning */
Benjamin Romerbd0d2dc2014-10-23 14:30:13 -04001398 if (state.alive == segment_state_running.alive &&
1399 state.operating ==
1400 segment_state_running.operating) {
Ken Cox12e364b2014-03-04 07:58:07 -06001401 if (notifiers->device_resume) {
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001402 (*notifiers->device_resume) (bus_no,
1403 dev_no);
Jes Sorensenf4c11552015-04-13 10:28:40 -04001404 notified = true;
Ken Cox12e364b2014-03-04 07:58:07 -06001405 }
1406 }
1407 /* ServerNotReady / ServerLost / SegmentStateStandby */
Benjamin Romerbd0d2dc2014-10-23 14:30:13 -04001408 else if (state.alive == segment_state_standby.alive &&
Benjamin Romer3f833b52014-10-23 14:30:12 -04001409 state.operating ==
Benjamin Romerbd0d2dc2014-10-23 14:30:13 -04001410 segment_state_standby.operating) {
Ken Cox12e364b2014-03-04 07:58:07 -06001411 /* technically this is standby case
1412 * where server is lost
1413 */
1414 if (notifiers->device_pause) {
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001415 (*notifiers->device_pause) (bus_no,
1416 dev_no);
Jes Sorensenf4c11552015-04-13 10:28:40 -04001417 notified = true;
Ken Cox12e364b2014-03-04 07:58:07 -06001418 }
Benjamin Romerbd0d2dc2014-10-23 14:30:13 -04001419 } else if (state.alive == segment_state_paused.alive &&
Benjamin Romer3f833b52014-10-23 14:30:12 -04001420 state.operating ==
Benjamin Romerbd0d2dc2014-10-23 14:30:13 -04001421 segment_state_paused.operating) {
Ken Cox12e364b2014-03-04 07:58:07 -06001422 /* this is lite pause where channel is
1423 * still valid just 'pause' of it
1424 */
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001425 if (bus_no == g_diagpool_bus_no &&
1426 dev_no == g_diagpool_dev_no) {
Ken Cox12e364b2014-03-04 07:58:07 -06001427 /* this will trigger the
1428 * diag_shutdown.sh script in
1429 * the visorchipset hotplug */
1430 kobject_uevent_env
Benjamin Romereb34e872015-03-16 13:58:45 -04001431 (&visorchipset_platform_device.dev.
Ken Cox12e364b2014-03-04 07:58:07 -06001432 kobj, KOBJ_ONLINE, envp);
1433 }
1434 }
1435 break;
1436 case CONTROLVM_DEVICE_DESTROY:
1437 if (notifiers->device_destroy) {
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001438 (*notifiers->device_destroy) (bus_no, dev_no);
Jes Sorensenf4c11552015-04-13 10:28:40 -04001439 notified = true;
Ken Cox12e364b2014-03-04 07:58:07 -06001440 }
1441 break;
1442 }
1443 }
1444 if (notified)
1445 /* The callback function just called above is responsible
Benjamin Romer929aa8a2014-10-31 09:57:33 -04001446 * for calling the appropriate visorchipset_busdev_responders
Ken Cox12e364b2014-03-04 07:58:07 -06001447 * function, which will call device_responder()
1448 */
1449 ;
1450 else
Benjamin Romer2836c6a2015-03-16 13:58:17 -04001451 device_responder(cmd, bus_no, dev_no, response);
Benjamin Romer8f1947a2015-03-16 13:57:59 -04001452 up(&notifier_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001453}
1454
1455static void
Benjamin Romer3ab47702014-10-23 14:30:31 -04001456bus_create(struct controlvm_message *inmsg)
Ken Cox12e364b2014-03-04 07:58:07 -06001457{
Benjamin Romer2ea51172014-10-23 14:30:25 -04001458 struct controlvm_message_packet *cmd = &inmsg->cmd;
Jes Sorensen52063ec2015-04-13 10:28:41 -04001459 u32 bus_no = cmd->create_bus.bus_no;
Ken Cox12e364b2014-03-04 07:58:07 -06001460 int rc = CONTROLVM_RESP_SUCCESS;
Jes Sorensene82ba622015-05-05 18:35:45 -04001461 struct visorchipset_bus_info *bus_info;
Ken Cox12e364b2014-03-04 07:58:07 -06001462
Jes Sorensen4f665202015-05-05 18:35:52 -04001463 bus_info = bus_find(&bus_info_list, bus_no);
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001464 if (bus_info && (bus_info->state.created == 1)) {
1465 POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001466 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001467 rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001468 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001469 }
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001470 bus_info = kzalloc(sizeof(*bus_info), GFP_KERNEL);
1471 if (!bus_info) {
1472 POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001473 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001474 rc = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001475 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001476 }
1477
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001478 INIT_LIST_HEAD(&bus_info->entry);
1479 bus_info->bus_no = bus_no;
Ken Cox12e364b2014-03-04 07:58:07 -06001480
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001481 POSTCODE_LINUX_3(BUS_CREATE_ENTRY_PC, bus_no, POSTCODE_SEVERITY_INFO);
Ken Cox12e364b2014-03-04 07:58:07 -06001482
Benjamin Romer98d7b592014-10-23 14:30:26 -04001483 if (inmsg->hdr.flags.test_message == 1)
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001484 bus_info->chan_info.addr_type = ADDRTYPE_LOCALTEST;
Ken Cox12e364b2014-03-04 07:58:07 -06001485 else
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001486 bus_info->chan_info.addr_type = ADDRTYPE_LOCALPHYSICAL;
Ken Cox12e364b2014-03-04 07:58:07 -06001487
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001488 bus_info->flags.server = inmsg->hdr.flags.server;
1489 bus_info->chan_info.channel_addr = cmd->create_bus.channel_addr;
1490 bus_info->chan_info.n_channel_bytes = cmd->create_bus.channel_bytes;
1491 bus_info->chan_info.channel_type_uuid =
Benjamin Romer9b1caee2014-10-31 09:57:23 -04001492 cmd->create_bus.bus_data_type_uuid;
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001493 bus_info->chan_info.channel_inst_uuid = cmd->create_bus.bus_inst_uuid;
Ken Cox12e364b2014-03-04 07:58:07 -06001494
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001495 list_add(&bus_info->entry, &bus_info_list);
Ken Cox12e364b2014-03-04 07:58:07 -06001496
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001497 POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, bus_no, POSTCODE_SEVERITY_INFO);
Ken Cox12e364b2014-03-04 07:58:07 -06001498
Benjamin Romer6c5fed32015-03-16 13:58:20 -04001499cleanup:
1500 bus_epilog(bus_no, CONTROLVM_BUS_CREATE, &inmsg->hdr,
Benjamin Romer98d7b592014-10-23 14:30:26 -04001501 rc, inmsg->hdr.flags.response_expected == 1);
Ken Cox12e364b2014-03-04 07:58:07 -06001502}
1503
1504static void
Benjamin Romer3ab47702014-10-23 14:30:31 -04001505bus_destroy(struct controlvm_message *inmsg)
Ken Cox12e364b2014-03-04 07:58:07 -06001506{
Benjamin Romer2ea51172014-10-23 14:30:25 -04001507 struct controlvm_message_packet *cmd = &inmsg->cmd;
Jes Sorensen52063ec2015-04-13 10:28:41 -04001508 u32 bus_no = cmd->destroy_bus.bus_no;
Benjamin Romerdff54cd2015-03-16 13:58:21 -04001509 struct visorchipset_bus_info *bus_info;
Ken Cox12e364b2014-03-04 07:58:07 -06001510 int rc = CONTROLVM_RESP_SUCCESS;
1511
Jes Sorensen4f665202015-05-05 18:35:52 -04001512 bus_info = bus_find(&bus_info_list, bus_no);
Benjamin Romerdff54cd2015-03-16 13:58:21 -04001513 if (!bus_info)
Ken Cox22ad57b2014-03-19 13:06:25 -05001514 rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
Benjamin Romerdff54cd2015-03-16 13:58:21 -04001515 else if (bus_info->state.created == 0)
Ken Cox22ad57b2014-03-19 13:06:25 -05001516 rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
Ken Cox12e364b2014-03-04 07:58:07 -06001517
Benjamin Romerdff54cd2015-03-16 13:58:21 -04001518 bus_epilog(bus_no, CONTROLVM_BUS_DESTROY, &inmsg->hdr,
Benjamin Romer98d7b592014-10-23 14:30:26 -04001519 rc, inmsg->hdr.flags.response_expected == 1);
Ken Cox12e364b2014-03-04 07:58:07 -06001520}
1521
1522static void
Benjamin Romer317d9612015-03-16 13:57:51 -04001523bus_configure(struct controlvm_message *inmsg,
1524 struct parser_context *parser_ctx)
Ken Cox12e364b2014-03-04 07:58:07 -06001525{
Benjamin Romer2ea51172014-10-23 14:30:25 -04001526 struct controlvm_message_packet *cmd = &inmsg->cmd;
Jes Sorensene82ba622015-05-05 18:35:45 -04001527 u32 bus_no;
1528 struct visorchipset_bus_info *bus_info;
Ken Cox12e364b2014-03-04 07:58:07 -06001529 int rc = CONTROLVM_RESP_SUCCESS;
1530 char s[99];
1531
Benjamin Romer654bada2015-03-16 13:58:22 -04001532 bus_no = cmd->configure_bus.bus_no;
1533 POSTCODE_LINUX_3(BUS_CONFIGURE_ENTRY_PC, bus_no,
1534 POSTCODE_SEVERITY_INFO);
Ken Cox12e364b2014-03-04 07:58:07 -06001535
Jes Sorensen4f665202015-05-05 18:35:52 -04001536 bus_info = bus_find(&bus_info_list, bus_no);
Benjamin Romer654bada2015-03-16 13:58:22 -04001537 if (!bus_info) {
1538 POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001539 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001540 rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
Benjamin Romer654bada2015-03-16 13:58:22 -04001541 } else if (bus_info->state.created == 0) {
1542 POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001543 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001544 rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
Benjamin Romer654bada2015-03-16 13:58:22 -04001545 } else if (bus_info->pending_msg_hdr.id != CONTROLVM_INVALID) {
1546 POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001547 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001548 rc = -CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT;
Benjamin Romer654bada2015-03-16 13:58:22 -04001549 } else {
1550 bus_info->partition_handle = cmd->configure_bus.guest_handle;
1551 bus_info->partition_uuid = parser_id_get(parser_ctx);
1552 parser_param_start(parser_ctx, PARSERSTRING_NAME);
1553 bus_info->name = parser_string_get(parser_ctx);
1554
1555 visorchannel_uuid_id(&bus_info->partition_uuid, s);
1556 POSTCODE_LINUX_3(BUS_CONFIGURE_EXIT_PC, bus_no,
1557 POSTCODE_SEVERITY_INFO);
Ken Cox12e364b2014-03-04 07:58:07 -06001558 }
Benjamin Romer654bada2015-03-16 13:58:22 -04001559 bus_epilog(bus_no, CONTROLVM_BUS_CONFIGURE, &inmsg->hdr,
Benjamin Romer98d7b592014-10-23 14:30:26 -04001560 rc, inmsg->hdr.flags.response_expected == 1);
Ken Cox12e364b2014-03-04 07:58:07 -06001561}
1562
1563static void
Benjamin Romer3ab47702014-10-23 14:30:31 -04001564my_device_create(struct controlvm_message *inmsg)
Ken Cox12e364b2014-03-04 07:58:07 -06001565{
Benjamin Romer2ea51172014-10-23 14:30:25 -04001566 struct controlvm_message_packet *cmd = &inmsg->cmd;
Jes Sorensen52063ec2015-04-13 10:28:41 -04001567 u32 bus_no = cmd->create_device.bus_no;
1568 u32 dev_no = cmd->create_device.dev_no;
Jes Sorensene82ba622015-05-05 18:35:45 -04001569 struct visorchipset_device_info *dev_info;
1570 struct visorchipset_bus_info *bus_info;
Ken Cox12e364b2014-03-04 07:58:07 -06001571 int rc = CONTROLVM_RESP_SUCCESS;
1572
Jes Sorensend480f6a2015-05-05 18:35:54 -04001573 dev_info = device_find(&dev_info_list, bus_no, dev_no);
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001574 if (dev_info && (dev_info->state.created == 1)) {
1575 POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001576 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001577 rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001578 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001579 }
Jes Sorensen4f665202015-05-05 18:35:52 -04001580 bus_info = bus_find(&bus_info_list, bus_no);
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001581 if (!bus_info) {
1582 POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001583 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001584 rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001585 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001586 }
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001587 if (bus_info->state.created == 0) {
1588 POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001589 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001590 rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001591 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001592 }
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001593 dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL);
1594 if (!dev_info) {
1595 POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001596 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001597 rc = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001598 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001599 }
Andreea-Cristina Bernat97a84f12014-03-14 04:20:06 +02001600
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001601 INIT_LIST_HEAD(&dev_info->entry);
1602 dev_info->bus_no = bus_no;
1603 dev_info->dev_no = dev_no;
1604 dev_info->dev_inst_uuid = cmd->create_device.dev_inst_uuid;
1605 POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, dev_no, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001606 POSTCODE_SEVERITY_INFO);
1607
Benjamin Romer98d7b592014-10-23 14:30:26 -04001608 if (inmsg->hdr.flags.test_message == 1)
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001609 dev_info->chan_info.addr_type = ADDRTYPE_LOCALTEST;
Ken Cox12e364b2014-03-04 07:58:07 -06001610 else
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001611 dev_info->chan_info.addr_type = ADDRTYPE_LOCALPHYSICAL;
1612 dev_info->chan_info.channel_addr = cmd->create_device.channel_addr;
1613 dev_info->chan_info.n_channel_bytes = cmd->create_device.channel_bytes;
1614 dev_info->chan_info.channel_type_uuid =
Benjamin Romer9b1caee2014-10-31 09:57:23 -04001615 cmd->create_device.data_type_uuid;
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001616 dev_info->chan_info.intr = cmd->create_device.intr;
1617 list_add(&dev_info->entry, &dev_info_list);
1618 POSTCODE_LINUX_4(DEVICE_CREATE_EXIT_PC, dev_no, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001619 POSTCODE_SEVERITY_INFO);
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001620cleanup:
Ken Cox12e364b2014-03-04 07:58:07 -06001621 /* get the bus and devNo for DiagPool channel */
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001622 if (dev_info &&
1623 is_diagpool_channel(dev_info->chan_info.channel_type_uuid)) {
1624 g_diagpool_bus_no = bus_no;
1625 g_diagpool_dev_no = dev_no;
Ken Cox12e364b2014-03-04 07:58:07 -06001626 }
Benjamin Romerc60c8e22015-03-16 13:58:23 -04001627 device_epilog(bus_no, dev_no, segment_state_running,
Ken Cox12e364b2014-03-04 07:58:07 -06001628 CONTROLVM_DEVICE_CREATE, &inmsg->hdr, rc,
David Kershner4da33362015-05-05 18:36:39 -04001629 inmsg->hdr.flags.response_expected == 1, 1);
Ken Cox12e364b2014-03-04 07:58:07 -06001630}
1631
1632static void
Benjamin Romer3ab47702014-10-23 14:30:31 -04001633my_device_changestate(struct controlvm_message *inmsg)
Ken Cox12e364b2014-03-04 07:58:07 -06001634{
Benjamin Romer2ea51172014-10-23 14:30:25 -04001635 struct controlvm_message_packet *cmd = &inmsg->cmd;
Jes Sorensen52063ec2015-04-13 10:28:41 -04001636 u32 bus_no = cmd->device_change_state.bus_no;
1637 u32 dev_no = cmd->device_change_state.dev_no;
Benjamin Romer2ea51172014-10-23 14:30:25 -04001638 struct spar_segment_state state = cmd->device_change_state.state;
Jes Sorensene82ba622015-05-05 18:35:45 -04001639 struct visorchipset_device_info *dev_info;
Ken Cox12e364b2014-03-04 07:58:07 -06001640 int rc = CONTROLVM_RESP_SUCCESS;
1641
Jes Sorensend480f6a2015-05-05 18:35:54 -04001642 dev_info = device_find(&dev_info_list, bus_no, dev_no);
Benjamin Romer0278a902015-03-16 13:58:24 -04001643 if (!dev_info) {
1644 POSTCODE_LINUX_4(DEVICE_CHANGESTATE_FAILURE_PC, dev_no, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001645 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001646 rc = -CONTROLVM_RESP_ERROR_DEVICE_INVALID;
Benjamin Romer0278a902015-03-16 13:58:24 -04001647 } else if (dev_info->state.created == 0) {
1648 POSTCODE_LINUX_4(DEVICE_CHANGESTATE_FAILURE_PC, dev_no, bus_no,
Ken Cox12e364b2014-03-04 07:58:07 -06001649 POSTCODE_SEVERITY_ERR);
Ken Cox22ad57b2014-03-19 13:06:25 -05001650 rc = -CONTROLVM_RESP_ERROR_DEVICE_INVALID;
Ken Cox12e364b2014-03-04 07:58:07 -06001651 }
Benjamin Romer0278a902015-03-16 13:58:24 -04001652 if ((rc >= CONTROLVM_RESP_SUCCESS) && dev_info)
1653 device_epilog(bus_no, dev_no, state,
1654 CONTROLVM_DEVICE_CHANGESTATE, &inmsg->hdr, rc,
David Kershner4da33362015-05-05 18:36:39 -04001655 inmsg->hdr.flags.response_expected == 1, 1);
Ken Cox12e364b2014-03-04 07:58:07 -06001656}
1657
1658static void
Benjamin Romer3ab47702014-10-23 14:30:31 -04001659my_device_destroy(struct controlvm_message *inmsg)
Ken Cox12e364b2014-03-04 07:58:07 -06001660{
Benjamin Romer2ea51172014-10-23 14:30:25 -04001661 struct controlvm_message_packet *cmd = &inmsg->cmd;
Jes Sorensen52063ec2015-04-13 10:28:41 -04001662 u32 bus_no = cmd->destroy_device.bus_no;
1663 u32 dev_no = cmd->destroy_device.dev_no;
Jes Sorensene82ba622015-05-05 18:35:45 -04001664 struct visorchipset_device_info *dev_info;
Ken Cox12e364b2014-03-04 07:58:07 -06001665 int rc = CONTROLVM_RESP_SUCCESS;
1666
Jes Sorensend480f6a2015-05-05 18:35:54 -04001667 dev_info = device_find(&dev_info_list, bus_no, dev_no);
Benjamin Romer61715c82015-03-16 13:58:25 -04001668 if (!dev_info)
Ken Cox22ad57b2014-03-19 13:06:25 -05001669 rc = -CONTROLVM_RESP_ERROR_DEVICE_INVALID;
Benjamin Romer61715c82015-03-16 13:58:25 -04001670 else if (dev_info->state.created == 0)
Ken Cox22ad57b2014-03-19 13:06:25 -05001671 rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
Ken Cox12e364b2014-03-04 07:58:07 -06001672
Benjamin Romer61715c82015-03-16 13:58:25 -04001673 if ((rc >= CONTROLVM_RESP_SUCCESS) && dev_info)
1674 device_epilog(bus_no, dev_no, segment_state_running,
Ken Cox12e364b2014-03-04 07:58:07 -06001675 CONTROLVM_DEVICE_DESTROY, &inmsg->hdr, rc,
David Kershner4da33362015-05-05 18:36:39 -04001676 inmsg->hdr.flags.response_expected == 1, 1);
Ken Cox12e364b2014-03-04 07:58:07 -06001677}
1678
1679/* When provided with the physical address of the controlvm channel
1680 * (phys_addr), the offset to the payload area we need to manage
1681 * (offset), and the size of this payload area (bytes), fills in the
Jes Sorensenf4c11552015-04-13 10:28:40 -04001682 * controlvm_payload_info struct. Returns true for success or false
Ken Cox12e364b2014-03-04 07:58:07 -06001683 * for failure.
1684 */
1685static int
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -04001686initialize_controlvm_payload_info(u64 phys_addr, u64 offset, u32 bytes,
Jes Sorensenc1f834e2015-04-13 10:28:39 -04001687 struct visor_controlvm_payload_info *info)
Ken Cox12e364b2014-03-04 07:58:07 -06001688{
Benjamin Romerc2422332014-07-29 15:09:40 -04001689 u8 __iomem *payload = NULL;
Ken Cox12e364b2014-03-04 07:58:07 -06001690 int rc = CONTROLVM_RESP_SUCCESS;
1691
Benjamin Romer38f736e2015-03-16 13:58:13 -04001692 if (!info) {
Ken Cox22ad57b2014-03-19 13:06:25 -05001693 rc = -CONTROLVM_RESP_ERROR_PAYLOAD_INVALID;
Benjamin Romerf118a392015-03-16 13:58:26 -04001694 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001695 }
Jes Sorensenc1f834e2015-04-13 10:28:39 -04001696 memset(info, 0, sizeof(struct visor_controlvm_payload_info));
Ken Cox12e364b2014-03-04 07:58:07 -06001697 if ((offset == 0) || (bytes == 0)) {
Ken Cox22ad57b2014-03-19 13:06:25 -05001698 rc = -CONTROLVM_RESP_ERROR_PAYLOAD_INVALID;
Benjamin Romerf118a392015-03-16 13:58:26 -04001699 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001700 }
1701 payload = ioremap_cache(phys_addr + offset, bytes);
Benjamin Romer38f736e2015-03-16 13:58:13 -04001702 if (!payload) {
Ken Cox22ad57b2014-03-19 13:06:25 -05001703 rc = -CONTROLVM_RESP_ERROR_IOREMAP_FAILED;
Benjamin Romerf118a392015-03-16 13:58:26 -04001704 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06001705 }
1706
1707 info->offset = offset;
1708 info->bytes = bytes;
1709 info->ptr = payload;
Ken Cox12e364b2014-03-04 07:58:07 -06001710
Benjamin Romerf118a392015-03-16 13:58:26 -04001711cleanup:
Ken Cox12e364b2014-03-04 07:58:07 -06001712 if (rc < 0) {
Benjamin Romerf118a392015-03-16 13:58:26 -04001713 if (payload) {
Ken Cox12e364b2014-03-04 07:58:07 -06001714 iounmap(payload);
1715 payload = NULL;
1716 }
1717 }
1718 return rc;
1719}
1720
1721static void
Jes Sorensenc1f834e2015-04-13 10:28:39 -04001722destroy_controlvm_payload_info(struct visor_controlvm_payload_info *info)
Ken Cox12e364b2014-03-04 07:58:07 -06001723{
Benjamin Romer597c3382015-03-16 13:58:27 -04001724 if (info->ptr) {
Ken Cox12e364b2014-03-04 07:58:07 -06001725 iounmap(info->ptr);
1726 info->ptr = NULL;
1727 }
Jes Sorensenc1f834e2015-04-13 10:28:39 -04001728 memset(info, 0, sizeof(struct visor_controlvm_payload_info));
Ken Cox12e364b2014-03-04 07:58:07 -06001729}
1730
1731static void
1732initialize_controlvm_payload(void)
1733{
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -04001734 u64 phys_addr = visorchannel_get_physaddr(controlvm_channel);
Benjamin Romercafefc02015-03-16 13:58:28 -04001735 u64 payload_offset = 0;
1736 u32 payload_bytes = 0;
Benjamin Romer26eb2c02014-08-18 09:34:53 -04001737
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001738 if (visorchannel_read(controlvm_channel,
Benjamin Romerd19642f2014-10-23 14:30:34 -04001739 offsetof(struct spar_controlvm_channel_protocol,
1740 request_payload_offset),
Benjamin Romercafefc02015-03-16 13:58:28 -04001741 &payload_offset, sizeof(payload_offset)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06001742 POSTCODE_LINUX_2(CONTROLVM_INIT_FAILURE_PC,
1743 POSTCODE_SEVERITY_ERR);
1744 return;
1745 }
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001746 if (visorchannel_read(controlvm_channel,
Benjamin Romerd19642f2014-10-23 14:30:34 -04001747 offsetof(struct spar_controlvm_channel_protocol,
1748 request_payload_bytes),
Benjamin Romercafefc02015-03-16 13:58:28 -04001749 &payload_bytes, sizeof(payload_bytes)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06001750 POSTCODE_LINUX_2(CONTROLVM_INIT_FAILURE_PC,
1751 POSTCODE_SEVERITY_ERR);
1752 return;
1753 }
1754 initialize_controlvm_payload_info(phys_addr,
Benjamin Romercafefc02015-03-16 13:58:28 -04001755 payload_offset, payload_bytes,
Benjamin Romer84982fb2015-03-16 13:58:07 -04001756 &controlvm_payload_info);
Ken Cox12e364b2014-03-04 07:58:07 -06001757}
1758
1759/* Send ACTION=online for DEVPATH=/sys/devices/platform/visorchipset.
1760 * Returns CONTROLVM_RESP_xxx code.
1761 */
1762int
1763visorchipset_chipset_ready(void)
1764{
Benjamin Romereb34e872015-03-16 13:58:45 -04001765 kobject_uevent(&visorchipset_platform_device.dev.kobj, KOBJ_ONLINE);
Ken Cox12e364b2014-03-04 07:58:07 -06001766 return CONTROLVM_RESP_SUCCESS;
1767}
1768EXPORT_SYMBOL_GPL(visorchipset_chipset_ready);
1769
1770int
1771visorchipset_chipset_selftest(void)
1772{
1773 char env_selftest[20];
1774 char *envp[] = { env_selftest, NULL };
Benjamin Romer26eb2c02014-08-18 09:34:53 -04001775
Ken Cox12e364b2014-03-04 07:58:07 -06001776 sprintf(env_selftest, "SPARSP_SELFTEST=%d", 1);
Benjamin Romereb34e872015-03-16 13:58:45 -04001777 kobject_uevent_env(&visorchipset_platform_device.dev.kobj, KOBJ_CHANGE,
Ken Cox12e364b2014-03-04 07:58:07 -06001778 envp);
1779 return CONTROLVM_RESP_SUCCESS;
1780}
1781EXPORT_SYMBOL_GPL(visorchipset_chipset_selftest);
1782
1783/* Send ACTION=offline for DEVPATH=/sys/devices/platform/visorchipset.
1784 * Returns CONTROLVM_RESP_xxx code.
1785 */
1786int
1787visorchipset_chipset_notready(void)
1788{
Benjamin Romereb34e872015-03-16 13:58:45 -04001789 kobject_uevent(&visorchipset_platform_device.dev.kobj, KOBJ_OFFLINE);
Ken Cox12e364b2014-03-04 07:58:07 -06001790 return CONTROLVM_RESP_SUCCESS;
1791}
1792EXPORT_SYMBOL_GPL(visorchipset_chipset_notready);
1793
1794static void
Benjamin Romer77a04492015-03-16 13:58:47 -04001795chipset_ready(struct controlvm_message_header *msg_hdr)
Ken Cox12e364b2014-03-04 07:58:07 -06001796{
1797 int rc = visorchipset_chipset_ready();
Benjamin Romer26eb2c02014-08-18 09:34:53 -04001798
Ken Cox12e364b2014-03-04 07:58:07 -06001799 if (rc != CONTROLVM_RESP_SUCCESS)
1800 rc = -rc;
Benjamin Romer77a04492015-03-16 13:58:47 -04001801 if (msg_hdr->flags.response_expected && !visorchipset_holdchipsetready)
1802 controlvm_respond(msg_hdr, rc);
1803 if (msg_hdr->flags.response_expected && visorchipset_holdchipsetready) {
Ken Cox12e364b2014-03-04 07:58:07 -06001804 /* Send CHIPSET_READY response when all modules have been loaded
1805 * and disks mounted for the partition
1806 */
Benjamin Romer77a04492015-03-16 13:58:47 -04001807 g_chipset_msg_hdr = *msg_hdr;
Ken Cox12e364b2014-03-04 07:58:07 -06001808 }
1809}
1810
1811static void
Benjamin Romer77a04492015-03-16 13:58:47 -04001812chipset_selftest(struct controlvm_message_header *msg_hdr)
Ken Cox12e364b2014-03-04 07:58:07 -06001813{
1814 int rc = visorchipset_chipset_selftest();
Benjamin Romer26eb2c02014-08-18 09:34:53 -04001815
Ken Cox12e364b2014-03-04 07:58:07 -06001816 if (rc != CONTROLVM_RESP_SUCCESS)
1817 rc = -rc;
Benjamin Romer77a04492015-03-16 13:58:47 -04001818 if (msg_hdr->flags.response_expected)
1819 controlvm_respond(msg_hdr, rc);
Ken Cox12e364b2014-03-04 07:58:07 -06001820}
1821
1822static void
Benjamin Romer77a04492015-03-16 13:58:47 -04001823chipset_notready(struct controlvm_message_header *msg_hdr)
Ken Cox12e364b2014-03-04 07:58:07 -06001824{
1825 int rc = visorchipset_chipset_notready();
Benjamin Romer26eb2c02014-08-18 09:34:53 -04001826
Ken Cox12e364b2014-03-04 07:58:07 -06001827 if (rc != CONTROLVM_RESP_SUCCESS)
1828 rc = -rc;
Benjamin Romer77a04492015-03-16 13:58:47 -04001829 if (msg_hdr->flags.response_expected)
1830 controlvm_respond(msg_hdr, rc);
Ken Cox12e364b2014-03-04 07:58:07 -06001831}
1832
1833/* This is your "one-stop" shop for grabbing the next message from the
1834 * CONTROLVM_QUEUE_EVENT queue in the controlvm channel.
1835 */
Jes Sorensenf4c11552015-04-13 10:28:40 -04001836static bool
Benjamin Romer3ab47702014-10-23 14:30:31 -04001837read_controlvm_event(struct controlvm_message *msg)
Ken Cox12e364b2014-03-04 07:58:07 -06001838{
Benjamin Romerc3d9a222015-03-16 13:58:05 -04001839 if (visorchannel_signalremove(controlvm_channel,
Ken Cox12e364b2014-03-04 07:58:07 -06001840 CONTROLVM_QUEUE_EVENT, msg)) {
1841 /* got a message */
Benjamin Romer0aca78442015-03-04 12:14:25 -05001842 if (msg->hdr.flags.test_message == 1)
Jes Sorensenf4c11552015-04-13 10:28:40 -04001843 return false;
1844 return true;
Ken Cox12e364b2014-03-04 07:58:07 -06001845 }
Jes Sorensenf4c11552015-04-13 10:28:40 -04001846 return false;
Ken Cox12e364b2014-03-04 07:58:07 -06001847}
1848
1849/*
1850 * The general parahotplug flow works as follows. The visorchipset
1851 * driver receives a DEVICE_CHANGESTATE message from Command
1852 * specifying a physical device to enable or disable. The CONTROLVM
1853 * message handler calls parahotplug_process_message, which then adds
1854 * the message to a global list and kicks off a udev event which
1855 * causes a user level script to enable or disable the specified
1856 * device. The udev script then writes to
1857 * /proc/visorchipset/parahotplug, which causes parahotplug_proc_write
1858 * to get called, at which point the appropriate CONTROLVM message is
1859 * retrieved from the list and responded to.
1860 */
1861
1862#define PARAHOTPLUG_TIMEOUT_MS 2000
1863
1864/*
1865 * Generate unique int to match an outstanding CONTROLVM message with a
1866 * udev script /proc response
1867 */
1868static int
1869parahotplug_next_id(void)
1870{
1871 static atomic_t id = ATOMIC_INIT(0);
Benjamin Romer26eb2c02014-08-18 09:34:53 -04001872
Ken Cox12e364b2014-03-04 07:58:07 -06001873 return atomic_inc_return(&id);
1874}
1875
1876/*
1877 * Returns the time (in jiffies) when a CONTROLVM message on the list
1878 * should expire -- PARAHOTPLUG_TIMEOUT_MS in the future
1879 */
1880static unsigned long
1881parahotplug_next_expiration(void)
1882{
Nicholas Mc Guire2cc1a1b2015-01-31 12:02:08 +01001883 return jiffies + msecs_to_jiffies(PARAHOTPLUG_TIMEOUT_MS);
Ken Cox12e364b2014-03-04 07:58:07 -06001884}
1885
1886/*
1887 * Create a parahotplug_request, which is basically a wrapper for a
1888 * CONTROLVM_MESSAGE that we can stick on a list
1889 */
1890static struct parahotplug_request *
Benjamin Romer3ab47702014-10-23 14:30:31 -04001891parahotplug_request_create(struct controlvm_message *msg)
Ken Cox12e364b2014-03-04 07:58:07 -06001892{
Quentin Lambertea0dcfc2015-02-10 15:12:07 +01001893 struct parahotplug_request *req;
1894
Benjamin Romer6a55e3c2015-03-16 13:58:30 -04001895 req = kmalloc(sizeof(*req), GFP_KERNEL | __GFP_NORETRY);
Benjamin Romer38f736e2015-03-16 13:58:13 -04001896 if (!req)
Ken Cox12e364b2014-03-04 07:58:07 -06001897 return NULL;
1898
1899 req->id = parahotplug_next_id();
1900 req->expiration = parahotplug_next_expiration();
1901 req->msg = *msg;
1902
1903 return req;
1904}
1905
1906/*
1907 * Free a parahotplug_request.
1908 */
1909static void
1910parahotplug_request_destroy(struct parahotplug_request *req)
1911{
1912 kfree(req);
1913}
1914
1915/*
1916 * Cause uevent to run the user level script to do the disable/enable
1917 * specified in (the CONTROLVM message in) the specified
1918 * parahotplug_request
1919 */
1920static void
1921parahotplug_request_kickoff(struct parahotplug_request *req)
1922{
Benjamin Romer2ea51172014-10-23 14:30:25 -04001923 struct controlvm_message_packet *cmd = &req->msg.cmd;
Ken Cox12e364b2014-03-04 07:58:07 -06001924 char env_cmd[40], env_id[40], env_state[40], env_bus[40], env_dev[40],
1925 env_func[40];
1926 char *envp[] = {
1927 env_cmd, env_id, env_state, env_bus, env_dev, env_func, NULL
1928 };
1929
1930 sprintf(env_cmd, "SPAR_PARAHOTPLUG=1");
1931 sprintf(env_id, "SPAR_PARAHOTPLUG_ID=%d", req->id);
1932 sprintf(env_state, "SPAR_PARAHOTPLUG_STATE=%d",
Benjamin Romer2ea51172014-10-23 14:30:25 -04001933 cmd->device_change_state.state.active);
Ken Cox12e364b2014-03-04 07:58:07 -06001934 sprintf(env_bus, "SPAR_PARAHOTPLUG_BUS=%d",
Benjamin Romer2ea51172014-10-23 14:30:25 -04001935 cmd->device_change_state.bus_no);
Ken Cox12e364b2014-03-04 07:58:07 -06001936 sprintf(env_dev, "SPAR_PARAHOTPLUG_DEVICE=%d",
Benjamin Romer2ea51172014-10-23 14:30:25 -04001937 cmd->device_change_state.dev_no >> 3);
Ken Cox12e364b2014-03-04 07:58:07 -06001938 sprintf(env_func, "SPAR_PARAHOTPLUG_FUNCTION=%d",
Benjamin Romer2ea51172014-10-23 14:30:25 -04001939 cmd->device_change_state.dev_no & 0x7);
Ken Cox12e364b2014-03-04 07:58:07 -06001940
Benjamin Romereb34e872015-03-16 13:58:45 -04001941 kobject_uevent_env(&visorchipset_platform_device.dev.kobj, KOBJ_CHANGE,
Ken Cox12e364b2014-03-04 07:58:07 -06001942 envp);
1943}
1944
1945/*
1946 * Remove any request from the list that's been on there too long and
1947 * respond with an error.
1948 */
1949static void
1950parahotplug_process_list(void)
1951{
Jes Sorensene82ba622015-05-05 18:35:45 -04001952 struct list_head *pos;
1953 struct list_head *tmp;
Ken Cox12e364b2014-03-04 07:58:07 -06001954
Benjamin Romerddf5de52015-03-16 13:58:41 -04001955 spin_lock(&parahotplug_request_list_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001956
Benjamin Romerddf5de52015-03-16 13:58:41 -04001957 list_for_each_safe(pos, tmp, &parahotplug_request_list) {
Ken Cox12e364b2014-03-04 07:58:07 -06001958 struct parahotplug_request *req =
1959 list_entry(pos, struct parahotplug_request, list);
Benjamin Romer55b33412015-03-16 13:58:29 -04001960
1961 if (!time_after_eq(jiffies, req->expiration))
1962 continue;
1963
1964 list_del(pos);
1965 if (req->msg.hdr.flags.response_expected)
1966 controlvm_respond_physdev_changestate(
1967 &req->msg.hdr,
1968 CONTROLVM_RESP_ERROR_DEVICE_UDEV_TIMEOUT,
1969 req->msg.cmd.device_change_state.state);
1970 parahotplug_request_destroy(req);
Ken Cox12e364b2014-03-04 07:58:07 -06001971 }
1972
Benjamin Romerddf5de52015-03-16 13:58:41 -04001973 spin_unlock(&parahotplug_request_list_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001974}
1975
1976/*
1977 * Called from the /proc handler, which means the user script has
1978 * finished the enable/disable. Find the matching identifier, and
1979 * respond to the CONTROLVM message with success.
1980 */
1981static int
Benjamin Romerb06bdf72014-07-31 12:00:49 -04001982parahotplug_request_complete(int id, u16 active)
Ken Cox12e364b2014-03-04 07:58:07 -06001983{
Jes Sorensene82ba622015-05-05 18:35:45 -04001984 struct list_head *pos;
1985 struct list_head *tmp;
Ken Cox12e364b2014-03-04 07:58:07 -06001986
Benjamin Romerddf5de52015-03-16 13:58:41 -04001987 spin_lock(&parahotplug_request_list_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06001988
1989 /* Look for a request matching "id". */
Benjamin Romerddf5de52015-03-16 13:58:41 -04001990 list_for_each_safe(pos, tmp, &parahotplug_request_list) {
Ken Cox12e364b2014-03-04 07:58:07 -06001991 struct parahotplug_request *req =
1992 list_entry(pos, struct parahotplug_request, list);
1993 if (req->id == id) {
1994 /* Found a match. Remove it from the list and
1995 * respond.
1996 */
1997 list_del(pos);
Benjamin Romerddf5de52015-03-16 13:58:41 -04001998 spin_unlock(&parahotplug_request_list_lock);
Benjamin Romer2ea51172014-10-23 14:30:25 -04001999 req->msg.cmd.device_change_state.state.active = active;
Benjamin Romer98d7b592014-10-23 14:30:26 -04002000 if (req->msg.hdr.flags.response_expected)
Ken Cox12e364b2014-03-04 07:58:07 -06002001 controlvm_respond_physdev_changestate(
2002 &req->msg.hdr, CONTROLVM_RESP_SUCCESS,
Benjamin Romer2ea51172014-10-23 14:30:25 -04002003 req->msg.cmd.device_change_state.state);
Ken Cox12e364b2014-03-04 07:58:07 -06002004 parahotplug_request_destroy(req);
2005 return 0;
2006 }
2007 }
2008
Benjamin Romerddf5de52015-03-16 13:58:41 -04002009 spin_unlock(&parahotplug_request_list_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06002010 return -1;
2011}
2012
2013/*
2014 * Enables or disables a PCI device by kicking off a udev script
2015 */
Ken Coxbd5b9b32014-03-13 15:39:22 -05002016static void
Benjamin Romer3ab47702014-10-23 14:30:31 -04002017parahotplug_process_message(struct controlvm_message *inmsg)
Ken Cox12e364b2014-03-04 07:58:07 -06002018{
2019 struct parahotplug_request *req;
2020
2021 req = parahotplug_request_create(inmsg);
2022
Benjamin Romer38f736e2015-03-16 13:58:13 -04002023 if (!req)
Ken Cox12e364b2014-03-04 07:58:07 -06002024 return;
Ken Cox12e364b2014-03-04 07:58:07 -06002025
Benjamin Romer2ea51172014-10-23 14:30:25 -04002026 if (inmsg->cmd.device_change_state.state.active) {
Ken Cox12e364b2014-03-04 07:58:07 -06002027 /* For enable messages, just respond with success
2028 * right away. This is a bit of a hack, but there are
2029 * issues with the early enable messages we get (with
2030 * either the udev script not detecting that the device
2031 * is up, or not getting called at all). Fortunately
2032 * the messages that get lost don't matter anyway, as
2033 * devices are automatically enabled at
2034 * initialization.
2035 */
2036 parahotplug_request_kickoff(req);
2037 controlvm_respond_physdev_changestate(&inmsg->hdr,
Benjamin Romer8e76e692015-03-16 13:58:52 -04002038 CONTROLVM_RESP_SUCCESS,
2039 inmsg->cmd.device_change_state.state);
Ken Cox12e364b2014-03-04 07:58:07 -06002040 parahotplug_request_destroy(req);
2041 } else {
2042 /* For disable messages, add the request to the
2043 * request list before kicking off the udev script. It
2044 * won't get responded to until the script has
2045 * indicated it's done.
2046 */
Benjamin Romerddf5de52015-03-16 13:58:41 -04002047 spin_lock(&parahotplug_request_list_lock);
2048 list_add_tail(&req->list, &parahotplug_request_list);
2049 spin_unlock(&parahotplug_request_list_lock);
Ken Cox12e364b2014-03-04 07:58:07 -06002050
2051 parahotplug_request_kickoff(req);
2052 }
2053}
2054
Ken Cox12e364b2014-03-04 07:58:07 -06002055/* Process a controlvm message.
2056 * Return result:
Prarit Bhargava779d0752015-05-05 18:37:01 -04002057 * false - this function will return false only in the case where the
Ken Cox12e364b2014-03-04 07:58:07 -06002058 * controlvm message was NOT processed, but processing must be
2059 * retried before reading the next controlvm message; a
2060 * scenario where this can occur is when we need to throttle
2061 * the allocation of memory in which to copy out controlvm
2062 * payload data
Jes Sorensenf4c11552015-04-13 10:28:40 -04002063 * true - processing of the controlvm message completed,
Ken Cox12e364b2014-03-04 07:58:07 -06002064 * either successfully or with an error.
2065 */
Jes Sorensenf4c11552015-04-13 10:28:40 -04002066static bool
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -04002067handle_command(struct controlvm_message inmsg, u64 channel_addr)
Ken Cox12e364b2014-03-04 07:58:07 -06002068{
Benjamin Romer2ea51172014-10-23 14:30:25 -04002069 struct controlvm_message_packet *cmd = &inmsg.cmd;
Jes Sorensene82ba622015-05-05 18:35:45 -04002070 u64 parm_addr;
2071 u32 parm_bytes;
Benjamin Romer317d9612015-03-16 13:57:51 -04002072 struct parser_context *parser_ctx = NULL;
Jes Sorensene82ba622015-05-05 18:35:45 -04002073 bool local_addr;
Benjamin Romer3ab47702014-10-23 14:30:31 -04002074 struct controlvm_message ackmsg;
Ken Cox12e364b2014-03-04 07:58:07 -06002075
2076 /* create parsing context if necessary */
Benjamin Romer818352a2015-03-16 13:58:31 -04002077 local_addr = (inmsg.hdr.flags.test_message == 1);
Benjamin Romer0aca78442015-03-04 12:14:25 -05002078 if (channel_addr == 0)
Jes Sorensenf4c11552015-04-13 10:28:40 -04002079 return true;
Benjamin Romer818352a2015-03-16 13:58:31 -04002080 parm_addr = channel_addr + inmsg.hdr.payload_vm_offset;
2081 parm_bytes = inmsg.hdr.payload_bytes;
Ken Cox12e364b2014-03-04 07:58:07 -06002082
2083 /* Parameter and channel addresses within test messages actually lie
2084 * within our OS-controlled memory. We need to know that, because it
2085 * makes a difference in how we compute the virtual address.
2086 */
Jes Sorensenebec8962015-05-05 18:35:57 -04002087 if (parm_addr && parm_bytes) {
Jes Sorensenf4c11552015-04-13 10:28:40 -04002088 bool retry = false;
Benjamin Romer26eb2c02014-08-18 09:34:53 -04002089
Ken Cox12e364b2014-03-04 07:58:07 -06002090 parser_ctx =
Benjamin Romer818352a2015-03-16 13:58:31 -04002091 parser_init_byte_stream(parm_addr, parm_bytes,
2092 local_addr, &retry);
Benjamin Romer1b088722015-03-04 12:14:26 -05002093 if (!parser_ctx && retry)
Jes Sorensenf4c11552015-04-13 10:28:40 -04002094 return false;
Ken Cox12e364b2014-03-04 07:58:07 -06002095 }
2096
Benjamin Romer818352a2015-03-16 13:58:31 -04002097 if (!local_addr) {
Ken Cox12e364b2014-03-04 07:58:07 -06002098 controlvm_init_response(&ackmsg, &inmsg.hdr,
2099 CONTROLVM_RESP_SUCCESS);
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002100 if (controlvm_channel)
2101 visorchannel_signalinsert(controlvm_channel,
Benjamin Romer1b088722015-03-04 12:14:26 -05002102 CONTROLVM_QUEUE_ACK,
2103 &ackmsg);
Ken Cox12e364b2014-03-04 07:58:07 -06002104 }
Benjamin Romer98d7b592014-10-23 14:30:26 -04002105 switch (inmsg.hdr.id) {
Ken Cox12e364b2014-03-04 07:58:07 -06002106 case CONTROLVM_CHIPSET_INIT:
Ken Cox12e364b2014-03-04 07:58:07 -06002107 chipset_init(&inmsg);
2108 break;
2109 case CONTROLVM_BUS_CREATE:
Ken Cox12e364b2014-03-04 07:58:07 -06002110 bus_create(&inmsg);
2111 break;
2112 case CONTROLVM_BUS_DESTROY:
Ken Cox12e364b2014-03-04 07:58:07 -06002113 bus_destroy(&inmsg);
2114 break;
2115 case CONTROLVM_BUS_CONFIGURE:
Ken Cox12e364b2014-03-04 07:58:07 -06002116 bus_configure(&inmsg, parser_ctx);
2117 break;
2118 case CONTROLVM_DEVICE_CREATE:
Ken Cox12e364b2014-03-04 07:58:07 -06002119 my_device_create(&inmsg);
2120 break;
2121 case CONTROLVM_DEVICE_CHANGESTATE:
Benjamin Romer2ea51172014-10-23 14:30:25 -04002122 if (cmd->device_change_state.flags.phys_device) {
Ken Cox12e364b2014-03-04 07:58:07 -06002123 parahotplug_process_message(&inmsg);
2124 } else {
Ken Cox12e364b2014-03-04 07:58:07 -06002125 /* save the hdr and cmd structures for later use */
2126 /* when sending back the response to Command */
2127 my_device_changestate(&inmsg);
Benjamin Romer4f44b722015-03-16 13:58:02 -04002128 g_devicechangestate_packet = inmsg.cmd;
Ken Cox12e364b2014-03-04 07:58:07 -06002129 break;
2130 }
2131 break;
2132 case CONTROLVM_DEVICE_DESTROY:
Ken Cox12e364b2014-03-04 07:58:07 -06002133 my_device_destroy(&inmsg);
2134 break;
2135 case CONTROLVM_DEVICE_CONFIGURE:
Ken Cox12e364b2014-03-04 07:58:07 -06002136 /* no op for now, just send a respond that we passed */
Benjamin Romer98d7b592014-10-23 14:30:26 -04002137 if (inmsg.hdr.flags.response_expected)
Ken Cox12e364b2014-03-04 07:58:07 -06002138 controlvm_respond(&inmsg.hdr, CONTROLVM_RESP_SUCCESS);
2139 break;
2140 case CONTROLVM_CHIPSET_READY:
Ken Cox12e364b2014-03-04 07:58:07 -06002141 chipset_ready(&inmsg.hdr);
2142 break;
2143 case CONTROLVM_CHIPSET_SELFTEST:
Ken Cox12e364b2014-03-04 07:58:07 -06002144 chipset_selftest(&inmsg.hdr);
2145 break;
2146 case CONTROLVM_CHIPSET_STOP:
Ken Cox12e364b2014-03-04 07:58:07 -06002147 chipset_notready(&inmsg.hdr);
2148 break;
2149 default:
Benjamin Romer98d7b592014-10-23 14:30:26 -04002150 if (inmsg.hdr.flags.response_expected)
Ken Cox12e364b2014-03-04 07:58:07 -06002151 controlvm_respond(&inmsg.hdr,
Benjamin Romer818352a2015-03-16 13:58:31 -04002152 -CONTROLVM_RESP_ERROR_MESSAGE_ID_UNKNOWN);
Ken Cox12e364b2014-03-04 07:58:07 -06002153 break;
2154 }
2155
Benjamin Romer38f736e2015-03-16 13:58:13 -04002156 if (parser_ctx) {
Ken Cox12e364b2014-03-04 07:58:07 -06002157 parser_done(parser_ctx);
2158 parser_ctx = NULL;
2159 }
Jes Sorensenf4c11552015-04-13 10:28:40 -04002160 return true;
Ken Cox12e364b2014-03-04 07:58:07 -06002161}
2162
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -04002163static u64 controlvm_get_channel_address(void)
Benjamin Romer524b0b62014-07-17 12:39:57 -04002164{
Benjamin Romer5fc02292014-07-31 12:00:51 -04002165 u64 addr = 0;
Benjamin Romerb3c55b12014-07-31 12:00:50 -04002166 u32 size = 0;
Benjamin Romer524b0b62014-07-17 12:39:57 -04002167
Benjamin Romer0aca78442015-03-04 12:14:25 -05002168 if (!VMCALL_SUCCESSFUL(issue_vmcall_io_controlvm_addr(&addr, &size)))
Benjamin Romer524b0b62014-07-17 12:39:57 -04002169 return 0;
Benjamin Romer0aca78442015-03-04 12:14:25 -05002170
Benjamin Romer524b0b62014-07-17 12:39:57 -04002171 return addr;
2172}
2173
Ken Cox12e364b2014-03-04 07:58:07 -06002174static void
2175controlvm_periodic_work(struct work_struct *work)
2176{
Benjamin Romer3ab47702014-10-23 14:30:31 -04002177 struct controlvm_message inmsg;
Jes Sorensenf4c11552015-04-13 10:28:40 -04002178 bool got_command = false;
2179 bool handle_command_failed = false;
Benjamin Romer1c1ed292015-03-16 13:58:32 -04002180 static u64 poll_count;
Ken Cox12e364b2014-03-04 07:58:07 -06002181
2182 /* make sure visorbus server is registered for controlvm callbacks */
David Kershner4da33362015-05-05 18:36:39 -04002183 if (visorchipset_visorbusregwait && !visorbusregistered)
Benjamin Romer1c1ed292015-03-16 13:58:32 -04002184 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06002185
Benjamin Romer1c1ed292015-03-16 13:58:32 -04002186 poll_count++;
2187 if (poll_count >= 250)
Ken Cox12e364b2014-03-04 07:58:07 -06002188 ; /* keep going */
2189 else
Benjamin Romer1c1ed292015-03-16 13:58:32 -04002190 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06002191
2192 /* Check events to determine if response to CHIPSET_READY
2193 * should be sent
2194 */
Benjamin Romer0639ba62015-03-16 13:58:04 -04002195 if (visorchipset_holdchipsetready &&
2196 (g_chipset_msg_hdr.id != CONTROLVM_INVALID)) {
Ken Cox12e364b2014-03-04 07:58:07 -06002197 if (check_chipset_events() == 1) {
Benjamin Romerda021f02015-03-16 13:57:58 -04002198 controlvm_respond(&g_chipset_msg_hdr, 0);
Ken Cox12e364b2014-03-04 07:58:07 -06002199 clear_chipset_events();
Benjamin Romerda021f02015-03-16 13:57:58 -04002200 memset(&g_chipset_msg_hdr, 0,
Benjamin Romer98d7b592014-10-23 14:30:26 -04002201 sizeof(struct controlvm_message_header));
Ken Cox12e364b2014-03-04 07:58:07 -06002202 }
2203 }
2204
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002205 while (visorchannel_signalremove(controlvm_channel,
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002206 CONTROLVM_QUEUE_RESPONSE,
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002207 &inmsg))
2208 ;
Benjamin Romer1c1ed292015-03-16 13:58:32 -04002209 if (!got_command) {
Benjamin Romer7166ed12015-03-16 13:58:38 -04002210 if (controlvm_pending_msg_valid) {
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002211 /* we throttled processing of a prior
2212 * msg, so try to process it again
2213 * rather than reading a new one
2214 */
Benjamin Romer7166ed12015-03-16 13:58:38 -04002215 inmsg = controlvm_pending_msg;
Jes Sorensenf4c11552015-04-13 10:28:40 -04002216 controlvm_pending_msg_valid = false;
Benjamin Romer1c1ed292015-03-16 13:58:32 -04002217 got_command = true;
Benjamin Romer75c1f8b2015-03-16 13:58:19 -04002218 } else {
Benjamin Romer1c1ed292015-03-16 13:58:32 -04002219 got_command = read_controlvm_event(&inmsg);
Benjamin Romer75c1f8b2015-03-16 13:58:19 -04002220 }
Ken Cox12e364b2014-03-04 07:58:07 -06002221 }
2222
Jes Sorensenf4c11552015-04-13 10:28:40 -04002223 handle_command_failed = false;
Benjamin Romer1c1ed292015-03-16 13:58:32 -04002224 while (got_command && (!handle_command_failed)) {
Benjamin Romerb53e0e92015-03-16 13:57:56 -04002225 most_recent_message_jiffies = jiffies;
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002226 if (handle_command(inmsg,
2227 visorchannel_get_physaddr
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002228 (controlvm_channel)))
Benjamin Romer1c1ed292015-03-16 13:58:32 -04002229 got_command = read_controlvm_event(&inmsg);
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002230 else {
2231 /* this is a scenario where throttling
2232 * is required, but probably NOT an
2233 * error...; we stash the current
2234 * controlvm msg so we will attempt to
2235 * reprocess it on our next loop
2236 */
Jes Sorensenf4c11552015-04-13 10:28:40 -04002237 handle_command_failed = true;
Benjamin Romer7166ed12015-03-16 13:58:38 -04002238 controlvm_pending_msg = inmsg;
Jes Sorensenf4c11552015-04-13 10:28:40 -04002239 controlvm_pending_msg_valid = true;
Ken Cox12e364b2014-03-04 07:58:07 -06002240 }
2241 }
2242
2243 /* parahotplug_worker */
2244 parahotplug_process_list();
2245
Benjamin Romer1c1ed292015-03-16 13:58:32 -04002246cleanup:
Ken Cox12e364b2014-03-04 07:58:07 -06002247
2248 if (time_after(jiffies,
Benjamin Romerb53e0e92015-03-16 13:57:56 -04002249 most_recent_message_jiffies + (HZ * MIN_IDLE_SECONDS))) {
Ken Cox12e364b2014-03-04 07:58:07 -06002250 /* it's been longer than MIN_IDLE_SECONDS since we
2251 * processed our last controlvm message; slow down the
2252 * polling
2253 */
Benjamin Romer911e2132015-03-16 13:57:47 -04002254 if (poll_jiffies != POLLJIFFIES_CONTROLVMCHANNEL_SLOW)
2255 poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_SLOW;
Ken Cox12e364b2014-03-04 07:58:07 -06002256 } else {
Benjamin Romer911e2132015-03-16 13:57:47 -04002257 if (poll_jiffies != POLLJIFFIES_CONTROLVMCHANNEL_FAST)
2258 poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
Ken Cox12e364b2014-03-04 07:58:07 -06002259 }
2260
Benjamin Romer9232d2d2015-03-16 13:57:57 -04002261 queue_delayed_work(periodic_controlvm_workqueue,
2262 &periodic_controlvm_work, poll_jiffies);
Ken Cox12e364b2014-03-04 07:58:07 -06002263}
2264
2265static void
2266setup_crash_devices_work_queue(struct work_struct *work)
2267{
Benjamin Romere6bdb902015-03-16 13:58:33 -04002268 struct controlvm_message local_crash_bus_msg;
2269 struct controlvm_message local_crash_dev_msg;
Benjamin Romer3ab47702014-10-23 14:30:31 -04002270 struct controlvm_message msg;
Benjamin Romere6bdb902015-03-16 13:58:33 -04002271 u32 local_crash_msg_offset;
2272 u16 local_crash_msg_count;
Ken Cox12e364b2014-03-04 07:58:07 -06002273
David Kershner4da33362015-05-05 18:36:39 -04002274 /* make sure visorbus is registered for controlvm callbacks */
2275 if (visorchipset_visorbusregwait && !visorbusregistered)
Benjamin Romere6bdb902015-03-16 13:58:33 -04002276 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06002277
2278 POSTCODE_LINUX_2(CRASH_DEV_ENTRY_PC, POSTCODE_SEVERITY_INFO);
2279
2280 /* send init chipset msg */
Benjamin Romer98d7b592014-10-23 14:30:26 -04002281 msg.hdr.id = CONTROLVM_CHIPSET_INIT;
Benjamin Romer2ea51172014-10-23 14:30:25 -04002282 msg.cmd.init_chipset.bus_count = 23;
2283 msg.cmd.init_chipset.switch_count = 0;
Ken Cox12e364b2014-03-04 07:58:07 -06002284
2285 chipset_init(&msg);
2286
Ken Cox12e364b2014-03-04 07:58:07 -06002287 /* get saved message count */
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002288 if (visorchannel_read(controlvm_channel,
Benjamin Romerd19642f2014-10-23 14:30:34 -04002289 offsetof(struct spar_controlvm_channel_protocol,
2290 saved_crash_message_count),
Benjamin Romere6bdb902015-03-16 13:58:33 -04002291 &local_crash_msg_count, sizeof(u16)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06002292 POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
2293 POSTCODE_SEVERITY_ERR);
2294 return;
2295 }
2296
Benjamin Romere6bdb902015-03-16 13:58:33 -04002297 if (local_crash_msg_count != CONTROLVM_CRASHMSG_MAX) {
Ken Cox12e364b2014-03-04 07:58:07 -06002298 POSTCODE_LINUX_3(CRASH_DEV_COUNT_FAILURE_PC,
Benjamin Romere6bdb902015-03-16 13:58:33 -04002299 local_crash_msg_count,
Ken Cox12e364b2014-03-04 07:58:07 -06002300 POSTCODE_SEVERITY_ERR);
2301 return;
2302 }
2303
2304 /* get saved crash message offset */
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002305 if (visorchannel_read(controlvm_channel,
Benjamin Romerd19642f2014-10-23 14:30:34 -04002306 offsetof(struct spar_controlvm_channel_protocol,
2307 saved_crash_message_offset),
Benjamin Romere6bdb902015-03-16 13:58:33 -04002308 &local_crash_msg_offset, sizeof(u32)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06002309 POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
2310 POSTCODE_SEVERITY_ERR);
2311 return;
2312 }
2313
2314 /* read create device message for storage bus offset */
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002315 if (visorchannel_read(controlvm_channel,
Benjamin Romere6bdb902015-03-16 13:58:33 -04002316 local_crash_msg_offset,
2317 &local_crash_bus_msg,
Benjamin Romer3ab47702014-10-23 14:30:31 -04002318 sizeof(struct controlvm_message)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06002319 POSTCODE_LINUX_2(CRASH_DEV_RD_BUS_FAIULRE_PC,
2320 POSTCODE_SEVERITY_ERR);
2321 return;
2322 }
2323
2324 /* read create device message for storage device */
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002325 if (visorchannel_read(controlvm_channel,
Benjamin Romere6bdb902015-03-16 13:58:33 -04002326 local_crash_msg_offset +
Benjamin Romer3ab47702014-10-23 14:30:31 -04002327 sizeof(struct controlvm_message),
Benjamin Romere6bdb902015-03-16 13:58:33 -04002328 &local_crash_dev_msg,
Benjamin Romer3ab47702014-10-23 14:30:31 -04002329 sizeof(struct controlvm_message)) < 0) {
Ken Cox12e364b2014-03-04 07:58:07 -06002330 POSTCODE_LINUX_2(CRASH_DEV_RD_DEV_FAIULRE_PC,
2331 POSTCODE_SEVERITY_ERR);
2332 return;
2333 }
2334
2335 /* reuse IOVM create bus message */
Jes Sorensenebec8962015-05-05 18:35:57 -04002336 if (local_crash_bus_msg.cmd.create_bus.channel_addr) {
Benjamin Romere6bdb902015-03-16 13:58:33 -04002337 bus_create(&local_crash_bus_msg);
Benjamin Romer75c1f8b2015-03-16 13:58:19 -04002338 } else {
Ken Cox12e364b2014-03-04 07:58:07 -06002339 POSTCODE_LINUX_2(CRASH_DEV_BUS_NULL_FAILURE_PC,
2340 POSTCODE_SEVERITY_ERR);
2341 return;
2342 }
2343
2344 /* reuse create device message for storage device */
Jes Sorensenebec8962015-05-05 18:35:57 -04002345 if (local_crash_dev_msg.cmd.create_device.channel_addr) {
Benjamin Romere6bdb902015-03-16 13:58:33 -04002346 my_device_create(&local_crash_dev_msg);
Benjamin Romer75c1f8b2015-03-16 13:58:19 -04002347 } else {
Ken Cox12e364b2014-03-04 07:58:07 -06002348 POSTCODE_LINUX_2(CRASH_DEV_DEV_NULL_FAILURE_PC,
2349 POSTCODE_SEVERITY_ERR);
2350 return;
2351 }
Ken Cox12e364b2014-03-04 07:58:07 -06002352 POSTCODE_LINUX_2(CRASH_DEV_EXIT_PC, POSTCODE_SEVERITY_INFO);
2353 return;
2354
Benjamin Romere6bdb902015-03-16 13:58:33 -04002355cleanup:
Ken Cox12e364b2014-03-04 07:58:07 -06002356
Benjamin Romer911e2132015-03-16 13:57:47 -04002357 poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_SLOW;
Ken Cox12e364b2014-03-04 07:58:07 -06002358
Benjamin Romer9232d2d2015-03-16 13:57:57 -04002359 queue_delayed_work(periodic_controlvm_workqueue,
2360 &periodic_controlvm_work, poll_jiffies);
Ken Cox12e364b2014-03-04 07:58:07 -06002361}
2362
2363static void
Jes Sorensen52063ec2015-04-13 10:28:41 -04002364bus_create_response(u32 bus_no, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06002365{
Benjamin Romer8e3fedd2015-03-16 13:58:43 -04002366 bus_responder(CONTROLVM_BUS_CREATE, bus_no, response);
Ken Cox12e364b2014-03-04 07:58:07 -06002367}
2368
2369static void
Jes Sorensen52063ec2015-04-13 10:28:41 -04002370bus_destroy_response(u32 bus_no, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06002371{
Benjamin Romer8e3fedd2015-03-16 13:58:43 -04002372 bus_responder(CONTROLVM_BUS_DESTROY, bus_no, response);
Ken Cox12e364b2014-03-04 07:58:07 -06002373}
2374
2375static void
Jes Sorensen52063ec2015-04-13 10:28:41 -04002376device_create_response(u32 bus_no, u32 dev_no, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06002377{
Benjamin Romer8e3fedd2015-03-16 13:58:43 -04002378 device_responder(CONTROLVM_DEVICE_CREATE, bus_no, dev_no, response);
Ken Cox12e364b2014-03-04 07:58:07 -06002379}
2380
2381static void
Jes Sorensen52063ec2015-04-13 10:28:41 -04002382device_destroy_response(u32 bus_no, u32 dev_no, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06002383{
Benjamin Romer8e3fedd2015-03-16 13:58:43 -04002384 device_responder(CONTROLVM_DEVICE_DESTROY, bus_no, dev_no, response);
Ken Cox12e364b2014-03-04 07:58:07 -06002385}
2386
2387void
Jes Sorensen52063ec2015-04-13 10:28:41 -04002388visorchipset_device_pause_response(u32 bus_no, u32 dev_no, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06002389{
Ken Cox12e364b2014-03-04 07:58:07 -06002390 device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE,
Benjamin Romer8420f412014-10-31 09:57:36 -04002391 bus_no, dev_no, response,
Benjamin Romerbd0d2dc2014-10-23 14:30:13 -04002392 segment_state_standby);
Ken Cox12e364b2014-03-04 07:58:07 -06002393}
Ken Cox927c7922014-03-05 14:52:25 -06002394EXPORT_SYMBOL_GPL(visorchipset_device_pause_response);
Ken Cox12e364b2014-03-04 07:58:07 -06002395
2396static void
Jes Sorensen52063ec2015-04-13 10:28:41 -04002397device_resume_response(u32 bus_no, u32 dev_no, int response)
Ken Cox12e364b2014-03-04 07:58:07 -06002398{
2399 device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE,
Benjamin Romer8e3fedd2015-03-16 13:58:43 -04002400 bus_no, dev_no, response,
Benjamin Romerbd0d2dc2014-10-23 14:30:13 -04002401 segment_state_running);
Ken Cox12e364b2014-03-04 07:58:07 -06002402}
2403
Jes Sorensenf4c11552015-04-13 10:28:40 -04002404bool
Jes Sorensen52063ec2015-04-13 10:28:41 -04002405visorchipset_get_bus_info(u32 bus_no, struct visorchipset_bus_info *bus_info)
Ken Cox12e364b2014-03-04 07:58:07 -06002406{
Jes Sorensen4f665202015-05-05 18:35:52 -04002407 void *p = bus_find(&bus_info_list, bus_no);
Benjamin Romer26eb2c02014-08-18 09:34:53 -04002408
Benjamin Romer0aca78442015-03-04 12:14:25 -05002409 if (!p)
Jes Sorensenf4c11552015-04-13 10:28:40 -04002410 return false;
Benjamin Romer77db7122014-10-31 09:57:37 -04002411 memcpy(bus_info, p, sizeof(struct visorchipset_bus_info));
Jes Sorensenf4c11552015-04-13 10:28:40 -04002412 return true;
Ken Cox12e364b2014-03-04 07:58:07 -06002413}
2414EXPORT_SYMBOL_GPL(visorchipset_get_bus_info);
2415
Jes Sorensenf4c11552015-04-13 10:28:40 -04002416bool
Jes Sorensen52063ec2015-04-13 10:28:41 -04002417visorchipset_set_bus_context(u32 bus_no, void *context)
Ken Cox12e364b2014-03-04 07:58:07 -06002418{
Jes Sorensen4f665202015-05-05 18:35:52 -04002419 struct visorchipset_bus_info *p = bus_find(&bus_info_list, bus_no);
Benjamin Romer26eb2c02014-08-18 09:34:53 -04002420
Benjamin Romer0aca78442015-03-04 12:14:25 -05002421 if (!p)
Jes Sorensenf4c11552015-04-13 10:28:40 -04002422 return false;
Ken Cox12e364b2014-03-04 07:58:07 -06002423 p->bus_driver_context = context;
Jes Sorensenf4c11552015-04-13 10:28:40 -04002424 return true;
Ken Cox12e364b2014-03-04 07:58:07 -06002425}
2426EXPORT_SYMBOL_GPL(visorchipset_set_bus_context);
2427
Jes Sorensenf4c11552015-04-13 10:28:40 -04002428bool
Jes Sorensen52063ec2015-04-13 10:28:41 -04002429visorchipset_get_device_info(u32 bus_no, u32 dev_no,
Benjamin Romerb486df12014-10-31 09:57:38 -04002430 struct visorchipset_device_info *dev_info)
Ken Cox12e364b2014-03-04 07:58:07 -06002431{
Jes Sorensend480f6a2015-05-05 18:35:54 -04002432 void *p = device_find(&dev_info_list, bus_no, dev_no);
Benjamin Romer26eb2c02014-08-18 09:34:53 -04002433
Benjamin Romer0aca78442015-03-04 12:14:25 -05002434 if (!p)
Jes Sorensenf4c11552015-04-13 10:28:40 -04002435 return false;
Benjamin Romerb486df12014-10-31 09:57:38 -04002436 memcpy(dev_info, p, sizeof(struct visorchipset_device_info));
Jes Sorensenf4c11552015-04-13 10:28:40 -04002437 return true;
Ken Cox12e364b2014-03-04 07:58:07 -06002438}
2439EXPORT_SYMBOL_GPL(visorchipset_get_device_info);
2440
Jes Sorensenf4c11552015-04-13 10:28:40 -04002441bool
Jes Sorensen52063ec2015-04-13 10:28:41 -04002442visorchipset_set_device_context(u32 bus_no, u32 dev_no, void *context)
Ken Cox12e364b2014-03-04 07:58:07 -06002443{
Jes Sorensend480f6a2015-05-05 18:35:54 -04002444 struct visorchipset_device_info *p;
2445
2446 p = device_find(&dev_info_list, bus_no, dev_no);
Benjamin Romer26eb2c02014-08-18 09:34:53 -04002447
Benjamin Romer0aca78442015-03-04 12:14:25 -05002448 if (!p)
Jes Sorensenf4c11552015-04-13 10:28:40 -04002449 return false;
Ken Cox12e364b2014-03-04 07:58:07 -06002450 p->bus_driver_context = context;
Jes Sorensenf4c11552015-04-13 10:28:40 -04002451 return true;
Ken Cox12e364b2014-03-04 07:58:07 -06002452}
2453EXPORT_SYMBOL_GPL(visorchipset_set_device_context);
2454
2455/* Generic wrapper function for allocating memory from a kmem_cache pool.
2456 */
2457void *
Jes Sorensenf4c11552015-04-13 10:28:40 -04002458visorchipset_cache_alloc(struct kmem_cache *pool, bool ok_to_block,
Ken Cox12e364b2014-03-04 07:58:07 -06002459 char *fn, int ln)
2460{
2461 gfp_t gfp;
2462 void *p;
2463
2464 if (ok_to_block)
2465 gfp = GFP_KERNEL;
2466 else
2467 gfp = GFP_ATOMIC;
2468 /* __GFP_NORETRY means "ok to fail", meaning
2469 * kmem_cache_alloc() can return NULL, implying the caller CAN
2470 * cope with failure. If you do NOT specify __GFP_NORETRY,
2471 * Linux will go to extreme measures to get memory for you
2472 * (like, invoke oom killer), which will probably cripple the
2473 * system.
2474 */
2475 gfp |= __GFP_NORETRY;
2476 p = kmem_cache_alloc(pool, gfp);
Benjamin Romer0aca78442015-03-04 12:14:25 -05002477 if (!p)
Ken Cox12e364b2014-03-04 07:58:07 -06002478 return NULL;
Benjamin Romer0aca78442015-03-04 12:14:25 -05002479
Ken Cox12e364b2014-03-04 07:58:07 -06002480 return p;
2481}
2482
2483/* Generic wrapper function for freeing memory from a kmem_cache pool.
2484 */
2485void
2486visorchipset_cache_free(struct kmem_cache *pool, void *p, char *fn, int ln)
2487{
Benjamin Romer0aca78442015-03-04 12:14:25 -05002488 if (!p)
Ken Cox12e364b2014-03-04 07:58:07 -06002489 return;
Benjamin Romer0aca78442015-03-04 12:14:25 -05002490
Ken Cox12e364b2014-03-04 07:58:07 -06002491 kmem_cache_free(pool, p);
2492}
2493
Benjamin Romer18b87ed2014-07-24 14:08:43 -04002494static ssize_t chipsetready_store(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -04002495 struct device_attribute *attr,
2496 const char *buf, size_t count)
Ken Cox12e364b2014-03-04 07:58:07 -06002497{
Benjamin Romer18b87ed2014-07-24 14:08:43 -04002498 char msgtype[64];
Ken Cox12e364b2014-03-04 07:58:07 -06002499
Benjamin Romer66e24b72014-07-25 13:55:10 -04002500 if (sscanf(buf, "%63s", msgtype) != 1)
Ken Cox12e364b2014-03-04 07:58:07 -06002501 return -EINVAL;
Benjamin Romer66e24b72014-07-25 13:55:10 -04002502
Jes Sorensenebec8962015-05-05 18:35:57 -04002503 if (!strcmp(msgtype, "CALLHOMEDISK_MOUNTED")) {
Benjamin Romer66e24b72014-07-25 13:55:10 -04002504 chipset_events[0] = 1;
2505 return count;
Jes Sorensenebec8962015-05-05 18:35:57 -04002506 } else if (!strcmp(msgtype, "MODULES_LOADED")) {
Benjamin Romer66e24b72014-07-25 13:55:10 -04002507 chipset_events[1] = 1;
2508 return count;
Benjamin Romere22a4a02014-08-18 09:34:54 -04002509 }
2510 return -EINVAL;
Ken Cox12e364b2014-03-04 07:58:07 -06002511}
2512
Benjamin Romere56fa7c2014-07-29 11:11:21 -04002513/* The parahotplug/devicedisabled interface gets called by our support script
2514 * when an SR-IOV device has been shut down. The ID is passed to the script
2515 * and then passed back when the device has been removed.
2516 */
2517static ssize_t devicedisabled_store(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -04002518 struct device_attribute *attr,
2519 const char *buf, size_t count)
Benjamin Romere56fa7c2014-07-29 11:11:21 -04002520{
Jes Sorensen94217362015-05-05 18:35:46 -04002521 unsigned int id;
Benjamin Romere56fa7c2014-07-29 11:11:21 -04002522
Jes Sorensenebec8962015-05-05 18:35:57 -04002523 if (kstrtouint(buf, 10, &id))
Benjamin Romere56fa7c2014-07-29 11:11:21 -04002524 return -EINVAL;
2525
2526 parahotplug_request_complete(id, 0);
2527 return count;
2528}
2529
2530/* The parahotplug/deviceenabled interface gets called by our support script
2531 * when an SR-IOV device has been recovered. The ID is passed to the script
2532 * and then passed back when the device has been brought back up.
2533 */
2534static ssize_t deviceenabled_store(struct device *dev,
Benjamin Romer8e76e692015-03-16 13:58:52 -04002535 struct device_attribute *attr,
2536 const char *buf, size_t count)
Benjamin Romere56fa7c2014-07-29 11:11:21 -04002537{
Jes Sorensen94217362015-05-05 18:35:46 -04002538 unsigned int id;
Benjamin Romere56fa7c2014-07-29 11:11:21 -04002539
Jes Sorensenebec8962015-05-05 18:35:57 -04002540 if (kstrtouint(buf, 10, &id))
Benjamin Romere56fa7c2014-07-29 11:11:21 -04002541 return -EINVAL;
2542
2543 parahotplug_request_complete(id, 1);
2544 return count;
2545}
2546
Erik Arfvidsone3420ed2015-05-05 18:36:13 -04002547static int
2548visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
2549{
2550 unsigned long physaddr = 0;
2551 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
Erik Arfvidson780fcad2015-05-05 18:36:35 -04002552 u64 addr = 0;
Erik Arfvidsone3420ed2015-05-05 18:36:13 -04002553
2554 /* sv_enable_dfp(); */
2555 if (offset & (PAGE_SIZE - 1))
2556 return -ENXIO; /* need aligned offsets */
2557
2558 switch (offset) {
2559 case VISORCHIPSET_MMAP_CONTROLCHANOFFSET:
2560 vma->vm_flags |= VM_IO;
2561 if (!*file_controlvm_channel)
2562 return -ENXIO;
2563
2564 visorchannel_read(*file_controlvm_channel,
2565 offsetof(struct spar_controlvm_channel_protocol,
2566 gp_control_channel),
2567 &addr, sizeof(addr));
2568 if (!addr)
2569 return -ENXIO;
2570
2571 physaddr = (unsigned long)addr;
2572 if (remap_pfn_range(vma, vma->vm_start,
2573 physaddr >> PAGE_SHIFT,
2574 vma->vm_end - vma->vm_start,
2575 /*pgprot_noncached */
2576 (vma->vm_page_prot))) {
2577 return -EAGAIN;
2578 }
2579 break;
2580 default:
2581 return -ENXIO;
2582 }
2583 return 0;
2584}
2585
2586static long visorchipset_ioctl(struct file *file, unsigned int cmd,
2587 unsigned long arg)
2588{
2589 s64 adjustment;
2590 s64 vrtc_offset;
2591
2592 switch (cmd) {
2593 case VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET:
2594 /* get the physical rtc offset */
2595 vrtc_offset = issue_vmcall_query_guest_virtual_time_offset();
2596 if (copy_to_user((void __user *)arg, &vrtc_offset,
2597 sizeof(vrtc_offset))) {
2598 return -EFAULT;
2599 }
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -04002600 return 0;
Erik Arfvidsone3420ed2015-05-05 18:36:13 -04002601 case VMCALL_UPDATE_PHYSICAL_TIME:
2602 if (copy_from_user(&adjustment, (void __user *)arg,
2603 sizeof(adjustment))) {
2604 return -EFAULT;
2605 }
2606 return issue_vmcall_update_physical_time(adjustment);
2607 default:
2608 return -EFAULT;
2609 }
2610}
2611
2612static const struct file_operations visorchipset_fops = {
2613 .owner = THIS_MODULE,
2614 .open = visorchipset_open,
2615 .read = NULL,
2616 .write = NULL,
2617 .unlocked_ioctl = visorchipset_ioctl,
2618 .release = visorchipset_release,
2619 .mmap = visorchipset_mmap,
2620};
2621
2622int
2623visorchipset_file_init(dev_t major_dev, struct visorchannel **controlvm_channel)
2624{
2625 int rc = 0;
2626
2627 file_controlvm_channel = controlvm_channel;
2628 cdev_init(&file_cdev, &visorchipset_fops);
2629 file_cdev.owner = THIS_MODULE;
2630 if (MAJOR(major_dev) == 0) {
Erik Arfvidson46168812015-05-05 18:36:14 -04002631 rc = alloc_chrdev_region(&major_dev, 0, 1, "visorchipset");
Erik Arfvidsone3420ed2015-05-05 18:36:13 -04002632 /* dynamic major device number registration required */
2633 if (rc < 0)
2634 return rc;
2635 } else {
2636 /* static major device number registration required */
Erik Arfvidson46168812015-05-05 18:36:14 -04002637 rc = register_chrdev_region(major_dev, 1, "visorchipset");
Erik Arfvidsone3420ed2015-05-05 18:36:13 -04002638 if (rc < 0)
2639 return rc;
2640 }
2641 rc = cdev_add(&file_cdev, MKDEV(MAJOR(major_dev), 0), 1);
2642 if (rc < 0) {
2643 unregister_chrdev_region(major_dev, 1);
2644 return rc;
2645 }
2646 return 0;
2647}
2648
Prarit Bhargava55c67dc2015-05-05 18:37:02 -04002649static int
2650visorchipset_init(struct acpi_device *acpi_device)
Ken Cox12e364b2014-03-04 07:58:07 -06002651{
David Kershner33078252015-05-05 18:36:48 -04002652 int rc = 0;
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -04002653 u64 addr;
Ken Cox12e364b2014-03-04 07:58:07 -06002654
David Kershner4da33362015-05-05 18:36:39 -04002655 memset(&busdev_notifiers, 0, sizeof(busdev_notifiers));
Benjamin Romer84982fb2015-03-16 13:58:07 -04002656 memset(&controlvm_payload_info, 0, sizeof(controlvm_payload_info));
Benjamin Romerea33b4ee52015-03-16 13:58:08 -04002657 memset(&livedump_info, 0, sizeof(livedump_info));
2658 atomic_set(&livedump_info.buffers_in_use, 0);
Ken Cox12e364b2014-03-04 07:58:07 -06002659
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002660 addr = controlvm_get_channel_address();
Jes Sorensenebec8962015-05-05 18:35:57 -04002661 if (addr) {
Jes Sorensendf942472015-05-05 18:37:10 -04002662 int tmp_sz = sizeof(struct spar_controlvm_channel_protocol);
2663 uuid_le uuid = SPAR_CONTROLVM_CHANNEL_PROTOCOL_UUID;
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002664 controlvm_channel =
Jes Sorensendf942472015-05-05 18:37:10 -04002665 visorchannel_create_with_lock(addr, tmp_sz,
2666 GFP_KERNEL, uuid);
Benjamin Romer93a84562014-10-23 14:30:05 -04002667 if (SPAR_CONTROLVM_CHANNEL_OK_CLIENT(
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002668 visorchannel_get_header(controlvm_channel))) {
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002669 initialize_controlvm_payload();
2670 } else {
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002671 visorchannel_destroy(controlvm_channel);
2672 controlvm_channel = NULL;
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002673 return -ENODEV;
2674 }
2675 } else {
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002676 return -ENODEV;
2677 }
2678
Benjamin Romer5aa8ae52015-03-16 13:58:44 -04002679 major_dev = MKDEV(visorchipset_major, 0);
2680 rc = visorchipset_file_init(major_dev, &controlvm_channel);
Ken Cox4cb005a2014-03-19 13:06:20 -05002681 if (rc < 0) {
Ken Cox4cb005a2014-03-19 13:06:20 -05002682 POSTCODE_LINUX_2(CHIPSET_INIT_FAILURE_PC, DIAG_SEVERITY_ERR);
Benjamin Romera6a39892015-03-16 13:58:34 -04002683 goto cleanup;
Ken Cox4cb005a2014-03-19 13:06:20 -05002684 }
Ken Cox9f8d0e82014-03-19 13:06:19 -05002685
Benjamin Romerda021f02015-03-16 13:57:58 -04002686 memset(&g_chipset_msg_hdr, 0, sizeof(struct controlvm_message_header));
Ken Cox12e364b2014-03-04 07:58:07 -06002687
David Kershner4da33362015-05-05 18:36:39 -04002688 /* if booting in a crash kernel */
2689 if (is_kdump_kernel())
2690 INIT_DELAYED_WORK(&periodic_controlvm_work,
2691 setup_crash_devices_work_queue);
2692 else
2693 INIT_DELAYED_WORK(&periodic_controlvm_work,
2694 controlvm_periodic_work);
2695 periodic_controlvm_workqueue =
2696 create_singlethread_workqueue("visorchipset_controlvm");
Ken Cox12e364b2014-03-04 07:58:07 -06002697
David Kershner4da33362015-05-05 18:36:39 -04002698 if (!periodic_controlvm_workqueue) {
2699 POSTCODE_LINUX_2(CREATE_WORKQUEUE_FAILED_PC,
2700 DIAG_SEVERITY_ERR);
2701 rc = -ENOMEM;
2702 goto cleanup;
2703 }
2704 most_recent_message_jiffies = jiffies;
2705 poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
2706 rc = queue_delayed_work(periodic_controlvm_workqueue,
2707 &periodic_controlvm_work, poll_jiffies);
2708 if (rc < 0) {
2709 POSTCODE_LINUX_2(QUEUE_DELAYED_WORK_PC,
2710 DIAG_SEVERITY_ERR);
2711 goto cleanup;
Ken Cox12e364b2014-03-04 07:58:07 -06002712 }
2713
Benjamin Romereb34e872015-03-16 13:58:45 -04002714 visorchipset_platform_device.dev.devt = major_dev;
2715 if (platform_device_register(&visorchipset_platform_device) < 0) {
Ken Cox4cb005a2014-03-19 13:06:20 -05002716 POSTCODE_LINUX_2(DEVICE_REGISTER_FAILURE_PC, DIAG_SEVERITY_ERR);
2717 rc = -1;
Benjamin Romera6a39892015-03-16 13:58:34 -04002718 goto cleanup;
Ken Cox4cb005a2014-03-19 13:06:20 -05002719 }
Ken Cox12e364b2014-03-04 07:58:07 -06002720 POSTCODE_LINUX_2(CHIPSET_INIT_SUCCESS_PC, POSTCODE_SEVERITY_INFO);
Prarit Bhargavac79b28f2015-05-05 18:36:15 -04002721
2722 rc = visorbus_init();
Benjamin Romera6a39892015-03-16 13:58:34 -04002723cleanup:
Ken Cox12e364b2014-03-04 07:58:07 -06002724 if (rc) {
Ken Cox12e364b2014-03-04 07:58:07 -06002725 POSTCODE_LINUX_3(CHIPSET_INIT_FAILURE_PC, rc,
2726 POSTCODE_SEVERITY_ERR);
2727 }
2728 return rc;
2729}
2730
Erik Arfvidsone3420ed2015-05-05 18:36:13 -04002731void
2732visorchipset_file_cleanup(dev_t major_dev)
2733{
2734 if (file_cdev.ops)
2735 cdev_del(&file_cdev);
2736 file_cdev.ops = NULL;
2737 unregister_chrdev_region(major_dev, 1);
2738}
2739
Prarit Bhargava55c67dc2015-05-05 18:37:02 -04002740static int
2741visorchipset_exit(struct acpi_device *acpi_device)
Ken Cox12e364b2014-03-04 07:58:07 -06002742{
Ken Cox12e364b2014-03-04 07:58:07 -06002743 POSTCODE_LINUX_2(DRIVER_EXIT_PC, POSTCODE_SEVERITY_INFO);
2744
Prarit Bhargavac79b28f2015-05-05 18:36:15 -04002745 visorbus_exit();
2746
David Kershner4da33362015-05-05 18:36:39 -04002747 cancel_delayed_work(&periodic_controlvm_work);
2748 flush_workqueue(periodic_controlvm_workqueue);
2749 destroy_workqueue(periodic_controlvm_workqueue);
2750 periodic_controlvm_workqueue = NULL;
2751 destroy_controlvm_payload_info(&controlvm_payload_info);
Benjamin Romer17833192014-07-15 13:30:41 -04002752
Ken Cox12e364b2014-03-04 07:58:07 -06002753 cleanup_controlvm_structures();
2754
Benjamin Romerda021f02015-03-16 13:57:58 -04002755 memset(&g_chipset_msg_hdr, 0, sizeof(struct controlvm_message_header));
Ken Cox12e364b2014-03-04 07:58:07 -06002756
Benjamin Romerc3d9a222015-03-16 13:58:05 -04002757 visorchannel_destroy(controlvm_channel);
Benjamin Romer8a1182e2014-07-17 12:39:58 -04002758
Sudip Mukherjeeaddceb12015-03-24 20:47:28 +05302759 visorchipset_file_cleanup(visorchipset_platform_device.dev.devt);
Ken Cox12e364b2014-03-04 07:58:07 -06002760 POSTCODE_LINUX_2(DRIVER_EXIT_PC, POSTCODE_SEVERITY_INFO);
Prarit Bhargava55c67dc2015-05-05 18:37:02 -04002761
2762 return 0;
2763}
2764
2765static const struct acpi_device_id unisys_device_ids[] = {
2766 {"PNP0A07", 0},
2767 {"", 0},
2768};
Prarit Bhargava55c67dc2015-05-05 18:37:02 -04002769
2770static struct acpi_driver unisys_acpi_driver = {
2771 .name = "unisys_acpi",
2772 .class = "unisys_acpi_class",
2773 .owner = THIS_MODULE,
2774 .ids = unisys_device_ids,
2775 .ops = {
2776 .add = visorchipset_init,
2777 .remove = visorchipset_exit,
2778 },
2779};
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -04002780static __init uint32_t visorutil_spar_detect(void)
2781{
2782 unsigned int eax, ebx, ecx, edx;
2783
2784 if (cpu_has_hypervisor) {
2785 /* check the ID */
2786 cpuid(UNISYS_SPAR_LEAF_ID, &eax, &ebx, &ecx, &edx);
2787 return (ebx == UNISYS_SPAR_ID_EBX) &&
2788 (ecx == UNISYS_SPAR_ID_ECX) &&
2789 (edx == UNISYS_SPAR_ID_EDX);
2790 } else {
2791 return 0;
2792 }
2793}
Prarit Bhargava55c67dc2015-05-05 18:37:02 -04002794
2795static int init_unisys(void)
2796{
2797 int result;
Erik Arfvidsond5b3f1d2015-05-05 18:37:04 -04002798 if (!visorutil_spar_detect())
Prarit Bhargava55c67dc2015-05-05 18:37:02 -04002799 return -ENODEV;
2800
2801 result = acpi_bus_register_driver(&unisys_acpi_driver);
2802 if (result)
2803 return -ENODEV;
2804
2805 pr_info("Unisys Visorchipset Driver Loaded.\n");
2806 return 0;
2807};
2808
2809static void exit_unisys(void)
2810{
2811 acpi_bus_unregister_driver(&unisys_acpi_driver);
Ken Cox12e364b2014-03-04 07:58:07 -06002812}
2813
Ken Cox12e364b2014-03-04 07:58:07 -06002814module_param_named(major, visorchipset_major, int, S_IRUGO);
Jes Sorensenb615d622015-05-05 18:35:38 -04002815MODULE_PARM_DESC(visorchipset_major,
2816 "major device number to use for the device node");
David Kershner4da33362015-05-05 18:36:39 -04002817module_param_named(visorbusregwait, visorchipset_visorbusregwait, int, S_IRUGO);
2818MODULE_PARM_DESC(visorchipset_visorbusreqwait,
Ken Cox12e364b2014-03-04 07:58:07 -06002819 "1 to have the module wait for the visor bus to register");
Ken Cox12e364b2014-03-04 07:58:07 -06002820module_param_named(holdchipsetready, visorchipset_holdchipsetready,
2821 int, S_IRUGO);
2822MODULE_PARM_DESC(visorchipset_holdchipsetready,
2823 "1 to hold response to CHIPSET_READY");
Jes Sorensenb615d622015-05-05 18:35:38 -04002824
Prarit Bhargava55c67dc2015-05-05 18:37:02 -04002825module_init(init_unisys);
2826module_exit(exit_unisys);
Ken Cox12e364b2014-03-04 07:58:07 -06002827
2828MODULE_AUTHOR("Unisys");
2829MODULE_LICENSE("GPL");
2830MODULE_DESCRIPTION("Supervisor chipset driver for service partition: ver "
2831 VERSION);
2832MODULE_VERSION(VERSION);