#define CURRENT_FILE_PC VISOR_BUS_PC_visorchipset_c
-#define POLLJIFFIES_CONTROLVMCHANNEL_FAST 1
+#define POLLJIFFIES_CONTROLVMCHANNEL_FAST 1
#define POLLJIFFIES_CONTROLVMCHANNEL_SLOW 100
#define MAX_CONTROLVM_PAYLOAD_BYTES (1024 * 128)
char *buf)
{
u8 tool_action = 0;
+ int err;
+
+ err = visorchannel_read(chipset_dev->controlvm_channel,
+ offsetof(struct spar_controlvm_channel_protocol,
+ tool_action),
+ &tool_action, sizeof(u8));
+ if (err)
+ return err;
- visorchannel_read(chipset_dev->controlvm_channel,
- offsetof(struct spar_controlvm_channel_protocol,
- tool_action), &tool_action, sizeof(u8));
return sprintf(buf, "%u\n", tool_action);
}
const char *buf, size_t count)
{
u8 tool_action;
- int ret;
+ int err;
if (kstrtou8(buf, 10, &tool_action))
return -EINVAL;
- ret = visorchannel_write
+ err = visorchannel_write
(chipset_dev->controlvm_channel,
offsetof(struct spar_controlvm_channel_protocol,
tool_action),
&tool_action, sizeof(u8));
- if (ret)
- return ret;
+ if (err)
+ return err;
return count;
}
static DEVICE_ATTR_RW(toolaction);
char *buf)
{
struct efi_spar_indication efi_spar_indication;
+ int err;
+
+ err = visorchannel_read(chipset_dev->controlvm_channel,
+ offsetof(struct spar_controlvm_channel_protocol,
+ efi_spar_ind),
+ &efi_spar_indication,
+ sizeof(struct efi_spar_indication));
- visorchannel_read(chipset_dev->controlvm_channel,
- offsetof(struct spar_controlvm_channel_protocol,
- efi_spar_ind), &efi_spar_indication,
- sizeof(struct efi_spar_indication));
+ if (err)
+ return err;
return sprintf(buf, "%u\n", efi_spar_indication.boot_to_tool);
}
struct device_attribute *attr,
const char *buf, size_t count)
{
- int val, ret;
+ int val, err;
struct efi_spar_indication efi_spar_indication;
if (kstrtoint(buf, 10, &val))
return -EINVAL;
efi_spar_indication.boot_to_tool = val;
- ret = visorchannel_write
+ err = visorchannel_write
(chipset_dev->controlvm_channel,
offsetof(struct spar_controlvm_channel_protocol,
efi_spar_ind), &(efi_spar_indication),
sizeof(struct efi_spar_indication));
- if (ret)
- return ret;
+ if (err)
+ return err;
return count;
}
static DEVICE_ATTR_RW(boottotool);
char *buf)
{
u32 error = 0;
+ int err;
- visorchannel_read(chipset_dev->controlvm_channel,
- offsetof(struct spar_controlvm_channel_protocol,
- installation_error),
- &error, sizeof(u32));
+ err = visorchannel_read(chipset_dev->controlvm_channel,
+ offsetof(struct spar_controlvm_channel_protocol,
+ installation_error),
+ &error, sizeof(u32));
+ if (err)
+ return err;
return sprintf(buf, "%i\n", error);
}
const char *buf, size_t count)
{
u32 error;
- int ret;
+ int err;
if (kstrtou32(buf, 10, &error))
return -EINVAL;
- ret = visorchannel_write
+ err = visorchannel_write
(chipset_dev->controlvm_channel,
offsetof(struct spar_controlvm_channel_protocol,
installation_error),
&error, sizeof(u32));
- if (ret)
- return ret;
+ if (err)
+ return err;
return count;
}
static DEVICE_ATTR_RW(error);
char *buf)
{
u32 text_id = 0;
+ int err;
+
+ err = visorchannel_read
+ (chipset_dev->controlvm_channel,
+ offsetof(struct spar_controlvm_channel_protocol,
+ installation_text_id),
+ &text_id, sizeof(u32));
+ if (err)
+ return err;
- visorchannel_read
- (chipset_dev->controlvm_channel,
- offsetof(struct spar_controlvm_channel_protocol,
- installation_text_id),
- &text_id, sizeof(u32));
return sprintf(buf, "%i\n", text_id);
}
struct device_attribute *attr, char *buf)
{
u16 remaining_steps = 0;
+ int err;
+
+ err = visorchannel_read(chipset_dev->controlvm_channel,
+ offsetof(struct spar_controlvm_channel_protocol,
+ installation_remaining_steps),
+ &remaining_steps, sizeof(u16));
+ if (err)
+ return err;
- visorchannel_read(chipset_dev->controlvm_channel,
- offsetof(struct spar_controlvm_channel_protocol,
- installation_remaining_steps),
- &remaining_steps, sizeof(u16));
return sprintf(buf, "%hu\n", remaining_steps);
}
* Cause uevent to run the user level script to do the disable/enable specified
* in the parahotplug_request.
*/
-static void
+static int
parahotplug_request_kickoff(struct parahotplug_request *req)
{
struct controlvm_message_packet *cmd = &req->msg.cmd;
sprintf(env_func, "SPAR_PARAHOTPLUG_FUNCTION=%d",
cmd->device_change_state.dev_no & 0x7);
- kobject_uevent_env(&chipset_dev->acpi_device->dev.kobj, KOBJ_CHANGE,
- envp);
+ return kobject_uevent_env(&chipset_dev->acpi_device->dev.kobj,
+ KOBJ_CHANGE, envp);
}
/*
* off a udev script
* @inmsg: the message indicating whether to enable or disable
*/
-static void
+static int
parahotplug_process_message(struct controlvm_message *inmsg)
{
struct parahotplug_request *req;
+ int err;
req = parahotplug_request_create(inmsg);
if (!req)
- return;
+ return -ENOMEM;
if (inmsg->cmd.device_change_state.state.active) {
/*
* devices are automatically enabled at
* initialization.
*/
- parahotplug_request_kickoff(req);
+ err = parahotplug_request_kickoff(req);
+ if (err)
+ goto err_respond;
controlvm_respond_physdev_changestate
(&inmsg->hdr,
CONTROLVM_RESP_SUCCESS,
inmsg->cmd.device_change_state.state);
parahotplug_request_destroy(req);
- } else {
- /*
- * 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.
- */
- spin_lock(¶hotplug_request_list_lock);
- list_add_tail(&req->list, ¶hotplug_request_list);
- spin_unlock(¶hotplug_request_list_lock);
-
- parahotplug_request_kickoff(req);
+ return 0;
}
+
+ /*
+ * 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.
+ */
+ spin_lock(¶hotplug_request_list_lock);
+ list_add_tail(&req->list, ¶hotplug_request_list);
+ spin_unlock(¶hotplug_request_list_lock);
+
+ err = parahotplug_request_kickoff(req);
+ if (err)
+ goto err_respond;
+ return 0;
+
+err_respond:
+ controlvm_respond_physdev_changestate
+ (&inmsg->hdr, err,
+ inmsg->cmd.device_change_state.state);
+ return err;
}
/*
static int
chipset_ready_uevent(struct controlvm_message_header *msg_hdr)
{
- kobject_uevent(&chipset_dev->acpi_device->dev.kobj, KOBJ_ONLINE);
+ int res;
+
+ res = kobject_uevent(&chipset_dev->acpi_device->dev.kobj,
+ KOBJ_ONLINE);
if (msg_hdr->flags.response_expected)
- return controlvm_respond(msg_hdr, CONTROLVM_RESP_SUCCESS);
+ controlvm_respond(msg_hdr, res);
- return 0;
+ return res;
}
/*
{
char env_selftest[20];
char *envp[] = { env_selftest, NULL };
+ int res;
sprintf(env_selftest, "SPARSP_SELFTEST=%d", 1);
- kobject_uevent_env(&chipset_dev->acpi_device->dev.kobj, KOBJ_CHANGE,
- envp);
+ res = kobject_uevent_env(&chipset_dev->acpi_device->dev.kobj,
+ KOBJ_CHANGE, envp);
if (msg_hdr->flags.response_expected)
- return controlvm_respond(msg_hdr, CONTROLVM_RESP_SUCCESS);
+ controlvm_respond(msg_hdr, res);
- return 0;
+ return res;
}
/*
static int
chipset_notready_uevent(struct controlvm_message_header *msg_hdr)
{
- kobject_uevent(&chipset_dev->acpi_device->dev.kobj, KOBJ_OFFLINE);
+ int res;
+ res = kobject_uevent(&chipset_dev->acpi_device->dev.kobj,
+ KOBJ_OFFLINE);
if (msg_hdr->flags.response_expected)
- return controlvm_respond(msg_hdr, CONTROLVM_RESP_SUCCESS);
+ controlvm_respond(msg_hdr, res);
- return 0;
+ return res;
}
-static inline unsigned int
+static unsigned int
issue_vmcall_io_controlvm_addr(u64 *control_addr, u32 *control_bytes)
{
struct vmcall_io_controlvm_addr_params params;
u64 physaddr;
physaddr = virt_to_phys(¶ms);
- ISSUE_IO_VMCALL(VMCALL_IO_CONTROLVM_ADDR, physaddr, result);
+ ISSUE_IO_VMCALL(VMCALL_CONTROLVM_ADDR, physaddr, result);
if (VMCALL_SUCCESSFUL(result)) {
*control_addr = params.address;
*control_bytes = params.channel_bytes;
dev_info->pending_msg_hdr = NULL;
}
-static inline s64 issue_vmcall_query_guest_virtual_time_offset(void)
-{
- u64 result = VMCALL_SUCCESS;
- u64 physaddr = 0;
-
- ISSUE_IO_VMCALL(VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET, physaddr,
- result);
- return result;
-}
-
-static inline int issue_vmcall_update_physical_time(u64 adjustment)
-{
- int result = VMCALL_SUCCESS;
-
- ISSUE_IO_VMCALL(VMCALL_UPDATE_PHYSICAL_TIME, adjustment, result);
- return result;
-}
-
static struct parser_context *
parser_init_byte_stream(u64 addr, u32 bytes, bool local, bool *retry)
{
* @channel_addr: address of the controlvm channel
*
* Return:
- * false - this function will return false only in the case where the
- * controlvm message was NOT processed, but processing must be
- * retried before 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
- * true - processing of the controlvm message completed,
- * either successfully or with an error
+ * 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.
*/
-static bool
+static int
handle_command(struct controlvm_message inmsg, u64 channel_addr)
{
struct controlvm_message_packet *cmd = &inmsg.cmd;
struct parser_context *parser_ctx = NULL;
bool local_addr;
struct controlvm_message ackmsg;
+ int err = 0;
/* create parsing context if necessary */
local_addr = (inmsg.hdr.flags.test_message == 1);
if (channel_addr == 0)
- return true;
+ return -EINVAL;
+
parm_addr = channel_addr + inmsg.hdr.payload_vm_offset;
parm_bytes = inmsg.hdr.payload_bytes;
parser_init_byte_stream(parm_addr, parm_bytes,
local_addr, &retry);
if (!parser_ctx && retry)
- return false;
+ return -EAGAIN;
}
if (!local_addr) {
controlvm_init_response(&ackmsg, &inmsg.hdr,
CONTROLVM_RESP_SUCCESS);
- if (chipset_dev->controlvm_channel)
- visorchannel_signalinsert(
- chipset_dev->controlvm_channel,
- CONTROLVM_QUEUE_ACK, &ackmsg);
+ err = visorchannel_signalinsert(chipset_dev->controlvm_channel,
+ CONTROLVM_QUEUE_ACK,
+ &ackmsg);
+ if (err)
+ return err;
}
switch (inmsg.hdr.id) {
case CONTROLVM_CHIPSET_INIT:
- chipset_init(&inmsg);
+ err = chipset_init(&inmsg);
break;
case CONTROLVM_BUS_CREATE:
- bus_create(&inmsg);
+ err = bus_create(&inmsg);
break;
case CONTROLVM_BUS_DESTROY:
- bus_destroy(&inmsg);
+ err = bus_destroy(&inmsg);
break;
case CONTROLVM_BUS_CONFIGURE:
- bus_configure(&inmsg, parser_ctx);
+ err = bus_configure(&inmsg, parser_ctx);
break;
case CONTROLVM_DEVICE_CREATE:
- my_device_create(&inmsg);
+ err = my_device_create(&inmsg);
break;
case CONTROLVM_DEVICE_CHANGESTATE:
if (cmd->device_change_state.flags.phys_device) {
- parahotplug_process_message(&inmsg);
+ err = parahotplug_process_message(&inmsg);
} else {
/*
* save the hdr and cmd structures for later use
* when sending back the response to Command
*/
- my_device_changestate(&inmsg);
+ err = my_device_changestate(&inmsg);
break;
}
break;
case CONTROLVM_DEVICE_DESTROY:
- my_device_destroy(&inmsg);
+ err = my_device_destroy(&inmsg);
break;
case CONTROLVM_DEVICE_CONFIGURE:
- /* no op for now, just send a respond that we passed */
+ /* no op just send a respond that we passed */
if (inmsg.hdr.flags.response_expected)
controlvm_respond(&inmsg.hdr, CONTROLVM_RESP_SUCCESS);
break;
case CONTROLVM_CHIPSET_READY:
- chipset_ready_uevent(&inmsg.hdr);
+ err = chipset_ready_uevent(&inmsg.hdr);
break;
case CONTROLVM_CHIPSET_SELFTEST:
- chipset_selftest_uevent(&inmsg.hdr);
+ err = chipset_selftest_uevent(&inmsg.hdr);
break;
case CONTROLVM_CHIPSET_STOP:
- chipset_notready_uevent(&inmsg.hdr);
+ err = chipset_notready_uevent(&inmsg.hdr);
break;
default:
+ err = -ENOMSG;
if (inmsg.hdr.flags.response_expected)
- controlvm_respond
- (&inmsg.hdr, -CONTROLVM_RESP_ID_UNKNOWN);
+ controlvm_respond(&inmsg.hdr,
+ -CONTROLVM_RESP_ID_UNKNOWN);
break;
}
parser_done(parser_ctx);
parser_ctx = NULL;
}
- return true;
+ return err;
}
/*
* channel
* @msg: pointer to the retrieved message
*
- * Return: true if a valid message was retrieved or false otherwise
+ * Return: 0 if valid message was retrieved or -error
*/
-static bool
+static int
read_controlvm_event(struct controlvm_message *msg)
{
- if (!visorchannel_signalremove(chipset_dev->controlvm_channel,
- CONTROLVM_QUEUE_EVENT, msg)) {
- /* got a message */
- if (msg->hdr.flags.test_message == 1)
- return false;
- return true;
- }
- return false;
+ int err;
+
+ err = visorchannel_signalremove(chipset_dev->controlvm_channel,
+ CONTROLVM_QUEUE_EVENT, msg);
+ if (err)
+ return err;
+
+ /* got a message */
+ if (msg->hdr.flags.test_message == 1)
+ return -EINVAL;
+
+ return 0;
}
/*
controlvm_periodic_work(struct work_struct *work)
{
struct controlvm_message inmsg;
- bool got_command = false;
- bool handle_command_failed = false;
-
- while (!visorchannel_signalremove(chipset_dev->controlvm_channel,
- CONTROLVM_QUEUE_RESPONSE,
- &inmsg))
- ;
- if (!got_command) {
- if (chipset_dev->controlvm_pending_msg_valid) {
- /*
- * we throttled processing of a prior
- * msg, so try to process it again
- * rather than reading a new one
- */
- inmsg = chipset_dev->controlvm_pending_msg;
- chipset_dev->controlvm_pending_msg_valid = false;
- got_command = true;
- } else {
- got_command = read_controlvm_event(&inmsg);
- }
+ int err;
+
+ /* Drain the RESPONSE queue make it empty */
+ do {
+ err = visorchannel_signalremove(chipset_dev->controlvm_channel,
+ CONTROLVM_QUEUE_RESPONSE,
+ &inmsg);
+ } while (!err);
+
+ if (err != -EAGAIN)
+ goto schedule_out;
+
+ if (chipset_dev->controlvm_pending_msg_valid) {
+ /*
+ * we throttled processing of a prior
+ * msg, so try to process it again
+ * rather than reading a new one
+ */
+ inmsg = chipset_dev->controlvm_pending_msg;
+ chipset_dev->controlvm_pending_msg_valid = false;
+ err = 0;
+ } else {
+ err = read_controlvm_event(&inmsg);
}
- handle_command_failed = false;
- while (got_command && (!handle_command_failed)) {
+ while (!err) {
chipset_dev->most_recent_message_jiffies = jiffies;
- if (handle_command(inmsg,
- visorchannel_get_physaddr
- (chipset_dev->controlvm_channel)))
- got_command = read_controlvm_event(&inmsg);
- else {
- /*
- * this is a scenario where throttling
- * is required, but probably NOT an
- * error...; we stash the current
- * controlvm msg so we will attempt to
- * reprocess it on our next loop
- */
- handle_command_failed = true;
+ err = handle_command(inmsg,
+ visorchannel_get_physaddr
+ (chipset_dev->controlvm_channel));
+ if (err == -EAGAIN) {
chipset_dev->controlvm_pending_msg = inmsg;
chipset_dev->controlvm_pending_msg_valid = true;
+ break;
}
+
+ err = read_controlvm_event(&inmsg);
}
/* parahotplug_worker */
parahotplug_process_list();
+schedule_out:
if (time_after(jiffies, chipset_dev->most_recent_message_jiffies +
(HZ * MIN_IDLE_SECONDS))) {
/*