2017-11-07 16:58:47 +03:00
// SPDX-License-Identifier: GPL-2.0
2017-08-22 20:26:51 +03:00
/*
2015-07-16 19:40:48 +03:00
* Copyright ( C ) 2010 - 2015 UNISYS CORPORATION
2014-03-04 17:58:07 +04:00
* All rights reserved .
*/
2015-05-06 01:37:02 +03:00
# include <linux/acpi.h>
2015-04-06 17:27:40 +03:00
# include <linux/crash_dump.h>
2017-12-07 20:11:07 +03:00
# include <linux/visorbus.h>
2014-03-04 17:58:07 +04:00
2015-05-06 01:37:02 +03:00
# include "visorbus_private.h"
2017-08-22 20:27:20 +03:00
/* {72120008-4AAB-11DC-8530-444553544200} */
2017-08-30 20:36:33 +03:00
# define VISOR_SIOVM_GUID GUID_INIT(0x72120008, 0x4AAB, 0x11DC, 0x85, 0x30, \
0x44 , 0x45 , 0x53 , 0x54 , 0x42 , 0x00 )
2017-08-22 20:27:20 +03:00
2017-08-22 20:26:54 +03:00
static const guid_t visor_vhba_channel_guid = VISOR_VHBA_CHANNEL_GUID ;
static const guid_t visor_siovm_guid = VISOR_SIOVM_GUID ;
static const guid_t visor_controlvm_channel_guid = VISOR_CONTROLVM_CHANNEL_GUID ;
2017-09-27 20:14:38 +03:00
# define POLLJIFFIES_CONTROLVM_FAST 1
# define POLLJIFFIES_CONTROLVM_SLOW 100
2014-03-04 17:58:07 +04:00
2015-12-09 18:27:05 +03:00
# define MAX_CONTROLVM_PAYLOAD_BYTES (1024 * 128)
2015-05-06 01:36:16 +03:00
2017-05-19 23:17:47 +03:00
# define UNISYS_VISOR_LEAF_ID 0x40000000
2015-05-06 01:37:04 +03:00
/* The s-Par leaf ID returns "UnisysSpar64" encoded across ebx, ecx, edx */
2017-05-19 23:17:47 +03:00
# define UNISYS_VISOR_ID_EBX 0x73696e55
# define UNISYS_VISOR_ID_ECX 0x70537379
# define UNISYS_VISOR_ID_EDX 0x34367261
2015-05-06 01:37:04 +03:00
2016-06-11 04:48:18 +03:00
/*
2017-08-30 20:36:29 +03:00
* When the controlvm channel is idle for at least MIN_IDLE_SECONDS , we switch
* to slow polling mode . As soon as we get a controlvm message , we switch back
* to fast polling mode .
2016-06-11 04:48:18 +03:00
*/
2014-03-04 17:58:07 +04:00
# define MIN_IDLE_SECONDS 10
2015-05-06 01:36:14 +03:00
struct parser_context {
unsigned long allocbytes ;
unsigned long param_bytes ;
u8 * curr ;
unsigned long bytes_remaining ;
bool byte_stream ;
2017-08-30 20:36:24 +03:00
struct visor_controlvm_parameters_header data ;
2015-05-06 01:36:14 +03:00
} ;
2017-08-22 20:27:01 +03:00
/* VMCALL_CONTROLVM_ADDR: Used by all guests, not just IO. */
2017-08-22 20:27:00 +03:00
# define VMCALL_CONTROLVM_ADDR 0x0501
enum vmcall_result {
VMCALL_RESULT_SUCCESS = 0 ,
VMCALL_RESULT_INVALID_PARAM = 1 ,
VMCALL_RESULT_DATA_UNAVAILABLE = 2 ,
VMCALL_RESULT_FAILURE_UNAVAILABLE = 3 ,
VMCALL_RESULT_DEVICE_ERROR = 4 ,
VMCALL_RESULT_DEVICE_NOT_READY = 5
} ;
/*
* struct vmcall_io_controlvm_addr_params - Structure for IO VMCALLS . Has
* parameters to VMCALL_CONTROLVM_ADDR
* interface .
* @ address : The Guest - relative physical address of the ControlVm channel .
* This VMCall fills this in with the appropriate address .
* Contents provided by this VMCALL ( OUT ) .
* @ channel_bytes : The size of the ControlVm channel in bytes This VMCall fills
* this in with the appropriate address . Contents provided by
* this VMCALL ( OUT ) .
* @ unused : Unused Bytes in the 64 - Bit Aligned Struct .
*/
struct vmcall_io_controlvm_addr_params {
u64 address ;
u32 channel_bytes ;
u8 unused [ 4 ] ;
} __packed ;
2017-02-21 20:53:29 +03:00
struct visorchipset_device {
struct acpi_device * acpi_device ;
unsigned long poll_jiffies ;
/* when we got our last controlvm message */
unsigned long most_recent_message_jiffies ;
struct delayed_work periodic_controlvm_work ;
struct visorchannel * controlvm_channel ;
unsigned long controlvm_payload_bytes_buffered ;
/*
* The following variables are used to handle the scenario where we are
* unable to offload the payload from a controlvm message due to memory
* requirements . In this scenario , we simply stash the controlvm
* message , then attempt to process it again the next time
* controlvm_periodic_work ( ) runs .
*/
struct controlvm_message controlvm_pending_msg ;
bool controlvm_pending_msg_valid ;
2017-08-30 20:36:13 +03:00
struct vmcall_io_controlvm_addr_params controlvm_params ;
2017-02-21 20:53:29 +03:00
} ;
2014-03-04 17:58:07 +04:00
2017-02-21 20:53:29 +03:00
static struct visorchipset_device * chipset_dev ;
2014-03-04 17:58:07 +04:00
struct parahotplug_request {
struct list_head list ;
int id ;
unsigned long expiration ;
2014-10-23 22:30:31 +04:00
struct controlvm_message msg ;
2014-03-04 17:58:07 +04:00
} ;
2014-07-22 17:56:25 +04:00
/* prototypes for attributes */
static ssize_t toolaction_show ( struct device * dev ,
2016-09-20 00:09:29 +03:00
struct device_attribute * attr ,
char * buf )
{
u8 tool_action = 0 ;
2017-03-28 16:34:23 +03:00
int err ;
err = visorchannel_read ( chipset_dev - > controlvm_channel ,
2017-05-19 23:17:49 +03:00
offsetof ( struct visor_controlvm_channel ,
2017-03-28 16:34:23 +03:00
tool_action ) ,
& tool_action , sizeof ( u8 ) ) ;
if ( err )
return err ;
2017-01-04 00:01:15 +03:00
return sprintf ( buf , " %u \n " , tool_action ) ;
2016-09-20 00:09:29 +03:00
}
2014-07-22 17:56:25 +04:00
static ssize_t toolaction_store ( struct device * dev ,
2015-03-16 20:58:52 +03:00
struct device_attribute * attr ,
2016-09-20 00:09:29 +03:00
const char * buf , size_t count )
{
u8 tool_action ;
2017-03-28 16:34:30 +03:00
int err ;
2016-09-20 00:09:29 +03:00
if ( kstrtou8 ( buf , 10 , & tool_action ) )
return - EINVAL ;
2017-05-19 23:17:49 +03:00
err = visorchannel_write ( chipset_dev - > controlvm_channel ,
offsetof ( struct visor_controlvm_channel ,
tool_action ) ,
& tool_action , sizeof ( u8 ) ) ;
2017-03-28 16:34:30 +03:00
if ( err )
return err ;
2016-09-20 00:09:29 +03:00
return count ;
}
2014-07-22 17:56:25 +04:00
static DEVICE_ATTR_RW ( toolaction ) ;
2014-07-22 17:56:26 +04:00
static ssize_t boottotool_show ( struct device * dev ,
2016-09-20 00:09:30 +03:00
struct device_attribute * attr ,
char * buf )
{
2017-05-19 23:17:49 +03:00
struct efi_visor_indication efi_visor_indication ;
2017-03-28 16:34:24 +03:00
int err ;
err = visorchannel_read ( chipset_dev - > controlvm_channel ,
2017-05-19 23:17:49 +03:00
offsetof ( struct visor_controlvm_channel ,
efi_visor_ind ) ,
& efi_visor_indication ,
sizeof ( struct efi_visor_indication ) ) ;
2017-03-28 16:34:24 +03:00
if ( err )
return err ;
2017-05-19 23:17:49 +03:00
return sprintf ( buf , " %u \n " , efi_visor_indication . boot_to_tool ) ;
2016-09-20 00:09:30 +03:00
}
2014-07-22 17:56:26 +04:00
static ssize_t boottotool_store ( struct device * dev ,
2016-09-20 00:09:30 +03:00
struct device_attribute * attr ,
const char * buf , size_t count )
{
2017-03-28 16:34:31 +03:00
int val , err ;
2017-05-19 23:17:49 +03:00
struct efi_visor_indication efi_visor_indication ;
2016-09-20 00:09:30 +03:00
if ( kstrtoint ( buf , 10 , & val ) )
return - EINVAL ;
2017-05-19 23:17:49 +03:00
efi_visor_indication . boot_to_tool = val ;
err = visorchannel_write ( chipset_dev - > controlvm_channel ,
offsetof ( struct visor_controlvm_channel ,
efi_visor_ind ) ,
& ( efi_visor_indication ) ,
sizeof ( struct efi_visor_indication ) ) ;
2017-03-28 16:34:31 +03:00
if ( err )
return err ;
2016-09-20 00:09:30 +03:00
return count ;
}
2014-07-22 17:56:26 +04:00
static DEVICE_ATTR_RW ( boottotool ) ;
2014-07-24 22:08:42 +04:00
static ssize_t error_show ( struct device * dev , struct device_attribute * attr ,
2016-09-20 00:09:31 +03:00
char * buf )
{
u32 error = 0 ;
2017-03-28 16:34:25 +03:00
int err ;
2016-09-20 00:09:31 +03:00
2017-03-28 16:34:25 +03:00
err = visorchannel_read ( chipset_dev - > controlvm_channel ,
2017-05-19 23:17:49 +03:00
offsetof ( struct visor_controlvm_channel ,
2017-03-28 16:34:25 +03:00
installation_error ) ,
& error , sizeof ( u32 ) ) ;
if ( err )
return err ;
2017-08-22 20:27:25 +03:00
return sprintf ( buf , " %u \n " , error ) ;
2016-09-20 00:09:31 +03:00
}
2014-07-24 22:08:42 +04:00
static ssize_t error_store ( struct device * dev , struct device_attribute * attr ,
2016-09-20 00:09:31 +03:00
const char * buf , size_t count )
{
u32 error ;
2017-03-28 16:34:32 +03:00
int err ;
2016-09-20 00:09:31 +03:00
if ( kstrtou32 ( buf , 10 , & error ) )
return - EINVAL ;
2017-05-19 23:17:49 +03:00
err = visorchannel_write ( chipset_dev - > controlvm_channel ,
offsetof ( struct visor_controlvm_channel ,
installation_error ) ,
& error , sizeof ( u32 ) ) ;
2017-03-28 16:34:32 +03:00
if ( err )
return err ;
2016-09-20 00:09:31 +03:00
return count ;
}
2014-07-24 22:08:42 +04:00
static DEVICE_ATTR_RW ( error ) ;
static ssize_t textid_show ( struct device * dev , struct device_attribute * attr ,
2016-09-20 00:09:32 +03:00
char * buf )
{
u32 text_id = 0 ;
2017-03-28 16:34:26 +03:00
int err ;
2017-05-19 23:17:49 +03:00
err = visorchannel_read ( chipset_dev - > controlvm_channel ,
offsetof ( struct visor_controlvm_channel ,
installation_text_id ) ,
& text_id , sizeof ( u32 ) ) ;
2017-03-28 16:34:26 +03:00
if ( err )
return err ;
2017-08-22 20:27:25 +03:00
return sprintf ( buf , " %u \n " , text_id ) ;
2016-09-20 00:09:32 +03:00
}
2014-07-24 22:08:42 +04:00
static ssize_t textid_store ( struct device * dev , struct device_attribute * attr ,
2016-09-20 00:09:32 +03:00
const char * buf , size_t count )
{
u32 text_id ;
2017-03-28 16:34:33 +03:00
int err ;
2016-09-20 00:09:32 +03:00
if ( kstrtou32 ( buf , 10 , & text_id ) )
return - EINVAL ;
2017-05-19 23:17:49 +03:00
err = visorchannel_write ( chipset_dev - > controlvm_channel ,
offsetof ( struct visor_controlvm_channel ,
installation_text_id ) ,
& text_id , sizeof ( u32 ) ) ;
2017-03-28 16:34:33 +03:00
if ( err )
return err ;
2016-09-20 00:09:32 +03:00
return count ;
}
2014-07-24 22:08:42 +04:00
static DEVICE_ATTR_RW ( textid ) ;
static ssize_t remaining_steps_show ( struct device * dev ,
2016-09-20 00:09:33 +03:00
struct device_attribute * attr , char * buf )
{
u16 remaining_steps = 0 ;
2017-03-28 16:34:27 +03:00
int err ;
err = visorchannel_read ( chipset_dev - > controlvm_channel ,
2017-05-19 23:17:49 +03:00
offsetof ( struct visor_controlvm_channel ,
2017-03-28 16:34:27 +03:00
installation_remaining_steps ) ,
& remaining_steps , sizeof ( u16 ) ) ;
if ( err )
return err ;
2017-01-04 00:01:15 +03:00
return sprintf ( buf , " %hu \n " , remaining_steps ) ;
2016-09-20 00:09:33 +03:00
}
2014-07-24 22:08:42 +04:00
static ssize_t remaining_steps_store ( struct device * dev ,
2015-03-16 20:58:52 +03:00
struct device_attribute * attr ,
2016-09-20 00:09:33 +03:00
const char * buf , size_t count )
{
u16 remaining_steps ;
2017-03-28 16:34:34 +03:00
int err ;
2016-09-20 00:09:33 +03:00
if ( kstrtou16 ( buf , 10 , & remaining_steps ) )
return - EINVAL ;
2017-05-19 23:17:49 +03:00
err = visorchannel_write ( chipset_dev - > controlvm_channel ,
offsetof ( struct visor_controlvm_channel ,
installation_remaining_steps ) ,
& remaining_steps , sizeof ( u16 ) ) ;
2017-03-28 16:34:34 +03:00
if ( err )
return err ;
2016-09-20 00:09:33 +03:00
return count ;
}
2014-07-24 22:08:42 +04:00
static DEVICE_ATTR_RW ( remaining_steps ) ;
2017-08-22 20:26:57 +03:00
static void controlvm_init_response ( struct controlvm_message * msg ,
struct controlvm_message_header * msg_hdr ,
int response )
2016-09-20 00:09:26 +03:00
{
memset ( msg , 0 , sizeof ( struct controlvm_message ) ) ;
memcpy ( & msg - > hdr , msg_hdr , sizeof ( struct controlvm_message_header ) ) ;
msg - > hdr . payload_bytes = 0 ;
msg - > hdr . payload_vm_offset = 0 ;
msg - > hdr . payload_max_bytes = 0 ;
if ( response < 0 ) {
msg - > hdr . flags . failed = 1 ;
msg - > hdr . completion_status = ( u32 ) ( - response ) ;
}
}
2017-08-22 20:26:57 +03:00
static int controlvm_respond_chipset_init (
struct controlvm_message_header * msg_hdr ,
int response ,
enum visor_chipset_feature features )
2016-09-20 00:09:26 +03:00
{
struct controlvm_message outmsg ;
controlvm_init_response ( & outmsg , msg_hdr , response ) ;
outmsg . cmd . init_chipset . features = features ;
2017-02-21 20:53:29 +03:00
return visorchannel_signalinsert ( chipset_dev - > controlvm_channel ,
2016-11-21 20:15:44 +03:00
CONTROLVM_QUEUE_REQUEST , & outmsg ) ;
2016-09-20 00:09:26 +03:00
}
2017-08-22 20:26:57 +03:00
static int chipset_init ( struct controlvm_message * inmsg )
2014-03-04 17:58:07 +04:00
{
static int chipset_inited ;
2017-05-19 23:17:50 +03:00
enum visor_chipset_feature features = 0 ;
2014-03-04 17:58:07 +04:00
int rc = CONTROLVM_RESP_SUCCESS ;
2016-11-21 20:15:45 +03:00
int res = 0 ;
2014-03-04 17:58:07 +04:00
if ( chipset_inited ) {
2016-12-22 19:08:58 +03:00
rc = - CONTROLVM_RESP_ALREADY_DONE ;
2016-11-21 20:15:45 +03:00
res = - EIO ;
2016-03-12 01:01:41 +03:00
goto out_respond ;
2014-03-04 17:58:07 +04:00
}
chipset_inited = 1 ;
2016-06-11 04:48:18 +03:00
/*
2017-08-30 20:36:29 +03:00
* Set features to indicate we support parahotplug ( if Command also
2017-09-27 20:14:06 +03:00
* supports it ) . Set the " reply " bit so Command knows this is a
* features - aware driver .
2016-02-08 18:41:44 +03:00
*/
2016-11-03 18:44:28 +03:00
features = inmsg - > cmd . init_chipset . features &
2017-05-19 23:17:50 +03:00
VISOR_CHIPSET_FEATURE_PARA_HOTPLUG ;
features | = VISOR_CHIPSET_FEATURE_REPLY ;
2014-03-04 17:58:07 +04:00
2016-03-12 01:01:41 +03:00
out_respond :
2014-10-23 22:30:26 +04:00
if ( inmsg - > hdr . flags . response_expected )
2016-11-21 20:15:45 +03:00
res = controlvm_respond_chipset_init ( & inmsg - > hdr , rc , features ) ;
return res ;
2014-03-04 17:58:07 +04:00
}
2017-08-22 20:26:57 +03:00
static int controlvm_respond ( struct controlvm_message_header * msg_hdr ,
2017-09-27 20:14:10 +03:00
int response , struct visor_segment_state * state )
2014-03-04 17:58:07 +04:00
{
2014-10-23 22:30:31 +04:00
struct controlvm_message outmsg ;
2014-08-18 17:34:53 +04:00
2015-03-16 20:58:46 +03:00
controlvm_init_response ( & outmsg , msg_hdr , response ) ;
2015-03-04 20:14:22 +03:00
if ( outmsg . hdr . flags . test_message = = 1 )
2016-11-21 20:15:46 +03:00
return - EINVAL ;
2017-04-18 23:55:01 +03:00
if ( state ) {
outmsg . cmd . device_change_state . state = * state ;
outmsg . cmd . device_change_state . flags . phys_device = 1 ;
}
2017-02-21 20:53:29 +03:00
return visorchannel_signalinsert ( chipset_dev - > controlvm_channel ,
2016-11-21 20:15:47 +03:00
CONTROLVM_QUEUE_REQUEST , & outmsg ) ;
2014-03-04 17:58:07 +04:00
}
2015-05-06 01:36:16 +03:00
enum crash_obj_type {
CRASH_DEV ,
CRASH_BUS ,
} ;
2017-08-22 20:26:57 +03:00
static int save_crash_message ( struct controlvm_message * msg ,
enum crash_obj_type cr_type )
2016-03-02 03:45:04 +03:00
{
u32 local_crash_msg_offset ;
u16 local_crash_msg_count ;
2016-11-21 20:15:48 +03:00
int err ;
2016-03-02 03:45:04 +03:00
2017-02-21 20:53:29 +03:00
err = visorchannel_read ( chipset_dev - > controlvm_channel ,
2017-05-19 23:17:49 +03:00
offsetof ( struct visor_controlvm_channel ,
2016-11-21 20:15:48 +03:00
saved_crash_message_count ) ,
& local_crash_msg_count , sizeof ( u16 ) ) ;
if ( err ) {
2017-04-18 23:55:16 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
" failed to read message count \n " ) ;
2016-11-21 20:15:48 +03:00
return err ;
2016-03-02 03:45:04 +03:00
}
if ( local_crash_msg_count ! = CONTROLVM_CRASHMSG_MAX ) {
2017-04-18 23:55:16 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
" invalid number of messages \n " ) ;
2016-11-21 20:15:48 +03:00
return - EIO ;
2016-03-02 03:45:04 +03:00
}
2017-02-21 20:53:29 +03:00
err = visorchannel_read ( chipset_dev - > controlvm_channel ,
2017-05-19 23:17:49 +03:00
offsetof ( struct visor_controlvm_channel ,
2016-11-21 20:15:48 +03:00
saved_crash_message_offset ) ,
& local_crash_msg_offset , sizeof ( u32 ) ) ;
if ( err ) {
2017-04-18 23:55:16 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
" failed to read offset \n " ) ;
2016-11-21 20:15:48 +03:00
return err ;
2016-03-02 03:45:04 +03:00
}
2017-05-19 23:17:35 +03:00
switch ( cr_type ) {
2016-12-22 19:08:59 +03:00
case CRASH_DEV :
local_crash_msg_offset + = sizeof ( struct controlvm_message ) ;
2017-02-21 20:53:29 +03:00
err = visorchannel_write ( chipset_dev - > controlvm_channel ,
2017-09-27 20:14:10 +03:00
local_crash_msg_offset , msg ,
2016-12-22 19:08:59 +03:00
sizeof ( struct controlvm_message ) ) ;
2016-11-21 20:15:48 +03:00
if ( err ) {
2017-04-18 23:55:16 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
" failed to write dev msg \n " ) ;
2016-11-21 20:15:48 +03:00
return err ;
2016-03-02 03:45:04 +03:00
}
2016-12-22 19:08:59 +03:00
break ;
case CRASH_BUS :
2017-02-21 20:53:29 +03:00
err = visorchannel_write ( chipset_dev - > controlvm_channel ,
2017-09-27 20:14:10 +03:00
local_crash_msg_offset , msg ,
2016-11-21 20:15:48 +03:00
sizeof ( struct controlvm_message ) ) ;
if ( err ) {
2017-04-18 23:55:16 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
" failed to write bus msg \n " ) ;
2016-11-21 20:15:48 +03:00
return err ;
2016-03-02 03:45:04 +03:00
}
2016-12-22 19:08:59 +03:00
break ;
default :
2017-04-18 23:55:16 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
" Invalid crash_obj_type \n " ) ;
2016-12-22 19:08:59 +03:00
break ;
2016-03-02 03:45:04 +03:00
}
2016-11-21 20:15:48 +03:00
return 0 ;
2016-03-02 03:45:04 +03:00
}
2017-08-22 20:26:57 +03:00
static int controlvm_responder ( enum controlvm_id cmd_id ,
struct controlvm_message_header * pending_msg_hdr ,
int response )
2014-03-04 17:58:07 +04:00
{
2015-06-01 20:00:27 +03:00
if ( pending_msg_hdr - > id ! = ( u32 ) cmd_id )
2016-11-21 20:15:49 +03:00
return - EINVAL ;
2015-03-04 20:14:25 +03:00
2017-04-18 23:55:01 +03:00
return controlvm_respond ( pending_msg_hdr , response , NULL ) ;
2014-03-04 17:58:07 +04:00
}
2017-09-27 20:14:39 +03:00
static int device_changestate_responder ( enum controlvm_id cmd_id ,
struct visor_device * p , int response ,
struct visor_segment_state state )
2014-03-04 17:58:07 +04:00
{
2014-10-23 22:30:31 +04:00
struct controlvm_message outmsg ;
2014-03-04 17:58:07 +04:00
2015-06-01 20:00:27 +03:00
if ( p - > pending_msg_hdr - > id ! = cmd_id )
2016-11-21 20:15:50 +03:00
return - EINVAL ;
2014-03-04 17:58:07 +04:00
2015-06-01 20:00:27 +03:00
controlvm_init_response ( & outmsg , p - > pending_msg_hdr , response ) ;
2017-08-22 20:27:23 +03:00
outmsg . cmd . device_change_state . bus_no = p - > chipset_bus_no ;
outmsg . cmd . device_change_state . dev_no = p - > chipset_dev_no ;
2017-09-27 20:14:39 +03:00
outmsg . cmd . device_change_state . state = state ;
2017-02-21 20:53:29 +03:00
return visorchannel_signalinsert ( chipset_dev - > controlvm_channel ,
2016-11-21 20:15:50 +03:00
CONTROLVM_QUEUE_REQUEST , & outmsg ) ;
2014-03-04 17:58:07 +04:00
}
2017-08-22 20:26:57 +03:00
static int visorbus_create ( struct controlvm_message * inmsg )
2014-03-04 17:58:07 +04:00
{
2014-10-23 22:30:25 +04:00
struct controlvm_message_packet * cmd = & inmsg - > cmd ;
2017-09-27 20:14:37 +03:00
struct controlvm_message_header * pmsg_hdr ;
2015-04-13 17:28:41 +03:00
u32 bus_no = cmd - > create_bus . bus_no ;
2015-06-04 16:22:41 +03:00
struct visor_device * bus_info ;
2015-06-01 20:00:26 +03:00
struct visorchannel * visorchannel ;
2016-11-03 18:44:22 +03:00
int err ;
2014-03-04 17:58:07 +04:00
2015-06-04 16:22:41 +03:00
bus_info = visorbus_get_device_by_id ( bus_no , BUS_ROOT_DEVICE , NULL ) ;
2017-09-27 20:14:48 +03:00
if ( bus_info & & bus_info - > state . created = = 1 ) {
2017-04-18 23:55:17 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
2017-06-30 22:43:25 +03:00
" failed %s: already exists \n " , __func__ ) ;
2016-11-03 18:44:22 +03:00
err = - EEXIST ;
goto err_respond ;
2014-03-04 17:58:07 +04:00
}
2015-03-16 20:58:20 +03:00
bus_info = kzalloc ( sizeof ( * bus_info ) , GFP_KERNEL ) ;
if ( ! bus_info ) {
2016-11-03 18:44:22 +03:00
err = - ENOMEM ;
goto err_respond ;
2014-03-04 17:58:07 +04:00
}
2015-06-04 16:22:49 +03:00
INIT_LIST_HEAD ( & bus_info - > list_all ) ;
2015-06-04 16:22:41 +03:00
bus_info - > chipset_bus_no = bus_no ;
bus_info - > chipset_dev_no = BUS_ROOT_DEVICE ;
2017-08-22 20:26:54 +03:00
if ( guid_equal ( & cmd - > create_bus . bus_inst_guid , & visor_siovm_guid ) ) {
2016-12-22 19:09:05 +03:00
err = save_crash_message ( inmsg , CRASH_BUS ) ;
if ( err )
goto err_free_bus_info ;
}
2016-11-03 18:44:19 +03:00
if ( inmsg - > hdr . flags . response_expected = = 1 ) {
2017-09-27 20:14:10 +03:00
pmsg_hdr = kzalloc ( sizeof ( * pmsg_hdr ) , GFP_KERNEL ) ;
2016-11-03 18:44:19 +03:00
if ( ! pmsg_hdr ) {
2016-11-03 18:44:22 +03:00
err = - ENOMEM ;
goto err_free_bus_info ;
2016-11-03 18:44:19 +03:00
}
memcpy ( pmsg_hdr , & inmsg - > hdr ,
sizeof ( struct controlvm_message_header ) ) ;
bus_info - > pending_msg_hdr = pmsg_hdr ;
}
2016-11-03 18:44:22 +03:00
visorchannel = visorchannel_create ( cmd - > create_bus . channel_addr ,
GFP_KERNEL ,
2017-09-27 20:14:44 +03:00
& cmd - > create_bus . bus_data_type_guid ,
false ) ;
2016-11-03 18:44:22 +03:00
if ( ! visorchannel ) {
err = - ENOMEM ;
goto err_free_pending_msg ;
}
bus_info - > visorchannel = visorchannel ;
2017-08-22 20:27:24 +03:00
/* Response will be handled by visorbus_create_instance on success */
err = visorbus_create_instance ( bus_info ) ;
2017-03-28 16:34:35 +03:00
if ( err )
goto err_destroy_channel ;
2016-11-03 18:44:22 +03:00
return 0 ;
2017-03-28 16:34:35 +03:00
err_destroy_channel :
visorchannel_destroy ( visorchannel ) ;
2016-11-03 18:44:22 +03:00
err_free_pending_msg :
kfree ( bus_info - > pending_msg_hdr ) ;
2016-11-03 18:44:19 +03:00
2016-11-03 18:44:22 +03:00
err_free_bus_info :
2016-11-03 18:44:19 +03:00
kfree ( bus_info ) ;
2014-03-04 17:58:07 +04:00
2016-11-03 18:44:22 +03:00
err_respond :
2016-11-03 18:44:19 +03:00
if ( inmsg - > hdr . flags . response_expected = = 1 )
2017-03-28 16:34:39 +03:00
controlvm_responder ( inmsg - > hdr . id , & inmsg - > hdr , err ) ;
2016-11-03 18:44:22 +03:00
return err ;
2014-03-04 17:58:07 +04:00
}
2017-08-22 20:26:57 +03:00
static int visorbus_destroy ( struct controlvm_message * inmsg )
2014-03-04 17:58:07 +04:00
{
2017-09-27 20:14:37 +03:00
struct controlvm_message_header * pmsg_hdr ;
2017-09-27 20:14:07 +03:00
u32 bus_no = inmsg - > cmd . destroy_bus . bus_no ;
2015-06-04 16:22:41 +03:00
struct visor_device * bus_info ;
2016-11-03 18:44:21 +03:00
int err ;
2014-03-04 17:58:07 +04:00
2015-06-04 16:22:41 +03:00
bus_info = visorbus_get_device_by_id ( bus_no , BUS_ROOT_DEVICE , NULL ) ;
2016-11-03 18:44:20 +03:00
if ( ! bus_info ) {
2016-11-03 18:44:21 +03:00
err = - ENODEV ;
goto err_respond ;
2016-11-03 18:44:20 +03:00
}
if ( bus_info - > state . created = = 0 ) {
2016-11-03 18:44:21 +03:00
err = - ENOENT ;
goto err_respond ;
2016-11-03 18:44:20 +03:00
}
if ( bus_info - > pending_msg_hdr ) {
/* only non-NULL if dev is still waiting on a response */
2016-11-03 18:44:21 +03:00
err = - EEXIST ;
goto err_respond ;
2016-11-03 18:44:20 +03:00
}
if ( inmsg - > hdr . flags . response_expected = = 1 ) {
pmsg_hdr = kzalloc ( sizeof ( * pmsg_hdr ) , GFP_KERNEL ) ;
if ( ! pmsg_hdr ) {
2016-11-03 18:44:21 +03:00
err = - ENOMEM ;
goto err_respond ;
2016-11-03 18:44:20 +03:00
}
memcpy ( pmsg_hdr , & inmsg - > hdr ,
sizeof ( struct controlvm_message_header ) ) ;
bus_info - > pending_msg_hdr = pmsg_hdr ;
}
2017-08-22 20:27:33 +03:00
/* Response will be handled by visorbus_remove_instance */
visorbus_remove_instance ( bus_info ) ;
2016-11-03 18:44:21 +03:00
return 0 ;
2016-11-03 18:44:20 +03:00
2016-11-03 18:44:21 +03:00
err_respond :
2016-11-03 18:44:20 +03:00
if ( inmsg - > hdr . flags . response_expected = = 1 )
2017-03-28 16:34:39 +03:00
controlvm_responder ( inmsg - > hdr . id , & inmsg - > hdr , err ) ;
2016-11-03 18:44:21 +03:00
return err ;
2014-03-04 17:58:07 +04:00
}
2017-08-30 20:36:27 +03:00
static const guid_t * parser_id_get ( struct parser_context * ctx )
{
return & ctx - > data . id ;
}
2017-09-27 20:14:08 +03:00
static void * parser_string_get ( u8 * pscan , int nscan )
2017-08-30 20:36:27 +03:00
{
int value_length ;
void * value ;
if ( nscan = = 0 )
return NULL ;
2017-09-27 20:14:08 +03:00
value_length = strnlen ( pscan , nscan ) ;
value = kzalloc ( value_length + 1 , GFP_KERNEL ) ;
2017-08-30 20:36:27 +03:00
if ( ! value )
return NULL ;
if ( value_length > 0 )
memcpy ( value , pscan , value_length ) ;
return value ;
}
static void * parser_name_get ( struct parser_context * ctx )
{
2017-09-27 20:14:37 +03:00
struct visor_controlvm_parameters_header * phdr ;
2017-08-30 20:36:27 +03:00
phdr = & ctx - > data ;
2017-11-17 20:27:38 +03:00
if ( ( unsigned long ) phdr - > name_offset +
( unsigned long ) phdr - > name_length > ctx - > param_bytes )
2017-08-30 20:36:27 +03:00
return NULL ;
ctx - > curr = ( char * ) & phdr + phdr - > name_offset ;
ctx - > bytes_remaining = phdr - > name_length ;
2017-09-27 20:14:08 +03:00
return parser_string_get ( ctx - > curr , phdr - > name_length ) ;
2017-08-30 20:36:27 +03:00
}
2017-08-22 20:26:57 +03:00
static int visorbus_configure ( struct controlvm_message * inmsg ,
struct parser_context * parser_ctx )
2014-03-04 17:58:07 +04:00
{
2014-10-23 22:30:25 +04:00
struct controlvm_message_packet * cmd = & inmsg - > cmd ;
2015-05-06 01:35:45 +03:00
u32 bus_no ;
2015-06-04 16:22:41 +03:00
struct visor_device * bus_info ;
2016-11-21 20:15:53 +03:00
int err = 0 ;
2014-03-04 17:58:07 +04:00
2015-03-16 20:58:22 +03:00
bus_no = cmd - > configure_bus . bus_no ;
2015-06-04 16:22:41 +03:00
bus_info = visorbus_get_device_by_id ( bus_no , BUS_ROOT_DEVICE , NULL ) ;
2015-03-16 20:58:22 +03:00
if ( ! bus_info ) {
2016-11-21 20:15:53 +03:00
err = - EINVAL ;
goto err_respond ;
2017-08-30 20:36:23 +03:00
}
if ( bus_info - > state . created = = 0 ) {
2016-11-21 20:15:53 +03:00
err = - EINVAL ;
goto err_respond ;
2017-08-30 20:36:23 +03:00
}
if ( bus_info - > pending_msg_hdr ) {
2016-11-21 20:15:53 +03:00
err = - EIO ;
goto err_respond ;
2014-03-04 17:58:07 +04:00
}
2017-09-27 20:14:11 +03:00
err = visorchannel_set_clientpartition ( bus_info - > visorchannel ,
cmd - > configure_bus . guest_handle ) ;
2016-11-21 20:15:53 +03:00
if ( err )
goto err_respond ;
2017-01-09 21:02:23 +03:00
if ( parser_ctx ) {
2017-08-22 20:26:54 +03:00
const guid_t * partition_guid = parser_id_get ( parser_ctx ) ;
guid_copy ( & bus_info - > partition_guid , partition_guid ) ;
2017-01-09 21:02:23 +03:00
bus_info - > name = parser_name_get ( parser_ctx ) ;
}
2016-11-21 20:15:53 +03:00
if ( inmsg - > hdr . flags . response_expected = = 1 )
2017-03-28 16:34:39 +03:00
controlvm_responder ( inmsg - > hdr . id , & inmsg - > hdr , err ) ;
2016-11-21 20:15:53 +03:00
return 0 ;
err_respond :
2017-04-18 23:55:18 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
2017-08-30 20:36:16 +03:00
" %s exited with err: %d \n " , __func__ , err ) ;
2016-11-03 18:44:23 +03:00
if ( inmsg - > hdr . flags . response_expected = = 1 )
2017-03-28 16:34:39 +03:00
controlvm_responder ( inmsg - > hdr . id , & inmsg - > hdr , err ) ;
2016-11-21 20:15:53 +03:00
return err ;
2014-03-04 17:58:07 +04:00
}
2017-08-22 20:26:57 +03:00
static int visorbus_device_create ( struct controlvm_message * inmsg )
2014-03-04 17:58:07 +04:00
{
2014-10-23 22:30:25 +04:00
struct controlvm_message_packet * cmd = & inmsg - > cmd ;
2017-09-27 20:14:37 +03:00
struct controlvm_message_header * pmsg_hdr ;
2015-04-13 17:28:41 +03:00
u32 bus_no = cmd - > create_device . bus_no ;
u32 dev_no = cmd - > create_device . dev_no ;
2017-09-27 20:14:37 +03:00
struct visor_device * dev_info ;
2015-06-04 16:22:41 +03:00
struct visor_device * bus_info ;
2015-06-01 20:00:26 +03:00
struct visorchannel * visorchannel ;
2016-12-22 19:09:04 +03:00
int err ;
2014-03-04 17:58:07 +04:00
2015-06-04 16:22:42 +03:00
bus_info = visorbus_get_device_by_id ( bus_no , BUS_ROOT_DEVICE , NULL ) ;
if ( ! bus_info ) {
2017-04-18 23:55:19 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
" failed to get bus by id: %d \n " , bus_no ) ;
2016-12-22 19:09:04 +03:00
err = - ENODEV ;
goto err_respond ;
2014-03-04 17:58:07 +04:00
}
2015-06-04 16:22:42 +03:00
if ( bus_info - > state . created = = 0 ) {
2017-04-18 23:55:19 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
" bus not created, id: %d \n " , bus_no ) ;
2016-12-22 19:09:04 +03:00
err = - EINVAL ;
goto err_respond ;
2014-03-04 17:58:07 +04:00
}
2015-06-04 16:22:42 +03:00
dev_info = visorbus_get_device_by_id ( bus_no , dev_no , NULL ) ;
2017-09-27 20:14:48 +03:00
if ( dev_info & & dev_info - > state . created = = 1 ) {
2017-04-18 23:55:19 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
" failed to get bus by id: %d/%d \n " , bus_no , dev_no ) ;
2016-12-22 19:09:04 +03:00
err = - EEXIST ;
goto err_respond ;
2014-03-04 17:58:07 +04:00
}
2015-06-04 16:22:42 +03:00
2015-03-16 20:58:23 +03:00
dev_info = kzalloc ( sizeof ( * dev_info ) , GFP_KERNEL ) ;
if ( ! dev_info ) {
2016-12-22 19:09:04 +03:00
err = - ENOMEM ;
goto err_respond ;
2014-03-04 17:58:07 +04:00
}
2015-06-04 16:22:42 +03:00
dev_info - > chipset_bus_no = bus_no ;
dev_info - > chipset_dev_no = dev_no ;
2017-08-22 20:26:54 +03:00
guid_copy ( & dev_info - > inst , & cmd - > create_device . dev_inst_guid ) ;
2015-06-04 16:22:42 +03:00
dev_info - > device . parent = & bus_info - > device ;
2017-09-27 20:14:44 +03:00
visorchannel = visorchannel_create ( cmd - > create_device . channel_addr ,
GFP_KERNEL ,
& cmd - > create_device . data_type_guid ,
true ) ;
2015-06-01 20:00:26 +03:00
if ( ! visorchannel ) {
2017-04-18 23:55:19 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
" failed to create visorchannel: %d/%d \n " ,
bus_no , dev_no ) ;
2016-12-22 19:09:04 +03:00
err = - ENOMEM ;
goto err_free_dev_info ;
2015-06-01 20:00:26 +03:00
}
dev_info - > visorchannel = visorchannel ;
2017-09-27 20:14:45 +03:00
guid_copy ( & dev_info - > channel_type_guid ,
& cmd - > create_device . data_type_guid ) ;
if ( guid_equal ( & cmd - > create_device . data_type_guid ,
& visor_vhba_channel_guid ) ) {
2016-12-22 19:09:04 +03:00
err = save_crash_message ( inmsg , CRASH_DEV ) ;
if ( err )
2017-03-28 16:34:38 +03:00
goto err_destroy_visorchannel ;
2016-12-22 19:09:04 +03:00
}
2016-11-03 18:44:24 +03:00
if ( inmsg - > hdr . flags . response_expected = = 1 ) {
pmsg_hdr = kzalloc ( sizeof ( * pmsg_hdr ) , GFP_KERNEL ) ;
if ( ! pmsg_hdr ) {
2016-12-22 19:09:04 +03:00
err = - ENOMEM ;
2017-03-28 16:34:38 +03:00
goto err_destroy_visorchannel ;
2016-11-03 18:44:24 +03:00
}
memcpy ( pmsg_hdr , & inmsg - > hdr ,
sizeof ( struct controlvm_message_header ) ) ;
dev_info - > pending_msg_hdr = pmsg_hdr ;
}
2017-08-22 20:27:34 +03:00
/* create_visor_device will send response */
err = create_visor_device ( dev_info ) ;
2017-03-28 16:34:38 +03:00
if ( err )
goto err_destroy_visorchannel ;
2016-12-22 19:09:04 +03:00
return 0 ;
2016-11-03 18:44:24 +03:00
2017-03-28 16:34:38 +03:00
err_destroy_visorchannel :
visorchannel_destroy ( visorchannel ) ;
2016-12-22 19:09:04 +03:00
err_free_dev_info :
2016-11-03 18:44:24 +03:00
kfree ( dev_info ) ;
2016-12-22 19:09:04 +03:00
err_respond :
2016-11-03 18:44:24 +03:00
if ( inmsg - > hdr . flags . response_expected = = 1 )
2017-03-28 16:34:39 +03:00
controlvm_responder ( inmsg - > hdr . id , & inmsg - > hdr , err ) ;
2016-12-22 19:09:04 +03:00
return err ;
2014-03-04 17:58:07 +04:00
}
2017-08-22 20:26:57 +03:00
static int visorbus_device_changestate ( struct controlvm_message * inmsg )
2014-03-04 17:58:07 +04:00
{
2014-10-23 22:30:25 +04:00
struct controlvm_message_packet * cmd = & inmsg - > cmd ;
2017-09-27 20:14:37 +03:00
struct controlvm_message_header * pmsg_hdr ;
2015-04-13 17:28:41 +03:00
u32 bus_no = cmd - > device_change_state . bus_no ;
u32 dev_no = cmd - > device_change_state . dev_no ;
2017-05-19 23:17:49 +03:00
struct visor_segment_state state = cmd - > device_change_state . state ;
2015-06-04 16:22:42 +03:00
struct visor_device * dev_info ;
2017-03-28 16:34:54 +03:00
int err = 0 ;
2014-03-04 17:58:07 +04:00
2015-06-04 16:22:42 +03:00
dev_info = visorbus_get_device_by_id ( bus_no , dev_no , NULL ) ;
2015-03-16 20:58:24 +03:00
if ( ! dev_info ) {
2016-12-22 19:09:06 +03:00
err = - ENODEV ;
2016-11-03 18:44:25 +03:00
goto err_respond ;
}
if ( dev_info - > state . created = = 0 ) {
2016-12-22 19:09:06 +03:00
err = - EINVAL ;
2016-11-03 18:44:25 +03:00
goto err_respond ;
2014-03-04 17:58:07 +04:00
}
2016-11-03 18:44:26 +03:00
if ( dev_info - > pending_msg_hdr ) {
/* only non-NULL if dev is still waiting on a response */
2016-12-22 19:09:06 +03:00
err = - EIO ;
2016-11-03 18:44:26 +03:00
goto err_respond ;
}
2017-09-27 20:14:26 +03:00
2016-11-03 18:44:26 +03:00
if ( inmsg - > hdr . flags . response_expected = = 1 ) {
pmsg_hdr = kzalloc ( sizeof ( * pmsg_hdr ) , GFP_KERNEL ) ;
if ( ! pmsg_hdr ) {
2016-12-22 19:09:06 +03:00
err = - ENOMEM ;
2016-11-03 18:44:26 +03:00
goto err_respond ;
}
memcpy ( pmsg_hdr , & inmsg - > hdr ,
sizeof ( struct controlvm_message_header ) ) ;
dev_info - > pending_msg_hdr = pmsg_hdr ;
}
if ( state . alive = = segment_state_running . alive & &
state . operating = = segment_state_running . operating )
2017-05-19 23:17:41 +03:00
/* Response will be sent from visorchipset_device_resume */
err = visorchipset_device_resume ( dev_info ) ;
2016-11-03 18:44:26 +03:00
/* ServerNotReady / ServerLost / SegmentStateStandby */
else if ( state . alive = = segment_state_standby . alive & &
state . operating = = segment_state_standby . operating )
/*
* technically this is standby case where server is lost .
2017-05-19 23:17:41 +03:00
* Response will be sent from visorchipset_device_pause .
2016-11-03 18:44:26 +03:00
*/
2017-05-19 23:17:41 +03:00
err = visorchipset_device_pause ( dev_info ) ;
2017-03-28 16:34:54 +03:00
if ( err )
goto err_respond ;
2016-12-22 19:09:06 +03:00
return 0 ;
2016-11-03 18:44:25 +03:00
err_respond :
2017-04-18 23:55:20 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev , " failed: %d \n " , err ) ;
2016-11-03 18:44:26 +03:00
if ( inmsg - > hdr . flags . response_expected = = 1 )
2017-03-28 16:34:39 +03:00
controlvm_responder ( inmsg - > hdr . id , & inmsg - > hdr , err ) ;
2016-12-22 19:09:06 +03:00
return err ;
2014-03-04 17:58:07 +04:00
}
2017-08-22 20:26:57 +03:00
static int visorbus_device_destroy ( struct controlvm_message * inmsg )
2014-03-04 17:58:07 +04:00
{
2014-10-23 22:30:25 +04:00
struct controlvm_message_packet * cmd = & inmsg - > cmd ;
2017-09-27 20:14:37 +03:00
struct controlvm_message_header * pmsg_hdr ;
2015-04-13 17:28:41 +03:00
u32 bus_no = cmd - > destroy_device . bus_no ;
u32 dev_no = cmd - > destroy_device . dev_no ;
2015-06-04 16:22:42 +03:00
struct visor_device * dev_info ;
2016-12-22 19:09:07 +03:00
int err ;
2014-03-04 17:58:07 +04:00
2015-06-04 16:22:42 +03:00
dev_info = visorbus_get_device_by_id ( bus_no , dev_no , NULL ) ;
2016-11-03 18:44:27 +03:00
if ( ! dev_info ) {
2016-12-22 19:09:07 +03:00
err = - ENODEV ;
2016-11-03 18:44:27 +03:00
goto err_respond ;
}
if ( dev_info - > state . created = = 0 ) {
2016-12-22 19:09:07 +03:00
err = - EINVAL ;
2016-11-03 18:44:27 +03:00
goto err_respond ;
}
if ( dev_info - > pending_msg_hdr ) {
/* only non-NULL if dev is still waiting on a response */
2016-12-22 19:09:07 +03:00
err = - EIO ;
2016-11-03 18:44:27 +03:00
goto err_respond ;
}
if ( inmsg - > hdr . flags . response_expected = = 1 ) {
pmsg_hdr = kzalloc ( sizeof ( * pmsg_hdr ) , GFP_KERNEL ) ;
if ( ! pmsg_hdr ) {
2016-12-22 19:09:07 +03:00
err = - ENOMEM ;
2016-11-03 18:44:27 +03:00
goto err_respond ;
}
memcpy ( pmsg_hdr , & inmsg - > hdr ,
sizeof ( struct controlvm_message_header ) ) ;
dev_info - > pending_msg_hdr = pmsg_hdr ;
}
2017-07-17 23:17:03 +03:00
kfree ( dev_info - > name ) ;
2017-08-22 20:27:35 +03:00
remove_visor_device ( dev_info ) ;
2016-12-22 19:09:07 +03:00
return 0 ;
2016-11-03 18:44:27 +03:00
err_respond :
if ( inmsg - > hdr . flags . response_expected = = 1 )
2017-03-28 16:34:39 +03:00
controlvm_responder ( inmsg - > hdr . id , & inmsg - > hdr , err ) ;
2016-12-22 19:09:07 +03:00
return err ;
2014-03-04 17:58:07 +04:00
}
/*
2016-12-22 19:09:02 +03:00
* The general parahotplug flow works as follows . The visorchipset receives
* a DEVICE_CHANGESTATE message from Command specifying a physical device
* to enable or disable . The CONTROLVM message handler calls
* parahotplug_process_message , which then adds the message to a global list
* and kicks off a udev event which causes a user level script to enable or
* disable the specified device . The udev script then writes to
* / sys / devices / platform / visorchipset / parahotplug , which causes the
* parahotplug store functions to get called , at which point the
2017-07-17 23:16:42 +03:00
* appropriate CONTROLVM message is retrieved from the list and responded to .
2014-03-04 17:58:07 +04:00
*/
# define PARAHOTPLUG_TIMEOUT_MS 2000
2017-02-21 20:53:25 +03:00
/*
2016-12-22 19:09:02 +03:00
* parahotplug_next_id ( ) - generate unique int to match an outstanding
* CONTROLVM message with a udev script / sys
* response
2016-06-11 04:48:18 +03:00
*
* Return : a unique integer value
2014-03-04 17:58:07 +04:00
*/
2017-08-22 20:26:57 +03:00
static int parahotplug_next_id ( void )
2014-03-04 17:58:07 +04:00
{
static atomic_t id = ATOMIC_INIT ( 0 ) ;
2014-08-18 17:34:53 +04:00
2014-03-04 17:58:07 +04:00
return atomic_inc_return ( & id ) ;
}
2017-02-21 20:53:25 +03:00
/*
2016-06-11 04:48:18 +03:00
* parahotplug_next_expiration ( ) - returns the time ( in jiffies ) when a
* CONTROLVM message on the list should expire
* - - PARAHOTPLUG_TIMEOUT_MS in the future
*
* Return : expected expiration time ( in jiffies )
2014-03-04 17:58:07 +04:00
*/
2017-08-22 20:26:57 +03:00
static unsigned long parahotplug_next_expiration ( void )
2014-03-04 17:58:07 +04:00
{
2015-01-31 14:02:08 +03:00
return jiffies + msecs_to_jiffies ( PARAHOTPLUG_TIMEOUT_MS ) ;
2014-03-04 17:58:07 +04:00
}
2017-02-21 20:53:25 +03:00
/*
2016-06-11 04:48:18 +03:00
* parahotplug_request_create ( ) - create a parahotplug_request , which is
* basically a wrapper for a CONTROLVM_MESSAGE
* that we can stick on a list
* @ msg : the message to insert in the request
*
* Return : the request containing the provided message
2014-03-04 17:58:07 +04:00
*/
2017-08-22 20:26:57 +03:00
static struct parahotplug_request * parahotplug_request_create (
struct controlvm_message * msg )
2014-03-04 17:58:07 +04:00
{
2015-02-10 17:12:07 +03:00
struct parahotplug_request * req ;
2017-04-18 23:55:08 +03:00
req = kmalloc ( sizeof ( * req ) , GFP_KERNEL ) ;
2015-03-16 20:58:13 +03:00
if ( ! req )
2014-03-04 17:58:07 +04:00
return NULL ;
req - > id = parahotplug_next_id ( ) ;
req - > expiration = parahotplug_next_expiration ( ) ;
req - > msg = * msg ;
return req ;
}
2017-02-21 20:53:25 +03:00
/*
2016-06-11 04:48:18 +03:00
* parahotplug_request_destroy ( ) - free a parahotplug_request
* @ req : the request to deallocate
2014-03-04 17:58:07 +04:00
*/
2017-08-22 20:26:57 +03:00
static void parahotplug_request_destroy ( struct parahotplug_request * req )
2014-03-04 17:58:07 +04:00
{
kfree ( req ) ;
}
2016-09-20 00:09:37 +03:00
static LIST_HEAD ( parahotplug_request_list ) ;
2017-06-30 22:43:08 +03:00
/* lock for above */
static DEFINE_SPINLOCK ( parahotplug_request_list_lock ) ;
2016-09-20 00:09:37 +03:00
2017-02-21 20:53:25 +03:00
/*
2016-06-11 04:48:18 +03:00
* parahotplug_request_complete ( ) - mark request as complete
* @ id : the id of the request
* @ active : indicates whether the request is assigned to active partition
*
2016-12-22 19:09:02 +03:00
* Called from the / sys handler , which means the user script has
2016-06-11 04:48:18 +03:00
* finished the enable / disable . Find the matching identifier , and
2014-03-04 17:58:07 +04:00
* respond to the CONTROLVM message with success .
2016-06-11 04:48:18 +03:00
*
* Return : 0 on success or - EINVAL on failure
2014-03-04 17:58:07 +04:00
*/
2017-08-22 20:26:57 +03:00
static int parahotplug_request_complete ( int id , u16 active )
2014-03-04 17:58:07 +04:00
{
2015-05-06 01:35:45 +03:00
struct list_head * pos ;
struct list_head * tmp ;
2017-09-27 20:14:10 +03:00
struct parahotplug_request * req ;
2014-03-04 17:58:07 +04:00
2015-03-16 20:58:41 +03:00
spin_lock ( & parahotplug_request_list_lock ) ;
2014-03-04 17:58:07 +04:00
/* Look for a request matching "id". */
2015-03-16 20:58:41 +03:00
list_for_each_safe ( pos , tmp , & parahotplug_request_list ) {
2017-09-27 20:14:10 +03:00
req = list_entry ( pos , struct parahotplug_request , list ) ;
2014-03-04 17:58:07 +04:00
if ( req - > id = = id ) {
2016-06-11 04:48:18 +03:00
/*
* Found a match . Remove it from the list and
2014-03-04 17:58:07 +04:00
* respond .
*/
list_del ( pos ) ;
2015-03-16 20:58:41 +03:00
spin_unlock ( & parahotplug_request_list_lock ) ;
2014-10-23 22:30:25 +04:00
req - > msg . cmd . device_change_state . state . active = active ;
2014-10-23 22:30:26 +04:00
if ( req - > msg . hdr . flags . response_expected )
2017-04-18 23:55:01 +03:00
controlvm_respond (
& req - > msg . hdr , CONTROLVM_RESP_SUCCESS ,
& req - > msg . cmd . device_change_state . state ) ;
2014-03-04 17:58:07 +04:00
parahotplug_request_destroy ( req ) ;
return 0 ;
}
}
2015-03-16 20:58:41 +03:00
spin_unlock ( & parahotplug_request_list_lock ) ;
2016-05-14 06:17:20 +03:00
return - EINVAL ;
2014-03-04 17:58:07 +04:00
}
2017-02-21 20:53:25 +03:00
/*
2016-09-20 00:09:34 +03:00
* devicedisabled_store ( ) - disables the hotplug device
* @ dev : sysfs interface variable not utilized in this function
* @ attr : sysfs interface variable not utilized in this function
* @ buf : buffer containing the device id
* @ count : the size of the buffer
*
* The parahotplug / devicedisabled interface gets called by our support script
* when an SR - IOV device has been shut down . The ID is passed to the script
* and then passed back when the device has been removed .
*
* Return : the size of the buffer for success or negative for error
*/
static ssize_t devicedisabled_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
unsigned int id ;
int err ;
if ( kstrtouint ( buf , 10 , & id ) )
return - EINVAL ;
err = parahotplug_request_complete ( id , 0 ) ;
if ( err < 0 )
return err ;
return count ;
}
static DEVICE_ATTR_WO ( devicedisabled ) ;
2017-02-21 20:53:25 +03:00
/*
2016-09-20 00:09:34 +03:00
* deviceenabled_store ( ) - enables the hotplug device
* @ dev : sysfs interface variable not utilized in this function
* @ attr : sysfs interface variable not utilized in this function
* @ buf : buffer containing the device id
* @ count : the size of the buffer
*
* The parahotplug / deviceenabled interface gets called by our support script
* when an SR - IOV device has been recovered . The ID is passed to the script
* and then passed back when the device has been brought back up .
*
* Return : the size of the buffer for success or negative for error
*/
static ssize_t deviceenabled_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
unsigned int id ;
if ( kstrtouint ( buf , 10 , & id ) )
return - EINVAL ;
parahotplug_request_complete ( id , 1 ) ;
return count ;
}
static DEVICE_ATTR_WO ( deviceenabled ) ;
static struct attribute * visorchipset_install_attrs [ ] = {
& dev_attr_toolaction . attr ,
& dev_attr_boottotool . attr ,
& dev_attr_error . attr ,
& dev_attr_textid . attr ,
& dev_attr_remaining_steps . attr ,
NULL
} ;
2016-10-16 01:41:14 +03:00
static const struct attribute_group visorchipset_install_group = {
2016-09-20 00:09:34 +03:00
. name = " install " ,
. attrs = visorchipset_install_attrs
} ;
static struct attribute * visorchipset_parahotplug_attrs [ ] = {
& dev_attr_devicedisabled . attr ,
& dev_attr_deviceenabled . attr ,
NULL
} ;
2017-07-18 11:10:54 +03:00
static const struct attribute_group visorchipset_parahotplug_group = {
2016-09-20 00:09:34 +03:00
. name = " parahotplug " ,
. attrs = visorchipset_parahotplug_attrs
} ;
static const struct attribute_group * visorchipset_dev_groups [ ] = {
& visorchipset_install_group ,
& visorchipset_parahotplug_group ,
NULL
} ;
2017-02-21 20:53:25 +03:00
/*
2016-09-20 00:09:34 +03:00
* parahotplug_request_kickoff ( ) - initiate parahotplug request
* @ req : the request to initiate
*
* Cause uevent to run the user level script to do the disable / enable specified
* in the parahotplug_request .
*/
2017-08-22 20:26:57 +03:00
static int parahotplug_request_kickoff ( struct parahotplug_request * req )
2016-09-20 00:09:34 +03:00
{
struct controlvm_message_packet * cmd = & req - > msg . cmd ;
char env_cmd [ 40 ] , env_id [ 40 ] , env_state [ 40 ] , env_bus [ 40 ] , env_dev [ 40 ] ,
2017-09-27 20:14:39 +03:00
env_func [ 40 ] ;
char * envp [ ] = { env_cmd , env_id , env_state , env_bus , env_dev ,
env_func , NULL
2016-09-20 00:09:34 +03:00
} ;
2017-05-19 23:17:48 +03:00
sprintf ( env_cmd , " VISOR_PARAHOTPLUG=1 " ) ;
sprintf ( env_id , " VISOR_PARAHOTPLUG_ID=%d " , req - > id ) ;
sprintf ( env_state , " VISOR_PARAHOTPLUG_STATE=%d " ,
2016-09-20 00:09:34 +03:00
cmd - > device_change_state . state . active ) ;
2017-05-19 23:17:48 +03:00
sprintf ( env_bus , " VISOR_PARAHOTPLUG_BUS=%d " ,
2016-09-20 00:09:34 +03:00
cmd - > device_change_state . bus_no ) ;
2017-05-19 23:17:48 +03:00
sprintf ( env_dev , " VISOR_PARAHOTPLUG_DEVICE=%d " ,
2016-09-20 00:09:34 +03:00
cmd - > device_change_state . dev_no > > 3 ) ;
2017-05-19 23:17:48 +03:00
sprintf ( env_func , " VISOR_PARAHOTPLUG_FUNCTION=%d " ,
2016-09-20 00:09:34 +03:00
cmd - > device_change_state . dev_no & 0x7 ) ;
2017-03-28 16:34:21 +03:00
return kobject_uevent_env ( & chipset_dev - > acpi_device - > dev . kobj ,
KOBJ_CHANGE , envp ) ;
2016-09-20 00:09:34 +03:00
}
2017-02-21 20:53:25 +03:00
/*
2016-06-11 04:48:18 +03:00
* parahotplug_process_message ( ) - enables or disables a PCI device by kicking
* off a udev script
* @ inmsg : the message indicating whether to enable or disable
2014-03-04 17:58:07 +04:00
*/
2017-08-22 20:26:57 +03:00
static int parahotplug_process_message ( struct controlvm_message * inmsg )
2014-03-04 17:58:07 +04:00
{
struct parahotplug_request * req ;
2017-03-28 16:34:21 +03:00
int err ;
2014-03-04 17:58:07 +04:00
req = parahotplug_request_create ( inmsg ) ;
2015-03-16 20:58:13 +03:00
if ( ! req )
2017-03-28 16:34:18 +03:00
return - ENOMEM ;
2017-04-18 23:55:05 +03:00
/*
* For enable messages , just respond with success right away , we don ' t
* need to wait to see if the enable was successful .
*/
2014-10-23 22:30:25 +04:00
if ( inmsg - > cmd . device_change_state . state . active ) {
2017-03-28 16:34:21 +03:00
err = parahotplug_request_kickoff ( req ) ;
if ( err )
goto err_respond ;
2017-04-18 23:55:01 +03:00
controlvm_respond ( & inmsg - > hdr , CONTROLVM_RESP_SUCCESS ,
& inmsg - > cmd . device_change_state . state ) ;
2014-03-04 17:58:07 +04:00
parahotplug_request_destroy ( req ) ;
2017-03-28 16:34:21 +03:00
return 0 ;
2014-03-04 17:58:07 +04:00
}
2017-03-28 16:34:21 +03:00
/*
2017-08-30 20:36:29 +03:00
* For disable messages , add the request to the request list before
* kicking off the udev script . It won ' t get responded to until the
* script has indicated it ' s done .
2017-03-28 16:34:21 +03:00
*/
spin_lock ( & parahotplug_request_list_lock ) ;
list_add_tail ( & req - > list , & parahotplug_request_list ) ;
spin_unlock ( & parahotplug_request_list_lock ) ;
err = parahotplug_request_kickoff ( req ) ;
if ( err )
goto err_respond ;
2017-03-28 16:34:18 +03:00
return 0 ;
2017-03-28 16:34:21 +03:00
err_respond :
2017-04-18 23:55:01 +03:00
controlvm_respond ( & inmsg - > hdr , err ,
& inmsg - > cmd . device_change_state . state ) ;
2017-03-28 16:34:21 +03:00
return err ;
2014-03-04 17:58:07 +04:00
}
2017-02-02 01:38:56 +03:00
/*
* chipset_ready_uevent ( ) - sends chipset_ready action
2016-09-20 00:09:34 +03:00
*
* Send ACTION = online for DEVPATH = / sys / devices / platform / visorchipset .
*
2017-02-02 01:38:56 +03:00
* Return : 0 on success , negative on failure
2016-09-20 00:09:34 +03:00
*/
2017-08-22 20:26:57 +03:00
static int chipset_ready_uevent ( struct controlvm_message_header * msg_hdr )
2016-09-20 00:09:34 +03:00
{
2017-03-28 16:34:22 +03:00
int res ;
2017-09-27 20:14:10 +03:00
res = kobject_uevent ( & chipset_dev - > acpi_device - > dev . kobj , KOBJ_ONLINE ) ;
2017-02-02 01:38:56 +03:00
if ( msg_hdr - > flags . response_expected )
2017-04-18 23:55:01 +03:00
controlvm_respond ( msg_hdr , res , NULL ) ;
2017-03-28 16:34:22 +03:00
return res ;
2016-09-20 00:09:34 +03:00
}
2017-02-02 01:38:56 +03:00
/*
* chipset_selftest_uevent ( ) - sends chipset_selftest action
*
* Send ACTION = online for DEVPATH = / sys / devices / platform / visorchipset .
*
* Return : 0 on success , negative on failure
*/
2017-08-22 20:26:57 +03:00
static int chipset_selftest_uevent ( struct controlvm_message_header * msg_hdr )
2016-09-20 00:09:34 +03:00
{
char env_selftest [ 20 ] ;
char * envp [ ] = { env_selftest , NULL } ;
2017-03-28 16:34:22 +03:00
int res ;
2016-09-20 00:09:34 +03:00
sprintf ( env_selftest , " SPARSP_SELFTEST=%d " , 1 ) ;
2017-03-28 16:34:22 +03:00
res = kobject_uevent_env ( & chipset_dev - > acpi_device - > dev . kobj ,
KOBJ_CHANGE , envp ) ;
2017-02-02 01:38:56 +03:00
if ( msg_hdr - > flags . response_expected )
2017-04-18 23:55:01 +03:00
controlvm_respond ( msg_hdr , res , NULL ) ;
2017-03-28 16:34:22 +03:00
return res ;
2016-09-20 00:09:34 +03:00
}
2017-02-02 01:38:56 +03:00
/*
* chipset_notready_uevent ( ) - sends chipset_notready action
2016-09-20 00:09:34 +03:00
*
* Send ACTION = offline for DEVPATH = / sys / devices / platform / visorchipset .
*
2017-02-02 01:38:56 +03:00
* Return : 0 on success , negative on failure
2016-09-20 00:09:34 +03:00
*/
2017-08-22 20:26:57 +03:00
static int chipset_notready_uevent ( struct controlvm_message_header * msg_hdr )
2016-09-20 00:09:34 +03:00
{
2017-07-17 23:16:42 +03:00
int res = kobject_uevent ( & chipset_dev - > acpi_device - > dev . kobj ,
2017-09-27 20:14:11 +03:00
KOBJ_OFFLINE ) ;
2017-07-17 23:16:42 +03:00
2016-09-20 00:09:34 +03:00
if ( msg_hdr - > flags . response_expected )
2017-04-18 23:55:01 +03:00
controlvm_respond ( msg_hdr , res , NULL ) ;
2017-03-28 16:34:22 +03:00
return res ;
2016-09-20 00:09:34 +03:00
}
2017-03-28 16:35:00 +03:00
static int unisys_vmcall ( unsigned long tuple , unsigned long param )
{
int result = 0 ;
unsigned int cpuid_eax , cpuid_ebx , cpuid_ecx , cpuid_edx ;
unsigned long reg_ebx ;
unsigned long reg_ecx ;
reg_ebx = param & 0xFFFFFFFF ;
reg_ecx = param > > 32 ;
cpuid ( 0x00000001 , & cpuid_eax , & cpuid_ebx , & cpuid_ecx , & cpuid_edx ) ;
if ( ! ( cpuid_ecx & 0x80000000 ) )
return - EPERM ;
__asm__ __volatile__ ( " .byte 0x00f, 0x001, 0x0c1 " : " =a " ( result ) :
2017-09-27 20:14:11 +03:00
" a " ( tuple ) , " b " ( reg_ebx ) , " c " ( reg_ecx ) ) ;
2017-03-28 16:35:01 +03:00
if ( result )
goto error ;
return 0 ;
2017-09-27 20:14:26 +03:00
2017-06-30 22:43:08 +03:00
/* Need to convert from VMCALL error codes to Linux */
error :
2017-03-28 16:35:01 +03:00
switch ( result ) {
case VMCALL_RESULT_INVALID_PARAM :
return - EINVAL ;
case VMCALL_RESULT_DATA_UNAVAILABLE :
return - ENODEV ;
default :
return - EFAULT ;
}
2017-03-28 16:35:00 +03:00
}
2017-08-22 20:26:53 +03:00
2017-08-30 20:36:19 +03:00
static int controlvm_channel_create ( struct visorchipset_device * dev )
2015-05-13 20:22:10 +03:00
{
2017-08-30 20:36:19 +03:00
struct visorchannel * chan ;
u64 addr ;
2017-08-30 20:36:13 +03:00
int err ;
2017-08-30 20:36:19 +03:00
err = unisys_vmcall ( VMCALL_CONTROLVM_ADDR ,
virt_to_phys ( & dev - > controlvm_params ) ) ;
2017-08-30 20:36:13 +03:00
if ( err )
return err ;
2017-08-30 20:36:19 +03:00
addr = dev - > controlvm_params . address ;
2017-09-27 20:14:44 +03:00
chan = visorchannel_create ( addr , GFP_KERNEL ,
& visor_controlvm_channel_guid , true ) ;
2017-08-30 20:36:19 +03:00
if ( ! chan )
return - ENOMEM ;
dev - > controlvm_channel = chan ;
2017-03-28 16:35:01 +03:00
return 0 ;
2015-05-13 20:22:10 +03:00
}
2017-08-22 20:26:57 +03:00
static void setup_crash_devices_work_queue ( struct work_struct * work )
2014-03-04 17:58:07 +04:00
{
2015-03-16 20:58:33 +03:00
struct controlvm_message local_crash_bus_msg ;
struct controlvm_message local_crash_dev_msg ;
2014-10-23 22:30:31 +04:00
struct controlvm_message msg ;
2015-03-16 20:58:33 +03:00
u32 local_crash_msg_offset ;
u16 local_crash_msg_count ;
2014-03-04 17:58:07 +04:00
/* send init chipset msg */
2014-10-23 22:30:26 +04:00
msg . hdr . id = CONTROLVM_CHIPSET_INIT ;
2014-10-23 22:30:25 +04:00
msg . cmd . init_chipset . bus_count = 23 ;
msg . cmd . init_chipset . switch_count = 0 ;
2014-03-04 17:58:07 +04:00
chipset_init ( & msg ) ;
/* get saved message count */
2017-02-21 20:53:29 +03:00
if ( visorchannel_read ( chipset_dev - > controlvm_channel ,
2017-05-19 23:17:49 +03:00
offsetof ( struct visor_controlvm_channel ,
2014-10-23 22:30:34 +04:00
saved_crash_message_count ) ,
2015-03-16 20:58:33 +03:00
& local_crash_msg_count , sizeof ( u16 ) ) < 0 ) {
2017-04-18 23:55:22 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
" failed to read channel \n " ) ;
2014-03-04 17:58:07 +04:00
return ;
}
2015-03-16 20:58:33 +03:00
if ( local_crash_msg_count ! = CONTROLVM_CRASHMSG_MAX ) {
2017-09-27 20:14:10 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev , " invalid count \n " ) ;
2014-03-04 17:58:07 +04:00
return ;
}
/* get saved crash message offset */
2017-02-21 20:53:29 +03:00
if ( visorchannel_read ( chipset_dev - > controlvm_channel ,
2017-05-19 23:17:49 +03:00
offsetof ( struct visor_controlvm_channel ,
2014-10-23 22:30:34 +04:00
saved_crash_message_offset ) ,
2015-03-16 20:58:33 +03:00
& local_crash_msg_offset , sizeof ( u32 ) ) < 0 ) {
2017-04-18 23:55:22 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
" failed to read channel \n " ) ;
2014-03-04 17:58:07 +04:00
return ;
}
/* read create device message for storage bus offset */
2017-02-21 20:53:29 +03:00
if ( visorchannel_read ( chipset_dev - > controlvm_channel ,
2015-03-16 20:58:33 +03:00
local_crash_msg_offset ,
& local_crash_bus_msg ,
2014-10-23 22:30:31 +04:00
sizeof ( struct controlvm_message ) ) < 0 ) {
2017-04-18 23:55:22 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
" failed to read channel \n " ) ;
2014-03-04 17:58:07 +04:00
return ;
}
/* read create device message for storage device */
2017-02-21 20:53:29 +03:00
if ( visorchannel_read ( chipset_dev - > controlvm_channel ,
2015-03-16 20:58:33 +03:00
local_crash_msg_offset +
2014-10-23 22:30:31 +04:00
sizeof ( struct controlvm_message ) ,
2015-03-16 20:58:33 +03:00
& local_crash_dev_msg ,
2014-10-23 22:30:31 +04:00
sizeof ( struct controlvm_message ) ) < 0 ) {
2017-04-18 23:55:22 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
" failed to read channel \n " ) ;
2014-03-04 17:58:07 +04:00
return ;
}
/* reuse IOVM create bus message */
2017-04-18 23:55:21 +03:00
if ( ! local_crash_bus_msg . cmd . create_bus . channel_addr ) {
2017-04-18 23:55:22 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
" no valid create_bus message \n " ) ;
2014-03-04 17:58:07 +04:00
return ;
}
2017-05-19 23:17:36 +03:00
visorbus_create ( & local_crash_bus_msg ) ;
2014-03-04 17:58:07 +04:00
/* reuse create device message for storage device */
2017-04-18 23:55:21 +03:00
if ( ! local_crash_dev_msg . cmd . create_device . channel_addr ) {
2017-04-18 23:55:22 +03:00
dev_err ( & chipset_dev - > acpi_device - > dev ,
" no valid create_device message \n " ) ;
2014-03-04 17:58:07 +04:00
return ;
}
2017-05-19 23:17:43 +03:00
visorbus_device_create ( & local_crash_dev_msg ) ;
2014-03-04 17:58:07 +04:00
}
2017-08-22 20:27:03 +03:00
void visorbus_response ( struct visor_device * bus_info , int response ,
int controlvm_id )
2014-03-04 17:58:07 +04:00
{
2017-09-27 20:14:16 +03:00
if ( ! bus_info - > pending_msg_hdr )
return ;
2015-06-01 20:00:27 +03:00
2017-09-27 20:14:16 +03:00
controlvm_responder ( controlvm_id , bus_info - > pending_msg_hdr , response ) ;
2015-06-01 20:00:27 +03:00
kfree ( bus_info - > pending_msg_hdr ) ;
bus_info - > pending_msg_hdr = NULL ;
2014-03-04 17:58:07 +04:00
}
2017-08-22 20:27:04 +03:00
void visorbus_device_changestate_response ( struct visor_device * dev_info ,
int response ,
struct visor_segment_state state )
2014-03-04 17:58:07 +04:00
{
2017-09-27 20:14:16 +03:00
if ( ! dev_info - > pending_msg_hdr )
return ;
2017-09-27 20:14:10 +03:00
device_changestate_responder ( CONTROLVM_DEVICE_CHANGESTATE , dev_info ,
response , state ) ;
2015-06-01 20:00:27 +03:00
kfree ( dev_info - > pending_msg_hdr ) ;
dev_info - > pending_msg_hdr = NULL ;
2014-03-04 17:58:07 +04:00
}
2017-08-30 20:36:27 +03:00
static void parser_done ( struct parser_context * ctx )
{
chipset_dev - > controlvm_payload_bytes_buffered - = ctx - > param_bytes ;
kfree ( ctx ) ;
}
2017-08-30 20:36:28 +03:00
static struct parser_context * parser_init_stream ( u64 addr , u32 bytes ,
bool * retry )
2016-09-20 00:09:22 +03:00
{
2017-11-17 20:27:38 +03:00
unsigned long allocbytes ;
2016-09-20 00:09:22 +03:00
struct parser_context * ctx ;
2017-07-17 23:17:09 +03:00
void * mapping ;
2016-09-20 00:09:22 +03:00
2016-12-22 19:09:00 +03:00
* retry = false ;
2017-08-30 20:36:24 +03:00
/* alloc an extra byte to ensure payload is \0 terminated */
2017-11-17 20:27:38 +03:00
allocbytes = ( unsigned long ) bytes + 1 + ( sizeof ( struct parser_context ) -
2017-08-30 20:36:24 +03:00
sizeof ( struct visor_controlvm_parameters_header ) ) ;
2017-09-27 20:14:10 +03:00
if ( ( chipset_dev - > controlvm_payload_bytes_buffered + bytes ) >
MAX_CONTROLVM_PAYLOAD_BYTES ) {
2016-12-22 19:09:00 +03:00
* retry = true ;
2016-09-20 00:09:22 +03:00
return NULL ;
}
2017-04-18 23:55:08 +03:00
ctx = kzalloc ( allocbytes , GFP_KERNEL ) ;
2016-09-20 00:09:22 +03:00
if ( ! ctx ) {
2016-12-22 19:09:00 +03:00
* retry = true ;
2016-09-20 00:09:22 +03:00
return NULL ;
}
ctx - > allocbytes = allocbytes ;
ctx - > param_bytes = bytes ;
2017-07-17 23:17:09 +03:00
mapping = memremap ( addr , bytes , MEMREMAP_WB ) ;
if ( ! mapping )
goto err_finish_ctx ;
2017-08-30 20:36:24 +03:00
memcpy ( & ctx - > data , mapping , bytes ) ;
2017-07-17 23:17:09 +03:00
memunmap ( mapping ) ;
2016-09-20 00:09:22 +03:00
ctx - > byte_stream = true ;
2017-02-21 20:53:29 +03:00
chipset_dev - > controlvm_payload_bytes_buffered + = ctx - > param_bytes ;
2016-09-20 00:09:22 +03:00
return ctx ;
err_finish_ctx :
2017-08-30 20:36:09 +03:00
kfree ( ctx ) ;
2016-09-20 00:09:22 +03:00
return NULL ;
}
2017-02-21 20:53:25 +03:00
/*
2016-09-20 00:09:21 +03:00
* handle_command ( ) - process a controlvm message
* @ inmsg : the message to process
* @ channel_addr : address of the controlvm channel
*
* Return :
2017-03-28 16:34:19 +03:00
* 0 - Successfully processed the message
* - EAGAIN - ControlVM message was not processed and should be retried
* reading the next controlvm message ; a scenario where this can
* occur is when we need to throttle the allocation of memory in
* which to copy out controlvm payload data .
* < 0 - error : ControlVM message was processed but an error occurred .
2016-09-20 00:09:21 +03:00
*/
2017-08-22 20:26:57 +03:00
static int handle_command ( struct controlvm_message inmsg , u64 channel_addr )
2016-09-20 00:09:21 +03:00
{
struct controlvm_message_packet * cmd = & inmsg . cmd ;
u64 parm_addr ;
u32 parm_bytes ;
struct parser_context * parser_ctx = NULL ;
struct controlvm_message ackmsg ;
2017-03-28 16:34:19 +03:00
int err = 0 ;
2016-09-20 00:09:21 +03:00
/* create parsing context if necessary */
parm_addr = channel_addr + inmsg . hdr . payload_vm_offset ;
parm_bytes = inmsg . hdr . payload_bytes ;
/*
* Parameter and channel addresses within test messages actually lie
* within our OS - controlled memory . We need to know that , because it
* makes a difference in how we compute the virtual address .
*/
2017-08-30 20:36:22 +03:00
if ( parm_bytes ) {
2017-09-27 20:14:37 +03:00
bool retry ;
2016-09-20 00:09:21 +03:00
2017-08-30 20:36:28 +03:00
parser_ctx = parser_init_stream ( parm_addr , parm_bytes , & retry ) ;
2016-09-20 00:09:21 +03:00
if ( ! parser_ctx & & retry )
2017-03-28 16:34:19 +03:00
return - EAGAIN ;
2016-09-20 00:09:21 +03:00
}
2017-07-17 23:17:09 +03:00
controlvm_init_response ( & ackmsg , & inmsg . hdr , CONTROLVM_RESP_SUCCESS ) ;
err = visorchannel_signalinsert ( chipset_dev - > controlvm_channel ,
CONTROLVM_QUEUE_ACK , & ackmsg ) ;
if ( err )
return err ;
2016-09-20 00:09:21 +03:00
switch ( inmsg . hdr . id ) {
case CONTROLVM_CHIPSET_INIT :
2017-03-28 16:34:19 +03:00
err = chipset_init ( & inmsg ) ;
2016-09-20 00:09:21 +03:00
break ;
case CONTROLVM_BUS_CREATE :
2017-05-19 23:17:36 +03:00
err = visorbus_create ( & inmsg ) ;
2016-09-20 00:09:21 +03:00
break ;
case CONTROLVM_BUS_DESTROY :
2017-05-19 23:17:36 +03:00
err = visorbus_destroy ( & inmsg ) ;
2016-09-20 00:09:21 +03:00
break ;
case CONTROLVM_BUS_CONFIGURE :
2017-05-19 23:17:36 +03:00
err = visorbus_configure ( & inmsg , parser_ctx ) ;
2016-09-20 00:09:21 +03:00
break ;
case CONTROLVM_DEVICE_CREATE :
2017-05-19 23:17:43 +03:00
err = visorbus_device_create ( & inmsg ) ;
2016-09-20 00:09:21 +03:00
break ;
case CONTROLVM_DEVICE_CHANGESTATE :
if ( cmd - > device_change_state . flags . phys_device ) {
2017-03-28 16:34:19 +03:00
err = parahotplug_process_message ( & inmsg ) ;
2016-09-20 00:09:21 +03:00
} else {
/*
2017-08-30 20:36:29 +03:00
* save the hdr and cmd structures for later use when
* sending back the response to Command
2016-09-20 00:09:21 +03:00
*/
2017-05-19 23:17:43 +03:00
err = visorbus_device_changestate ( & inmsg ) ;
2016-09-20 00:09:21 +03:00
break ;
}
break ;
case CONTROLVM_DEVICE_DESTROY :
2017-05-19 23:17:43 +03:00
err = visorbus_device_destroy ( & inmsg ) ;
2016-09-20 00:09:21 +03:00
break ;
case CONTROLVM_DEVICE_CONFIGURE :
2017-03-28 16:34:19 +03:00
/* no op just send a respond that we passed */
2016-09-20 00:09:21 +03:00
if ( inmsg . hdr . flags . response_expected )
2017-04-18 23:55:01 +03:00
controlvm_respond ( & inmsg . hdr , CONTROLVM_RESP_SUCCESS ,
NULL ) ;
2016-09-20 00:09:21 +03:00
break ;
case CONTROLVM_CHIPSET_READY :
2017-03-28 16:34:19 +03:00
err = chipset_ready_uevent ( & inmsg . hdr ) ;
2016-09-20 00:09:21 +03:00
break ;
case CONTROLVM_CHIPSET_SELFTEST :
2017-03-28 16:34:19 +03:00
err = chipset_selftest_uevent ( & inmsg . hdr ) ;
2016-09-20 00:09:21 +03:00
break ;
case CONTROLVM_CHIPSET_STOP :
2017-03-28 16:34:19 +03:00
err = chipset_notready_uevent ( & inmsg . hdr ) ;
2016-09-20 00:09:21 +03:00
break ;
default :
2017-03-28 16:34:19 +03:00
err = - ENOMSG ;
2016-09-20 00:09:21 +03:00
if ( inmsg . hdr . flags . response_expected )
2017-03-28 16:34:19 +03:00
controlvm_respond ( & inmsg . hdr ,
2017-04-18 23:55:01 +03:00
- CONTROLVM_RESP_ID_UNKNOWN , NULL ) ;
2016-09-20 00:09:21 +03:00
break ;
}
if ( parser_ctx ) {
parser_done ( parser_ctx ) ;
parser_ctx = NULL ;
}
2017-03-28 16:34:19 +03:00
return err ;
2016-09-20 00:09:21 +03:00
}
2017-02-21 20:53:25 +03:00
/*
2016-09-20 00:09:23 +03:00
* read_controlvm_event ( ) - retreives the next message from the
* CONTROLVM_QUEUE_EVENT queue in the controlvm
* channel
* @ msg : pointer to the retrieved message
*
2017-03-28 16:34:19 +03:00
* Return : 0 if valid message was retrieved or - error
2016-09-20 00:09:23 +03:00
*/
2017-08-22 20:26:57 +03:00
static int read_controlvm_event ( struct controlvm_message * msg )
2016-09-20 00:09:23 +03:00
{
2017-07-17 23:16:42 +03:00
int err = visorchannel_signalremove ( chipset_dev - > controlvm_channel ,
2017-09-27 20:14:39 +03:00
CONTROLVM_QUEUE_EVENT , msg ) ;
2017-09-27 20:14:26 +03:00
2017-03-28 16:34:19 +03:00
if ( err )
return err ;
/* got a message */
if ( msg - > hdr . flags . test_message = = 1 )
return - EINVAL ;
return 0 ;
2016-09-20 00:09:23 +03:00
}
2017-02-21 20:53:25 +03:00
/*
2016-09-20 00:09:24 +03:00
* parahotplug_process_list ( ) - remove any request from the list that ' s been on
* there too long and respond with an error
*/
2017-08-22 20:26:57 +03:00
static void parahotplug_process_list ( void )
2016-09-20 00:09:24 +03:00
{
struct list_head * pos ;
struct list_head * tmp ;
spin_lock ( & parahotplug_request_list_lock ) ;
list_for_each_safe ( pos , tmp , & parahotplug_request_list ) {
struct parahotplug_request * req =
list_entry ( pos , struct parahotplug_request , list ) ;
if ( ! time_after_eq ( jiffies , req - > expiration ) )
continue ;
list_del ( pos ) ;
if ( req - > msg . hdr . flags . response_expected )
2017-04-18 23:55:01 +03:00
controlvm_respond (
2016-09-20 00:09:24 +03:00
& req - > msg . hdr ,
2016-12-22 19:08:58 +03:00
CONTROLVM_RESP_DEVICE_UDEV_TIMEOUT ,
2017-04-18 23:55:01 +03:00
& req - > msg . cmd . device_change_state . state ) ;
2016-09-20 00:09:24 +03:00
parahotplug_request_destroy ( req ) ;
}
spin_unlock ( & parahotplug_request_list_lock ) ;
}
2017-08-22 20:26:57 +03:00
static void controlvm_periodic_work ( struct work_struct * work )
2016-09-20 00:09:20 +03:00
{
struct controlvm_message inmsg ;
2017-04-18 23:55:06 +03:00
int count = 0 ;
2017-03-28 16:34:20 +03:00
int err ;
/* Drain the RESPONSE queue make it empty */
do {
err = visorchannel_signalremove ( chipset_dev - > controlvm_channel ,
CONTROLVM_QUEUE_RESPONSE ,
& inmsg ) ;
2017-04-18 23:55:06 +03:00
} while ( ( ! err ) & & ( + + count < CONTROLVM_MESSAGE_MAX ) ) ;
2017-03-28 16:34:20 +03:00
if ( err ! = - EAGAIN )
goto schedule_out ;
if ( chipset_dev - > controlvm_pending_msg_valid ) {
/*
2017-08-30 20:36:29 +03:00
* we throttled processing of a prior msg , so try to process
* it again rather than reading a new one
2017-03-28 16:34:20 +03:00
*/
inmsg = chipset_dev - > controlvm_pending_msg ;
chipset_dev - > controlvm_pending_msg_valid = false ;
err = 0 ;
} else {
err = read_controlvm_event ( & inmsg ) ;
2016-09-20 00:09:20 +03:00
}
2017-03-28 16:34:20 +03:00
while ( ! err ) {
2017-02-21 20:53:29 +03:00
chipset_dev - > most_recent_message_jiffies = jiffies ;
2017-03-28 16:34:20 +03:00
err = handle_command ( inmsg ,
visorchannel_get_physaddr
( chipset_dev - > controlvm_channel ) ) ;
if ( err = = - EAGAIN ) {
2017-02-21 20:53:29 +03:00
chipset_dev - > controlvm_pending_msg = inmsg ;
chipset_dev - > controlvm_pending_msg_valid = true ;
2017-03-28 16:34:20 +03:00
break ;
2016-09-20 00:09:20 +03:00
}
2017-03-28 16:34:20 +03:00
err = read_controlvm_event ( & inmsg ) ;
2016-09-20 00:09:20 +03:00
}
/* parahotplug_worker */
parahotplug_process_list ( ) ;
2017-05-19 23:17:58 +03:00
/*
* The controlvm messages are sent in a bulk . If we start receiving messages , we
* want the polling to be fast . If we do not receive any message for
* MIN_IDLE_SECONDS , we can slow down the polling .
*/
2017-03-28 16:34:20 +03:00
schedule_out :
2017-02-21 20:53:29 +03:00
if ( time_after ( jiffies , chipset_dev - > most_recent_message_jiffies +
( HZ * MIN_IDLE_SECONDS ) ) ) {
2016-09-20 00:09:20 +03:00
/*
2017-08-30 20:36:29 +03:00
* it ' s been longer than MIN_IDLE_SECONDS since we processed
* our last controlvm message ; slow down the polling
2016-09-20 00:09:20 +03:00
*/
2017-09-27 20:14:38 +03:00
if ( chipset_dev - > poll_jiffies ! = POLLJIFFIES_CONTROLVM_SLOW )
chipset_dev - > poll_jiffies = POLLJIFFIES_CONTROLVM_SLOW ;
2016-09-20 00:09:20 +03:00
} else {
2017-09-27 20:14:38 +03:00
if ( chipset_dev - > poll_jiffies ! = POLLJIFFIES_CONTROLVM_FAST )
chipset_dev - > poll_jiffies = POLLJIFFIES_CONTROLVM_FAST ;
2016-09-20 00:09:20 +03:00
}
2017-02-21 20:53:29 +03:00
schedule_delayed_work ( & chipset_dev - > periodic_controlvm_work ,
chipset_dev - > poll_jiffies ) ;
2016-09-20 00:09:20 +03:00
}
2017-08-22 20:26:57 +03:00
static int visorchipset_init ( struct acpi_device * acpi_device )
2014-03-04 17:58:07 +04:00
{
2016-04-05 06:31:37 +03:00
int err = - ENODEV ;
2017-02-21 20:53:29 +03:00
struct visorchannel * controlvm_channel ;
2015-05-13 20:21:57 +03:00
2017-02-21 20:53:29 +03:00
chipset_dev = kzalloc ( sizeof ( * chipset_dev ) , GFP_KERNEL ) ;
if ( ! chipset_dev )
2016-04-05 06:31:37 +03:00
goto error ;
2017-08-30 20:36:19 +03:00
err = controlvm_channel_create ( chipset_dev ) ;
if ( err )
goto error_free_chipset_dev ;
2017-02-21 20:53:29 +03:00
acpi_device - > driver_data = chipset_dev ;
chipset_dev - > acpi_device = acpi_device ;
2017-09-27 20:14:38 +03:00
chipset_dev - > poll_jiffies = POLLJIFFIES_CONTROLVM_FAST ;
2017-02-21 20:53:31 +03:00
err = sysfs_create_groups ( & chipset_dev - > acpi_device - > dev . kobj ,
visorchipset_dev_groups ) ;
if ( err < 0 )
goto error_destroy_channel ;
2017-08-30 20:36:19 +03:00
controlvm_channel = chipset_dev - > controlvm_channel ;
2017-07-17 23:17:02 +03:00
if ( ! visor_check_channel ( visorchannel_get_header ( controlvm_channel ) ,
2017-08-30 20:36:35 +03:00
& chipset_dev - > acpi_device - > dev ,
2017-08-22 20:26:54 +03:00
& visor_controlvm_channel_guid ,
2017-07-17 23:17:02 +03:00
" controlvm " ,
sizeof ( struct visor_controlvm_channel ) ,
VISOR_CONTROLVM_CHANNEL_VERSIONID ,
VISOR_CHANNEL_SIGNATURE ) )
2017-02-21 20:53:31 +03:00
goto error_delete_groups ;
2015-05-06 01:36:39 +03:00
/* if booting in a crash kernel */
if ( is_kdump_kernel ( ) )
2017-02-21 20:53:29 +03:00
INIT_DELAYED_WORK ( & chipset_dev - > periodic_controlvm_work ,
2015-05-06 01:36:39 +03:00
setup_crash_devices_work_queue ) ;
else
2017-02-21 20:53:29 +03:00
INIT_DELAYED_WORK ( & chipset_dev - > periodic_controlvm_work ,
2015-05-06 01:36:39 +03:00
controlvm_periodic_work ) ;
2017-02-21 20:53:29 +03:00
chipset_dev - > most_recent_message_jiffies = jiffies ;
2017-09-27 20:14:38 +03:00
chipset_dev - > poll_jiffies = POLLJIFFIES_CONTROLVM_FAST ;
2017-02-21 20:53:29 +03:00
schedule_delayed_work ( & chipset_dev - > periodic_controlvm_work ,
chipset_dev - > poll_jiffies ) ;
2016-04-05 06:31:37 +03:00
err = visorbus_init ( ) ;
if ( err < 0 )
2017-02-21 20:53:31 +03:00
goto error_cancel_work ;
2016-04-05 06:31:37 +03:00
return 0 ;
error_cancel_work :
2017-02-21 20:53:29 +03:00
cancel_delayed_work_sync ( & chipset_dev - > periodic_controlvm_work ) ;
2016-04-05 06:31:37 +03:00
2017-02-21 20:53:31 +03:00
error_delete_groups :
sysfs_remove_groups ( & chipset_dev - > acpi_device - > dev . kobj ,
visorchipset_dev_groups ) ;
2016-04-05 06:31:37 +03:00
error_destroy_channel :
2017-02-21 20:53:29 +03:00
visorchannel_destroy ( chipset_dev - > controlvm_channel ) ;
error_free_chipset_dev :
kfree ( chipset_dev ) ;
2016-04-05 06:31:37 +03:00
error :
2017-04-18 23:55:23 +03:00
dev_err ( & acpi_device - > dev , " failed with error %d \n " , err ) ;
2016-04-05 06:31:37 +03:00
return err ;
2015-05-06 01:36:13 +03:00
}
2017-08-22 20:26:57 +03:00
static int visorchipset_exit ( struct acpi_device * acpi_device )
2014-03-04 17:58:07 +04:00
{
2015-05-06 01:36:15 +03:00
visorbus_exit ( ) ;
2017-02-21 20:53:29 +03:00
cancel_delayed_work_sync ( & chipset_dev - > periodic_controlvm_work ) ;
2017-02-21 20:53:31 +03:00
sysfs_remove_groups ( & chipset_dev - > acpi_device - > dev . kobj ,
visorchipset_dev_groups ) ;
2017-02-21 20:53:29 +03:00
visorchannel_destroy ( chipset_dev - > controlvm_channel ) ;
kfree ( chipset_dev ) ;
2015-05-06 01:37:02 +03:00
return 0 ;
}
static const struct acpi_device_id unisys_device_ids [ ] = {
{ " PNP0A07 " , 0 } ,
{ " " , 0 } ,
} ;
static struct acpi_driver unisys_acpi_driver = {
. name = " unisys_acpi " ,
. class = " unisys_acpi_class " ,
. owner = THIS_MODULE ,
. ids = unisys_device_ids ,
. ops = {
. add = visorchipset_init ,
. remove = visorchipset_exit ,
2017-04-18 23:55:04 +03:00
} ,
2015-05-06 01:37:02 +03:00
} ;
2015-07-09 20:27:53 +03:00
MODULE_DEVICE_TABLE ( acpi , unisys_device_ids ) ;
2017-04-18 23:55:03 +03:00
static __init int visorutil_spar_detect ( void )
2015-05-06 01:37:04 +03:00
{
unsigned int eax , ebx , ecx , edx ;
2016-03-29 18:41:55 +03:00
if ( boot_cpu_has ( X86_FEATURE_HYPERVISOR ) ) {
2015-05-06 01:37:04 +03:00
/* check the ID */
2017-05-19 23:17:47 +03:00
cpuid ( UNISYS_VISOR_LEAF_ID , & eax , & ebx , & ecx , & edx ) ;
return ( ebx = = UNISYS_VISOR_ID_EBX ) & &
( ecx = = UNISYS_VISOR_ID_ECX ) & &
( edx = = UNISYS_VISOR_ID_EDX ) ;
2015-05-06 01:37:04 +03:00
}
2017-08-30 20:36:25 +03:00
return 0 ;
2015-05-06 01:37:04 +03:00
}
2015-05-06 01:37:02 +03:00
2017-09-15 22:23:13 +03:00
static int __init init_unisys ( void )
2015-05-06 01:37:02 +03:00
{
int result ;
2015-06-13 18:40:49 +03:00
2015-05-06 01:37:04 +03:00
if ( ! visorutil_spar_detect ( ) )
2015-05-06 01:37:02 +03:00
return - ENODEV ;
result = acpi_bus_register_driver ( & unisys_acpi_driver ) ;
if ( result )
return - ENODEV ;
pr_info ( " Unisys Visorchipset Driver Loaded. \n " ) ;
return 0 ;
} ;
2017-09-15 22:23:13 +03:00
static void __exit exit_unisys ( void )
2015-05-06 01:37:02 +03:00
{
acpi_bus_unregister_driver ( & unisys_acpi_driver ) ;
2014-03-04 17:58:07 +04:00
}
2015-05-06 01:37:02 +03:00
module_init ( init_unisys ) ;
module_exit ( exit_unisys ) ;
2014-03-04 17:58:07 +04:00
MODULE_AUTHOR ( " Unisys " ) ;
MODULE_LICENSE ( " GPL " ) ;
2016-09-26 18:03:46 +03:00
MODULE_DESCRIPTION ( " s-Par visorbus driver for virtual device buses " ) ;