summaryrefslogtreecommitdiff
path: root/drivers/staging/unisys
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/unisys')
-rw-r--r--drivers/staging/unisys/include/channel.h221
-rw-r--r--drivers/staging/unisys/include/channel_guid.h55
-rw-r--r--drivers/staging/unisys/include/diagchannel.h38
-rw-r--r--drivers/staging/unisys/include/guestlinuxdebug.h180
-rw-r--r--drivers/staging/unisys/include/iochannel.h1
-rw-r--r--drivers/staging/unisys/include/periodic_work.h40
-rw-r--r--drivers/staging/unisys/include/vbushelper.h46
-rw-r--r--drivers/staging/unisys/include/version.h45
-rw-r--r--drivers/staging/unisys/include/visorbus.h111
-rw-r--r--drivers/staging/unisys/visorbus/Makefile1
-rw-r--r--drivers/staging/unisys/visorbus/controlvmchannel.h76
-rw-r--r--drivers/staging/unisys/visorbus/controlvmcompletionstatus.h101
-rw-r--r--drivers/staging/unisys/visorbus/iovmcall_gnuc.h48
-rw-r--r--drivers/staging/unisys/visorbus/periodic_work.c204
-rw-r--r--drivers/staging/unisys/visorbus/vbuschannel.h211
-rw-r--r--drivers/staging/unisys/visorbus/vbusdeviceinfo.h213
-rw-r--r--drivers/staging/unisys/visorbus/visorbus_main.c841
-rw-r--r--drivers/staging/unisys/visorbus/visorbus_private.h99
-rw-r--r--drivers/staging/unisys/visorbus/visorchannel.c573
-rw-r--r--drivers/staging/unisys/visorbus/visorchipset.c1593
-rw-r--r--drivers/staging/unisys/visorbus/vmcallinterface.h190
-rw-r--r--drivers/staging/unisys/visorhba/visorhba_main.c70
-rw-r--r--drivers/staging/unisys/visorinput/ultrainputreport.h2
-rw-r--r--drivers/staging/unisys/visorinput/visorinput.c149
-rw-r--r--drivers/staging/unisys/visornic/visornic_main.c100
25 files changed, 2173 insertions, 3035 deletions
diff --git a/drivers/staging/unisys/include/channel.h b/drivers/staging/unisys/include/channel.h
index db4e6b28755b..259ef6487959 100644
--- a/drivers/staging/unisys/include/channel.h
+++ b/drivers/staging/unisys/include/channel.h
@@ -75,28 +75,6 @@ enum channel_clientstate {
/* access channel anytime */
};
-static inline const u8 *
-ULTRA_CHANNELCLI_STRING(u32 state)
-{
- switch (state) {
- case CHANNELCLI_DETACHED:
- return (const u8 *)("DETACHED");
- case CHANNELCLI_DISABLED:
- return (const u8 *)("DISABLED");
- case CHANNELCLI_ATTACHING:
- return (const u8 *)("ATTACHING");
- case CHANNELCLI_ATTACHED:
- return (const u8 *)("ATTACHED");
- case CHANNELCLI_BUSY:
- return (const u8 *)("BUSY");
- case CHANNELCLI_OWNED:
- return (const u8 *)("OWNED");
- default:
- break;
- }
- return (const u8 *)("?");
-}
-
#define SPAR_CHANNEL_SERVER_READY(ch) \
(readl(&(ch)->srv_state) == CHANNELSRV_READY)
@@ -132,22 +110,6 @@ ULTRA_CHANNELCLI_STRING(u32 state)
/* throttling invalid boot channel statetransition error due to busy channel */
#define ULTRA_CLIERRORBOOT_THROTTLEMSG_BUSY 0x04
-/* Values for ULTRA_CHANNEL_PROTOCOL.CliErrorOS: */
-/* throttling invalid guest OS channel statetransition error due to
- * client disabled
- */
-#define ULTRA_CLIERROROS_THROTTLEMSG_DISABLED 0x01
-
-/* throttling invalid guest OS channel statetransition error due to
- * client not attached
- */
-#define ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED 0x02
-
-/* throttling invalid guest OS channel statetransition error due to
- * busy channel
- */
-#define ULTRA_CLIERROROS_THROTTLEMSG_BUSY 0x04
-
/* Values for ULTRA_CHANNEL_PROTOCOL.Features: This define exists so
* that windows guest can look at the FeatureFlags in the io channel,
* and configure the windows driver to use interrupts or not based on
@@ -347,148 +309,6 @@ static inline int spar_check_channel_server(uuid_le typeuuid, char *name,
return 1;
}
-/* Given a file pathname <s> (with '/' or '\' separating directory nodes),
- * returns a pointer to the beginning of a node within that pathname such
- * that the number of nodes from that pointer to the end of the string is
- * NOT more than <n>. Note that if the pathname has less than <n> nodes
- * in it, the return pointer will be to the beginning of the string.
- */
-static inline u8 *
-pathname_last_n_nodes(u8 *s, unsigned int n)
-{
- u8 *p = s;
- unsigned int node_count = 0;
-
- while (*p != '\0') {
- if ((*p == '/') || (*p == '\\'))
- node_count++;
- p++;
- }
- if (node_count <= n)
- return s;
- while (n > 0) {
- p--;
- if (p == s)
- break; /* should never happen, unless someone
- * is changing the string while we are
- * looking at it!!
- */
- if ((*p == '/') || (*p == '\\'))
- n--;
- }
- return p + 1;
-}
-
-static inline int
-spar_channel_client_acquire_os(void __iomem *ch, u8 *id)
-{
- struct channel_header __iomem *hdr = ch;
-
- if (readl(&hdr->cli_state_os) == CHANNELCLI_DISABLED) {
- if ((readb(&hdr->cli_error_os)
- & ULTRA_CLIERROROS_THROTTLEMSG_DISABLED) == 0) {
- /* we are NOT throttling this message */
- writeb(readb(&hdr->cli_error_os) |
- ULTRA_CLIERROROS_THROTTLEMSG_DISABLED,
- &hdr->cli_error_os);
- /* throttle until acquire successful */
-
- pr_info("%s Channel StateTransition INVALID! - acquire failed because OS client DISABLED\n",
- id);
- }
- return 0;
- }
- if ((readl(&hdr->cli_state_os) != CHANNELCLI_OWNED) &&
- (readl(&hdr->cli_state_boot) == CHANNELCLI_DISABLED)) {
- /* Our competitor is DISABLED, so we can transition to OWNED */
- pr_info("%s Channel StateTransition (%s) %s(%d)-->%s(%d)\n",
- id, "cli_state_os",
- ULTRA_CHANNELCLI_STRING(readl(&hdr->cli_state_os)),
- readl(&hdr->cli_state_os),
- ULTRA_CHANNELCLI_STRING(CHANNELCLI_OWNED),
- CHANNELCLI_OWNED);
- writel(CHANNELCLI_OWNED, &hdr->cli_state_os);
- mb(); /* required for channel synch */
- }
- if (readl(&hdr->cli_state_os) == CHANNELCLI_OWNED) {
- if (readb(&hdr->cli_error_os)) {
- /* we are in an error msg throttling state;
- * come out of it
- */
- pr_info("%s Channel OS client acquire now successful\n",
- id);
- writeb(0, &hdr->cli_error_os);
- }
- return 1;
- }
-
- /* We have to do it the "hard way". We transition to BUSY,
- * and can use the channel iff our competitor has not also
- * transitioned to BUSY.
- */
- if (readl(&hdr->cli_state_os) != CHANNELCLI_ATTACHED) {
- if ((readb(&hdr->cli_error_os)
- & ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED) == 0) {
- /* we are NOT throttling this message */
- writeb(readb(&hdr->cli_error_os) |
- ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED,
- &hdr->cli_error_os);
- /* throttle until acquire successful */
- pr_info("%s Channel StateTransition INVALID! - acquire failed because OS client NOT ATTACHED (state=%s(%d))\n",
- id, ULTRA_CHANNELCLI_STRING(
- readl(&hdr->cli_state_os)),
- readl(&hdr->cli_state_os));
- }
- return 0;
- }
- writel(CHANNELCLI_BUSY, &hdr->cli_state_os);
- mb(); /* required for channel synch */
- if (readl(&hdr->cli_state_boot) == CHANNELCLI_BUSY) {
- if ((readb(&hdr->cli_error_os)
- & ULTRA_CLIERROROS_THROTTLEMSG_BUSY) == 0) {
- /* we are NOT throttling this message */
- writeb(readb(&hdr->cli_error_os) |
- ULTRA_CLIERROROS_THROTTLEMSG_BUSY,
- &hdr->cli_error_os);
- /* throttle until acquire successful */
- pr_info("%s Channel StateTransition failed - host OS acquire failed because boot BUSY\n",
- id);
- }
- /* reset busy */
- writel(CHANNELCLI_ATTACHED, &hdr->cli_state_os);
- mb(); /* required for channel synch */
- return 0;
- }
- if (readb(&hdr->cli_error_os)) {
- /* we are in an error msg throttling state; come out of it */
- pr_info("%s Channel OS client acquire now successful\n", id);
- writeb(0, &hdr->cli_error_os);
- }
- return 1;
-}
-
-static inline void
-spar_channel_client_release_os(void __iomem *ch, u8 *id)
-{
- struct channel_header __iomem *hdr = ch;
-
- if (readb(&hdr->cli_error_os)) {
- /* we are in an error msg throttling state; come out of it */
- pr_info("%s Channel OS client error state cleared\n", id);
- writeb(0, &hdr->cli_error_os);
- }
- if (readl(&hdr->cli_state_os) == CHANNELCLI_OWNED)
- return;
- if (readl(&hdr->cli_state_os) != CHANNELCLI_BUSY) {
- pr_info("%s Channel StateTransition INVALID! - release failed because OS client NOT BUSY (state=%s(%d))\n",
- id, ULTRA_CHANNELCLI_STRING(
- readl(&hdr->cli_state_os)),
- readl(&hdr->cli_state_os));
- /* return; */
- }
- writel(CHANNELCLI_ATTACHED, &hdr->cli_state_os); /* release busy */
-}
-
/*
* Routine Description:
* Tries to insert the prebuilt signal pointed to by pSignal into the nth
@@ -569,4 +389,45 @@ unsigned int spar_signal_remove_all(struct channel_header *ch, u32 queue,
unsigned char spar_signalqueue_empty(struct channel_header __iomem *ch,
u32 queue);
+/*
+ * CHANNEL Guids
+ */
+
+/* {414815ed-c58c-11da-95a9-00e08161165f} */
+#define SPAR_VHBA_CHANNEL_PROTOCOL_UUID \
+ UUID_LE(0x414815ed, 0xc58c, 0x11da, \
+ 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f)
+static const uuid_le spar_vhba_channel_protocol_uuid =
+ SPAR_VHBA_CHANNEL_PROTOCOL_UUID;
+#define SPAR_VHBA_CHANNEL_PROTOCOL_UUID_STR \
+ "414815ed-c58c-11da-95a9-00e08161165f"
+
+/* {8cd5994d-c58e-11da-95a9-00e08161165f} */
+#define SPAR_VNIC_CHANNEL_PROTOCOL_UUID \
+ UUID_LE(0x8cd5994d, 0xc58e, 0x11da, \
+ 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f)
+static const uuid_le spar_vnic_channel_protocol_uuid =
+ SPAR_VNIC_CHANNEL_PROTOCOL_UUID;
+#define SPAR_VNIC_CHANNEL_PROTOCOL_UUID_STR \
+ "8cd5994d-c58e-11da-95a9-00e08161165f"
+
+/* {72120008-4AAB-11DC-8530-444553544200} */
+#define SPAR_SIOVM_UUID \
+ UUID_LE(0x72120008, 0x4AAB, 0x11DC, \
+ 0x85, 0x30, 0x44, 0x45, 0x53, 0x54, 0x42, 0x00)
+static const uuid_le spar_siovm_uuid = SPAR_SIOVM_UUID;
+
+/* {5b52c5ac-e5f5-4d42-8dff-429eaecd221f} */
+#define SPAR_CONTROLDIRECTOR_CHANNEL_PROTOCOL_UUID \
+ UUID_LE(0x5b52c5ac, 0xe5f5, 0x4d42, \
+ 0x8d, 0xff, 0x42, 0x9e, 0xae, 0xcd, 0x22, 0x1f)
+
+static const uuid_le spar_controldirector_channel_protocol_uuid =
+ SPAR_CONTROLDIRECTOR_CHANNEL_PROTOCOL_UUID;
+
+/* {b4e79625-aede-4eAA-9e11-D3eddcd4504c} */
+#define SPAR_DIAG_POOL_CHANNEL_PROTOCOL_UUID \
+ UUID_LE(0xb4e79625, 0xaede, 0x4eaa, \
+ 0x9e, 0x11, 0xd3, 0xed, 0xdc, 0xd4, 0x50, 0x4c)
+
#endif
diff --git a/drivers/staging/unisys/include/channel_guid.h b/drivers/staging/unisys/include/channel_guid.h
deleted file mode 100644
index 17cb499cb53c..000000000000
--- a/drivers/staging/unisys/include/channel_guid.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/*
- * CHANNEL Guids
- */
-
-/* {414815ed-c58c-11da-95a9-00e08161165f} */
-#define SPAR_VHBA_CHANNEL_PROTOCOL_UUID \
- UUID_LE(0x414815ed, 0xc58c, 0x11da, \
- 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f)
-static const uuid_le spar_vhba_channel_protocol_uuid =
- SPAR_VHBA_CHANNEL_PROTOCOL_UUID;
-#define SPAR_VHBA_CHANNEL_PROTOCOL_UUID_STR \
- "414815ed-c58c-11da-95a9-00e08161165f"
-
-/* {8cd5994d-c58e-11da-95a9-00e08161165f} */
-#define SPAR_VNIC_CHANNEL_PROTOCOL_UUID \
- UUID_LE(0x8cd5994d, 0xc58e, 0x11da, \
- 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f)
-static const uuid_le spar_vnic_channel_protocol_uuid =
- SPAR_VNIC_CHANNEL_PROTOCOL_UUID;
-#define SPAR_VNIC_CHANNEL_PROTOCOL_UUID_STR \
- "8cd5994d-c58e-11da-95a9-00e08161165f"
-
-/* {72120008-4AAB-11DC-8530-444553544200} */
-#define SPAR_SIOVM_UUID \
- UUID_LE(0x72120008, 0x4AAB, 0x11DC, \
- 0x85, 0x30, 0x44, 0x45, 0x53, 0x54, 0x42, 0x00)
-static const uuid_le spar_siovm_uuid = SPAR_SIOVM_UUID;
-
-/* {5b52c5ac-e5f5-4d42-8dff-429eaecd221f} */
-#define SPAR_CONTROLDIRECTOR_CHANNEL_PROTOCOL_UUID \
- UUID_LE(0x5b52c5ac, 0xe5f5, 0x4d42, \
- 0x8d, 0xff, 0x42, 0x9e, 0xae, 0xcd, 0x22, 0x1f)
-
-static const uuid_le spar_controldirector_channel_protocol_uuid =
- SPAR_CONTROLDIRECTOR_CHANNEL_PROTOCOL_UUID;
-
-/* {b4e79625-aede-4eAA-9e11-D3eddcd4504c} */
-#define SPAR_DIAG_POOL_CHANNEL_PROTOCOL_UUID \
- UUID_LE(0xb4e79625, 0xaede, 0x4eaa, \
- 0x9e, 0x11, 0xd3, 0xed, 0xdc, 0xd4, 0x50, 0x4c)
diff --git a/drivers/staging/unisys/include/diagchannel.h b/drivers/staging/unisys/include/diagchannel.h
deleted file mode 100644
index 6e813c77b97e..000000000000
--- a/drivers/staging/unisys/include/diagchannel.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef _DIAG_CHANNEL_H_
-#define _DIAG_CHANNEL_H_
-
-/* Levels of severity for diagnostic events, in order from lowest severity to
- * highest (i.e. fatal errors are the most severe, and should always be logged,
- * but info events rarely need to be logged except during debugging). The
- * values DIAG_SEVERITY_ENUM_BEGIN and DIAG_SEVERITY_ENUM_END are not valid
- * severity values. They exist merely to dilineate the list, so that future
- * additions won't require changes to the driver (i.e. when checking for
- * out-of-range severities in SetSeverity). The values DIAG_SEVERITY_OVERRIDE
- * and DIAG_SEVERITY_SHUTOFF are not valid severity values for logging events
- * but they are valid for controlling the amount of event data. Changes made
- * to the enum, need to be reflected in s-Par.
- */
-enum diag_severity {
- DIAG_SEVERITY_VERBOSE = 0,
- DIAG_SEVERITY_INFO = 1,
- DIAG_SEVERITY_WARNING = 2,
- DIAG_SEVERITY_ERR = 3,
- DIAG_SEVERITY_PRINT = 4,
-};
-
-#endif
diff --git a/drivers/staging/unisys/include/guestlinuxdebug.h b/drivers/staging/unisys/include/guestlinuxdebug.h
deleted file mode 100644
index b81287f5e2c3..000000000000
--- a/drivers/staging/unisys/include/guestlinuxdebug.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/* Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef __GUESTLINUXDEBUG_H__
-#define __GUESTLINUXDEBUG_H__
-
-/*
- * This file contains supporting interface for "vmcallinterface.h", particularly
- * regarding adding additional structure and functionality to linux
- * ISSUE_IO_VMCALL_POSTCODE_SEVERITY
- */
-
-/******* INFO ON ISSUE_POSTCODE_LINUX() BELOW *******/
-enum driver_pc { /* POSTCODE driver identifier tuples */
- /* visorchipset driver files */
- VISOR_CHIPSET_PC = 0xA0,
- VISOR_CHIPSET_PC_controlvm_c = 0xA1,
- VISOR_CHIPSET_PC_controlvm_cm2 = 0xA2,
- VISOR_CHIPSET_PC_controlvm_direct_c = 0xA3,
- VISOR_CHIPSET_PC_file_c = 0xA4,
- VISOR_CHIPSET_PC_parser_c = 0xA5,
- VISOR_CHIPSET_PC_testing_c = 0xA6,
- VISOR_CHIPSET_PC_visorchipset_main_c = 0xA7,
- VISOR_CHIPSET_PC_visorswitchbus_c = 0xA8,
- /* visorbus driver files */
- VISOR_BUS_PC = 0xB0,
- VISOR_BUS_PC_businst_attr_c = 0xB1,
- VISOR_BUS_PC_channel_attr_c = 0xB2,
- VISOR_BUS_PC_devmajorminor_attr_c = 0xB3,
- VISOR_BUS_PC_visorbus_main_c = 0xB4,
- /* visorclientbus driver files */
- VISOR_CLIENT_BUS_PC = 0xC0,
- VISOR_CLIENT_BUS_PC_visorclientbus_main_c = 0xC1,
- /* virt hba driver files */
- VIRT_HBA_PC = 0xC2,
- VIRT_HBA_PC_virthba_c = 0xC3,
- /* virtpci driver files */
- VIRT_PCI_PC = 0xC4,
- VIRT_PCI_PC_virtpci_c = 0xC5,
- /* virtnic driver files */
- VIRT_NIC_PC = 0xC6,
- VIRT_NIC_P_virtnic_c = 0xC7,
- /* uislib driver files */
- UISLIB_PC = 0xD0,
- UISLIB_PC_uislib_c = 0xD1,
- UISLIB_PC_uisqueue_c = 0xD2,
- UISLIB_PC_uisthread_c = 0xD3,
- UISLIB_PC_uisutils_c = 0xD4,
-};
-
-enum event_pc { /* POSTCODE event identifier tuples */
- ATTACH_PORT_ENTRY_PC = 0x001,
- ATTACH_PORT_FAILURE_PC = 0x002,
- ATTACH_PORT_SUCCESS_PC = 0x003,
- BUS_FAILURE_PC = 0x004,
- BUS_CREATE_ENTRY_PC = 0x005,
- BUS_CREATE_FAILURE_PC = 0x006,
- BUS_CREATE_EXIT_PC = 0x007,
- BUS_CONFIGURE_ENTRY_PC = 0x008,
- BUS_CONFIGURE_FAILURE_PC = 0x009,
- BUS_CONFIGURE_EXIT_PC = 0x00A,
- CHIPSET_INIT_ENTRY_PC = 0x00B,
- CHIPSET_INIT_SUCCESS_PC = 0x00C,
- CHIPSET_INIT_FAILURE_PC = 0x00D,
- CHIPSET_INIT_EXIT_PC = 0x00E,
- CREATE_WORKQUEUE_PC = 0x00F,
- CREATE_WORKQUEUE_FAILED_PC = 0x0A0,
- CONTROLVM_INIT_FAILURE_PC = 0x0A1,
- DEVICE_CREATE_ENTRY_PC = 0x0A2,
- DEVICE_CREATE_FAILURE_PC = 0x0A3,
- DEVICE_CREATE_SUCCESS_PC = 0x0A4,
- DEVICE_CREATE_EXIT_PC = 0x0A5,
- DEVICE_ADD_PC = 0x0A6,
- DEVICE_REGISTER_FAILURE_PC = 0x0A7,
- DEVICE_CHANGESTATE_ENTRY_PC = 0x0A8,
- DEVICE_CHANGESTATE_FAILURE_PC = 0x0A9,
- DEVICE_CHANGESTATE_EXIT_PC = 0x0AA,
- DRIVER_ENTRY_PC = 0x0AB,
- DRIVER_EXIT_PC = 0x0AC,
- MALLOC_FAILURE_PC = 0x0AD,
- QUEUE_DELAYED_WORK_PC = 0x0AE,
- UISLIB_THREAD_FAILURE_PC = 0x0B7,
- VBUS_CHANNEL_ENTRY_PC = 0x0B8,
- VBUS_CHANNEL_FAILURE_PC = 0x0B9,
- VBUS_CHANNEL_EXIT_PC = 0x0BA,
- VHBA_CREATE_ENTRY_PC = 0x0BB,
- VHBA_CREATE_FAILURE_PC = 0x0BC,
- VHBA_CREATE_EXIT_PC = 0x0BD,
- VHBA_CREATE_SUCCESS_PC = 0x0BE,
- VHBA_COMMAND_HANDLER_PC = 0x0BF,
- VHBA_PROBE_ENTRY_PC = 0x0C0,
- VHBA_PROBE_FAILURE_PC = 0x0C1,
- VHBA_PROBE_EXIT_PC = 0x0C2,
- VNIC_CREATE_ENTRY_PC = 0x0C3,
- VNIC_CREATE_FAILURE_PC = 0x0C4,
- VNIC_CREATE_SUCCESS_PC = 0x0C5,
- VNIC_PROBE_ENTRY_PC = 0x0C6,
- VNIC_PROBE_FAILURE_PC = 0x0C7,
- VNIC_PROBE_EXIT_PC = 0x0C8,
- VPCI_CREATE_ENTRY_PC = 0x0C9,
- VPCI_CREATE_FAILURE_PC = 0x0CA,
- VPCI_CREATE_EXIT_PC = 0x0CB,
- VPCI_PROBE_ENTRY_PC = 0x0CC,
- VPCI_PROBE_FAILURE_PC = 0x0CD,
- VPCI_PROBE_EXIT_PC = 0x0CE,
- CRASH_DEV_ENTRY_PC = 0x0CF,
- CRASH_DEV_EXIT_PC = 0x0D0,
- CRASH_DEV_HADDR_NULL = 0x0D1,
- CRASH_DEV_CONTROLVM_NULL = 0x0D2,
- CRASH_DEV_RD_BUS_FAIULRE_PC = 0x0D3,
- CRASH_DEV_RD_DEV_FAIULRE_PC = 0x0D4,
- CRASH_DEV_BUS_NULL_FAILURE_PC = 0x0D5,
- CRASH_DEV_DEV_NULL_FAILURE_PC = 0x0D6,
- CRASH_DEV_CTRL_RD_FAILURE_PC = 0x0D7,
- CRASH_DEV_COUNT_FAILURE_PC = 0x0D8,
- SAVE_MSG_BUS_FAILURE_PC = 0x0D9,
- SAVE_MSG_DEV_FAILURE_PC = 0x0DA,
- CALLHOME_INIT_FAILURE_PC = 0x0DB
-};
-
-#ifdef __GNUC__
-
-#define POSTCODE_SEVERITY_ERR DIAG_SEVERITY_ERR
-#define POSTCODE_SEVERITY_WARNING DIAG_SEVERITY_WARNING
-/* TODO-> Info currently doesn't show, so we set info=warning */
-#define POSTCODE_SEVERITY_INFO DIAG_SEVERITY_PRINT
-
-/* example call of POSTCODE_LINUX_2(VISOR_CHIPSET_PC, POSTCODE_SEVERITY_ERR);
- * Please also note that the resulting postcode is in hex, so if you are
- * searching for the __LINE__ number, convert it first to decimal. The line
- * number combined with driver and type of call, will allow you to track down
- * exactly what line an error occurred on, or where the last driver
- * entered/exited from.
- */
-
-/* BASE FUNCTIONS */
-#define POSTCODE_LINUX_A(DRIVER_PC, EVENT_PC, pc32bit, severity) \
-do { \
- unsigned long long post_code_temp; \
- post_code_temp = (((u64)DRIVER_PC) << 56) | (((u64)EVENT_PC) << 44) | \
- ((((u64)__LINE__) & 0xFFF) << 32) | \
- (((u64)pc32bit) & 0xFFFFFFFF); \
- ISSUE_IO_VMCALL_POSTCODE_SEVERITY(post_code_temp, severity); \
-} while (0)
-
-#define POSTCODE_LINUX_B(DRIVER_PC, EVENT_PC, pc16bit1, pc16bit2, severity) \
-do { \
- unsigned long long post_code_temp; \
- post_code_temp = (((u64)DRIVER_PC) << 56) | (((u64)EVENT_PC) << 44) | \
- ((((u64)__LINE__) & 0xFFF) << 32) | \
- ((((u64)pc16bit1) & 0xFFFF) << 16) | \
- (((u64)pc16bit2) & 0xFFFF); \
- ISSUE_IO_VMCALL_POSTCODE_SEVERITY(post_code_temp, severity); \
-} while (0)
-
-/* MOST COMMON */
-#define POSTCODE_LINUX_2(EVENT_PC, severity) \
- POSTCODE_LINUX_A(CURRENT_FILE_PC, EVENT_PC, 0x0000, severity)
-
-#define POSTCODE_LINUX_3(EVENT_PC, pc32bit, severity) \
- POSTCODE_LINUX_A(CURRENT_FILE_PC, EVENT_PC, pc32bit, severity)
-
-#define POSTCODE_LINUX_4(EVENT_PC, pc16bit1, pc16bit2, severity) \
- POSTCODE_LINUX_B(CURRENT_FILE_PC, EVENT_PC, pc16bit1, \
- pc16bit2, severity)
-
-#endif
-#endif
diff --git a/drivers/staging/unisys/include/iochannel.h b/drivers/staging/unisys/include/iochannel.h
index 5ccf81485d72..cba4433bcd51 100644
--- a/drivers/staging/unisys/include/iochannel.h
+++ b/drivers/staging/unisys/include/iochannel.h
@@ -33,7 +33,6 @@
#include <linux/dma-direction.h>
#include "channel.h"
-#include "channel_guid.h"
#define ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
#define ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
diff --git a/drivers/staging/unisys/include/periodic_work.h b/drivers/staging/unisys/include/periodic_work.h
deleted file mode 100644
index 0b3335a4b206..000000000000
--- a/drivers/staging/unisys/include/periodic_work.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* periodic_work.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef __PERIODIC_WORK_H__
-#define __PERIODIC_WORK_H__
-
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-
-/* PERIODIC_WORK an opaque structure to users.
- * Fields are declared only in the implementation .c files.
- */
-struct periodic_work;
-
-struct periodic_work *
-visor_periodic_work_create(ulong jiffy_interval,
- struct workqueue_struct *workqueue,
- void (*workfunc)(void *),
- void *workfuncarg,
- const char *devnam);
-void visor_periodic_work_destroy(struct periodic_work *pw);
-bool visor_periodic_work_nextperiod(struct periodic_work *pw);
-bool visor_periodic_work_start(struct periodic_work *pw);
-bool visor_periodic_work_stop(struct periodic_work *pw);
-
-#endif
diff --git a/drivers/staging/unisys/include/vbushelper.h b/drivers/staging/unisys/include/vbushelper.h
deleted file mode 100644
index f1b6aacb79d7..000000000000
--- a/drivers/staging/unisys/include/vbushelper.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* vbushelper.h
- *
- * Copyright (C) 2011 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef __VBUSHELPER_H__
-#define __VBUSHELPER_H__
-
-/* TARGET_HOSTNAME specified as -DTARGET_HOSTNAME=\"thename\" on the
- * command line
- */
-
-#define TARGET_HOSTNAME "linuxguest"
-
-static inline void bus_device_info_init(
- struct ultra_vbus_deviceinfo *bus_device_info_ptr,
- const char *dev_type, const char *drv_name,
- const char *ver, const char *ver_tag)
-{
- memset(bus_device_info_ptr, 0, sizeof(struct ultra_vbus_deviceinfo));
- snprintf(bus_device_info_ptr->devtype,
- sizeof(bus_device_info_ptr->devtype),
- "%s", (dev_type) ? dev_type : "unknownType");
- snprintf(bus_device_info_ptr->drvname,
- sizeof(bus_device_info_ptr->drvname),
- "%s", (drv_name) ? drv_name : "unknownDriver");
- snprintf(bus_device_info_ptr->infostrs,
- sizeof(bus_device_info_ptr->infostrs), "%s\t%s\t%s",
- (ver) ? ver : "unknownVer",
- (ver_tag) ? ver_tag : "unknownVerTag",
- TARGET_HOSTNAME);
-}
-
-#endif
diff --git a/drivers/staging/unisys/include/version.h b/drivers/staging/unisys/include/version.h
deleted file mode 100644
index 83d1da7a2f81..000000000000
--- a/drivers/staging/unisys/include/version.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/* version.h */
-
-/* Common version/release info needed by all components goes here.
- * (This file must compile cleanly in all environments.)
- * Ultimately, this will be combined with defines generated dynamically as
- * part of the sysgen, and some of the defines below may in fact end up
- * being replaced with dynamically generated ones.
- */
-#ifndef __VERSION_H__
-#define __VERSION_H__
-
-#define SPARVER1 "1"
-#define SPARVER2 "0"
-#define SPARVER3 "0"
-#define SPARVER4 "0"
-
-#define VERSION SPARVER1 "." SPARVER2 "." SPARVER3 "." SPARVER4
-
-/* Here are various version forms needed in Windows environments.
- */
-#define VISOR_PRODUCTVERSION SPARVERCOMMA
-#define VISOR_PRODUCTVERSION_STR SPARVER1 "." SPARVER2 "." SPARVER3 "." \
- SPARVER4
-#define VISOR_OBJECTVERSION_STR SPARVER1 "," SPARVER2 "," SPARVER3 "," \
- SPARVER4
-
-#define COPYRIGHT "Unisys Corporation"
-#define COPYRIGHTDATE "2010 - 2013"
-
-#endif
diff --git a/drivers/staging/unisys/include/visorbus.h b/drivers/staging/unisys/include/visorbus.h
index 9baf1ec70d01..677627c72c4c 100644
--- a/drivers/staging/unisys/include/visorbus.h
+++ b/drivers/staging/unisys/include/visorbus.h
@@ -34,8 +34,9 @@
#include <linux/poll.h>
#include <linux/kernel.h>
#include <linux/uuid.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
-#include "periodic_work.h"
#include "channel.h"
struct visor_driver;
@@ -65,8 +66,6 @@ struct visor_channeltype_descriptor {
* struct visor_driver - Information provided by each visor driver when it
* registers with the visorbus driver.
* @name: Name of the visor driver.
- * @version: The numbered version of the driver (x.x.xxx).
- * @vertag: A human readable version string.
* @owner: The module owner.
* @channel_types: Types of channels handled by this driver, ending with
* a zero GUID. Our specialized BUS.match() method knows
@@ -93,12 +92,9 @@ struct visor_channeltype_descriptor {
* @resume: Behaves similar to pause.
* @driver: Private reference to the device driver. For use by bus
* driver only.
- * @version_attr: Private version field. For use by bus driver only.
*/
struct visor_driver {
const char *name;
- const char *version;
- const char *vertag;
struct module *owner;
struct visor_channeltype_descriptor *channel_types;
int (*probe)(struct visor_device *dev);
@@ -111,7 +107,6 @@ struct visor_driver {
/* These fields are for private use by the bus driver only. */
struct device_driver driver;
- struct driver_attribute version_attr;
};
#define to_visor_driver(x) ((x) ? \
@@ -120,33 +115,33 @@ struct visor_driver {
/**
* struct visor_device - A device type for things "plugged" into the visorbus
* bus
- * visorchannel: Points to the channel that the device is
+ * @visorchannel: Points to the channel that the device is
* associated with.
- * channel_type_guid: Identifies the channel type to the bus driver.
- * device: Device struct meant for use by the bus driver
+ * @channel_type_guid: Identifies the channel type to the bus driver.
+ * @device: Device struct meant for use by the bus driver
* only.
- * list_all: Used by the bus driver to enumerate devices.
- * periodic_work: Device work queue. Private use by bus driver
- * only.
- * being_removed: Indicates that the device is being removed from
+ * @list_all: Used by the bus driver to enumerate devices.
+ * @timer: Timer fired periodically to do interrupt-type
+ * activity.
+ * @being_removed: Indicates that the device is being removed from
* the bus. Private bus driver use only.
- * visordriver_callback_lock: Used by the bus driver to lock when handling
+ * @visordriver_callback_lock: Used by the bus driver to lock when handling
* channel events.
- * pausing: Indicates that a change towards a paused state.
+ * @pausing: Indicates that a change towards a paused state.
* is in progress. Only modified by the bus driver.
- * resuming: Indicates that a change towards a running state
+ * @resuming: Indicates that a change towards a running state
* is in progress. Only modified by the bus driver.
- * chipset_bus_no: Private field used by the bus driver.
- * chipset_dev_no: Private field used the bus driver.
- * state: Used to indicate the current state of the
+ * @chipset_bus_no: Private field used by the bus driver.
+ * @chipset_dev_no: Private field used the bus driver.
+ * @state: Used to indicate the current state of the
* device.
- * inst: Unique GUID for this instance of the device.
- * name: Name of the device.
- * pending_msg_hdr: For private use by bus driver to respond to
+ * @inst: Unique GUID for this instance of the device.
+ * @name: Name of the device.
+ * @pending_msg_hdr: For private use by bus driver to respond to
* hypervisor requests.
- * vbus_hdr_info: A pointer to header info. Private use by bus
+ * @vbus_hdr_info: A pointer to header info. Private use by bus
* driver.
- * partition_uuid: Indicates client partion id. This should be the
+ * @partition_uuid: Indicates client partion id. This should be the
* same across all visor_devices in the current
* guest. Private use by bus driver only.
*/
@@ -157,9 +152,10 @@ struct visor_device {
/* These fields are for private use by the bus driver only. */
struct device device;
struct list_head list_all;
- struct periodic_work *periodic_work;
+ struct timer_list timer;
+ bool timer_active;
bool being_removed;
- struct semaphore visordriver_callback_lock;
+ struct mutex visordriver_callback_lock;
bool pausing;
bool resuming;
u32 chipset_bus_no;
@@ -174,7 +170,6 @@ struct visor_device {
#define to_visor_device(x) container_of(x, struct visor_device, device)
-#ifndef STANDALONE_CLIENT
int visorbus_register_visor_driver(struct visor_driver *);
void visorbus_unregister_visor_driver(struct visor_driver *);
int visorbus_read_channel(struct visor_device *dev,
@@ -183,50 +178,34 @@ int visorbus_read_channel(struct visor_device *dev,
int visorbus_write_channel(struct visor_device *dev,
unsigned long offset, void *src,
unsigned long nbytes);
-int visorbus_clear_channel(struct visor_device *dev,
- unsigned long offset, u8 ch, unsigned long nbytes);
void visorbus_enable_channel_interrupts(struct visor_device *dev);
void visorbus_disable_channel_interrupts(struct visor_device *dev);
-#endif
-/* Note that for visorchannel_create()
- * <channel_bytes> and <guid> arguments may be 0 if we are a channel CLIENT.
- * In this case, the values can simply be read from the channel header.
+/* Levels of severity for diagnostic events, in order from lowest severity to
+ * highest (i.e. fatal errors are the most severe, and should always be logged,
+ * but info events rarely need to be logged except during debugging). The
+ * values DIAG_SEVERITY_ENUM_BEGIN and DIAG_SEVERITY_ENUM_END are not valid
+ * severity values. They exist merely to dilineate the list, so that future
+ * additions won't require changes to the driver (i.e. when checking for
+ * out-of-range severities in SetSeverity). The values DIAG_SEVERITY_OVERRIDE
+ * and DIAG_SEVERITY_SHUTOFF are not valid severity values for logging events
+ * but they are valid for controlling the amount of event data. Changes made
+ * to the enum, need to be reflected in s-Par.
*/
-struct visorchannel *visorchannel_create(u64 physaddr,
- unsigned long channel_bytes,
- gfp_t gfp, uuid_le guid);
-struct visorchannel *visorchannel_create_with_lock(u64 physaddr,
- unsigned long channel_bytes,
- gfp_t gfp, uuid_le guid);
-void visorchannel_destroy(struct visorchannel *channel);
-int visorchannel_read(struct visorchannel *channel, ulong offset,
- void *local, ulong nbytes);
-int visorchannel_write(struct visorchannel *channel, ulong offset,
- void *local, ulong nbytes);
-int visorchannel_clear(struct visorchannel *channel, ulong offset,
- u8 ch, ulong nbytes);
-bool visorchannel_signalremove(struct visorchannel *channel, u32 queue,
- void *msg);
-bool visorchannel_signalinsert(struct visorchannel *channel, u32 queue,
- void *msg);
-bool visorchannel_signalempty(struct visorchannel *channel, u32 queue);
+enum diag_severity {
+ DIAG_SEVERITY_VERBOSE = 0,
+ DIAG_SEVERITY_INFO = 1,
+ DIAG_SEVERITY_WARNING = 2,
+ DIAG_SEVERITY_ERR = 3,
+ DIAG_SEVERITY_PRINT = 4,
+};
-int visorchannel_signalqueue_slots_avail(struct visorchannel *channel,
- u32 queue);
-int visorchannel_signalqueue_max_slots(struct visorchannel *channel, u32 queue);
-u64 visorchannel_get_physaddr(struct visorchannel *channel);
-ulong visorchannel_get_nbytes(struct visorchannel *channel);
-char *visorchannel_id(struct visorchannel *channel, char *s);
-char *visorchannel_zoneid(struct visorchannel *channel, char *s);
-u64 visorchannel_get_clientpartition(struct visorchannel *channel);
-int visorchannel_set_clientpartition(struct visorchannel *channel,
- u64 partition_handle);
+int visorchannel_signalremove(struct visorchannel *channel, u32 queue,
+ void *msg);
+int visorchannel_signalinsert(struct visorchannel *channel, u32 queue,
+ void *msg);
+bool visorchannel_signalempty(struct visorchannel *channel, u32 queue);
uuid_le visorchannel_get_uuid(struct visorchannel *channel);
-char *visorchannel_uuid_id(uuid_le *guid, char *s);
-void visorchannel_debug(struct visorchannel *channel, int num_queues,
- struct seq_file *seq, u32 off);
-void __iomem *visorchannel_get_header(struct visorchannel *channel);
#define BUS_ROOT_DEVICE UINT_MAX
struct visor_device *visorbus_get_device_by_id(u32 bus_no, u32 dev_no,
diff --git a/drivers/staging/unisys/visorbus/Makefile b/drivers/staging/unisys/visorbus/Makefile
index fc790e7592fc..f3730d8c953e 100644
--- a/drivers/staging/unisys/visorbus/Makefile
+++ b/drivers/staging/unisys/visorbus/Makefile
@@ -7,6 +7,5 @@ obj-$(CONFIG_UNISYS_VISORBUS) += visorbus.o
visorbus-y := visorbus_main.o
visorbus-y += visorchannel.o
visorbus-y += visorchipset.o
-visorbus-y += periodic_work.o
ccflags-y += -Idrivers/staging/unisys/include
diff --git a/drivers/staging/unisys/visorbus/controlvmchannel.h b/drivers/staging/unisys/visorbus/controlvmchannel.h
index 03e36fb6a5a0..f0bfc4ded892 100644
--- a/drivers/staging/unisys/visorbus/controlvmchannel.h
+++ b/drivers/staging/unisys/visorbus/controlvmchannel.h
@@ -482,4 +482,80 @@ struct spar_controlvm_parameters_header {
u32 reserved; /* Natural alignment */
};
+/* General Errors------------------------------------------------------[0-99] */
+#define CONTROLVM_RESP_SUCCESS 0
+#define CONTROLVM_RESP_ERROR_ALREADY_DONE 1
+#define CONTROLVM_RESP_ERROR_IOREMAP_FAILED 2
+#define CONTROLVM_RESP_ERROR_KMALLOC_FAILED 3
+#define CONTROLVM_RESP_ERROR_MESSAGE_ID_UNKNOWN 4
+#define CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT 5
+
+/* CONTROLVM_INIT_CHIPSET-------------------------------------------[100-199] */
+#define CONTROLVM_RESP_ERROR_CLIENT_SWITCHCOUNT_NONZERO 100
+#define CONTROLVM_RESP_ERROR_EXPECTED_CHIPSET_INIT 101
+
+/* Maximum Limit----------------------------------------------------[200-299] */
+#define CONTROLVM_RESP_ERROR_MAX_BUSES 201 /* BUS_CREATE */
+#define CONTROLVM_RESP_ERROR_MAX_DEVICES 202 /* DEVICE_CREATE */
+/* Payload and Parameter Related------------------------------------[400-499] */
+#define CONTROLVM_RESP_ERROR_PAYLOAD_INVALID 400 /* SWITCH_ATTACHEXTPORT,
+ * DEVICE_CONFIGURE
+ */
+#define CONTROLVM_RESP_ERROR_INITIATOR_PARAMETER_INVALID 401 /* Multiple */
+#define CONTROLVM_RESP_ERROR_TARGET_PARAMETER_INVALID 402 /* DEVICE_CONFIGURE */
+#define CONTROLVM_RESP_ERROR_CLIENT_PARAMETER_INVALID 403 /* DEVICE_CONFIGURE */
+/* Specified[Packet Structure] Value-------------------------------[500-599] */
+#define CONTROLVM_RESP_ERROR_BUS_INVALID 500 /* SWITCH_ATTACHINTPORT,
+ * BUS_CONFIGURE,
+ * DEVICE_CREATE,
+ * DEVICE_CONFIG
+ * DEVICE_DESTROY
+ */
+#define CONTROLVM_RESP_ERROR_DEVICE_INVALID 501 /* SWITCH_ATTACHINTPORT */
+ /* DEVICE_CREATE,
+ * DEVICE_CONFIGURE,
+ * DEVICE_DESTROY
+ */
+#define CONTROLVM_RESP_ERROR_CHANNEL_INVALID 502 /* DEVICE_CREATE,
+ * DEVICE_CONFIGURE
+ */
+/* Partition Driver Callback Interface----------------------[600-699] */
+#define CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE 604 /* BUS_CREATE,
+ * BUS_DESTROY,
+ * DEVICE_CREATE,
+ * DEVICE_DESTROY
+ */
+/* Unable to invoke VIRTPCI callback */
+#define CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR 605
+ /* BUS_CREATE,
+ * BUS_DESTROY,
+ * DEVICE_CREATE,
+ * DEVICE_DESTROY
+ */
+/* VIRTPCI Callback returned error */
+#define CONTROLVM_RESP_ERROR_GENERIC_DRIVER_CALLBACK_ERROR 606
+ /* SWITCH_ATTACHEXTPORT,
+ * SWITCH_DETACHEXTPORT
+ * DEVICE_CONFIGURE
+ */
+
+/* generic device callback returned error */
+/* Bus Related------------------------------------------------------[700-799] */
+#define CONTROLVM_RESP_ERROR_BUS_DEVICE_ATTACHED 700 /* BUS_DESTROY */
+/* Channel Related--------------------------------------------------[800-899] */
+#define CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN 800 /* GET_CHANNELINFO,
+ * DEVICE_DESTROY
+ */
+#define CONTROLVM_RESP_ERROR_CHANNEL_SIZE_TOO_SMALL 801 /* DEVICE_CREATE */
+/* Chipset Shutdown Related---------------------------------------[1000-1099] */
+#define CONTROLVM_RESP_ERROR_CHIPSET_SHUTDOWN_FAILED 1000
+#define CONTROLVM_RESP_ERROR_CHIPSET_SHUTDOWN_ALREADY_ACTIVE 1001
+
+/* Chipset Stop Related-------------------------------------------[1100-1199] */
+#define CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_BUS 1100
+#define CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_SWITCH 1101
+
+/* Device Related-------------------------------------------------[1400-1499] */
+#define CONTROLVM_RESP_ERROR_DEVICE_UDEV_TIMEOUT 1400
+
#endif /* __CONTROLVMCHANNEL_H__ */
diff --git a/drivers/staging/unisys/visorbus/controlvmcompletionstatus.h b/drivers/staging/unisys/visorbus/controlvmcompletionstatus.h
deleted file mode 100644
index 23ad0ea6c9fc..000000000000
--- a/drivers/staging/unisys/visorbus/controlvmcompletionstatus.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* controlvmcompletionstatus.c
- *
- * Copyright (C) 2010 - 2015 UNISYS CORPORATION
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/* Defines for all valid values returned in the response message header
- * completionStatus field. See controlvmchannel.h for description of
- * the header: _CONTROLVM_MESSAGE_HEADER.
- */
-
-#ifndef __CONTROLVMCOMPLETIONSTATUS_H__
-#define __CONTROLVMCOMPLETIONSTATUS_H__
-
-/* General Errors------------------------------------------------------[0-99] */
-#define CONTROLVM_RESP_SUCCESS 0
-#define CONTROLVM_RESP_ERROR_ALREADY_DONE 1
-#define CONTROLVM_RESP_ERROR_IOREMAP_FAILED 2
-#define CONTROLVM_RESP_ERROR_KMALLOC_FAILED 3
-#define CONTROLVM_RESP_ERROR_MESSAGE_ID_UNKNOWN 4
-#define CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT 5
-
-/* CONTROLVM_INIT_CHIPSET-------------------------------------------[100-199] */
-#define CONTROLVM_RESP_ERROR_CLIENT_SWITCHCOUNT_NONZERO 100
-#define CONTROLVM_RESP_ERROR_EXPECTED_CHIPSET_INIT 101
-
-/* Maximum Limit----------------------------------------------------[200-299] */
-#define CONTROLVM_RESP_ERROR_MAX_BUSES 201 /* BUS_CREATE */
-#define CONTROLVM_RESP_ERROR_MAX_DEVICES 202 /* DEVICE_CREATE */
-/* Payload and Parameter Related------------------------------------[400-499] */
-#define CONTROLVM_RESP_ERROR_PAYLOAD_INVALID 400 /* SWITCH_ATTACHEXTPORT,
- * DEVICE_CONFIGURE
- */
-#define CONTROLVM_RESP_ERROR_INITIATOR_PARAMETER_INVALID 401 /* Multiple */
-#define CONTROLVM_RESP_ERROR_TARGET_PARAMETER_INVALID 402 /* DEVICE_CONFIGURE */
-#define CONTROLVM_RESP_ERROR_CLIENT_PARAMETER_INVALID 403 /* DEVICE_CONFIGURE */
-/* Specified[Packet Structure] Value-------------------------------[500-599] */
-#define CONTROLVM_RESP_ERROR_BUS_INVALID 500 /* SWITCH_ATTACHINTPORT,
- * BUS_CONFIGURE,
- * DEVICE_CREATE,
- * DEVICE_CONFIG
- * DEVICE_DESTROY
- */
-#define CONTROLVM_RESP_ERROR_DEVICE_INVALID 501 /* SWITCH_ATTACHINTPORT */
- /* DEVICE_CREATE,
- * DEVICE_CONFIGURE,
- * DEVICE_DESTROY
- */
-#define CONTROLVM_RESP_ERROR_CHANNEL_INVALID 502 /* DEVICE_CREATE,
- * DEVICE_CONFIGURE
- */
-/* Partition Driver Callback Interface----------------------[600-699] */
-#define CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE 604 /* BUS_CREATE,
- * BUS_DESTROY,
- * DEVICE_CREATE,
- * DEVICE_DESTROY
- */
-/* Unable to invoke VIRTPCI callback */
-#define CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR 605
- /* BUS_CREATE,
- * BUS_DESTROY,
- * DEVICE_CREATE,
- * DEVICE_DESTROY
- */
-/* VIRTPCI Callback returned error */
-#define CONTROLVM_RESP_ERROR_GENERIC_DRIVER_CALLBACK_ERROR 606
- /* SWITCH_ATTACHEXTPORT,
- * SWITCH_DETACHEXTPORT
- * DEVICE_CONFIGURE
- */
-
-/* generic device callback returned error */
-/* Bus Related------------------------------------------------------[700-799] */
-#define CONTROLVM_RESP_ERROR_BUS_DEVICE_ATTACHED 700 /* BUS_DESTROY */
-/* Channel Related--------------------------------------------------[800-899] */
-#define CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN 800 /* GET_CHANNELINFO,
- * DEVICE_DESTROY
- */
-#define CONTROLVM_RESP_ERROR_CHANNEL_SIZE_TOO_SMALL 801 /* DEVICE_CREATE */
-/* Chipset Shutdown Related---------------------------------------[1000-1099] */
-#define CONTROLVM_RESP_ERROR_CHIPSET_SHUTDOWN_FAILED 1000
-#define CONTROLVM_RESP_ERROR_CHIPSET_SHUTDOWN_ALREADY_ACTIVE 1001
-
-/* Chipset Stop Related-------------------------------------------[1100-1199] */
-#define CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_BUS 1100
-#define CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_SWITCH 1101
-
-/* Device Related-------------------------------------------------[1400-1499] */
-#define CONTROLVM_RESP_ERROR_DEVICE_UDEV_TIMEOUT 1400
-
-#endif /* __CONTROLVMCOMPLETIONSTATUS_H__ not defined */
diff --git a/drivers/staging/unisys/visorbus/iovmcall_gnuc.h b/drivers/staging/unisys/visorbus/iovmcall_gnuc.h
deleted file mode 100644
index 98ea7f381a3c..000000000000
--- a/drivers/staging/unisys/visorbus/iovmcall_gnuc.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Copyright (C) 2010 - 2015 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/* Linux GCC Version (32-bit and 64-bit) */
-static inline unsigned long
-__unisys_vmcall_gnuc(unsigned long tuple, unsigned long reg_ebx,
- unsigned long reg_ecx)
-{
- unsigned long result = 0;
- unsigned int cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx;
-
- cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx);
- if (!(cpuid_ecx & 0x80000000))
- return -EPERM;
-
- __asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) :
- "a"(tuple), "b"(reg_ebx), "c"(reg_ecx));
- return result;
-}
-
-static inline unsigned long
-__unisys_extended_vmcall_gnuc(unsigned long long tuple,
- unsigned long long reg_ebx,
- unsigned long long reg_ecx,
- unsigned long long reg_edx)
-{
- unsigned long result = 0;
- unsigned int cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx;
-
- cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx);
- if (!(cpuid_ecx & 0x80000000))
- return -EPERM;
-
- __asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) :
- "a"(tuple), "b"(reg_ebx), "c"(reg_ecx), "d"(reg_edx));
- return result;
-}
diff --git a/drivers/staging/unisys/visorbus/periodic_work.c b/drivers/staging/unisys/visorbus/periodic_work.c
deleted file mode 100644
index 00b152764f84..000000000000
--- a/drivers/staging/unisys/visorbus/periodic_work.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/* periodic_work.c
- *
- * Copyright (C) 2010 - 2015 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/*
- * Helper functions to schedule periodic work in Linux kernel mode.
- */
-#include <linux/sched.h>
-
-#include "periodic_work.h"
-
-#define MYDRVNAME "periodic_work"
-
-struct periodic_work {
- rwlock_t lock;
- struct delayed_work work;
- void (*workfunc)(void *);
- void *workfuncarg;
- bool is_scheduled;
- bool want_to_stop;
- ulong jiffy_interval;
- struct workqueue_struct *workqueue;
- const char *devnam;
-};
-
-static void periodic_work_func(struct work_struct *work)
-{
- struct periodic_work *pw;
-
- pw = container_of(work, struct periodic_work, work.work);
- (*pw->workfunc)(pw->workfuncarg);
-}
-
-struct periodic_work
-*visor_periodic_work_create(ulong jiffy_interval,
- struct workqueue_struct *workqueue,
- void (*workfunc)(void *),
- void *workfuncarg,
- const char *devnam)
-{
- struct periodic_work *pw;
-
- pw = kzalloc(sizeof(*pw), GFP_KERNEL | __GFP_NORETRY);
- if (!pw)
- return NULL;
-
- rwlock_init(&pw->lock);
- pw->jiffy_interval = jiffy_interval;
- pw->workqueue = workqueue;
- pw->workfunc = workfunc;
- pw->workfuncarg = workfuncarg;
- pw->devnam = devnam;
- return pw;
-}
-EXPORT_SYMBOL_GPL(visor_periodic_work_create);
-
-void visor_periodic_work_destroy(struct periodic_work *pw)
-{
- kfree(pw);
-}
-EXPORT_SYMBOL_GPL(visor_periodic_work_destroy);
-
-/** Call this from your periodic work worker function to schedule the next
- * call.
- * If this function returns false, there was a failure and the
- * periodic work is no longer scheduled
- */
-bool visor_periodic_work_nextperiod(struct periodic_work *pw)
-{
- bool rc = false;
-
- write_lock(&pw->lock);
- if (pw->want_to_stop) {
- pw->is_scheduled = false;
- pw->want_to_stop = false;
- rc = true; /* yes, true; see visor_periodic_work_stop() */
- goto unlock;
- } else if (!queue_delayed_work(pw->workqueue, &pw->work,
- pw->jiffy_interval)) {
- pw->is_scheduled = false;
- rc = false;
- goto unlock;
- }
- rc = true;
-unlock:
- write_unlock(&pw->lock);
- return rc;
-}
-EXPORT_SYMBOL_GPL(visor_periodic_work_nextperiod);
-
-/** This function returns true iff new periodic work was actually started.
- * If this function returns false, then no work was started
- * (either because it was already started, or because of a failure).
- */
-bool visor_periodic_work_start(struct periodic_work *pw)
-{
- bool rc = false;
-
- write_lock(&pw->lock);
- if (pw->is_scheduled) {
- rc = false;
- goto unlock;
- }
- if (pw->want_to_stop) {
- rc = false;
- goto unlock;
- }
- INIT_DELAYED_WORK(&pw->work, &periodic_work_func);
- if (!queue_delayed_work(pw->workqueue, &pw->work,
- pw->jiffy_interval)) {
- rc = false;
- goto unlock;
- }
- pw->is_scheduled = true;
- rc = true;
-unlock:
- write_unlock(&pw->lock);
- return rc;
-}
-EXPORT_SYMBOL_GPL(visor_periodic_work_start);
-
-/** This function returns true iff your call actually stopped the periodic
- * work.
- *
- * -- PAY ATTENTION... this is important --
- *
- * NO NO #1
- *
- * Do NOT call this function from some function that is running on the
- * same workqueue as the work you are trying to stop might be running
- * on! If you violate this rule, visor_periodic_work_stop() MIGHT work,
- * but it also MIGHT get hung up in an infinite loop saying
- * "waiting for delayed work...". This will happen if the delayed work
- * you are trying to cancel has been put in the workqueue list, but can't
- * run yet because we are running that same workqueue thread right now.
- *
- * Bottom line: If you need to call visor_periodic_work_stop() from a
- * workitem, be sure the workitem is on a DIFFERENT workqueue than the
- * workitem that you are trying to cancel.
- *
- * If I could figure out some way to check for this "no no" condition in
- * the code, I would. It would have saved me the trouble of writing this
- * long comment. And also, don't think this is some "theoretical" race
- * condition. It is REAL, as I have spent the day chasing it.
- *
- * NO NO #2
- *
- * Take close note of the locks that you own when you call this function.
- * You must NOT own any locks that are needed by the periodic work
- * function that is currently installed. If you DO, a deadlock may result,
- * because stopping the periodic work often involves waiting for the last
- * iteration of the periodic work function to complete. Again, if you hit
- * this deadlock, you will get hung up in an infinite loop saying
- * "waiting for delayed work...".
- */
-bool visor_periodic_work_stop(struct periodic_work *pw)
-{
- bool stopped_something = false;
-
- write_lock(&pw->lock);
- stopped_something = pw->is_scheduled && (!pw->want_to_stop);
- while (pw->is_scheduled) {
- pw->want_to_stop = true;
- if (cancel_delayed_work(&pw->work)) {
- /* We get here if the delayed work was pending as
- * delayed work, but was NOT run.
- */
- WARN_ON(!pw->is_scheduled);
- pw->is_scheduled = false;
- } else {
- /* If we get here, either the delayed work:
- * - was run, OR,
- * - is running RIGHT NOW on another processor, OR,
- * - wasn't even scheduled (there is a miniscule
- * timing window where this could be the case)
- * flush_workqueue() would make sure it is finished
- * executing, but that still isn't very useful, which
- * explains the loop...
- */
- }
- if (pw->is_scheduled) {
- write_unlock(&pw->lock);
- schedule_timeout_interruptible(msecs_to_jiffies(10));
- write_lock(&pw->lock);
- } else {
- pw->want_to_stop = false;
- }
- }
- write_unlock(&pw->lock);
- return stopped_something;
-}
-EXPORT_SYMBOL_GPL(visor_periodic_work_stop);
diff --git a/drivers/staging/unisys/visorbus/vbuschannel.h b/drivers/staging/unisys/visorbus/vbuschannel.h
index 90fa12e62f26..e97917522f6a 100644
--- a/drivers/staging/unisys/visorbus/vbuschannel.h
+++ b/drivers/staging/unisys/visorbus/vbuschannel.h
@@ -23,7 +23,6 @@
* the client devices and client drivers for the server end to see.
*/
#include <linux/uuid.h>
-#include "vbusdeviceinfo.h"
#include "channel.h"
/* {193b331b-c58f-11da-95a9-00e08161165f} */
@@ -58,6 +57,216 @@ static const uuid_le spar_vbus_channel_protocol_uuid =
actual_bytes))
#pragma pack(push, 1) /* both GCC and VC now allow this pragma */
+
+/*
+ * An array of this struct is present in the channel area for each vbus.
+ * (See vbuschannel.h.)
+ * It is filled in by the client side to provide info about the device
+ * and driver from the client's perspective.
+ */
+struct ultra_vbus_deviceinfo {
+ u8 devtype[16]; /* short string identifying the device type */
+ u8 drvname[16]; /* driver .sys file name */
+ u8 infostrs[96]; /* kernel version */
+ u8 reserved[128]; /* pad size to 256 bytes */
+};
+
+/**
+ * vbuschannel_sanitize_buffer() - remove non-printable chars from buffer
+ * @p: destination buffer where chars are written to
+ * @remain: number of bytes that can be written starting at #p
+ * @src: pointer to source buffer
+ * @srcmax: number of valid characters at #src
+ *
+ * Reads chars from the buffer at @src for @srcmax bytes, and writes to
+ * the buffer at @p, which is @remain bytes long, ensuring never to
+ * overflow the buffer at @p, using the following rules:
+ * - printable characters are simply copied from the buffer at @src to the
+ * buffer at @p
+ * - intervening streaks of non-printable characters in the buffer at @src
+ * are replaced with a single space in the buffer at @p
+ * Note that we pay no attention to '\0'-termination.
+ *
+ * Pass @p == NULL and @remain == 0 for this special behavior -- In this
+ * case, we simply return the number of bytes that WOULD HAVE been written
+ * to a buffer at @p, had it been infinitely big.
+ *
+ * Return: the number of bytes written to @p (or WOULD HAVE been written to
+ * @p, as described in the previous paragraph)
+ */
+static inline int
+vbuschannel_sanitize_buffer(char *p, int remain, char *src, int srcmax)
+{
+ int chars = 0;
+ int nonprintable_streak = 0;
+
+ while (srcmax > 0) {
+ if ((*src >= ' ') && (*src < 0x7f)) {
+ if (nonprintable_streak) {
+ if (remain > 0) {
+ *p = ' ';
+ p++;
+ remain--;
+ chars++;
+ } else if (!p) {
+ chars++;
+ }
+ nonprintable_streak = 0;
+ }
+ if (remain > 0) {
+ *p = *src;
+ p++;
+ remain--;
+ chars++;
+ } else if (!p) {
+ chars++;
+ }
+ } else {
+ nonprintable_streak = 1;
+ }
+ src++;
+ srcmax--;
+ }
+ return chars;
+}
+
+#define VBUSCHANNEL_ADDACHAR(ch, p, remain, chars) \
+ do { \
+ if (remain <= 0) \
+ break; \
+ *p = ch; \
+ p++; chars++; remain--; \
+ } while (0)
+
+/**
+ * vbuschannel_itoa() - convert non-negative int to string
+ * @p: destination string
+ * @remain: max number of bytes that can be written to @p
+ * @num: input int to convert
+ *
+ * Converts the non-negative value at @num to an ascii decimal string
+ * at @p, writing at most @remain bytes. Note there is NO '\0' termination
+ * written to @p.
+ *
+ * Return: number of bytes written to @p
+ *
+ */
+static inline int
+vbuschannel_itoa(char *p, int remain, int num)
+{
+ int digits = 0;
+ char s[32];
+ int i;
+
+ if (num == 0) {
+ /* '0' is a special case */
+ if (remain <= 0)
+ return 0;
+ *p = '0';
+ return 1;
+ }
+ /* form a backwards decimal ascii string in <s> */
+ while (num > 0) {
+ if (digits >= (int)sizeof(s))
+ return 0;
+ s[digits++] = (num % 10) + '0';
+ num = num / 10;
+ }
+ if (remain < digits) {
+ /* not enough room left at <p> to hold number, so fill with
+ * '?'
+ */
+ for (i = 0; i < remain; i++, p++)
+ *p = '?';
+ return remain;
+ }
+ /* plug in the decimal ascii string representing the number, by */
+ /* reversing the string we just built in <s> */
+ i = digits;
+ while (i > 0) {
+ i--;
+ *p = s[i];
+ p++;
+ }
+ return digits;
+}
+
+/**
+ * vbuschannel_devinfo_to_string() - format a struct ultra_vbus_deviceinfo
+ * to a printable string
+ * @devinfo: the struct ultra_vbus_deviceinfo to format
+ * @p: destination string area
+ * @remain: size of destination string area in bytes
+ * @devix: the device index to be included in the output data, or -1 if no
+ * device index is to be included
+ *
+ * Reads @devInfo, and converts its contents to a printable string at @p,
+ * writing at most @remain bytes. Note there is NO '\0' termination
+ * written to @p.
+ *
+ * Return: number of bytes written to @p
+ */
+static inline int
+vbuschannel_devinfo_to_string(struct ultra_vbus_deviceinfo *devinfo,
+ char *p, int remain, int devix)
+{
+ char *psrc;
+ int nsrc, x, i, pad;
+ int chars = 0;
+
+ psrc = &devinfo->devtype[0];
+ nsrc = sizeof(devinfo->devtype);
+ if (vbuschannel_sanitize_buffer(NULL, 0, psrc, nsrc) <= 0)
+ return 0;
+
+ /* emit device index */
+ if (devix >= 0) {
+ VBUSCHANNEL_ADDACHAR('[', p, remain, chars);
+ x = vbuschannel_itoa(p, remain, devix);
+ p += x;
+ remain -= x;
+ chars += x;
+ VBUSCHANNEL_ADDACHAR(']', p, remain, chars);
+ } else {
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+ }
+
+ /* emit device type */
+ x = vbuschannel_sanitize_buffer(p, remain, psrc, nsrc);
+ p += x;
+ remain -= x;
+ chars += x;
+ pad = 15 - x; /* pad device type to be exactly 15 chars */
+ for (i = 0; i < pad; i++)
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+
+ /* emit driver name */
+ psrc = &devinfo->drvname[0];
+ nsrc = sizeof(devinfo->drvname);
+ x = vbuschannel_sanitize_buffer(p, remain, psrc, nsrc);
+ p += x;
+ remain -= x;
+ chars += x;
+ pad = 15 - x; /* pad driver name to be exactly 15 chars */
+ for (i = 0; i < pad; i++)
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+ VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
+
+ /* emit strings */
+ psrc = &devinfo->infostrs[0];
+ nsrc = sizeof(devinfo->infostrs);
+ x = vbuschannel_sanitize_buffer(p, remain, psrc, nsrc);
+ p += x;
+ remain -= x;
+ chars += x;
+ VBUSCHANNEL_ADDACHAR('\n', p, remain, chars);
+
+ return chars;
+}
+
struct spar_vbus_headerinfo {
u32 struct_bytes; /* size of this struct in bytes */
u32 device_info_struct_bytes; /* sizeof(ULTRA_VBUS_DEVICEINFO) */
diff --git a/drivers/staging/unisys/visorbus/vbusdeviceinfo.h b/drivers/staging/unisys/visorbus/vbusdeviceinfo.h
deleted file mode 100644
index abdab4ad0b36..000000000000
--- a/drivers/staging/unisys/visorbus/vbusdeviceinfo.h
+++ /dev/null
@@ -1,213 +0,0 @@
-/* Copyright (C) 2010 - 2015 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef __VBUSDEVICEINFO_H__
-#define __VBUSDEVICEINFO_H__
-
-#include <linux/types.h>
-
-#pragma pack(push, 1) /* both GCC and VC now allow this pragma */
-
-/* An array of this struct is present in the channel area for each vbus.
- * (See vbuschannel.h.)
- * It is filled in by the client side to provide info about the device
- * and driver from the client's perspective.
- */
-struct ultra_vbus_deviceinfo {
- u8 devtype[16]; /* short string identifying the device type */
- u8 drvname[16]; /* driver .sys file name */
- u8 infostrs[96]; /* sequence of tab-delimited id strings: */
- /* <DRIVER_REV> <DRIVER_VERTAG> <DRIVER_COMPILETIME> */
- u8 reserved[128]; /* pad size to 256 bytes */
-};
-
-#pragma pack(pop)
-
-/* Reads chars from the buffer at <src> for <srcmax> bytes, and writes to
- * the buffer at <p>, which is <remain> bytes long, ensuring never to
- * overflow the buffer at <p>, using the following rules:
- * - printable characters are simply copied from the buffer at <src> to the
- * buffer at <p>
- * - intervening streaks of non-printable characters in the buffer at <src>
- * are replaced with a single space in the buffer at <p>
- * Note that we pay no attention to '\0'-termination.
- * Returns the number of bytes written to <p>.
- *
- * Pass <p> == NULL and <remain> == 0 for this special behavior. In this
- * case, we simply return the number of bytes that WOULD HAVE been written
- * to a buffer at <p>, had it been infinitely big.
- */
-static inline int
-vbuschannel_sanitize_buffer(char *p, int remain, char *src, int srcmax)
-{
- int chars = 0;
- int nonprintable_streak = 0;
-
- while (srcmax > 0) {
- if ((*src >= ' ') && (*src < 0x7f)) {
- if (nonprintable_streak) {
- if (remain > 0) {
- *p = ' ';
- p++;
- remain--;
- chars++;
- } else if (!p) {
- chars++;
- }
- nonprintable_streak = 0;
- }
- if (remain > 0) {
- *p = *src;
- p++;
- remain--;
- chars++;
- } else if (!p) {
- chars++;
- }
- } else {
- nonprintable_streak = 1;
- }
- src++;
- srcmax--;
- }
- return chars;
-}
-
-#define VBUSCHANNEL_ADDACHAR(ch, p, remain, chars) \
- do { \
- if (remain <= 0) \
- break; \
- *p = ch; \
- p++; chars++; remain--; \
- } while (0)
-
-/* Converts the non-negative value at <num> to an ascii decimal string
- * at <p>, writing at most <remain> bytes. Note there is NO '\0' termination
- * written to <p>.
- *
- * Returns the number of bytes written to <p>.
- *
- * Note that we create this function because we need to do this operation in
- * an environment-independent way (since we are in a common header file).
- */
-static inline int
-vbuschannel_itoa(char *p, int remain, int num)
-{
- int digits = 0;
- char s[32];
- int i;
-
- if (num == 0) {
- /* '0' is a special case */
- if (remain <= 0)
- return 0;
- *p = '0';
- return 1;
- }
- /* form a backwards decimal ascii string in <s> */
- while (num > 0) {
- if (digits >= (int)sizeof(s))
- return 0;
- s[digits++] = (num % 10) + '0';
- num = num / 10;
- }
- if (remain < digits) {
- /* not enough room left at <p> to hold number, so fill with
- * '?'
- */
- for (i = 0; i < remain; i++, p++)
- *p = '?';
- return remain;
- }
- /* plug in the decimal ascii string representing the number, by */
- /* reversing the string we just built in <s> */
- i = digits;
- while (i > 0) {
- i--;
- *p = s[i];
- p++;
- }
- return digits;
-}
-
-/* Reads <devInfo>, and converts its contents to a printable string at <p>,
- * writing at most <remain> bytes. Note there is NO '\0' termination
- * written to <p>.
- *
- * Pass <devix> >= 0 if you want a device index presented.
- *
- * Returns the number of bytes written to <p>.
- */
-static inline int
-vbuschannel_devinfo_to_string(struct ultra_vbus_deviceinfo *devinfo,
- char *p, int remain, int devix)
-{
- char *psrc;
- int nsrc, x, i, pad;
- int chars = 0;
-
- psrc = &devinfo->devtype[0];
- nsrc = sizeof(devinfo->devtype);
- if (vbuschannel_sanitize_buffer(NULL, 0, psrc, nsrc) <= 0)
- return 0;
-
- /* emit device index */
- if (devix >= 0) {
- VBUSCHANNEL_ADDACHAR('[', p, remain, chars);
- x = vbuschannel_itoa(p, remain, devix);
- p += x;
- remain -= x;
- chars += x;
- VBUSCHANNEL_ADDACHAR(']', p, remain, chars);
- } else {
- VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
- VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
- VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
- }
-
- /* emit device type */
- x = vbuschannel_sanitize_buffer(p, remain, psrc, nsrc);
- p += x;
- remain -= x;
- chars += x;
- pad = 15 - x; /* pad device type to be exactly 15 chars */
- for (i = 0; i < pad; i++)
- VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
- VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
-
- /* emit driver name */
- psrc = &devinfo->drvname[0];
- nsrc = sizeof(devinfo->drvname);
- x = vbuschannel_sanitize_buffer(p, remain, psrc, nsrc);
- p += x;
- remain -= x;
- chars += x;
- pad = 15 - x; /* pad driver name to be exactly 15 chars */
- for (i = 0; i < pad; i++)
- VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
- VBUSCHANNEL_ADDACHAR(' ', p, remain, chars);
-
- /* emit strings */
- psrc = &devinfo->infostrs[0];
- nsrc = sizeof(devinfo->infostrs);
- x = vbuschannel_sanitize_buffer(p, remain, psrc, nsrc);
- p += x;
- remain -= x;
- chars += x;
- VBUSCHANNEL_ADDACHAR('\n', p, remain, chars);
-
- return chars;
-}
-
-#endif
diff --git a/drivers/staging/unisys/visorbus/visorbus_main.c b/drivers/staging/unisys/visorbus/visorbus_main.c
index d32b8980a1cf..fec0a54916fe 100644
--- a/drivers/staging/unisys/visorbus/visorbus_main.c
+++ b/drivers/staging/unisys/visorbus/visorbus_main.c
@@ -18,62 +18,22 @@
#include "visorbus.h"
#include "visorbus_private.h"
-#include "version.h"
-#include "periodic_work.h"
-#include "vbuschannel.h"
-#include "guestlinuxdebug.h"
#include "vmcallinterface.h"
#define MYDRVNAME "visorbus"
/* module parameters */
-static int visorbus_debug;
static int visorbus_forcematch;
static int visorbus_forcenomatch;
-static int visorbus_debugref;
-#define SERIALLOOPBACKCHANADDR (100 * 1024 * 1024)
/* Display string that is guaranteed to be no longer the 99 characters*/
#define LINESIZE 99
#define CURRENT_FILE_PC VISOR_BUS_PC_visorbus_main_c
-#define POLLJIFFIES_TESTWORK 100
#define POLLJIFFIES_NORMALCHANNEL 10
static int busreg_rc = -ENODEV; /* stores the result from bus registration */
-static int visorbus_uevent(struct device *xdev, struct kobj_uevent_env *env);
-static int visorbus_match(struct device *xdev, struct device_driver *xdrv);
-static void fix_vbus_dev_info(struct visor_device *visordev);
-
-/* BUS type attributes
- *
- * define & implement display of bus attributes under
- * /sys/bus/visorbus.
- *
- */
-
-static ssize_t version_show(struct bus_type *bus, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%s\n", VERSION);
-}
-
-static BUS_ATTR_RO(version);
-
-static struct attribute *visorbus_bus_attrs[] = {
- &bus_attr_version.attr,
- NULL,
-};
-
-static const struct attribute_group visorbus_bus_group = {
- .attrs = visorbus_bus_attrs,
-};
-
-static const struct attribute_group *visorbus_bus_groups[] = {
- &visorbus_bus_group,
- NULL,
-};
-
/*
* DEVICE type attributes
*
@@ -106,61 +66,14 @@ static const struct attribute_group *visorbus_dev_groups[] = {
NULL,
};
-/** This describes the TYPE of bus.
- * (Don't confuse this with an INSTANCE of the bus.)
- */
-struct bus_type visorbus_type = {
- .name = "visorbus",
- .match = visorbus_match,
- .uevent = visorbus_uevent,
- .dev_groups = visorbus_dev_groups,
- .bus_groups = visorbus_bus_groups,
-};
-
-static struct delayed_work periodic_work;
-
-/* YES, we need 2 workqueues.
- * The reason is, workitems on the test queue may need to cancel
- * workitems on the other queue. You will be in for trouble if you try to
- * do this with workitems queued on the same workqueue.
- */
-static struct workqueue_struct *periodic_test_workqueue;
-static struct workqueue_struct *periodic_dev_workqueue;
-static long long bus_count; /** number of bus instances */
- /** ever-increasing */
-
-static void chipset_bus_create(struct visor_device *bus_info);
-static void chipset_bus_destroy(struct visor_device *bus_info);
-static void chipset_device_create(struct visor_device *dev_info);
-static void chipset_device_destroy(struct visor_device *dev_info);
-static void chipset_device_pause(struct visor_device *dev_info);
-static void chipset_device_resume(struct visor_device *dev_info);
-
-/** These functions are implemented herein, and are called by the chipset
- * driver to notify us about specific events.
- */
-static struct visorchipset_busdev_notifiers chipset_notifiers = {
- .bus_create = chipset_bus_create,
- .bus_destroy = chipset_bus_destroy,
- .device_create = chipset_device_create,
- .device_destroy = chipset_device_destroy,
- .device_pause = chipset_device_pause,
- .device_resume = chipset_device_resume,
-};
-
-/** These functions are implemented in the chipset driver, and we call them
- * herein when we want to acknowledge a specific event.
- */
-static struct visorchipset_busdev_responders chipset_responders;
-
/* filled in with info about parent chipset driver when we register with it */
static struct ultra_vbus_deviceinfo chipset_driverinfo;
/* filled in with info about this driver, wrt it servicing client busses */
static struct ultra_vbus_deviceinfo clientbus_driverinfo;
-/** list of visor_device structs, linked via .list_all */
+/* list of visor_device structs, linked via .list_all */
static LIST_HEAD(list_all_bus_instances);
-/** list of visor_device structs, linked via .list_all */
+/* list of visor_device structs, linked via .list_all */
static LIST_HEAD(list_all_device_instances);
static int
@@ -177,9 +90,14 @@ visorbus_uevent(struct device *xdev, struct kobj_uevent_env *env)
return 0;
}
-/* This is called automatically upon adding a visor_device (device_add), or
- * adding a visor_driver (visorbus_register_visor_driver), and returns 1 iff the
- * provided driver can control the specified device.
+/**
+ * visorbus_match() - called automatically upon adding a visor_device
+ * (device_add), or adding a visor_driver
+ * (visorbus_register_visor_driver)
+ * @xdev: struct device for the device being matched
+ * @xdrv: struct device_driver for driver to match device against
+ *
+ * Return: 1 iff the provided driver can control the specified device
*/
static int
visorbus_match(struct device *xdev, struct device_driver *xdrv)
@@ -211,9 +129,22 @@ visorbus_match(struct device *xdev, struct device_driver *xdrv)
return 0;
}
-/** This is called when device_unregister() is called for the bus device
- * instance, after all other tasks involved with destroying the device
- * are complete.
+/*
+ * This describes the TYPE of bus.
+ * (Don't confuse this with an INSTANCE of the bus.)
+ */
+struct bus_type visorbus_type = {
+ .name = "visorbus",
+ .match = visorbus_match,
+ .uevent = visorbus_uevent,
+ .dev_groups = visorbus_dev_groups,
+};
+
+/**
+ * visorbus_releae_busdevice() - called when device_unregister() is called for
+ * the bus device instance, after all other tasks
+ * involved with destroying the dev are complete
+ * @xdev: struct device for the bus being released
*/
static void
visorbus_release_busdevice(struct device *xdev)
@@ -223,18 +154,16 @@ visorbus_release_busdevice(struct device *xdev)
kfree(dev);
}
-/** This is called when device_unregister() is called for each child
- * device instance.
+/**
+ * visorbus_release_device() - called when device_unregister() is called for
+ * each child device instance
+ * @xdev: struct device for the visor device being released
*/
static void
visorbus_release_device(struct device *xdev)
{
struct visor_device *dev = to_visor_device(xdev);
- if (dev->periodic_work) {
- visor_periodic_work_destroy(dev->periodic_work);
- dev->periodic_work = NULL;
- }
if (dev->visorchannel) {
visorchannel_destroy(dev->visorchannel);
dev->visorchannel = NULL;
@@ -242,9 +171,11 @@ visorbus_release_device(struct device *xdev)
kfree(dev);
}
-/* begin implementation of specific channel attributes to appear under
-* /sys/bus/visorbus<x>/dev<y>/channel
-*/
+/*
+ * begin implementation of specific channel attributes to appear under
+ * /sys/bus/visorbus<x>/dev<y>/channel
+ */
+
static ssize_t physaddr_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -349,15 +280,11 @@ static const struct attribute_group *visorbus_channel_groups[] = {
/* end implementation of specific channel attributes */
-/* BUS instance attributes
+/*
+ * BUS instance attributes
*
* define & implement display of bus attributes under
- * /sys/bus/visorbus/busses/visorbus<n>.
- *
- * This is a bit hoaky because the kernel does not yet have the infrastructure
- * to separate bus INSTANCE attributes from bus TYPE attributes...
- * so we roll our own. See businst.c / businst.h.
- *
+ * /sys/bus/visorbus/devices/visorbus<n>.
*/
static ssize_t partition_handle_show(struct device *dev,
@@ -434,8 +361,8 @@ static ssize_t client_bus_info_show(struct device *dev,
if (vdev->name)
partition_name = vdev->name;
shift = snprintf(pos, remain,
- "Client device / client driver info for %s eartition (vbus #%d):\n",
- partition_name, vdev->chipset_dev_no);
+ "Client device / client driver info for %s partition (vbus #%u):\n",
+ partition_name, vdev->chipset_bus_no);
pos += shift;
remain -= shift;
shift = visorchannel_read(channel,
@@ -508,103 +435,48 @@ static const struct attribute_group *visorbus_groups[] = {
NULL
};
-/* DRIVER attributes
- *
- * define & implement display of driver attributes under
- * /sys/bus/visorbus/drivers/<drivername>.
- *
- */
-
-static ssize_t
-DRIVER_ATTR_version(struct device_driver *xdrv, char *buf)
-{
- struct visor_driver *drv = to_visor_driver(xdrv);
-
- return snprintf(buf, PAGE_SIZE, "%s\n", drv->version);
-}
-
-static int
-register_driver_attributes(struct visor_driver *drv)
-{
- struct driver_attribute version =
- __ATTR(version, S_IRUGO, DRIVER_ATTR_version, NULL);
- drv->version_attr = version;
- return driver_create_file(&drv->driver, &drv->version_attr);
-}
-
-static void
-unregister_driver_attributes(struct visor_driver *drv)
-{
- driver_remove_file(&drv->driver, &drv->version_attr);
-}
-
static void
-dev_periodic_work(void *xdev)
+dev_periodic_work(unsigned long __opaque)
{
- struct visor_device *dev = xdev;
+ struct visor_device *dev = (struct visor_device *)__opaque;
struct visor_driver *drv = to_visor_driver(dev->device.driver);
- down(&dev->visordriver_callback_lock);
if (drv->channel_interrupt)
drv->channel_interrupt(dev);
- up(&dev->visordriver_callback_lock);
- if (!visor_periodic_work_nextperiod(dev->periodic_work))
- put_device(&dev->device);
+ mod_timer(&dev->timer, jiffies + POLLJIFFIES_NORMALCHANNEL);
}
static void
dev_start_periodic_work(struct visor_device *dev)
{
- if (dev->being_removed)
+ if (dev->being_removed || dev->timer_active)
return;
/* now up by at least 2 */
get_device(&dev->device);
- if (!visor_periodic_work_start(dev->periodic_work))
- put_device(&dev->device);
+ dev->timer.expires = jiffies + POLLJIFFIES_NORMALCHANNEL;
+ add_timer(&dev->timer);
+ dev->timer_active = true;
}
static void
dev_stop_periodic_work(struct visor_device *dev)
{
- if (visor_periodic_work_stop(dev->periodic_work))
- put_device(&dev->device);
-}
-
-/** This is called automatically upon adding a visor_device (device_add), or
- * adding a visor_driver (visorbus_register_visor_driver), but only after
- * visorbus_match has returned 1 to indicate a successful match between
- * driver and device.
- */
-static int
-visordriver_probe_device(struct device *xdev)
-{
- int res;
- struct visor_driver *drv;
- struct visor_device *dev;
-
- drv = to_visor_driver(xdev->driver);
- dev = to_visor_device(xdev);
-
- if (!drv->probe)
- return -ENODEV;
-
- down(&dev->visordriver_callback_lock);
- dev->being_removed = false;
-
- res = drv->probe(dev);
- if (res >= 0) {
- /* success: reference kept via unmatched get_device() */
- get_device(&dev->device);
- fix_vbus_dev_info(dev);
- }
-
- up(&dev->visordriver_callback_lock);
- return res;
+ if (!dev->timer_active)
+ return;
+ del_timer_sync(&dev->timer);
+ dev->timer_active = false;
+ put_device(&dev->device);
}
-/** This is called when device_unregister() is called for each child device
- * instance, to notify the appropriate visorbus_driver that the device is
- * going away, and to decrease the reference count of the device.
+/**
+ * visordriver_remove_device() - handle visor device going away
+ * @xdev: struct device for the visor device being removed
+ *
+ * This is called when device_unregister() is called for each child device
+ * instance, to notify the appropriate visorbus function driver that the device
+ * is going away, and to decrease the reference count of the device.
+ *
+ * Return: 0 iff successful
*/
static int
visordriver_remove_device(struct device *xdev)
@@ -614,105 +486,44 @@ visordriver_remove_device(struct device *xdev)
dev = to_visor_device(xdev);
drv = to_visor_driver(xdev->driver);
- down(&dev->visordriver_callback_lock);
+ mutex_lock(&dev->visordriver_callback_lock);
dev->being_removed = true;
if (drv->remove)
drv->remove(dev);
- up(&dev->visordriver_callback_lock);
+ mutex_unlock(&dev->visordriver_callback_lock);
dev_stop_periodic_work(dev);
put_device(&dev->device);
return 0;
}
-/** A particular type of visor driver calls this function to register
- * the driver. The caller MUST fill in the following fields within the
- * #drv structure:
- * name, version, owner, channel_types, probe, remove
+/**
+ * visorbus_unregister_visor_driver() - unregisters the provided driver
+ * @drv: the driver to unregister
*
- * Here's how the whole Linux bus / driver / device model works.
- *
- * At system start-up, the visorbus kernel module is loaded, which registers
- * visorbus_type as a bus type, using bus_register().
- *
- * All kernel modules that support particular device types on a
- * visorbus bus are loaded. Each of these kernel modules calls
- * visorbus_register_visor_driver() in their init functions, passing a
- * visor_driver struct. visorbus_register_visor_driver() in turn calls
- * register_driver(&visor_driver.driver). This .driver member is
- * initialized with generic methods (like probe), whose sole responsibility
- * is to act as a broker for the real methods, which are within the
- * visor_driver struct. (This is the way the subclass behavior is
- * implemented, since visor_driver is essentially a subclass of the
- * generic driver.) Whenever a driver_register() happens, core bus code in
- * the kernel does (see device_attach() in drivers/base/dd.c):
- *
- * for each dev associated with the bus (the bus that driver is on) that
- * does not yet have a driver
- * if bus.match(dev,newdriver) == yes_matched ** .match specified
- * ** during bus_register().
- * newdriver.probe(dev) ** for visor drivers, this will call
- * ** the generic driver.probe implemented in visorbus.c,
- * ** which in turn calls the probe specified within the
- * ** struct visor_driver (which was specified by the
- * ** actual device driver as part of
- * ** visorbus_register_visor_driver()).
- *
- * The above dance also happens when a new device appears.
- * So the question is, how are devices created within the system?
- * Basically, just call device_add(dev). See pci_bus_add_devices().
- * pci_scan_device() shows an example of how to build a device struct. It
- * returns the newly-created struct to pci_scan_single_device(), who adds it
- * to the list of devices at PCIBUS.devices. That list of devices is what
- * is traversed by pci_bus_add_devices().
- *
- */
-int visorbus_register_visor_driver(struct visor_driver *drv)
-{
- int rc = 0;
-
- if (busreg_rc < 0)
- return -ENODEV; /*can't register on a nonexistent bus*/
-
- drv->driver.name = drv->name;
- drv->driver.bus = &visorbus_type;
- drv->driver.probe = visordriver_probe_device;
- drv->driver.remove = visordriver_remove_device;
- drv->driver.owner = drv->owner;
-
- /* driver_register does this:
- * bus_add_driver(drv)
- * ->if (drv.bus) ** (bus_type) **
- * driver_attach(drv)
- * for each dev with bus type of drv.bus
- * if (!dev.drv) ** no driver assigned yet **
- * if (bus.match(dev,drv)) [visorbus_match]
- * dev.drv = drv
- * if (!drv.probe(dev)) [visordriver_probe_device]
- * dev.drv = NULL
- */
-
- rc = driver_register(&drv->driver);
- if (rc < 0)
- return rc;
- rc = register_driver_attributes(drv);
- if (rc < 0)
- driver_unregister(&drv->driver);
- return rc;
-}
-EXPORT_SYMBOL_GPL(visorbus_register_visor_driver);
-
-/** A particular type of visor driver calls this function to unregister
- * the driver, i.e., within its module_exit function.
+ * A visor function driver calls this function to unregister the driver,
+ * i.e., within its module_exit function.
*/
void
visorbus_unregister_visor_driver(struct visor_driver *drv)
{
- unregister_driver_attributes(drv);
driver_unregister(&drv->driver);
}
EXPORT_SYMBOL_GPL(visorbus_unregister_visor_driver);
+/**
+ * visorbus_read_channel() - reads from the designated channel into
+ * the provided buffer
+ * @dev: the device whose channel is read from
+ * @offset: the offset into the channel at which reading starts
+ * @dest: the destination buffer that is written into from the channel
+ * @nbytes: the number of bytes to read from the channel
+ *
+ * If receiving a message, use the visorchannel_signalremove()
+ * function instead.
+ *
+ * Return: integer indicating success (zero) or failure (non-zero)
+ */
int
visorbus_read_channel(struct visor_device *dev, unsigned long offset,
void *dest, unsigned long nbytes)
@@ -721,6 +532,19 @@ visorbus_read_channel(struct visor_device *dev, unsigned long offset,
}
EXPORT_SYMBOL_GPL(visorbus_read_channel);
+/**
+ * visorbus_write_channel() - writes the provided buffer into the designated
+ * channel
+ * @dev: the device whose channel is written to
+ * @offset: the offset into the channel at which writing starts
+ * @src: the source buffer that is written into the channel
+ * @nbytes: the number of bytes to write into the channel
+ *
+ * If sending a message, use the visorchannel_signalinsert()
+ * function instead.
+ *
+ * Return: integer indicating success (zero) or failure (non-zero)
+ */
int
visorbus_write_channel(struct visor_device *dev, unsigned long offset,
void *src, unsigned long nbytes)
@@ -729,16 +553,13 @@ visorbus_write_channel(struct visor_device *dev, unsigned long offset,
}
EXPORT_SYMBOL_GPL(visorbus_write_channel);
-int
-visorbus_clear_channel(struct visor_device *dev, unsigned long offset, u8 ch,
- unsigned long nbytes)
-{
- return visorchannel_clear(dev->visorchannel, offset, ch, nbytes);
-}
-EXPORT_SYMBOL_GPL(visorbus_clear_channel);
-
-/** We don't really have a real interrupt, so for now we just call the
- * interrupt function periodically...
+/**
+ * visorbus_enable_channel_interrupts() - enables interrupts on the
+ * designated device
+ * @dev: the device on which to enable interrupts
+ *
+ * Currently we don't yet have a real interrupt, so for now we just call the
+ * interrupt function periodically via a timer.
*/
void
visorbus_enable_channel_interrupts(struct visor_device *dev)
@@ -747,6 +568,11 @@ visorbus_enable_channel_interrupts(struct visor_device *dev)
}
EXPORT_SYMBOL_GPL(visorbus_enable_channel_interrupts);
+/**
+ * visorbus_disable_channel_interrupts() - disables interrupts on the
+ * designated device
+ * @dev: the device on which to disable interrupts
+ */
void
visorbus_disable_channel_interrupts(struct visor_device *dev)
{
@@ -754,19 +580,28 @@ visorbus_disable_channel_interrupts(struct visor_device *dev)
}
EXPORT_SYMBOL_GPL(visorbus_disable_channel_interrupts);
-/** This is how everything starts from the device end.
- * This function is called when a channel first appears via a ControlVM
- * message. In response, this function allocates a visor_device to
- * correspond to the new channel, and attempts to connect it the appropriate
- * driver. If the appropriate driver is found, the visor_driver.probe()
- * function for that driver will be called, and will be passed the new
- * visor_device that we just created.
+/**
+ * create_visor_device() - create visor device as a result of receiving the
+ * controlvm device_create message for a new device
+ * @dev: a freshly-zeroed struct visor_device, containing only filled-in values
+ * for chipset_bus_no and chipset_dev_no, that will be initialized
+ *
+ * This is how everything starts from the device end.
+ * This function is called when a channel first appears via a ControlVM
+ * message. In response, this function allocates a visor_device to
+ * correspond to the new channel, and attempts to connect it the appropriate
+ * driver. If the appropriate driver is found, the visor_driver.probe()
+ * function for that driver will be called, and will be passed the new
+ * visor_device that we just created.
+ *
+ * It's ok if the appropriate driver is not yet loaded, because in that case
+ * the new device struct will just stick around in the bus' list of devices.
+ * When the appropriate driver calls visorbus_register_visor_driver(), the
+ * visor_driver.probe() for the new driver will be called with the new
+ * device.
*
- * It's ok if the appropriate driver is not yet loaded, because in that case
- * the new device struct will just stick around in the bus' list of devices.
- * When the appropriate driver calls visorbus_register_visor_driver(), the
- * visor_driver.probe() for the new driver will be called with the new
- * device.
+ * Return: 0 if successful, otherwise the negative value returned by
+ * device_add() indicating the reason for failure
*/
static int
create_visor_device(struct visor_device *dev)
@@ -778,33 +613,27 @@ create_visor_device(struct visor_device *dev)
POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, chipset_dev_no, chipset_bus_no,
POSTCODE_SEVERITY_INFO);
- sema_init(&dev->visordriver_callback_lock, 1); /* unlocked */
+ mutex_init(&dev->visordriver_callback_lock);
dev->device.bus = &visorbus_type;
dev->device.groups = visorbus_channel_groups;
device_initialize(&dev->device);
dev->device.release = visorbus_release_device;
/* keep a reference just for us (now 2) */
get_device(&dev->device);
- dev->periodic_work =
- visor_periodic_work_create(POLLJIFFIES_NORMALCHANNEL,
- periodic_dev_workqueue,
- dev_periodic_work,
- dev, dev_name(&dev->device));
- if (!dev->periodic_work) {
- POSTCODE_LINUX_3(DEVICE_CREATE_FAILURE_PC, chipset_dev_no,
- DIAG_SEVERITY_ERR);
- err = -EINVAL;
- goto err_put;
- }
+ init_timer(&dev->timer);
+ dev->timer.data = (unsigned long)(dev);
+ dev->timer.function = dev_periodic_work;
- /* bus_id must be a unique name with respect to this bus TYPE
+ /*
+ * bus_id must be a unique name with respect to this bus TYPE
* (NOT bus instance). That's why we need to include the bus
* number within the name.
*/
dev_set_name(&dev->device, "vbus%u:dev%u",
chipset_bus_no, chipset_dev_no);
- /* device_add does this:
+ /*
+ * device_add does this:
* bus_add_device(dev)
* ->device_attach(dev)
* ->for each driver drv registered on the bus that dev is on
@@ -864,11 +693,20 @@ get_vbus_header_info(struct visorchannel *chan,
return 0;
}
-/* Write the contents of <info> to the struct
- * spar_vbus_channel_protocol.chp_info.
+/**
+ * write_vbus_chp_info() - write the contents of <info> to the struct
+ * spar_vbus_channel_protocol.chp_info
+ * @chan: indentifies the s-Par channel that will be updated
+ * @hdr_info: used to find appropriate channel offset to write data
+ * @info: contains the information to write
+ *
+ * Writes chipset info into the channel memory to be used for diagnostic
+ * purposes.
+ *
+ * Returns no value since this is debug information and not needed for
+ * device functionality.
*/
-
-static int
+static void
write_vbus_chp_info(struct visorchannel *chan,
struct spar_vbus_headerinfo *hdr_info,
struct ultra_vbus_deviceinfo *info)
@@ -876,18 +714,25 @@ write_vbus_chp_info(struct visorchannel *chan,
int off = sizeof(struct channel_header) + hdr_info->chp_info_offset;
if (hdr_info->chp_info_offset == 0)
- return -EFAULT;
+ return;
- if (visorchannel_write(chan, off, info, sizeof(*info)) < 0)
- return -EFAULT;
- return 0;
+ visorchannel_write(chan, off, info, sizeof(*info));
}
-/* Write the contents of <info> to the struct
- * spar_vbus_channel_protocol.bus_info.
+/**
+ * write_vbus_bus_info() - write the contents of <info> to the struct
+ * spar_vbus_channel_protocol.bus_info
+ * @chan: indentifies the s-Par channel that will be updated
+ * @hdr_info: used to find appropriate channel offset to write data
+ * @info: contains the information to write
+ *
+ * Writes bus info into the channel memory to be used for diagnostic
+ * purposes.
+ *
+ * Returns no value since this is debug information and not needed for
+ * device functionality.
*/
-
-static int
+static void
write_vbus_bus_info(struct visorchannel *chan,
struct spar_vbus_headerinfo *hdr_info,
struct ultra_vbus_deviceinfo *info)
@@ -895,37 +740,46 @@ write_vbus_bus_info(struct visorchannel *chan,
int off = sizeof(struct channel_header) + hdr_info->bus_info_offset;
if (hdr_info->bus_info_offset == 0)
- return -EFAULT;
+ return;
- if (visorchannel_write(chan, off, info, sizeof(*info)) < 0)
- return -EFAULT;
- return 0;
+ visorchannel_write(chan, off, info, sizeof(*info));
}
-/* Write the contents of <info> to the
- * struct spar_vbus_channel_protocol.dev_info[<devix>].
+/**
+ * write_vbus_dev_info() - write the contents of <info> to the struct
+ * spar_vbus_channel_protocol.dev_info[<devix>]
+ * @chan: indentifies the s-Par channel that will be updated
+ * @hdr_info: used to find appropriate channel offset to write data
+ * @info: contains the information to write
+ * @devix: the relative device number (0..n-1) of the device on the bus
+ *
+ * Writes device info into the channel memory to be used for diagnostic
+ * purposes.
+ *
+ * Returns no value since this is debug information and not needed for
+ * device functionality.
*/
-static int
+static void
write_vbus_dev_info(struct visorchannel *chan,
struct spar_vbus_headerinfo *hdr_info,
- struct ultra_vbus_deviceinfo *info, int devix)
+ struct ultra_vbus_deviceinfo *info, unsigned int devix)
{
int off =
(sizeof(struct channel_header) + hdr_info->dev_info_offset) +
(hdr_info->device_info_struct_bytes * devix);
if (hdr_info->dev_info_offset == 0)
- return -EFAULT;
+ return;
- if (visorchannel_write(chan, off, info, sizeof(*info)) < 0)
- return -EFAULT;
- return 0;
+ visorchannel_write(chan, off, info, sizeof(*info));
}
-/* For a child device just created on a client bus, fill in
- * information about the driver that is controlling this device into
- * the the appropriate slot within the vbus channel of the bus
- * instance.
+/**
+ * fix_vbus_dev_info() - for a child device just created on a client bus, fill
+ * in information about the driver that is controlling
+ * this device into the the appropriate slot within the
+ * vbus channel of the bus instance
+ * @visordev: struct visor_device for the desired device
*/
static void
fix_vbus_dev_info(struct visor_device *visordev)
@@ -933,8 +787,8 @@ fix_vbus_dev_info(struct visor_device *visordev)
int i;
struct visor_device *bdev;
struct visor_driver *visordrv;
- int bus_no = visordev->chipset_bus_no;
- int dev_no = visordev->chipset_dev_no;
+ u32 bus_no = visordev->chipset_bus_no;
+ u32 dev_no = visordev->chipset_dev_no;
struct ultra_vbus_deviceinfo dev_info;
const char *chan_type_name = NULL;
struct spar_vbus_headerinfo *hdr_info;
@@ -942,17 +796,16 @@ fix_vbus_dev_info(struct visor_device *visordev)
if (!visordev->device.driver)
return;
- hdr_info = (struct spar_vbus_headerinfo *)visordev->vbus_hdr_info;
- if (!hdr_info)
- return;
-
bdev = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL);
if (!bdev)
return;
-
+ hdr_info = (struct spar_vbus_headerinfo *)bdev->vbus_hdr_info;
+ if (!hdr_info)
+ return;
visordrv = to_visor_driver(visordev->device.driver);
- /* Within the list of device types (by GUID) that the driver
+ /*
+ * Within the list of device types (by GUID) that the driver
* says it supports, find out which one of those types matches
* the type of this device, so that we can include the device
* type name
@@ -966,20 +819,148 @@ fix_vbus_dev_info(struct visor_device *visordev)
}
}
- bus_device_info_init(&dev_info, chan_type_name,
- visordrv->name, visordrv->version,
- visordrv->vertag);
+ bus_device_info_init(&dev_info, chan_type_name, visordrv->name);
write_vbus_dev_info(bdev->visorchannel, hdr_info, &dev_info, dev_no);
- /* Re-write bus+chipset info, because it is possible that this
- * was previously written by our evil counterpart, virtpci.
- */
+ /*
+ * Re-write bus+chipset info, because it is possible that this
+ * was previously written by our evil counterpart, virtpci.
+ */
write_vbus_chp_info(bdev->visorchannel, hdr_info, &chipset_driverinfo);
write_vbus_bus_info(bdev->visorchannel, hdr_info,
&clientbus_driverinfo);
}
-/** Create a device instance for the visor bus itself.
+/**
+ * visordriver_probe_device() - handle new visor device coming online
+ * @xdev: struct device for the visor device being probed
+ *
+ * This is called automatically upon adding a visor_device (device_add), or
+ * adding a visor_driver (visorbus_register_visor_driver), but only after
+ * visorbus_match() has returned 1 to indicate a successful match between
+ * driver and device.
+ *
+ * If successful, a reference to the device will be held onto via get_device().
+ *
+ * Return: 0 if successful, meaning the function driver's probe() function
+ * was successful with this device, otherwise a negative errno
+ * value indicating failure reason
+ */
+static int
+visordriver_probe_device(struct device *xdev)
+{
+ int res;
+ struct visor_driver *drv;
+ struct visor_device *dev;
+
+ drv = to_visor_driver(xdev->driver);
+ dev = to_visor_device(xdev);
+
+ if (!drv->probe)
+ return -ENODEV;
+
+ mutex_lock(&dev->visordriver_callback_lock);
+ dev->being_removed = false;
+
+ res = drv->probe(dev);
+ if (res >= 0) {
+ /* success: reference kept via unmatched get_device() */
+ get_device(&dev->device);
+ fix_vbus_dev_info(dev);
+ }
+
+ mutex_unlock(&dev->visordriver_callback_lock);
+ return res;
+}
+
+/**
+ * visorbus_register_visor_driver() - registers the provided visor driver
+ * for handling one or more visor device
+ * types (channel_types)
+ * @drv: the driver to register
+ *
+ * A visor function driver calls this function to register
+ * the driver. The caller MUST fill in the following fields within the
+ * #drv structure:
+ * name, version, owner, channel_types, probe, remove
+ *
+ * Here's how the whole Linux bus / driver / device model works.
+ *
+ * At system start-up, the visorbus kernel module is loaded, which registers
+ * visorbus_type as a bus type, using bus_register().
+ *
+ * All kernel modules that support particular device types on a
+ * visorbus bus are loaded. Each of these kernel modules calls
+ * visorbus_register_visor_driver() in their init functions, passing a
+ * visor_driver struct. visorbus_register_visor_driver() in turn calls
+ * register_driver(&visor_driver.driver). This .driver member is
+ * initialized with generic methods (like probe), whose sole responsibility
+ * is to act as a broker for the real methods, which are within the
+ * visor_driver struct. (This is the way the subclass behavior is
+ * implemented, since visor_driver is essentially a subclass of the
+ * generic driver.) Whenever a driver_register() happens, core bus code in
+ * the kernel does (see device_attach() in drivers/base/dd.c):
+ *
+ * for each dev associated with the bus (the bus that driver is on) that
+ * does not yet have a driver
+ * if bus.match(dev,newdriver) == yes_matched ** .match specified
+ * ** during bus_register().
+ * newdriver.probe(dev) ** for visor drivers, this will call
+ * ** the generic driver.probe implemented in visorbus.c,
+ * ** which in turn calls the probe specified within the
+ * ** struct visor_driver (which was specified by the
+ * ** actual device driver as part of
+ * ** visorbus_register_visor_driver()).
+ *
+ * The above dance also happens when a new device appears.
+ * So the question is, how are devices created within the system?
+ * Basically, just call device_add(dev). See pci_bus_add_devices().
+ * pci_scan_device() shows an example of how to build a device struct. It
+ * returns the newly-created struct to pci_scan_single_device(), who adds it
+ * to the list of devices at PCIBUS.devices. That list of devices is what
+ * is traversed by pci_bus_add_devices().
+ *
+ * Return: integer indicating success (zero) or failure (non-zero)
+ */
+int visorbus_register_visor_driver(struct visor_driver *drv)
+{
+ int rc = 0;
+
+ if (busreg_rc < 0)
+ return -ENODEV; /*can't register on a nonexistent bus*/
+
+ drv->driver.name = drv->name;
+ drv->driver.bus = &visorbus_type;
+ drv->driver.probe = visordriver_probe_device;
+ drv->driver.remove = visordriver_remove_device;
+ drv->driver.owner = drv->owner;
+
+ /*
+ * driver_register does this:
+ * bus_add_driver(drv)
+ * ->if (drv.bus) ** (bus_type) **
+ * driver_attach(drv)
+ * for each dev with bus type of drv.bus
+ * if (!dev.drv) ** no driver assigned yet **
+ * if (bus.match(dev,drv)) [visorbus_match]
+ * dev.drv = drv
+ * if (!drv.probe(dev)) [visordriver_probe_device]
+ * dev.drv = NULL
+ */
+
+ rc = driver_register(&drv->driver);
+ if (rc < 0)
+ driver_unregister(&drv->driver);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(visorbus_register_visor_driver);
+
+/**
+ * create_bus_instance() - create a device instance for the visor bus itself
+ * @dev: struct visor_device indicating the bus instance
+ *
+ * Return: 0 for success, otherwise negative errno value indicating reason for
+ * failure
*/
static int
create_bus_instance(struct visor_device *dev)
@@ -1014,25 +995,26 @@ create_bus_instance(struct visor_device *dev)
} else {
kfree(hdr_info);
}
- bus_count++;
list_add_tail(&dev->list_all, &list_all_bus_instances);
dev_set_drvdata(&dev->device, dev);
return 0;
}
-/** Remove a device instance for the visor bus itself.
+/**
+ * remove_bus_instance() - remove a device instance for the visor bus itself
+ * @dev: struct visor_device indentifying the bus to remove
*/
static void
remove_bus_instance(struct visor_device *dev)
{
- /* Note that this will result in the release method for
+ /*
+ * Note that this will result in the release method for
* dev->dev being called, which will call
* visorbus_release_busdevice(). This has something to do with
* the put_device() done in device_unregister(), but I have never
* successfully been able to trace thru the code to see where/how
* release() gets called. But I know it does.
*/
- bus_count--;
if (dev->visorchannel) {
visorchannel_destroy(dev->visorchannel);
dev->visorchannel = NULL;
@@ -1042,8 +1024,11 @@ remove_bus_instance(struct visor_device *dev)
device_unregister(&dev->device);
}
-/** Create and register the one-and-only one instance of
- * the visor bus type (visorbus_type).
+/**
+ * create_bus_type() - create and register the one-and-only one instance of
+ * the visor bus type (visorbus_type)
+ * Return: 0 for success, otherwise negative errno value returned by
+ * bus_register() indicating the reason for failure
*/
static int
create_bus_type(void)
@@ -1052,7 +1037,9 @@ create_bus_type(void)
return busreg_rc;
}
-/** Remove the one-and-only one instance of the visor bus type (visorbus_type).
+/**
+ * remove_bus_type() - remove the one-and-only one instance of the visor bus
+ * type (visorbus_type)
*/
static void
remove_bus_type(void)
@@ -1060,7 +1047,8 @@ remove_bus_type(void)
bus_unregister(&visorbus_type);
}
-/** Remove all child visor bus device instances.
+/**
+ * remove_all_visor_devices() - remove all child visor bus device instances
*/
static void
remove_all_visor_devices(void)
@@ -1075,7 +1063,7 @@ remove_all_visor_devices(void)
}
}
-static void
+void
chipset_bus_create(struct visor_device *dev)
{
int rc;
@@ -1092,19 +1080,17 @@ chipset_bus_create(struct visor_device *dev)
POSTCODE_LINUX_3(CHIPSET_INIT_SUCCESS_PC, bus_no,
POSTCODE_SEVERITY_INFO);
- if (chipset_responders.bus_create)
- (*chipset_responders.bus_create) (dev, rc);
+ bus_create_response(dev, rc);
}
-static void
+void
chipset_bus_destroy(struct visor_device *dev)
{
remove_bus_instance(dev);
- if (chipset_responders.bus_destroy)
- (*chipset_responders.bus_destroy)(dev, 0);
+ bus_destroy_response(dev, 0);
}
-static void
+void
chipset_device_create(struct visor_device *dev_info)
{
int rc;
@@ -1115,8 +1101,7 @@ chipset_device_create(struct visor_device *dev_info)
POSTCODE_SEVERITY_INFO);
rc = create_visor_device(dev_info);
- if (chipset_responders.device_create)
- chipset_responders.device_create(dev_info, rc);
+ device_create_response(dev_info, rc);
if (rc < 0)
POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
@@ -1126,18 +1111,22 @@ chipset_device_create(struct visor_device *dev_info)
POSTCODE_SEVERITY_INFO);
}
-static void
+void
chipset_device_destroy(struct visor_device *dev_info)
{
remove_visor_device(dev_info);
- if (chipset_responders.device_destroy)
- (*chipset_responders.device_destroy) (dev_info, 0);
+ device_destroy_response(dev_info, 0);
}
-/* This is the callback function specified for a function driver, to
- * be called when a pending "pause device" operation has been
- * completed.
+/**
+ * pause_state_change_complete() - the callback function to be called by a
+ * visorbus function driver when a
+ * pending "pause device" operation has
+ * completed
+ * @dev: struct visor_device identifying the paused device
+ * @status: 0 iff the pause state change completed successfully, otherwise
+ * a negative errno value indicating the reason for failure
*/
static void
pause_state_change_complete(struct visor_device *dev, int status)
@@ -1146,19 +1135,18 @@ pause_state_change_complete(struct visor_device *dev, int status)
return;
dev->pausing = false;
- if (!chipset_responders.device_pause) /* this can never happen! */
- return;
- /* Notify the chipset driver that the pause is complete, which
- * will presumably want to send some sort of response to the
- * initiator.
- */
- (*chipset_responders.device_pause) (dev, status);
+ device_pause_response(dev, status);
}
-/* This is the callback function specified for a function driver, to
- * be called when a pending "resume device" operation has been
- * completed.
+/**
+ * resume_state_change_complete() - the callback function to be called by a
+ * visorbus function driver when a
+ * pending "resume device" operation has
+ * completed
+ * @dev: struct visor_device identifying the resumed device
+ * @status: 0 iff the resume state change completed successfully, otherwise
+ * a negative errno value indicating the reason for failure
*/
static void
resume_state_change_complete(struct visor_device *dev, int status)
@@ -1167,19 +1155,25 @@ resume_state_change_complete(struct visor_device *dev, int status)
return;
dev->resuming = false;
- if (!chipset_responders.device_resume) /* this can never happen! */
- return;
- /* Notify the chipset driver that the resume is complete,
+ /*
+ * Notify the chipset driver that the resume is complete,
* which will presumably want to send some sort of response to
* the initiator.
*/
- (*chipset_responders.device_resume) (dev, status);
+ device_resume_response(dev, status);
}
-/* Tell the subordinate function driver for a specific device to pause
- * or resume that device. Result is returned asynchronously via a
- * callback function.
+/**
+ * initiate_chipset_device_pause_resume() - start a pause or resume operation
+ * for a visor device
+ * @dev: struct visor_device identifying the device being paused or resumed
+ * @is_pause: true to indicate pause operation, false to indicate resume
+ *
+ * Tell the subordinate function driver for a specific device to pause
+ * or resume that device. Success/failure result is returned asynchronously
+ * via a callback function; see pause_state_change_complete() and
+ * resume_state_change_complete().
*/
static void
initiate_chipset_device_pause_resume(struct visor_device *dev, bool is_pause)
@@ -1189,9 +1183,9 @@ initiate_chipset_device_pause_resume(struct visor_device *dev, bool is_pause)
void (*notify_func)(struct visor_device *dev, int response) = NULL;
if (is_pause)
- notify_func = chipset_responders.device_pause;
+ notify_func = device_pause_response;
else
- notify_func = chipset_responders.device_resume;
+ notify_func = device_resume_response;
if (!notify_func)
return;
@@ -1206,7 +1200,8 @@ initiate_chipset_device_pause_resume(struct visor_device *dev, bool is_pause)
return;
}
- /* Note that even though both drv->pause() and drv->resume
+ /*
+ * Note that even though both drv->pause() and drv->resume
* specify a callback function, it is NOT necessary for us to
* increment our local module usage count. Reason is, there
* is already a linkage dependency between child function
@@ -1246,33 +1241,41 @@ initiate_chipset_device_pause_resume(struct visor_device *dev, bool is_pause)
}
}
-static void
+/**
+ * chipset_device_pause() - start a pause operation for a visor device
+ * @dev_info: struct visor_device identifying the device being paused
+ *
+ * Tell the subordinate function driver for a specific device to pause
+ * that device. Success/failure result is returned asynchronously
+ * via a callback function; see pause_state_change_complete().
+ */
+void
chipset_device_pause(struct visor_device *dev_info)
{
initiate_chipset_device_pause_resume(dev_info, true);
}
-static void
+/**
+ * chipset_device_resume() - start a resume operation for a visor device
+ * @dev_info: struct visor_device identifying the device being resumed
+ *
+ * Tell the subordinate function driver for a specific device to resume
+ * that device. Success/failure result is returned asynchronously
+ * via a callback function; see resume_state_change_complete().
+ */
+void
chipset_device_resume(struct visor_device *dev_info)
{
initiate_chipset_device_pause_resume(dev_info, false);
}
-struct channel_size_info {
- uuid_le guid;
- unsigned long min_size;
- unsigned long max_size;
-};
-
int
visorbus_init(void)
{
int err;
POSTCODE_LINUX_3(DRIVER_ENTRY_PC, 0, POSTCODE_SEVERITY_INFO);
- bus_device_info_init(&clientbus_driverinfo,
- "clientbus", "visorbus",
- VERSION, NULL);
+ bus_device_info_init(&clientbus_driverinfo, "clientbus", "visorbus");
err = create_bus_type();
if (err < 0) {
@@ -1280,19 +1283,7 @@ visorbus_init(void)
goto error;
}
- periodic_dev_workqueue = create_singlethread_workqueue("visorbus_dev");
- if (!periodic_dev_workqueue) {
- POSTCODE_LINUX_2(CREATE_WORKQUEUE_PC, DIAG_SEVERITY_ERR);
- err = -ENOMEM;
- goto error;
- }
-
- /* This enables us to receive notifications when devices appear for
- * which this service partition is to be a server for.
- */
- visorchipset_register_busdev(&chipset_notifiers,
- &chipset_responders,
- &chipset_driverinfo);
+ bus_device_info_init(&chipset_driverinfo, "chipset", "visorchipset");
return 0;
@@ -1306,20 +1297,8 @@ visorbus_exit(void)
{
struct list_head *listentry, *listtmp;
- visorchipset_register_busdev(NULL, NULL, NULL);
remove_all_visor_devices();
- flush_workqueue(periodic_dev_workqueue); /* better not be any work! */
- destroy_workqueue(periodic_dev_workqueue);
- periodic_dev_workqueue = NULL;
-
- if (periodic_test_workqueue) {
- cancel_delayed_work(&periodic_work);
- flush_workqueue(periodic_test_workqueue);
- destroy_workqueue(periodic_test_workqueue);
- periodic_test_workqueue = NULL;
- }
-
list_for_each_safe(listentry, listtmp, &list_all_bus_instances) {
struct visor_device *dev = list_entry(listentry,
struct visor_device,
@@ -1329,9 +1308,6 @@ visorbus_exit(void)
remove_bus_type();
}
-module_param_named(debug, visorbus_debug, int, S_IRUGO);
-MODULE_PARM_DESC(visorbus_debug, "1 to debug");
-
module_param_named(forcematch, visorbus_forcematch, int, S_IRUGO);
MODULE_PARM_DESC(visorbus_forcematch,
"1 to force a successful dev <--> drv match");
@@ -1339,6 +1315,3 @@ MODULE_PARM_DESC(visorbus_forcematch,
module_param_named(forcenomatch, visorbus_forcenomatch, int, S_IRUGO);
MODULE_PARM_DESC(visorbus_forcenomatch,
"1 to force an UNsuccessful dev <--> drv match");
-
-module_param_named(debugref, visorbus_debugref, int, S_IRUGO);
-MODULE_PARM_DESC(visorbus_debugref, "1 to debug reference counting");
diff --git a/drivers/staging/unisys/visorbus/visorbus_private.h b/drivers/staging/unisys/visorbus/visorbus_private.h
index 39edd2018453..15403fb52847 100644
--- a/drivers/staging/unisys/visorbus/visorbus_private.h
+++ b/drivers/staging/unisys/visorbus/visorbus_private.h
@@ -1,4 +1,4 @@
-/* visorchipset.h
+/* visorbus_private.h
*
* Copyright (C) 2010 - 2015 UNISYS CORPORATION
* All rights reserved.
@@ -14,55 +14,72 @@
* details.
*/
-#ifndef __VISORCHIPSET_H__
-#define __VISORCHIPSET_H__
+#ifndef __VISORBUS_PRIVATE_H__
+#define __VISORBUS_PRIVATE_H__
#include <linux/uuid.h>
+#include <linux/utsname.h>
#include "controlvmchannel.h"
-#include "vbusdeviceinfo.h"
-#include "vbushelper.h"
+#include "vbuschannel.h"
-/* These functions will be called from within visorchipset when certain
- * events happen. (The implementation of these functions is outside of
- * visorchipset.)
+/* TARGET_HOSTNAME specified as -DTARGET_HOSTNAME=\"thename\" on the
+ * command line
*/
-struct visorchipset_busdev_notifiers {
- void (*bus_create)(struct visor_device *bus_info);
- void (*bus_destroy)(struct visor_device *bus_info);
- void (*device_create)(struct visor_device *bus_info);
- void (*device_destroy)(struct visor_device *bus_info);
- void (*device_pause)(struct visor_device *bus_info);
- void (*device_resume)(struct visor_device *bus_info);
-};
-/* These functions live inside visorchipset, and will be called to indicate
- * responses to specific events (by code outside of visorchipset).
- * For now, the value for each response is simply either:
- * 0 = it worked
- * -1 = it failed
- */
-struct visorchipset_busdev_responders {
- void (*bus_create)(struct visor_device *p, int response);
- void (*bus_destroy)(struct visor_device *p, int response);
- void (*device_create)(struct visor_device *p, int response);
- void (*device_destroy)(struct visor_device *p, int response);
- void (*device_pause)(struct visor_device *p, int response);
- void (*device_resume)(struct visor_device *p, int response);
-};
+static inline void bus_device_info_init(
+ struct ultra_vbus_deviceinfo *bus_device_info_ptr,
+ const char *dev_type, const char *drv_name)
+{
+ memset(bus_device_info_ptr, 0, sizeof(struct ultra_vbus_deviceinfo));
+ snprintf(bus_device_info_ptr->devtype,
+ sizeof(bus_device_info_ptr->devtype),
+ "%s", (dev_type) ? dev_type : "unknownType");
+ snprintf(bus_device_info_ptr->drvname,
+ sizeof(bus_device_info_ptr->drvname),
+ "%s", (drv_name) ? drv_name : "unknownDriver");
+ snprintf(bus_device_info_ptr->infostrs,
+ sizeof(bus_device_info_ptr->infostrs), "kernel ver. %s",
+ utsname()->release);
+}
-/** Register functions (in the bus driver) to get called by visorchipset
- * whenever a bus or device appears for which this guest is to be the
- * client for. visorchipset will fill in <responders>, to indicate
- * functions the bus driver should call to indicate message responses.
- */
-void
-visorchipset_register_busdev(
- struct visorchipset_busdev_notifiers *notifiers,
- struct visorchipset_busdev_responders *responders,
- struct ultra_vbus_deviceinfo *driver_info);
+void chipset_bus_create(struct visor_device *bus_info);
+void chipset_bus_destroy(struct visor_device *bus_info);
+void chipset_device_create(struct visor_device *dev_info);
+void chipset_device_destroy(struct visor_device *dev_info);
+void chipset_device_pause(struct visor_device *dev_info);
+void chipset_device_resume(struct visor_device *dev_info);
+
+void bus_create_response(struct visor_device *p, int response);
+void bus_destroy_response(struct visor_device *p, int response);
+void device_create_response(struct visor_device *p, int response);
+void device_destroy_response(struct visor_device *p, int response);
+void device_resume_response(struct visor_device *p, int response);
+void device_pause_response(struct visor_device *p, int response);
-/* visorbus init and exit functions */
int visorbus_init(void);
void visorbus_exit(void);
+
+/* visorchannel access functions */
+
+struct visorchannel *visorchannel_create(u64 physaddr,
+ unsigned long channel_bytes,
+ gfp_t gfp, uuid_le guid);
+struct visorchannel *visorchannel_create_with_lock(u64 physaddr,
+ unsigned long channel_bytes,
+ gfp_t gfp, uuid_le guid);
+void visorchannel_destroy(struct visorchannel *channel);
+int visorchannel_read(struct visorchannel *channel, ulong offset,
+ void *local, ulong nbytes);
+int visorchannel_write(struct visorchannel *channel, ulong offset,
+ void *local, ulong nbytes);
+u64 visorchannel_get_physaddr(struct visorchannel *channel);
+ulong visorchannel_get_nbytes(struct visorchannel *channel);
+char *visorchannel_id(struct visorchannel *channel, char *s);
+char *visorchannel_zoneid(struct visorchannel *channel, char *s);
+u64 visorchannel_get_clientpartition(struct visorchannel *channel);
+int visorchannel_set_clientpartition(struct visorchannel *channel,
+ u64 partition_handle);
+char *visorchannel_uuid_id(uuid_le *guid, char *s);
+void __iomem *visorchannel_get_header(struct visorchannel *channel);
#endif
diff --git a/drivers/staging/unisys/visorbus/visorchannel.c b/drivers/staging/unisys/visorbus/visorchannel.c
index 43373582cf1d..300a65dc5c6c 100644
--- a/drivers/staging/unisys/visorbus/visorchannel.c
+++ b/drivers/staging/unisys/visorbus/visorchannel.c
@@ -15,14 +15,13 @@
*/
/*
- * This provides Supervisor channel communication primitives, which are
+ * This provides s-Par channel communication primitives, which are
* independent of the mechanism used to access the channel data.
*/
#include <linux/uuid.h>
#include <linux/io.h>
-#include "version.h"
#include "visorbus.h"
#include "controlvmchannel.h"
@@ -55,110 +54,6 @@ struct visorchannel {
uuid_le inst;
};
-/* Creates the struct visorchannel abstraction for a data area in memory,
- * but does NOT modify this data area.
- */
-static struct visorchannel *
-visorchannel_create_guts(u64 physaddr, unsigned long channel_bytes,
- gfp_t gfp, unsigned long off,
- uuid_le guid, bool needs_lock)
-{
- struct visorchannel *channel;
- int err;
- size_t size = sizeof(struct channel_header);
-
- if (physaddr == 0)
- return NULL;
-
- channel = kzalloc(sizeof(*channel), gfp);
- if (!channel)
- return NULL;
-
- channel->needs_lock = needs_lock;
- spin_lock_init(&channel->insert_lock);
- spin_lock_init(&channel->remove_lock);
-
- /* Video driver constains the efi framebuffer so it will get a
- * conflict resource when requesting its full mem region. Since
- * we are only using the efi framebuffer for video we can ignore
- * this. Remember that we haven't requested it so we don't try to
- * release later on.
- */
- channel->requested = request_mem_region(physaddr, size, MYDRVNAME);
- if (!channel->requested) {
- if (uuid_le_cmp(guid, spar_video_guid)) {
- /* Not the video channel we care about this */
- goto err_destroy_channel;
- }
- }
-
- channel->mapped = memremap(physaddr, size, MEMREMAP_WB);
- if (!channel->mapped) {
- release_mem_region(physaddr, size);
- goto err_destroy_channel;
- }
-
- channel->physaddr = physaddr;
- channel->nbytes = size;
-
- err = visorchannel_read(channel, 0, &channel->chan_hdr,
- sizeof(struct channel_header));
- if (err)
- goto err_destroy_channel;
-
- /* we had better be a CLIENT of this channel */
- if (channel_bytes == 0)
- channel_bytes = (ulong)channel->chan_hdr.size;
- if (uuid_le_cmp(guid, NULL_UUID_LE) == 0)
- guid = channel->chan_hdr.chtype;
-
- memunmap(channel->mapped);
- if (channel->requested)
- release_mem_region(channel->physaddr, channel->nbytes);
- channel->mapped = NULL;
- channel->requested = request_mem_region(channel->physaddr,
- channel_bytes, MYDRVNAME);
- if (!channel->requested) {
- if (uuid_le_cmp(guid, spar_video_guid)) {
- /* Different we care about this */
- goto err_destroy_channel;
- }
- }
-
- channel->mapped = memremap(channel->physaddr, channel_bytes,
- MEMREMAP_WB);
- if (!channel->mapped) {
- release_mem_region(channel->physaddr, channel_bytes);
- goto err_destroy_channel;
- }
-
- channel->nbytes = channel_bytes;
- channel->guid = guid;
- return channel;
-
-err_destroy_channel:
- visorchannel_destroy(channel);
- return NULL;
-}
-
-struct visorchannel *
-visorchannel_create(u64 physaddr, unsigned long channel_bytes,
- gfp_t gfp, uuid_le guid)
-{
- return visorchannel_create_guts(physaddr, channel_bytes, gfp, 0, guid,
- false);
-}
-EXPORT_SYMBOL_GPL(visorchannel_create);
-
-struct visorchannel *
-visorchannel_create_with_lock(u64 physaddr, unsigned long channel_bytes,
- gfp_t gfp, uuid_le guid)
-{
- return visorchannel_create_guts(physaddr, channel_bytes, gfp, 0, guid,
- true);
-}
-EXPORT_SYMBOL_GPL(visorchannel_create_with_lock);
-
void
visorchannel_destroy(struct visorchannel *channel)
{
@@ -171,21 +66,18 @@ visorchannel_destroy(struct visorchannel *channel)
}
kfree(channel);
}
-EXPORT_SYMBOL_GPL(visorchannel_destroy);
u64
visorchannel_get_physaddr(struct visorchannel *channel)
{
return channel->physaddr;
}
-EXPORT_SYMBOL_GPL(visorchannel_get_physaddr);
ulong
visorchannel_get_nbytes(struct visorchannel *channel)
{
return channel->nbytes;
}
-EXPORT_SYMBOL_GPL(visorchannel_get_nbytes);
char *
visorchannel_uuid_id(uuid_le *guid, char *s)
@@ -193,28 +85,24 @@ visorchannel_uuid_id(uuid_le *guid, char *s)
sprintf(s, "%pUL", guid);
return s;
}
-EXPORT_SYMBOL_GPL(visorchannel_uuid_id);
char *
visorchannel_id(struct visorchannel *channel, char *s)
{
return visorchannel_uuid_id(&channel->guid, s);
}
-EXPORT_SYMBOL_GPL(visorchannel_id);
char *
visorchannel_zoneid(struct visorchannel *channel, char *s)
{
return visorchannel_uuid_id(&channel->chan_hdr.zone_uuid, s);
}
-EXPORT_SYMBOL_GPL(visorchannel_zoneid);
u64
visorchannel_get_clientpartition(struct visorchannel *channel)
{
return channel->chan_hdr.partition_handle;
}
-EXPORT_SYMBOL_GPL(visorchannel_get_clientpartition);
int
visorchannel_set_clientpartition(struct visorchannel *channel,
@@ -223,8 +111,13 @@ visorchannel_set_clientpartition(struct visorchannel *channel,
channel->chan_hdr.partition_handle = partition_handle;
return 0;
}
-EXPORT_SYMBOL_GPL(visorchannel_set_clientpartition);
+/**
+ * visorchannel_get_uuid() - queries the UUID of the designated channel
+ * @channel: the channel to query
+ *
+ * Return: the UUID of the provided channel
+ */
uuid_le
visorchannel_get_uuid(struct visorchannel *channel)
{
@@ -243,7 +136,6 @@ visorchannel_read(struct visorchannel *channel, ulong offset,
return 0;
}
-EXPORT_SYMBOL_GPL(visorchannel_read);
int
visorchannel_write(struct visorchannel *channel, ulong offset,
@@ -265,156 +157,125 @@ visorchannel_write(struct visorchannel *channel, ulong offset,
return 0;
}
-EXPORT_SYMBOL_GPL(visorchannel_write);
-
-int
-visorchannel_clear(struct visorchannel *channel, ulong offset, u8 ch,
- ulong nbytes)
-{
- int err;
- int bufsize = PAGE_SIZE;
- int written = 0;
- u8 *buf;
-
- buf = (u8 *)__get_free_page(GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- memset(buf, ch, bufsize);
-
- while (nbytes > 0) {
- int thisbytes = bufsize;
-
- if (nbytes < thisbytes)
- thisbytes = nbytes;
- err = visorchannel_write(channel, offset + written,
- buf, thisbytes);
- if (err)
- goto out_free_page;
-
- written += thisbytes;
- nbytes -= thisbytes;
- }
- err = 0;
-
-out_free_page:
- free_page((unsigned long)buf);
- return err;
-}
-EXPORT_SYMBOL_GPL(visorchannel_clear);
void __iomem *
visorchannel_get_header(struct visorchannel *channel)
{
return (void __iomem *)&channel->chan_hdr;
}
-EXPORT_SYMBOL_GPL(visorchannel_get_header);
-/** Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a
- * channel header
+/*
+ * Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a
+ * channel header
*/
#define SIG_QUEUE_OFFSET(chan_hdr, q) \
((chan_hdr)->ch_space_offset + \
((q) * sizeof(struct signal_queue_header)))
-/** Return offset of a specific queue entry (data) from the beginning of a
- * channel header
+/*
+ * Return offset of a specific queue entry (data) from the beginning of a
+ * channel header
*/
#define SIG_DATA_OFFSET(chan_hdr, q, sig_hdr, slot) \
(SIG_QUEUE_OFFSET(chan_hdr, q) + (sig_hdr)->sig_base_offset + \
((slot) * (sig_hdr)->signal_size))
-/** Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back
- * into host memory
+/*
+ * Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back
+ * into host memory
*/
#define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD) \
- (visorchannel_write(channel, \
- SIG_QUEUE_OFFSET(&channel->chan_hdr, queue) +\
- offsetof(struct signal_queue_header, FIELD), \
- &((sig_hdr)->FIELD), \
- sizeof((sig_hdr)->FIELD)) >= 0)
+ visorchannel_write(channel, \
+ SIG_QUEUE_OFFSET(&channel->chan_hdr, queue) +\
+ offsetof(struct signal_queue_header, FIELD), \
+ &((sig_hdr)->FIELD), \
+ sizeof((sig_hdr)->FIELD))
-static bool
+static int
sig_read_header(struct visorchannel *channel, u32 queue,
struct signal_queue_header *sig_hdr)
{
- int err;
-
if (channel->chan_hdr.ch_space_offset < sizeof(struct channel_header))
- return false;
+ return -EINVAL;
/* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */
- err = visorchannel_read(channel,
- SIG_QUEUE_OFFSET(&channel->chan_hdr, queue),
- sig_hdr, sizeof(struct signal_queue_header));
- if (err)
- return false;
-
- return true;
+ return visorchannel_read(channel,
+ SIG_QUEUE_OFFSET(&channel->chan_hdr, queue),
+ sig_hdr, sizeof(struct signal_queue_header));
}
-static inline bool
+static inline int
sig_read_data(struct visorchannel *channel, u32 queue,
struct signal_queue_header *sig_hdr, u32 slot, void *data)
{
- int err;
int signal_data_offset = SIG_DATA_OFFSET(&channel->chan_hdr, queue,
sig_hdr, slot);
- err = visorchannel_read(channel, signal_data_offset,
- data, sig_hdr->signal_size);
- if (err)
- return false;
-
- return true;
+ return visorchannel_read(channel, signal_data_offset,
+ data, sig_hdr->signal_size);
}
-static inline bool
+static inline int
sig_write_data(struct visorchannel *channel, u32 queue,
struct signal_queue_header *sig_hdr, u32 slot, void *data)
{
- int err;
int signal_data_offset = SIG_DATA_OFFSET(&channel->chan_hdr, queue,
sig_hdr, slot);
- err = visorchannel_write(channel, signal_data_offset,
- data, sig_hdr->signal_size);
- if (err)
- return false;
-
- return true;
+ return visorchannel_write(channel, signal_data_offset,
+ data, sig_hdr->signal_size);
}
-static bool
+static int
signalremove_inner(struct visorchannel *channel, u32 queue, void *msg)
{
struct signal_queue_header sig_hdr;
+ int error;
+
+ error = sig_read_header(channel, queue, &sig_hdr);
+ if (error)
+ return error;
- if (!sig_read_header(channel, queue, &sig_hdr))
- return false;
if (sig_hdr.head == sig_hdr.tail)
- return false; /* no signals to remove */
+ return -EIO; /* no signals to remove */
sig_hdr.tail = (sig_hdr.tail + 1) % sig_hdr.max_slots;
- if (!sig_read_data(channel, queue, &sig_hdr, sig_hdr.tail, msg))
- return false;
+
+ error = sig_read_data(channel, queue, &sig_hdr, sig_hdr.tail, msg);
+ if (error)
+ return error;
+
sig_hdr.num_received++;
- /* For each data field in SIGNAL_QUEUE_HEADER that was modified,
+ /*
+ * For each data field in SIGNAL_QUEUE_HEADER that was modified,
* update host memory.
*/
mb(); /* required for channel synch */
- if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, tail))
- return false;
- if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_received))
- return false;
- return true;
+
+ error = SIG_WRITE_FIELD(channel, queue, &sig_hdr, tail);
+ if (error)
+ return error;
+ error = SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_received);
+ if (error)
+ return error;
+
+ return 0;
}
-bool
+/**
+ * visorchannel_signalremove() - removes a message from the designated
+ * channel/queue
+ * @channel: the channel the message will be removed from
+ * @queue: the queue the message will be removed from
+ * @msg: the message to remove
+ *
+ * Return: integer error code indicating the status of the removal
+ */
+int
visorchannel_signalremove(struct visorchannel *channel, u32 queue, void *msg)
{
- bool rc;
+ int rc;
unsigned long flags;
if (channel->needs_lock) {
@@ -429,6 +290,15 @@ visorchannel_signalremove(struct visorchannel *channel, u32 queue, void *msg)
}
EXPORT_SYMBOL_GPL(visorchannel_signalremove);
+/**
+ * visorchannel_signalempty() - checks if the designated channel/queue
+ * contains any messages
+ * @channel: the channel to query
+ * @queue: the queue in the channel to query
+ *
+ * Return: boolean indicating whether any messages in the designated
+ * channel/queue are present
+ */
bool
visorchannel_signalempty(struct visorchannel *channel, u32 queue)
{
@@ -439,7 +309,7 @@ visorchannel_signalempty(struct visorchannel *channel, u32 queue)
if (channel->needs_lock)
spin_lock_irqsave(&channel->remove_lock, flags);
- if (!sig_read_header(channel, queue, &sig_hdr))
+ if (sig_read_header(channel, queue, &sig_hdr))
rc = true;
if (sig_hdr.head == sig_hdr.tail)
rc = true;
@@ -450,13 +320,15 @@ visorchannel_signalempty(struct visorchannel *channel, u32 queue)
}
EXPORT_SYMBOL_GPL(visorchannel_signalempty);
-static bool
+static int
signalinsert_inner(struct visorchannel *channel, u32 queue, void *msg)
{
struct signal_queue_header sig_hdr;
+ int error;
- if (!sig_read_header(channel, queue, &sig_hdr))
- return false;
+ error = sig_read_header(channel, queue, &sig_hdr);
+ if (error)
+ return error;
sig_hdr.head = (sig_hdr.head + 1) % sig_hdr.max_slots;
if (sig_hdr.head == sig_hdr.tail) {
@@ -467,169 +339,176 @@ signalinsert_inner(struct visorchannel *channel, u32 queue, void *msg)
num_overflows),
&sig_hdr.num_overflows,
sizeof(sig_hdr.num_overflows));
- return false;
+ return -EIO;
}
- if (!sig_write_data(channel, queue, &sig_hdr, sig_hdr.head, msg))
- return false;
+ error = sig_write_data(channel, queue, &sig_hdr, sig_hdr.head, msg);
+ if (error)
+ return error;
sig_hdr.num_sent++;
- /* For each data field in SIGNAL_QUEUE_HEADER that was modified,
+ /*
+ * For each data field in SIGNAL_QUEUE_HEADER that was modified,
* update host memory.
*/
mb(); /* required for channel synch */
- if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, head))
- return false;
- if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_sent))
- return false;
- return true;
+ error = SIG_WRITE_FIELD(channel, queue, &sig_hdr, head);
+ if (error)
+ return error;
+ error = SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_sent);
+ if (error)
+ return error;
+
+ return 0;
}
-bool
-visorchannel_signalinsert(struct visorchannel *channel, u32 queue, void *msg)
+/**
+ * visorchannel_create_guts() - creates the struct visorchannel abstraction
+ * for a data area in memory, but does NOT modify
+ * this data area
+ * @physaddr: physical address of start of channel
+ * @channel_bytes: size of the channel in bytes; this may 0 if the channel has
+ * already been initialized in memory (which is true for all
+ * channels provided to guest environments by the s-Par
+ * back-end), in which case the actual channel size will be
+ * read from the channel header in memory
+ * @gfp: gfp_t to use when allocating memory for the data struct
+ * @guid: uuid that identifies channel type; this may 0 if the channel
+ * has already been initialized in memory (which is true for all
+ * channels provided to guest environments by the s-Par
+ * back-end), in which case the actual channel guid will be
+ * read from the channel header in memory
+ * @needs_lock: must specify true if you have multiple threads of execution
+ * that will be calling visorchannel methods of this
+ * visorchannel at the same time
+ *
+ * Return: pointer to visorchannel that was created if successful,
+ * otherwise NULL
+ */
+static struct visorchannel *
+visorchannel_create_guts(u64 physaddr, unsigned long channel_bytes,
+ gfp_t gfp, uuid_le guid, bool needs_lock)
{
- bool rc;
- unsigned long flags;
+ struct visorchannel *channel;
+ int err;
+ size_t size = sizeof(struct channel_header);
- if (channel->needs_lock) {
- spin_lock_irqsave(&channel->insert_lock, flags);
- rc = signalinsert_inner(channel, queue, msg);
- spin_unlock_irqrestore(&channel->insert_lock, flags);
- } else {
- rc = signalinsert_inner(channel, queue, msg);
+ if (physaddr == 0)
+ return NULL;
+
+ channel = kzalloc(sizeof(*channel), gfp);
+ if (!channel)
+ return NULL;
+
+ channel->needs_lock = needs_lock;
+ spin_lock_init(&channel->insert_lock);
+ spin_lock_init(&channel->remove_lock);
+
+ /*
+ * Video driver constains the efi framebuffer so it will get a
+ * conflict resource when requesting its full mem region. Since
+ * we are only using the efi framebuffer for video we can ignore
+ * this. Remember that we haven't requested it so we don't try to
+ * release later on.
+ */
+ channel->requested = request_mem_region(physaddr, size, MYDRVNAME);
+ if (!channel->requested) {
+ if (uuid_le_cmp(guid, spar_video_guid)) {
+ /* Not the video channel we care about this */
+ goto err_destroy_channel;
+ }
}
- return rc;
-}
-EXPORT_SYMBOL_GPL(visorchannel_signalinsert);
+ channel->mapped = memremap(physaddr, size, MEMREMAP_WB);
+ if (!channel->mapped) {
+ release_mem_region(physaddr, size);
+ goto err_destroy_channel;
+ }
-int
-visorchannel_signalqueue_slots_avail(struct visorchannel *channel, u32 queue)
-{
- struct signal_queue_header sig_hdr;
- u32 slots_avail, slots_used;
- u32 head, tail;
-
- if (!sig_read_header(channel, queue, &sig_hdr))
- return 0;
- head = sig_hdr.head;
- tail = sig_hdr.tail;
- if (head < tail)
- head = head + sig_hdr.max_slots;
- slots_used = head - tail;
- slots_avail = sig_hdr.max_signals - slots_used;
- return (int)slots_avail;
-}
-EXPORT_SYMBOL_GPL(visorchannel_signalqueue_slots_avail);
+ channel->physaddr = physaddr;
+ channel->nbytes = size;
-int
-visorchannel_signalqueue_max_slots(struct visorchannel *channel, u32 queue)
-{
- struct signal_queue_header sig_hdr;
+ err = visorchannel_read(channel, 0, &channel->chan_hdr,
+ sizeof(struct channel_header));
+ if (err)
+ goto err_destroy_channel;
+
+ /* we had better be a CLIENT of this channel */
+ if (channel_bytes == 0)
+ channel_bytes = (ulong)channel->chan_hdr.size;
+ if (uuid_le_cmp(guid, NULL_UUID_LE) == 0)
+ guid = channel->chan_hdr.chtype;
+
+ memunmap(channel->mapped);
+ if (channel->requested)
+ release_mem_region(channel->physaddr, channel->nbytes);
+ channel->mapped = NULL;
+ channel->requested = request_mem_region(channel->physaddr,
+ channel_bytes, MYDRVNAME);
+ if (!channel->requested) {
+ if (uuid_le_cmp(guid, spar_video_guid)) {
+ /* Different we care about this */
+ goto err_destroy_channel;
+ }
+ }
+
+ channel->mapped = memremap(channel->physaddr, channel_bytes,
+ MEMREMAP_WB);
+ if (!channel->mapped) {
+ release_mem_region(channel->physaddr, channel_bytes);
+ goto err_destroy_channel;
+ }
+
+ channel->nbytes = channel_bytes;
+ channel->guid = guid;
+ return channel;
- if (!sig_read_header(channel, queue, &sig_hdr))
- return 0;
- return (int)sig_hdr.max_signals;
+err_destroy_channel:
+ visorchannel_destroy(channel);
+ return NULL;
}
-EXPORT_SYMBOL_GPL(visorchannel_signalqueue_max_slots);
-static void
-sigqueue_debug(struct signal_queue_header *q, int which, struct seq_file *seq)
+struct visorchannel *
+visorchannel_create(u64 physaddr, unsigned long channel_bytes,
+ gfp_t gfp, uuid_le guid)
{
- seq_printf(seq, "Signal Queue #%d\n", which);
- seq_printf(seq, " VersionId = %lu\n", (ulong)q->version);
- seq_printf(seq, " Type = %lu\n", (ulong)q->chtype);
- seq_printf(seq, " oSignalBase = %llu\n",
- (long long)q->sig_base_offset);
- seq_printf(seq, " SignalSize = %lu\n", (ulong)q->signal_size);
- seq_printf(seq, " MaxSignalSlots = %lu\n",
- (ulong)q->max_slots);
- seq_printf(seq, " MaxSignals = %lu\n", (ulong)q->max_signals);
- seq_printf(seq, " FeatureFlags = %-16.16Lx\n",
- (long long)q->features);
- seq_printf(seq, " NumSignalsSent = %llu\n",
- (long long)q->num_sent);
- seq_printf(seq, " NumSignalsReceived = %llu\n",
- (long long)q->num_received);
- seq_printf(seq, " NumOverflows = %llu\n",
- (long long)q->num_overflows);
- seq_printf(seq, " Head = %lu\n", (ulong)q->head);
- seq_printf(seq, " Tail = %lu\n", (ulong)q->tail);
+ return visorchannel_create_guts(physaddr, channel_bytes, gfp, guid,
+ false);
}
-void
-visorchannel_debug(struct visorchannel *channel, int num_queues,
- struct seq_file *seq, u32 off)
+struct visorchannel *
+visorchannel_create_with_lock(u64 physaddr, unsigned long channel_bytes,
+ gfp_t gfp, uuid_le guid)
{
- u64 addr = 0;
- ulong nbytes = 0, nbytes_region = 0;
- struct channel_header hdr;
- struct channel_header *phdr = &hdr;
- int i = 0;
- int errcode = 0;
+ return visorchannel_create_guts(physaddr, channel_bytes, gfp, guid,
+ true);
+}
- if (!channel)
- return;
+/**
+ * visorchannel_signalinsert() - inserts a message into the designated
+ * channel/queue
+ * @channel: the channel the message will be added to
+ * @queue: the queue the message will be added to
+ * @msg: the message to insert
+ *
+ * Return: integer error code indicating the status of the insertion
+ */
+int
+visorchannel_signalinsert(struct visorchannel *channel, u32 queue, void *msg)
+{
+ int rc;
+ unsigned long flags;
- addr = visorchannel_get_physaddr(channel);
- nbytes_region = visorchannel_get_nbytes(channel);
- errcode = visorchannel_read(channel, off,
- phdr, sizeof(struct channel_header));
- if (errcode < 0) {
- seq_printf(seq,
- "Read of channel header failed with errcode=%d)\n",
- errcode);
- if (off == 0) {
- phdr = &channel->chan_hdr;
- seq_puts(seq, "(following data may be stale)\n");
- } else {
- return;
- }
+ if (channel->needs_lock) {
+ spin_lock_irqsave(&channel->insert_lock, flags);
+ rc = signalinsert_inner(channel, queue, msg);
+ spin_unlock_irqrestore(&channel->insert_lock, flags);
+ } else {
+ rc = signalinsert_inner(channel, queue, msg);
}
- nbytes = (ulong)(phdr->size);
- seq_printf(seq, "--- Begin channel @0x%-16.16Lx for 0x%lx bytes (region=0x%lx bytes) ---\n",
- addr + off, nbytes, nbytes_region);
- seq_printf(seq, "Type = %pUL\n", &phdr->chtype);
- seq_printf(seq, "ZoneGuid = %pUL\n", &phdr->zone_uuid);
- seq_printf(seq, "Signature = 0x%-16.16Lx\n",
- (long long)phdr->signature);
- seq_printf(seq, "LegacyState = %lu\n", (ulong)phdr->legacy_state);
- seq_printf(seq, "SrvState = %lu\n", (ulong)phdr->srv_state);
- seq_printf(seq, "CliStateBoot = %lu\n", (ulong)phdr->cli_state_boot);
- seq_printf(seq, "CliStateOS = %lu\n", (ulong)phdr->cli_state_os);
- seq_printf(seq, "HeaderSize = %lu\n", (ulong)phdr->header_size);
- seq_printf(seq, "Size = %llu\n", (long long)phdr->size);
- seq_printf(seq, "Features = 0x%-16.16llx\n",
- (long long)phdr->features);
- seq_printf(seq, "PartitionHandle = 0x%-16.16llx\n",
- (long long)phdr->partition_handle);
- seq_printf(seq, "Handle = 0x%-16.16llx\n",
- (long long)phdr->handle);
- seq_printf(seq, "VersionId = %lu\n", (ulong)phdr->version_id);
- seq_printf(seq, "oChannelSpace = %llu\n",
- (long long)phdr->ch_space_offset);
- if ((phdr->ch_space_offset == 0) || (errcode < 0))
- ;
- else
- for (i = 0; i < num_queues; i++) {
- struct signal_queue_header q;
-
- errcode = visorchannel_read(channel,
- off +
- phdr->ch_space_offset +
- (i * sizeof(q)),
- &q, sizeof(q));
- if (errcode < 0) {
- seq_printf(seq,
- "failed to read signal queue #%d from channel @0x%-16.16Lx errcode=%d\n",
- i, addr, errcode);
- continue;
- }
- sigqueue_debug(&q, i, seq);
- }
- seq_printf(seq, "--- End channel @0x%-16.16Lx for 0x%lx bytes ---\n",
- addr + off, nbytes);
+
+ return rc;
}
-EXPORT_SYMBOL_GPL(visorchannel_debug);
+EXPORT_SYMBOL_GPL(visorchannel_signalinsert);
diff --git a/drivers/staging/unisys/visorbus/visorchipset.c b/drivers/staging/unisys/visorbus/visorchipset.c
index d248c946a13b..59871495ea85 100644
--- a/drivers/staging/unisys/visorbus/visorchipset.c
+++ b/drivers/staging/unisys/visorbus/visorchipset.c
@@ -25,21 +25,12 @@
#include <linux/uuid.h>
#include <linux/crash_dump.h>
-#include "channel_guid.h"
-#include "controlvmchannel.h"
-#include "controlvmcompletionstatus.h"
-#include "guestlinuxdebug.h"
-#include "periodic_work.h"
-#include "version.h"
#include "visorbus.h"
#include "visorbus_private.h"
#include "vmcallinterface.h"
#define CURRENT_FILE_PC VISOR_CHIPSET_PC_visorchipset_main_c
-#define MAX_NAME_SIZE 128
-#define MAX_IP_SIZE 50
-#define MAXOUTSTANDINGCHANNELCOMMAND 256
#define POLLJIFFIES_CONTROLVMCHANNEL_FAST 1
#define POLLJIFFIES_CONTROLVMCHANNEL_SLOW 100
@@ -58,9 +49,6 @@
* Module parameters
*/
static int visorchipset_major;
-static int visorchipset_visorbusregwait = 1; /* default is on */
-static unsigned long controlvm_payload_bytes_buffered;
-static u32 dump_vhba_bus;
static int
visorchipset_open(struct inode *inode, struct file *file)
@@ -79,15 +67,15 @@ visorchipset_release(struct inode *inode, struct file *file)
return 0;
}
-/* 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.
-*/
+/*
+ * 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.
+ */
#define MIN_IDLE_SECONDS 10
static unsigned long poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
/* when we got our last controlvm message */
static unsigned long most_recent_message_jiffies;
-static int visorbusregistered;
struct parser_context {
unsigned long allocbytes;
@@ -99,51 +87,36 @@ struct parser_context {
};
static struct delayed_work periodic_controlvm_work;
-static DEFINE_SEMAPHORE(notifier_lock);
static struct cdev file_cdev;
static struct visorchannel **file_controlvm_channel;
-static struct controlvm_message_packet g_devicechangestate_packet;
-
-static LIST_HEAD(bus_info_list);
-static LIST_HEAD(dev_info_list);
static struct visorchannel *controlvm_channel;
/* Manages the request payload in the controlvm channel */
struct visor_controlvm_payload_info {
u8 *ptr; /* pointer to base address of payload pool */
- u64 offset; /* offset from beginning of controlvm
+ u64 offset; /*
+ * offset from beginning of controlvm
* channel to beginning of payload * pool
*/
u32 bytes; /* number of bytes in payload pool */
};
static struct visor_controlvm_payload_info controlvm_payload_info;
+static unsigned long controlvm_payload_bytes_buffered;
-/* The following globals are used to handle the scenario where we are unable to
- * offload the payload from a controlvm message due to memory requirements. In
+/*
+ * The following globals 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.
*/
static struct controlvm_message controlvm_pending_msg;
static bool controlvm_pending_msg_valid;
-/* This identifies a data buffer that has been received via a controlvm messages
- * in a remote --> local CONTROLVM_TRANSMIT_FILE conversation.
- */
-struct putfile_buffer_entry {
- struct list_head next; /* putfile_buffer_entry list */
- struct parser_context *parser_ctx; /* points to input data buffer */
-};
-
-/* List of struct putfile_request *, via next_putfile_request member.
- * Each entry in this list identifies an outstanding TRANSMIT_FILE
- * conversation.
- */
-static LIST_HEAD(putfile_request_list);
-
-/* This describes a buffer and its current state of transfer (e.g., how many
+/*
+ * This describes a buffer and its current state of transfer (e.g., how many
* bytes have already been supplied as putfile data, and how many bytes are
* remaining) for a putfile_request.
*/
@@ -155,8 +128,9 @@ struct putfile_active_buffer {
};
#define PUTFILE_REQUEST_SIG 0x0906101302281211
-/* This identifies a single remote --> local CONTROLVM_TRANSMIT_FILE
- * conversation. Structs of this type are dynamically linked into
+/*
+ * This identifies a single remote --> local CONTROLVM_TRANSMIT_FILE
+ * conversation. Structs of this type are dynamically linked into
* <Putfile_request_list>.
*/
struct putfile_request {
@@ -168,7 +142,8 @@ struct putfile_request {
/* link to next struct putfile_request */
struct list_head next_putfile_request;
- /* head of putfile_buffer_entry list, which describes the data to be
+ /*
+ * head of putfile_buffer_entry list, which describes the data to be
* supplied as putfile data;
* - this list is added to when controlvm messages come in that supply
* file data
@@ -184,11 +159,13 @@ struct putfile_request {
/* data not yet read within current putfile_buffer_entry */
struct putfile_active_buffer active_buf;
- /* <0 = failed, 0 = in-progress, >0 = successful; */
- /* note that this must be set with req_list_lock, and if you set <0, */
- /* it is your responsibility to also free up all of the other objects */
- /* in this struct (like input_buffer_list, active_buf.parser_ctx) */
- /* before releasing the lock */
+ /*
+ * <0 = failed, 0 = in-progress, >0 = successful;
+ * note that this must be set with req_list_lock, and if you set <0,
+ * it is your responsibility to also free up all of the other objects
+ * in this struct (like input_buffer_list, active_buf.parser_ctx)
+ * before releasing the lock
+ */
int completion_status;
};
@@ -199,289 +176,11 @@ struct parahotplug_request {
struct controlvm_message msg;
};
-static LIST_HEAD(parahotplug_request_list);
-static DEFINE_SPINLOCK(parahotplug_request_list_lock); /* lock for above */
-static void parahotplug_process_list(void);
-
-/* Manages the info for a CONTROLVM_DUMP_CAPTURESTATE /
- * CONTROLVM_REPORTEVENT.
- */
-static struct visorchipset_busdev_notifiers busdev_notifiers;
-
-static void bus_create_response(struct visor_device *p, int response);
-static void bus_destroy_response(struct visor_device *p, int response);
-static void device_create_response(struct visor_device *p, int response);
-static void device_destroy_response(struct visor_device *p, int response);
-static void device_resume_response(struct visor_device *p, int response);
-
-static void visorchipset_device_pause_response(struct visor_device *p,
- int response);
-
-static struct visorchipset_busdev_responders busdev_responders = {
- .bus_create = bus_create_response,
- .bus_destroy = bus_destroy_response,
- .device_create = device_create_response,
- .device_destroy = device_destroy_response,
- .device_pause = visorchipset_device_pause_response,
- .device_resume = device_resume_response,
-};
-
/* info for /dev/visorchipset */
-static dev_t major_dev = -1; /**< indicates major num for device */
+static dev_t major_dev = -1; /*< indicates major num for device */
/* prototypes for attributes */
static ssize_t toolaction_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-static ssize_t toolaction_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count);
-static DEVICE_ATTR_RW(toolaction);
-
-static ssize_t boottotool_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-static ssize_t boottotool_store(struct device *dev,
- struct device_attribute *attr, const char *buf,
- size_t count);
-static DEVICE_ATTR_RW(boottotool);
-
-static ssize_t error_show(struct device *dev, struct device_attribute *attr,
- char *buf);
-static ssize_t error_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count);
-static DEVICE_ATTR_RW(error);
-
-static ssize_t textid_show(struct device *dev, struct device_attribute *attr,
- char *buf);
-static ssize_t textid_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count);
-static DEVICE_ATTR_RW(textid);
-
-static ssize_t remaining_steps_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-static ssize_t remaining_steps_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count);
-static DEVICE_ATTR_RW(remaining_steps);
-
-static ssize_t devicedisabled_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count);
-static DEVICE_ATTR_WO(devicedisabled);
-
-static ssize_t deviceenabled_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t 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
-};
-
-static struct attribute_group visorchipset_install_group = {
- .name = "install",
- .attrs = visorchipset_install_attrs
-};
-
-static struct attribute *visorchipset_parahotplug_attrs[] = {
- &dev_attr_devicedisabled.attr,
- &dev_attr_deviceenabled.attr,
- NULL
-};
-
-static struct attribute_group visorchipset_parahotplug_group = {
- .name = "parahotplug",
- .attrs = visorchipset_parahotplug_attrs
-};
-
-static const struct attribute_group *visorchipset_dev_groups[] = {
- &visorchipset_install_group,
- &visorchipset_parahotplug_group,
- NULL
-};
-
-static void visorchipset_dev_release(struct device *dev)
-{
-}
-
-/* /sys/devices/platform/visorchipset */
-static struct platform_device visorchipset_platform_device = {
- .name = "visorchipset",
- .id = -1,
- .dev.groups = visorchipset_dev_groups,
- .dev.release = visorchipset_dev_release,
-};
-
-/* Function prototypes */
-static void controlvm_respond(struct controlvm_message_header *msg_hdr,
- int response);
-static void controlvm_respond_chipset_init(
- struct controlvm_message_header *msg_hdr, int response,
- enum ultra_chipset_feature features);
-static void controlvm_respond_physdev_changestate(
- struct controlvm_message_header *msg_hdr, int response,
- struct spar_segment_state state);
-
-static void parser_done(struct parser_context *ctx);
-
-static struct parser_context *
-parser_init_byte_stream(u64 addr, u32 bytes, bool local, bool *retry)
-{
- int allocbytes = sizeof(struct parser_context) + bytes;
- struct parser_context *ctx;
-
- if (retry)
- *retry = false;
-
- /*
- * alloc an 0 extra byte to ensure payload is
- * '\0'-terminated
- */
- allocbytes++;
- if ((controlvm_payload_bytes_buffered + bytes)
- > MAX_CONTROLVM_PAYLOAD_BYTES) {
- if (retry)
- *retry = true;
- return NULL;
- }
- ctx = kzalloc(allocbytes, GFP_KERNEL | __GFP_NORETRY);
- if (!ctx) {
- if (retry)
- *retry = true;
- return NULL;
- }
-
- ctx->allocbytes = allocbytes;
- ctx->param_bytes = bytes;
- ctx->curr = NULL;
- ctx->bytes_remaining = 0;
- ctx->byte_stream = false;
- if (local) {
- void *p;
-
- if (addr > virt_to_phys(high_memory - 1))
- goto err_finish_ctx;
- p = __va((unsigned long)(addr));
- memcpy(ctx->data, p, bytes);
- } else {
- void *mapping = memremap(addr, bytes, MEMREMAP_WB);
-
- if (!mapping)
- goto err_finish_ctx;
- memcpy(ctx->data, mapping, bytes);
- memunmap(mapping);
- }
-
- ctx->byte_stream = true;
- controlvm_payload_bytes_buffered += ctx->param_bytes;
-
- return ctx;
-
-err_finish_ctx:
- parser_done(ctx);
- return NULL;
-}
-
-static uuid_le
-parser_id_get(struct parser_context *ctx)
-{
- struct spar_controlvm_parameters_header *phdr = NULL;
-
- if (!ctx)
- return NULL_UUID_LE;
- phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
- return phdr->id;
-}
-
-/** Describes the state from the perspective of which controlvm messages have
- * been received for a bus or device.
- */
-
-enum PARSER_WHICH_STRING {
- PARSERSTRING_INITIATOR,
- PARSERSTRING_TARGET,
- PARSERSTRING_CONNECTION,
- PARSERSTRING_NAME, /* TODO: only PARSERSTRING_NAME is used ? */
-};
-
-static void
-parser_param_start(struct parser_context *ctx,
- enum PARSER_WHICH_STRING which_string)
-{
- struct spar_controlvm_parameters_header *phdr = NULL;
-
- if (!ctx)
- return;
-
- phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
- switch (which_string) {
- case PARSERSTRING_INITIATOR:
- ctx->curr = ctx->data + phdr->initiator_offset;
- ctx->bytes_remaining = phdr->initiator_length;
- break;
- case PARSERSTRING_TARGET:
- ctx->curr = ctx->data + phdr->target_offset;
- ctx->bytes_remaining = phdr->target_length;
- break;
- case PARSERSTRING_CONNECTION:
- ctx->curr = ctx->data + phdr->connection_offset;
- ctx->bytes_remaining = phdr->connection_length;
- break;
- case PARSERSTRING_NAME:
- ctx->curr = ctx->data + phdr->name_offset;
- ctx->bytes_remaining = phdr->name_length;
- break;
- default:
- break;
- }
-}
-
-static void parser_done(struct parser_context *ctx)
-{
- if (!ctx)
- return;
- controlvm_payload_bytes_buffered -= ctx->param_bytes;
- kfree(ctx);
-}
-
-static void *
-parser_string_get(struct parser_context *ctx)
-{
- u8 *pscan;
- unsigned long nscan;
- int value_length = -1;
- void *value = NULL;
- int i;
-
- if (!ctx)
- return NULL;
- pscan = ctx->curr;
- nscan = ctx->bytes_remaining;
- if (nscan == 0)
- return NULL;
- if (!pscan)
- return NULL;
- for (i = 0, value_length = -1; i < nscan; i++)
- if (pscan[i] == '\0') {
- value_length = i;
- break;
- }
- if (value_length < 0) /* '\0' was not included in the length */
- value_length = nscan;
- value = kmalloc(value_length + 1, GFP_KERNEL | __GFP_NORETRY);
- if (!value)
- return NULL;
- if (value_length > 0)
- memcpy(value, pscan, value_length);
- ((u8 *)(value))[value_length] = '\0';
- return value;
-}
-
-static ssize_t toolaction_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
@@ -513,6 +212,7 @@ static ssize_t toolaction_store(struct device *dev,
return ret;
return count;
}
+static DEVICE_ATTR_RW(toolaction);
static ssize_t boottotool_show(struct device *dev,
struct device_attribute *attr,
@@ -549,6 +249,7 @@ static ssize_t boottotool_store(struct device *dev,
return ret;
return count;
}
+static DEVICE_ATTR_RW(boottotool);
static ssize_t error_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -580,6 +281,7 @@ static ssize_t error_store(struct device *dev, struct device_attribute *attr,
return ret;
return count;
}
+static DEVICE_ATTR_RW(error);
static ssize_t textid_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -612,6 +314,7 @@ static ssize_t textid_store(struct device *dev, struct device_attribute *attr,
return ret;
return count;
}
+static DEVICE_ATTR_RW(textid);
static ssize_t remaining_steps_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -644,6 +347,103 @@ static ssize_t remaining_steps_store(struct device *dev,
return ret;
return count;
}
+static DEVICE_ATTR_RW(remaining_steps);
+
+static uuid_le
+parser_id_get(struct parser_context *ctx)
+{
+ struct spar_controlvm_parameters_header *phdr = NULL;
+
+ if (!ctx)
+ return NULL_UUID_LE;
+ phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
+ return phdr->id;
+}
+
+/*
+ * Describes the state from the perspective of which controlvm messages have
+ * been received for a bus or device.
+ */
+
+enum PARSER_WHICH_STRING {
+ PARSERSTRING_INITIATOR,
+ PARSERSTRING_TARGET,
+ PARSERSTRING_CONNECTION,
+ PARSERSTRING_NAME, /* TODO: only PARSERSTRING_NAME is used ? */
+};
+
+static void
+parser_param_start(struct parser_context *ctx,
+ enum PARSER_WHICH_STRING which_string)
+{
+ struct spar_controlvm_parameters_header *phdr = NULL;
+
+ if (!ctx)
+ return;
+
+ phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
+ switch (which_string) {
+ case PARSERSTRING_INITIATOR:
+ ctx->curr = ctx->data + phdr->initiator_offset;
+ ctx->bytes_remaining = phdr->initiator_length;
+ break;
+ case PARSERSTRING_TARGET:
+ ctx->curr = ctx->data + phdr->target_offset;
+ ctx->bytes_remaining = phdr->target_length;
+ break;
+ case PARSERSTRING_CONNECTION:
+ ctx->curr = ctx->data + phdr->connection_offset;
+ ctx->bytes_remaining = phdr->connection_length;
+ break;
+ case PARSERSTRING_NAME:
+ ctx->curr = ctx->data + phdr->name_offset;
+ ctx->bytes_remaining = phdr->name_length;
+ break;
+ default:
+ break;
+ }
+}
+
+static void parser_done(struct parser_context *ctx)
+{
+ if (!ctx)
+ return;
+ controlvm_payload_bytes_buffered -= ctx->param_bytes;
+ kfree(ctx);
+}
+
+static void *
+parser_string_get(struct parser_context *ctx)
+{
+ u8 *pscan;
+ unsigned long nscan;
+ int value_length = -1;
+ void *value = NULL;
+ int i;
+
+ if (!ctx)
+ return NULL;
+ pscan = ctx->curr;
+ nscan = ctx->bytes_remaining;
+ if (nscan == 0)
+ return NULL;
+ if (!pscan)
+ return NULL;
+ for (i = 0, value_length = -1; i < nscan; i++)
+ if (pscan[i] == '\0') {
+ value_length = i;
+ break;
+ }
+ if (value_length < 0) /* '\0' was not included in the length */
+ value_length = nscan;
+ value = kmalloc(value_length + 1, GFP_KERNEL | __GFP_NORETRY);
+ if (!value)
+ return NULL;
+ if (value_length > 0)
+ memcpy(value, pscan, value_length);
+ ((u8 *)(value))[value_length] = '\0';
+ return value;
+}
struct visor_busdev {
u32 bus_no;
@@ -683,32 +483,36 @@ struct visor_device *visorbus_get_device_by_id(u32 bus_no, u32 dev_no,
vdev = to_visor_device(dev);
return vdev;
}
-EXPORT_SYMBOL(visorbus_get_device_by_id);
-void
-visorchipset_register_busdev(
- struct visorchipset_busdev_notifiers *notifiers,
- struct visorchipset_busdev_responders *responders,
- struct ultra_vbus_deviceinfo *driver_info)
-{
- down(&notifier_lock);
- if (!notifiers) {
- memset(&busdev_notifiers, 0,
- sizeof(busdev_notifiers));
- visorbusregistered = 0; /* clear flag */
- } else {
- busdev_notifiers = *notifiers;
- visorbusregistered = 1; /* set flag */
+static void
+controlvm_init_response(struct controlvm_message *msg,
+ struct controlvm_message_header *msg_hdr, int response)
+{
+ 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);
}
- if (responders)
- *responders = busdev_responders;
- if (driver_info)
- bus_device_info_init(driver_info, "chipset", "visorchipset",
- VERSION, NULL);
+}
+
+static void
+controlvm_respond_chipset_init(struct controlvm_message_header *msg_hdr,
+ int response,
+ enum ultra_chipset_feature features)
+{
+ struct controlvm_message outmsg;
- up(&notifier_lock);
+ controlvm_init_response(&outmsg, msg_hdr, response);
+ outmsg.cmd.init_chipset.features = features;
+ if (visorchannel_signalinsert(controlvm_channel,
+ CONTROLVM_QUEUE_REQUEST, &outmsg)) {
+ return;
+ }
}
-EXPORT_SYMBOL_GPL(visorchipset_register_busdev);
static void
chipset_init(struct controlvm_message *inmsg)
@@ -725,14 +529,16 @@ chipset_init(struct controlvm_message *inmsg)
chipset_inited = 1;
POSTCODE_LINUX_2(CHIPSET_INIT_EXIT_PC, POSTCODE_SEVERITY_INFO);
- /* Set features to indicate we support parahotplug (if Command
+ /*
+ * Set features to indicate we support parahotplug (if Command
* also supports it).
*/
features =
inmsg->cmd.init_chipset.
features & ULTRA_CHIPSET_FEATURE_PARA_HOTPLUG;
- /* Set the "reply" bit so Command knows this is a
+ /*
+ * Set the "reply" bit so Command knows this is a
* features-aware driver.
*/
features |= ULTRA_CHIPSET_FEATURE_REPLY;
@@ -743,21 +549,6 @@ out_respond:
}
static void
-controlvm_init_response(struct controlvm_message *msg,
- struct controlvm_message_header *msg_hdr, int response)
-{
- 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);
- }
-}
-
-static void
controlvm_respond(struct controlvm_message_header *msg_hdr, int response)
{
struct controlvm_message outmsg;
@@ -766,23 +557,8 @@ controlvm_respond(struct controlvm_message_header *msg_hdr, int response)
if (outmsg.hdr.flags.test_message == 1)
return;
- if (!visorchannel_signalinsert(controlvm_channel,
- CONTROLVM_QUEUE_REQUEST, &outmsg)) {
- return;
- }
-}
-
-static void
-controlvm_respond_chipset_init(struct controlvm_message_header *msg_hdr,
- int response,
- enum ultra_chipset_feature features)
-{
- struct controlvm_message outmsg;
-
- controlvm_init_response(&outmsg, msg_hdr, response);
- outmsg.cmd.init_chipset.features = features;
- if (!visorchannel_signalinsert(controlvm_channel,
- CONTROLVM_QUEUE_REQUEST, &outmsg)) {
+ if (visorchannel_signalinsert(controlvm_channel,
+ CONTROLVM_QUEUE_REQUEST, &outmsg)) {
return;
}
}
@@ -796,8 +572,8 @@ static void controlvm_respond_physdev_changestate(
controlvm_init_response(&outmsg, msg_hdr, response);
outmsg.cmd.device_change_state.state = state;
outmsg.cmd.device_change_state.flags.phys_device = 1;
- if (!visorchannel_signalinsert(controlvm_channel,
- CONTROLVM_QUEUE_REQUEST, &outmsg)) {
+ if (visorchannel_signalinsert(controlvm_channel,
+ CONTROLVM_QUEUE_REQUEST, &outmsg)) {
return;
}
}
@@ -894,8 +670,8 @@ device_changestate_responder(enum controlvm_id cmd_id,
outmsg.cmd.device_change_state.dev_no = dev_no;
outmsg.cmd.device_change_state.state = response_state;
- if (!visorchannel_signalinsert(controlvm_channel,
- CONTROLVM_QUEUE_REQUEST, &outmsg))
+ if (visorchannel_signalinsert(controlvm_channel,
+ CONTROLVM_QUEUE_REQUEST, &outmsg))
return;
}
@@ -920,20 +696,20 @@ bus_epilog(struct visor_device *bus_info,
{
struct controlvm_message_header *pmsg_hdr = NULL;
- down(&notifier_lock);
-
if (!bus_info) {
- /* relying on a valid passed in response code */
- /* be lazy and re-use msg_hdr for this failure, is this ok?? */
+ /*
+ * relying on a valid passed in response code
+ * be lazy and re-use msg_hdr for this failure, is this ok??
+ */
pmsg_hdr = msg_hdr;
- goto out_respond_and_unlock;
+ goto out_respond;
}
if (bus_info->pending_msg_hdr) {
/* only non-NULL if dev is still waiting on a response */
response = -CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT;
pmsg_hdr = bus_info->pending_msg_hdr;
- goto out_respond_and_unlock;
+ goto out_respond;
}
if (need_response) {
@@ -942,7 +718,7 @@ bus_epilog(struct visor_device *bus_info,
POSTCODE_LINUX_4(MALLOC_FAILURE_PC, cmd,
bus_info->chipset_bus_no,
POSTCODE_SEVERITY_ERR);
- goto out_unlock;
+ return;
}
memcpy(pmsg_hdr, msg_hdr,
@@ -953,25 +729,16 @@ bus_epilog(struct visor_device *bus_info,
if (response == CONTROLVM_RESP_SUCCESS) {
switch (cmd) {
case CONTROLVM_BUS_CREATE:
- if (busdev_notifiers.bus_create) {
- (*busdev_notifiers.bus_create) (bus_info);
- goto out_unlock;
- }
+ chipset_bus_create(bus_info);
break;
case CONTROLVM_BUS_DESTROY:
- if (busdev_notifiers.bus_destroy) {
- (*busdev_notifiers.bus_destroy) (bus_info);
- goto out_unlock;
- }
+ chipset_bus_destroy(bus_info);
break;
}
}
-out_respond_and_unlock:
+out_respond:
bus_responder(cmd, pmsg_hdr, response);
-
-out_unlock:
- up(&notifier_lock);
}
static void
@@ -980,31 +747,29 @@ device_epilog(struct visor_device *dev_info,
struct controlvm_message_header *msg_hdr, int response,
bool need_response, bool for_visorbus)
{
- struct visorchipset_busdev_notifiers *notifiers;
struct controlvm_message_header *pmsg_hdr = NULL;
- notifiers = &busdev_notifiers;
-
- down(&notifier_lock);
if (!dev_info) {
- /* relying on a valid passed in response code */
- /* be lazy and re-use msg_hdr for this failure, is this ok?? */
+ /*
+ * relying on a valid passed in response code
+ * be lazy and re-use msg_hdr for this failure, is this ok??
+ */
pmsg_hdr = msg_hdr;
- goto out_respond_and_unlock;
+ goto out_respond;
}
if (dev_info->pending_msg_hdr) {
/* only non-NULL if dev is still waiting on a response */
response = -CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT;
pmsg_hdr = dev_info->pending_msg_hdr;
- goto out_respond_and_unlock;
+ goto out_respond;
}
if (need_response) {
pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL);
if (!pmsg_hdr) {
response = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
- goto out_respond_and_unlock;
+ goto out_respond;
}
memcpy(pmsg_hdr, msg_hdr,
@@ -1015,48 +780,34 @@ device_epilog(struct visor_device *dev_info,
if (response >= 0) {
switch (cmd) {
case CONTROLVM_DEVICE_CREATE:
- if (notifiers->device_create) {
- (*notifiers->device_create) (dev_info);
- goto out_unlock;
- }
+ chipset_device_create(dev_info);
break;
case CONTROLVM_DEVICE_CHANGESTATE:
/* ServerReady / ServerRunning / SegmentStateRunning */
if (state.alive == segment_state_running.alive &&
state.operating ==
segment_state_running.operating) {
- if (notifiers->device_resume) {
- (*notifiers->device_resume) (dev_info);
- goto out_unlock;
- }
+ chipset_device_resume(dev_info);
}
/* ServerNotReady / ServerLost / SegmentStateStandby */
else if (state.alive == segment_state_standby.alive &&
state.operating ==
segment_state_standby.operating) {
- /* technically this is standby case
+ /*
+ * technically this is standby case
* where server is lost
*/
- if (notifiers->device_pause) {
- (*notifiers->device_pause) (dev_info);
- goto out_unlock;
- }
+ chipset_device_pause(dev_info);
}
break;
case CONTROLVM_DEVICE_DESTROY:
- if (notifiers->device_destroy) {
- (*notifiers->device_destroy) (dev_info);
- goto out_unlock;
- }
+ chipset_device_destroy(dev_info);
break;
}
}
-out_respond_and_unlock:
+out_respond:
device_responder(cmd, pmsg_hdr, response);
-
-out_unlock:
- up(&notifier_lock);
}
static void
@@ -1103,10 +854,8 @@ bus_create(struct controlvm_message *inmsg)
goto out_bus_epilog;
}
bus_info->visorchannel = visorchannel;
- if (uuid_le_cmp(cmd->create_bus.bus_inst_uuid, spar_siovm_uuid) == 0) {
- dump_vhba_bus = bus_no;
+ if (uuid_le_cmp(cmd->create_bus.bus_inst_uuid, spar_siovm_uuid) == 0)
save_crash_message(inmsg, CRASH_BUS);
- }
POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, bus_no, POSTCODE_SEVERITY_INFO);
@@ -1303,11 +1052,19 @@ my_device_destroy(struct controlvm_message *inmsg)
inmsg->hdr.flags.response_expected == 1, 1);
}
-/* When provided with the physical address of the controlvm channel
+/**
+ * initialize_controlvm_payload_info() - init controlvm_payload_info struct
+ * @phys_addr: the physical address of controlvm channel
+ * @offset: the offset to payload
+ * @bytes: the size of the payload in bytes
+ * @info: the returning valid struct
+ *
+ * When provided with the physical address of the controlvm channel
* (phys_addr), the offset to the payload area we need to manage
* (offset), and the size of this payload area (bytes), fills in the
- * controlvm_payload_info struct. Returns true for success or false
- * for failure.
+ * controlvm_payload_info struct.
+ *
+ * Return: CONTROLVM_RESP_SUCCESS for success or a negative for failure
*/
static int
initialize_controlvm_payload_info(u64 phys_addr, u64 offset, u32 bytes,
@@ -1371,95 +1128,14 @@ initialize_controlvm_payload(void)
&controlvm_payload_info);
}
-/* Send ACTION=online for DEVPATH=/sys/devices/platform/visorchipset.
- * Returns CONTROLVM_RESP_xxx code.
- */
-static int
-visorchipset_chipset_ready(void)
-{
- kobject_uevent(&visorchipset_platform_device.dev.kobj, KOBJ_ONLINE);
- return CONTROLVM_RESP_SUCCESS;
-}
-
-static int
-visorchipset_chipset_selftest(void)
-{
- char env_selftest[20];
- char *envp[] = { env_selftest, NULL };
-
- sprintf(env_selftest, "SPARSP_SELFTEST=%d", 1);
- kobject_uevent_env(&visorchipset_platform_device.dev.kobj, KOBJ_CHANGE,
- envp);
- return CONTROLVM_RESP_SUCCESS;
-}
-
-/* Send ACTION=offline for DEVPATH=/sys/devices/platform/visorchipset.
- * Returns CONTROLVM_RESP_xxx code.
- */
-static int
-visorchipset_chipset_notready(void)
-{
- kobject_uevent(&visorchipset_platform_device.dev.kobj, KOBJ_OFFLINE);
- return CONTROLVM_RESP_SUCCESS;
-}
-
-static void
-chipset_ready(struct controlvm_message_header *msg_hdr)
-{
- int rc = visorchipset_chipset_ready();
-
- if (rc != CONTROLVM_RESP_SUCCESS)
- rc = -rc;
- if (msg_hdr->flags.response_expected)
- controlvm_respond(msg_hdr, rc);
-}
-
-static void
-chipset_selftest(struct controlvm_message_header *msg_hdr)
-{
- int rc = visorchipset_chipset_selftest();
-
- if (rc != CONTROLVM_RESP_SUCCESS)
- rc = -rc;
- if (msg_hdr->flags.response_expected)
- controlvm_respond(msg_hdr, rc);
-}
-
-static void
-chipset_notready(struct controlvm_message_header *msg_hdr)
-{
- int rc = visorchipset_chipset_notready();
-
- if (rc != CONTROLVM_RESP_SUCCESS)
- rc = -rc;
- if (msg_hdr->flags.response_expected)
- controlvm_respond(msg_hdr, rc);
-}
-
-/* This is your "one-stop" shop for grabbing the next message from the
- * CONTROLVM_QUEUE_EVENT queue in the controlvm channel.
- */
-static bool
-read_controlvm_event(struct controlvm_message *msg)
-{
- if (visorchannel_signalremove(controlvm_channel,
- CONTROLVM_QUEUE_EVENT, msg)) {
- /* got a message */
- if (msg->hdr.flags.test_message == 1)
- return false;
- return true;
- }
- return false;
-}
-
/*
- * The general parahotplug flow works as follows. The visorchipset
+ * The general parahotplug flow works as follows. The visorchipset
* driver receives a DEVICE_CHANGESTATE message from Command
- * specifying a physical device to enable or disable. The CONTROLVM
+ * 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
+ * device. The udev script then writes to
* /proc/visorchipset/parahotplug, which causes parahotplug_proc_write
* to get called, at which point the appropriate CONTROLVM message is
* retrieved from the list and responded to.
@@ -1467,9 +1143,11 @@ read_controlvm_event(struct controlvm_message *msg)
#define PARAHOTPLUG_TIMEOUT_MS 2000
-/*
- * Generate unique int to match an outstanding CONTROLVM message with a
- * udev script /proc response
+/**
+ * parahotplug_next_id() - generate unique int to match an outstanding CONTROLVM
+ * message with a udev script /proc response
+ *
+ * Return: a unique integer value
*/
static int
parahotplug_next_id(void)
@@ -1479,9 +1157,12 @@ parahotplug_next_id(void)
return atomic_inc_return(&id);
}
-/*
- * Returns the time (in jiffies) when a CONTROLVM message on the list
- * should expire -- PARAHOTPLUG_TIMEOUT_MS in the future
+/**
+ * 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)
*/
static unsigned long
parahotplug_next_expiration(void)
@@ -1489,9 +1170,13 @@ parahotplug_next_expiration(void)
return jiffies + msecs_to_jiffies(PARAHOTPLUG_TIMEOUT_MS);
}
-/*
- * Create a parahotplug_request, which is basically a wrapper for a
- * CONTROLVM_MESSAGE that we can stick on a list
+/**
+ * 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
*/
static struct parahotplug_request *
parahotplug_request_create(struct controlvm_message *msg)
@@ -1509,8 +1194,9 @@ parahotplug_request_create(struct controlvm_message *msg)
return req;
}
-/*
- * Free a parahotplug_request.
+/**
+ * parahotplug_request_destroy() - free a parahotplug_request
+ * @req: the request to deallocate
*/
static void
parahotplug_request_destroy(struct parahotplug_request *req)
@@ -1518,71 +1204,19 @@ parahotplug_request_destroy(struct parahotplug_request *req)
kfree(req);
}
-/*
- * Cause uevent to run the user level script to do the disable/enable
- * specified in (the CONTROLVM message in) the specified
- * parahotplug_request
- */
-static void
-parahotplug_request_kickoff(struct parahotplug_request *req)
-{
- struct controlvm_message_packet *cmd = &req->msg.cmd;
- char env_cmd[40], env_id[40], env_state[40], env_bus[40], env_dev[40],
- env_func[40];
- char *envp[] = {
- env_cmd, env_id, env_state, env_bus, env_dev, env_func, NULL
- };
-
- sprintf(env_cmd, "SPAR_PARAHOTPLUG=1");
- sprintf(env_id, "SPAR_PARAHOTPLUG_ID=%d", req->id);
- sprintf(env_state, "SPAR_PARAHOTPLUG_STATE=%d",
- cmd->device_change_state.state.active);
- sprintf(env_bus, "SPAR_PARAHOTPLUG_BUS=%d",
- cmd->device_change_state.bus_no);
- sprintf(env_dev, "SPAR_PARAHOTPLUG_DEVICE=%d",
- cmd->device_change_state.dev_no >> 3);
- sprintf(env_func, "SPAR_PARAHOTPLUG_FUNCTION=%d",
- cmd->device_change_state.dev_no & 0x7);
-
- kobject_uevent_env(&visorchipset_platform_device.dev.kobj, KOBJ_CHANGE,
- envp);
-}
-
-/*
- * Remove any request from the list that's been on there too long and
- * respond with an error.
- */
-static void
-parahotplug_process_list(void)
-{
- 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)
- controlvm_respond_physdev_changestate(
- &req->msg.hdr,
- CONTROLVM_RESP_ERROR_DEVICE_UDEV_TIMEOUT,
- req->msg.cmd.device_change_state.state);
- parahotplug_request_destroy(req);
- }
-
- spin_unlock(&parahotplug_request_list_lock);
-}
+static LIST_HEAD(parahotplug_request_list);
+static DEFINE_SPINLOCK(parahotplug_request_list_lock); /* lock for above */
-/*
+/**
+ * parahotplug_request_complete() - mark request as complete
+ * @id: the id of the request
+ * @active: indicates whether the request is assigned to active partition
+ *
* Called from the /proc handler, which means the user script has
- * finished the enable/disable. Find the matching identifier, and
+ * finished the enable/disable. Find the matching identifier, and
* respond to the CONTROLVM message with success.
+ *
+ * Return: 0 on success or -EINVAL on failure
*/
static int
parahotplug_request_complete(int id, u16 active)
@@ -1597,7 +1231,8 @@ parahotplug_request_complete(int id, u16 active)
struct parahotplug_request *req =
list_entry(pos, struct parahotplug_request, list);
if (req->id == id) {
- /* Found a match. Remove it from the list and
+ /*
+ * Found a match. Remove it from the list and
* respond.
*/
list_del(pos);
@@ -1616,8 +1251,142 @@ parahotplug_request_complete(int id, u16 active)
return -EINVAL;
}
-/*
- * Enables or disables a PCI device by kicking off a udev script
+/**
+ * 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);
+
+/**
+ * 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
+};
+
+static struct attribute_group visorchipset_install_group = {
+ .name = "install",
+ .attrs = visorchipset_install_attrs
+};
+
+static struct attribute *visorchipset_parahotplug_attrs[] = {
+ &dev_attr_devicedisabled.attr,
+ &dev_attr_deviceenabled.attr,
+ NULL
+};
+
+static struct attribute_group visorchipset_parahotplug_group = {
+ .name = "parahotplug",
+ .attrs = visorchipset_parahotplug_attrs
+};
+
+static const struct attribute_group *visorchipset_dev_groups[] = {
+ &visorchipset_install_group,
+ &visorchipset_parahotplug_group,
+ NULL
+};
+
+static void visorchipset_dev_release(struct device *dev)
+{
+}
+
+/* /sys/devices/platform/visorchipset */
+static struct platform_device visorchipset_platform_device = {
+ .name = "visorchipset",
+ .id = -1,
+ .dev.groups = visorchipset_dev_groups,
+ .dev.release = visorchipset_dev_release,
+};
+
+/**
+ * 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.
+ */
+static void
+parahotplug_request_kickoff(struct parahotplug_request *req)
+{
+ struct controlvm_message_packet *cmd = &req->msg.cmd;
+ char env_cmd[40], env_id[40], env_state[40], env_bus[40], env_dev[40],
+ env_func[40];
+ char *envp[] = {
+ env_cmd, env_id, env_state, env_bus, env_dev, env_func, NULL
+ };
+
+ sprintf(env_cmd, "SPAR_PARAHOTPLUG=1");
+ sprintf(env_id, "SPAR_PARAHOTPLUG_ID=%d", req->id);
+ sprintf(env_state, "SPAR_PARAHOTPLUG_STATE=%d",
+ cmd->device_change_state.state.active);
+ sprintf(env_bus, "SPAR_PARAHOTPLUG_BUS=%d",
+ cmd->device_change_state.bus_no);
+ sprintf(env_dev, "SPAR_PARAHOTPLUG_DEVICE=%d",
+ cmd->device_change_state.dev_no >> 3);
+ sprintf(env_func, "SPAR_PARAHOTPLUG_FUNCTION=%d",
+ cmd->device_change_state.dev_no & 0x7);
+
+ kobject_uevent_env(&visorchipset_platform_device.dev.kobj, KOBJ_CHANGE,
+ envp);
+}
+
+/**
+ * parahotplug_process_message() - enables or disables a PCI device by kicking
+ * off a udev script
+ * @inmsg: the message indicating whether to enable or disable
*/
static void
parahotplug_process_message(struct controlvm_message *inmsg)
@@ -1630,14 +1399,16 @@ parahotplug_process_message(struct controlvm_message *inmsg)
return;
if (inmsg->cmd.device_change_state.state.active) {
- /* For enable messages, just respond with success
- * right away. This is a bit of a hack, but there are
- * issues with the early enable messages we get (with
- * either the udev script not detecting that the device
- * is up, or not getting called at all). Fortunately
- * the messages that get lost don't matter anyway, as
- * devices are automatically enabled at
- * initialization.
+ /*
+ * For enable messages, just respond with success
+ * right away. This is a bit of a hack, but there are
+ * issues with the early enable messages we get (with
+ * either the udev script not detecting that the device
+ * is up, or not getting called at all). Fortunately
+ * the messages that get lost don't matter anyway, as
+ *
+ * devices are automatically enabled at
+ * initialization.
*/
parahotplug_request_kickoff(req);
controlvm_respond_physdev_changestate
@@ -1646,11 +1417,12 @@ parahotplug_process_message(struct controlvm_message *inmsg)
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.
- */
+ /*
+ * 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(&parahotplug_request_list_lock);
list_add_tail(&req->list, &parahotplug_request_list);
spin_unlock(&parahotplug_request_list_lock);
@@ -1659,113 +1431,77 @@ parahotplug_process_message(struct controlvm_message *inmsg)
}
}
-/* Process a controlvm message.
- * Return result:
- * 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.
+/**
+ * visorchipset_chipset_ready() - sends chipset_ready action
+ *
+ * Send ACTION=online for DEVPATH=/sys/devices/platform/visorchipset.
+ *
+ * Return: CONTROLVM_RESP_SUCCESS
*/
-static bool
-handle_command(struct controlvm_message inmsg, u64 channel_addr)
+static int
+visorchipset_chipset_ready(void)
{
- struct controlvm_message_packet *cmd = &inmsg.cmd;
- u64 parm_addr;
- u32 parm_bytes;
- struct parser_context *parser_ctx = NULL;
- bool local_addr;
- struct controlvm_message ackmsg;
+ kobject_uevent(&visorchipset_platform_device.dev.kobj, KOBJ_ONLINE);
+ return CONTROLVM_RESP_SUCCESS;
+}
- /* create parsing context if necessary */
- local_addr = (inmsg.hdr.flags.test_message == 1);
- if (channel_addr == 0)
- return true;
- parm_addr = channel_addr + inmsg.hdr.payload_vm_offset;
- parm_bytes = inmsg.hdr.payload_bytes;
+static int
+visorchipset_chipset_selftest(void)
+{
+ char env_selftest[20];
+ char *envp[] = { env_selftest, NULL };
- /* 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.
- */
- if (parm_addr && parm_bytes) {
- bool retry = false;
+ sprintf(env_selftest, "SPARSP_SELFTEST=%d", 1);
+ kobject_uevent_env(&visorchipset_platform_device.dev.kobj, KOBJ_CHANGE,
+ envp);
+ return CONTROLVM_RESP_SUCCESS;
+}
- parser_ctx =
- parser_init_byte_stream(parm_addr, parm_bytes,
- local_addr, &retry);
- if (!parser_ctx && retry)
- return false;
- }
+/**
+ * visorchipset_chipset_notready() - sends chipset_notready action
+ *
+ * Send ACTION=offline for DEVPATH=/sys/devices/platform/visorchipset.
+ *
+ * Return: CONTROLVM_RESP_SUCCESS
+ */
+static int
+visorchipset_chipset_notready(void)
+{
+ kobject_uevent(&visorchipset_platform_device.dev.kobj, KOBJ_OFFLINE);
+ return CONTROLVM_RESP_SUCCESS;
+}
- if (!local_addr) {
- controlvm_init_response(&ackmsg, &inmsg.hdr,
- CONTROLVM_RESP_SUCCESS);
- if (controlvm_channel)
- visorchannel_signalinsert(controlvm_channel,
- CONTROLVM_QUEUE_ACK,
- &ackmsg);
- }
- switch (inmsg.hdr.id) {
- case CONTROLVM_CHIPSET_INIT:
- chipset_init(&inmsg);
- break;
- case CONTROLVM_BUS_CREATE:
- bus_create(&inmsg);
- break;
- case CONTROLVM_BUS_DESTROY:
- bus_destroy(&inmsg);
- break;
- case CONTROLVM_BUS_CONFIGURE:
- bus_configure(&inmsg, parser_ctx);
- break;
- case CONTROLVM_DEVICE_CREATE:
- my_device_create(&inmsg);
- break;
- case CONTROLVM_DEVICE_CHANGESTATE:
- if (cmd->device_change_state.flags.phys_device) {
- 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);
- g_devicechangestate_packet = inmsg.cmd;
- break;
- }
- break;
- case CONTROLVM_DEVICE_DESTROY:
- my_device_destroy(&inmsg);
- break;
- case CONTROLVM_DEVICE_CONFIGURE:
- /* no op for now, 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(&inmsg.hdr);
- break;
- case CONTROLVM_CHIPSET_SELFTEST:
- chipset_selftest(&inmsg.hdr);
- break;
- case CONTROLVM_CHIPSET_STOP:
- chipset_notready(&inmsg.hdr);
- break;
- default:
- if (inmsg.hdr.flags.response_expected)
- controlvm_respond
- (&inmsg.hdr,
- -CONTROLVM_RESP_ERROR_MESSAGE_ID_UNKNOWN);
- break;
- }
+static void
+chipset_ready(struct controlvm_message_header *msg_hdr)
+{
+ int rc = visorchipset_chipset_ready();
- if (parser_ctx) {
- parser_done(parser_ctx);
- parser_ctx = NULL;
- }
- return true;
+ if (rc != CONTROLVM_RESP_SUCCESS)
+ rc = -rc;
+ if (msg_hdr->flags.response_expected)
+ controlvm_respond(msg_hdr, rc);
+}
+
+static void
+chipset_selftest(struct controlvm_message_header *msg_hdr)
+{
+ int rc = visorchipset_chipset_selftest();
+
+ if (rc != CONTROLVM_RESP_SUCCESS)
+ rc = -rc;
+ if (msg_hdr->flags.response_expected)
+ controlvm_respond(msg_hdr, rc);
+}
+
+static void
+chipset_notready(struct controlvm_message_header *msg_hdr)
+{
+ int rc = visorchipset_chipset_notready();
+
+ if (rc != CONTROLVM_RESP_SUCCESS)
+ rc = -rc;
+ if (msg_hdr->flags.response_expected)
+ controlvm_respond(msg_hdr, rc);
}
static inline unsigned int
@@ -1796,76 +1532,6 @@ static u64 controlvm_get_channel_address(void)
}
static void
-controlvm_periodic_work(struct work_struct *work)
-{
- struct controlvm_message inmsg;
- bool got_command = false;
- bool handle_command_failed = false;
-
- /* make sure visorbus server is registered for controlvm callbacks */
- if (visorchipset_visorbusregwait && !visorbusregistered)
- goto cleanup;
-
- while (visorchannel_signalremove(controlvm_channel,
- CONTROLVM_QUEUE_RESPONSE,
- &inmsg))
- ;
- if (!got_command) {
- if (controlvm_pending_msg_valid) {
- /* we throttled processing of a prior
- * msg, so try to process it again
- * rather than reading a new one
- */
- inmsg = controlvm_pending_msg;
- controlvm_pending_msg_valid = false;
- got_command = true;
- } else {
- got_command = read_controlvm_event(&inmsg);
- }
- }
-
- handle_command_failed = false;
- while (got_command && (!handle_command_failed)) {
- most_recent_message_jiffies = jiffies;
- if (handle_command(inmsg,
- visorchannel_get_physaddr
- (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;
- controlvm_pending_msg = inmsg;
- controlvm_pending_msg_valid = true;
- }
- }
-
- /* parahotplug_worker */
- parahotplug_process_list();
-
-cleanup:
-
- if (time_after(jiffies,
- most_recent_message_jiffies + (HZ * MIN_IDLE_SECONDS))) {
- /* it's been longer than MIN_IDLE_SECONDS since we
- * processed our last controlvm message; slow down the
- * polling
- */
- if (poll_jiffies != POLLJIFFIES_CONTROLVMCHANNEL_SLOW)
- poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_SLOW;
- } else {
- if (poll_jiffies != POLLJIFFIES_CONTROLVMCHANNEL_FAST)
- poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
- }
-
- schedule_delayed_work(&periodic_controlvm_work, poll_jiffies);
-}
-
-static void
setup_crash_devices_work_queue(struct work_struct *work)
{
struct controlvm_message local_crash_bus_msg;
@@ -1874,13 +1540,6 @@ setup_crash_devices_work_queue(struct work_struct *work)
u32 local_crash_msg_offset;
u16 local_crash_msg_count;
- /* make sure visorbus is registered for controlvm callbacks */
- if (visorchipset_visorbusregwait && !visorbusregistered) {
- poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_SLOW;
- schedule_delayed_work(&periodic_controlvm_work, poll_jiffies);
- return;
- }
-
POSTCODE_LINUX_2(CRASH_DEV_ENTRY_PC, POSTCODE_SEVERITY_INFO);
/* send init chipset msg */
@@ -1958,7 +1617,7 @@ setup_crash_devices_work_queue(struct work_struct *work)
POSTCODE_LINUX_2(CRASH_DEV_EXIT_PC, POSTCODE_SEVERITY_INFO);
}
-static void
+void
bus_create_response(struct visor_device *bus_info, int response)
{
if (response >= 0)
@@ -1971,7 +1630,7 @@ bus_create_response(struct visor_device *bus_info, int response)
bus_info->pending_msg_hdr = NULL;
}
-static void
+void
bus_destroy_response(struct visor_device *bus_info, int response)
{
bus_responder(CONTROLVM_BUS_DESTROY, bus_info->pending_msg_hdr,
@@ -1981,7 +1640,7 @@ bus_destroy_response(struct visor_device *bus_info, int response)
bus_info->pending_msg_hdr = NULL;
}
-static void
+void
device_create_response(struct visor_device *dev_info, int response)
{
if (response >= 0)
@@ -1994,7 +1653,7 @@ device_create_response(struct visor_device *dev_info, int response)
dev_info->pending_msg_hdr = NULL;
}
-static void
+void
device_destroy_response(struct visor_device *dev_info, int response)
{
device_responder(CONTROLVM_DEVICE_DESTROY, dev_info->pending_msg_hdr,
@@ -2004,9 +1663,9 @@ device_destroy_response(struct visor_device *dev_info, int response)
dev_info->pending_msg_hdr = NULL;
}
-static void
-visorchipset_device_pause_response(struct visor_device *dev_info,
- int response)
+void
+device_pause_response(struct visor_device *dev_info,
+ int response)
{
device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE,
dev_info, response,
@@ -2016,7 +1675,7 @@ visorchipset_device_pause_response(struct visor_device *dev_info,
dev_info->pending_msg_hdr = NULL;
}
-static void
+void
device_resume_response(struct visor_device *dev_info, int response)
{
device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE,
@@ -2027,40 +1686,6 @@ device_resume_response(struct visor_device *dev_info, int response)
dev_info->pending_msg_hdr = NULL;
}
-/* 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.
- */
-static ssize_t devicedisabled_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, 0);
- return count;
-}
-
-/* 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.
- */
-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 int
visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
{
@@ -2191,6 +1816,298 @@ visorchipset_file_cleanup(dev_t major_dev)
unregister_chrdev_region(major_dev, 1);
}
+static struct parser_context *
+parser_init_byte_stream(u64 addr, u32 bytes, bool local, bool *retry)
+{
+ int allocbytes = sizeof(struct parser_context) + bytes;
+ struct parser_context *ctx;
+
+ if (retry)
+ *retry = false;
+
+ /*
+ * alloc an 0 extra byte to ensure payload is
+ * '\0'-terminated
+ */
+ allocbytes++;
+ if ((controlvm_payload_bytes_buffered + bytes)
+ > MAX_CONTROLVM_PAYLOAD_BYTES) {
+ if (retry)
+ *retry = true;
+ return NULL;
+ }
+ ctx = kzalloc(allocbytes, GFP_KERNEL | __GFP_NORETRY);
+ if (!ctx) {
+ if (retry)
+ *retry = true;
+ return NULL;
+ }
+
+ ctx->allocbytes = allocbytes;
+ ctx->param_bytes = bytes;
+ ctx->curr = NULL;
+ ctx->bytes_remaining = 0;
+ ctx->byte_stream = false;
+ if (local) {
+ void *p;
+
+ if (addr > virt_to_phys(high_memory - 1))
+ goto err_finish_ctx;
+ p = __va((unsigned long)(addr));
+ memcpy(ctx->data, p, bytes);
+ } else {
+ void *mapping = memremap(addr, bytes, MEMREMAP_WB);
+
+ if (!mapping)
+ goto err_finish_ctx;
+ memcpy(ctx->data, mapping, bytes);
+ memunmap(mapping);
+ }
+
+ ctx->byte_stream = true;
+ controlvm_payload_bytes_buffered += ctx->param_bytes;
+
+ return ctx;
+
+err_finish_ctx:
+ parser_done(ctx);
+ return NULL;
+}
+
+/**
+ * handle_command() - process a controlvm message
+ * @inmsg: the message to process
+ * @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
+ */
+static bool
+handle_command(struct controlvm_message inmsg, u64 channel_addr)
+{
+ struct controlvm_message_packet *cmd = &inmsg.cmd;
+ u64 parm_addr;
+ u32 parm_bytes;
+ struct parser_context *parser_ctx = NULL;
+ bool local_addr;
+ struct controlvm_message ackmsg;
+
+ /* create parsing context if necessary */
+ local_addr = (inmsg.hdr.flags.test_message == 1);
+ if (channel_addr == 0)
+ return true;
+ 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.
+ */
+ if (parm_addr && parm_bytes) {
+ bool retry = false;
+
+ parser_ctx =
+ parser_init_byte_stream(parm_addr, parm_bytes,
+ local_addr, &retry);
+ if (!parser_ctx && retry)
+ return false;
+ }
+
+ if (!local_addr) {
+ controlvm_init_response(&ackmsg, &inmsg.hdr,
+ CONTROLVM_RESP_SUCCESS);
+ if (controlvm_channel)
+ visorchannel_signalinsert(controlvm_channel,
+ CONTROLVM_QUEUE_ACK,
+ &ackmsg);
+ }
+ switch (inmsg.hdr.id) {
+ case CONTROLVM_CHIPSET_INIT:
+ chipset_init(&inmsg);
+ break;
+ case CONTROLVM_BUS_CREATE:
+ bus_create(&inmsg);
+ break;
+ case CONTROLVM_BUS_DESTROY:
+ bus_destroy(&inmsg);
+ break;
+ case CONTROLVM_BUS_CONFIGURE:
+ bus_configure(&inmsg, parser_ctx);
+ break;
+ case CONTROLVM_DEVICE_CREATE:
+ my_device_create(&inmsg);
+ break;
+ case CONTROLVM_DEVICE_CHANGESTATE:
+ if (cmd->device_change_state.flags.phys_device) {
+ 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);
+ break;
+ }
+ break;
+ case CONTROLVM_DEVICE_DESTROY:
+ my_device_destroy(&inmsg);
+ break;
+ case CONTROLVM_DEVICE_CONFIGURE:
+ /* no op for now, 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(&inmsg.hdr);
+ break;
+ case CONTROLVM_CHIPSET_SELFTEST:
+ chipset_selftest(&inmsg.hdr);
+ break;
+ case CONTROLVM_CHIPSET_STOP:
+ chipset_notready(&inmsg.hdr);
+ break;
+ default:
+ if (inmsg.hdr.flags.response_expected)
+ controlvm_respond
+ (&inmsg.hdr,
+ -CONTROLVM_RESP_ERROR_MESSAGE_ID_UNKNOWN);
+ break;
+ }
+
+ if (parser_ctx) {
+ parser_done(parser_ctx);
+ parser_ctx = NULL;
+ }
+ return true;
+}
+
+/**
+ * read_controlvm_event() - retreives the next message from the
+ * CONTROLVM_QUEUE_EVENT queue in the controlvm
+ * channel
+ * @msg: pointer to the retrieved message
+ *
+ * Return: true if a valid message was retrieved or false otherwise
+ */
+static bool
+read_controlvm_event(struct controlvm_message *msg)
+{
+ if (!visorchannel_signalremove(controlvm_channel,
+ CONTROLVM_QUEUE_EVENT, msg)) {
+ /* got a message */
+ if (msg->hdr.flags.test_message == 1)
+ return false;
+ return true;
+ }
+ return false;
+}
+
+/**
+ * parahotplug_process_list() - remove any request from the list that's been on
+ * there too long and respond with an error
+ */
+static void
+parahotplug_process_list(void)
+{
+ 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)
+ controlvm_respond_physdev_changestate(
+ &req->msg.hdr,
+ CONTROLVM_RESP_ERROR_DEVICE_UDEV_TIMEOUT,
+ req->msg.cmd.device_change_state.state);
+ parahotplug_request_destroy(req);
+ }
+
+ spin_unlock(&parahotplug_request_list_lock);
+}
+
+static void
+controlvm_periodic_work(struct work_struct *work)
+{
+ struct controlvm_message inmsg;
+ bool got_command = false;
+ bool handle_command_failed = false;
+
+ while (!visorchannel_signalremove(controlvm_channel,
+ CONTROLVM_QUEUE_RESPONSE,
+ &inmsg))
+ ;
+ if (!got_command) {
+ if (controlvm_pending_msg_valid) {
+ /*
+ * we throttled processing of a prior
+ * msg, so try to process it again
+ * rather than reading a new one
+ */
+ inmsg = controlvm_pending_msg;
+ controlvm_pending_msg_valid = false;
+ got_command = true;
+ } else {
+ got_command = read_controlvm_event(&inmsg);
+ }
+ }
+
+ handle_command_failed = false;
+ while (got_command && (!handle_command_failed)) {
+ most_recent_message_jiffies = jiffies;
+ if (handle_command(inmsg,
+ visorchannel_get_physaddr
+ (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;
+ controlvm_pending_msg = inmsg;
+ controlvm_pending_msg_valid = true;
+ }
+ }
+
+ /* parahotplug_worker */
+ parahotplug_process_list();
+
+ if (time_after(jiffies,
+ most_recent_message_jiffies + (HZ * MIN_IDLE_SECONDS))) {
+ /*
+ * it's been longer than MIN_IDLE_SECONDS since we
+ * processed our last controlvm message; slow down the
+ * polling
+ */
+ if (poll_jiffies != POLLJIFFIES_CONTROLVMCHANNEL_SLOW)
+ poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_SLOW;
+ } else {
+ if (poll_jiffies != POLLJIFFIES_CONTROLVMCHANNEL_FAST)
+ poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
+ }
+
+ schedule_delayed_work(&periodic_controlvm_work, poll_jiffies);
+}
+
static int
visorchipset_init(struct acpi_device *acpi_device)
{
@@ -2202,7 +2119,6 @@ visorchipset_init(struct acpi_device *acpi_device)
if (!addr)
goto error;
- memset(&busdev_notifiers, 0, sizeof(busdev_notifiers));
memset(&controlvm_payload_info, 0, sizeof(controlvm_payload_info));
controlvm_channel = visorchannel_create_with_lock(addr, 0,
@@ -2341,15 +2257,10 @@ static void exit_unisys(void)
module_param_named(major, visorchipset_major, int, S_IRUGO);
MODULE_PARM_DESC(visorchipset_major,
"major device number to use for the device node");
-module_param_named(visorbusregwait, visorchipset_visorbusregwait, int, S_IRUGO);
-MODULE_PARM_DESC(visorchipset_visorbusregwait,
- "1 to have the module wait for the visor bus to register");
module_init(init_unisys);
module_exit(exit_unisys);
MODULE_AUTHOR("Unisys");
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Supervisor chipset driver for service partition: ver "
- VERSION);
-MODULE_VERSION(VERSION);
+MODULE_DESCRIPTION("s-Par visorbus driver for virtual device buses");
diff --git a/drivers/staging/unisys/visorbus/vmcallinterface.h b/drivers/staging/unisys/visorbus/vmcallinterface.h
index c043fa41ceda..86e695d5a441 100644
--- a/drivers/staging/unisys/visorbus/vmcallinterface.h
+++ b/drivers/staging/unisys/visorbus/vmcallinterface.h
@@ -20,11 +20,39 @@
* Virtualization. The VMCALLs are provided by Monitor and used by IO code
* running on IO Partitions.
*/
+static inline unsigned long
+__unisys_vmcall_gnuc(unsigned long tuple, unsigned long reg_ebx,
+ unsigned long reg_ecx)
+{
+ unsigned long result = 0;
+ unsigned int cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx;
-#ifdef __GNUC__
-#include "iovmcall_gnuc.h"
-#endif /* */
-#include "diagchannel.h"
+ cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx);
+ if (!(cpuid_ecx & 0x80000000))
+ return -EPERM;
+
+ __asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) :
+ "a"(tuple), "b"(reg_ebx), "c"(reg_ecx));
+ return result;
+}
+
+static inline unsigned long
+__unisys_extended_vmcall_gnuc(unsigned long long tuple,
+ unsigned long long reg_ebx,
+ unsigned long long reg_ecx,
+ unsigned long long reg_edx)
+{
+ unsigned long result = 0;
+ unsigned int cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx;
+
+ cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx);
+ if (!(cpuid_ecx & 0x80000000))
+ return -EPERM;
+
+ __asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) :
+ "a"(tuple), "b"(reg_ebx), "c"(reg_ecx), "d"(reg_edx));
+ return result;
+}
#ifdef VMCALL_IO_CONTROLVM_ADDR
#undef VMCALL_IO_CONTROLVM_ADDR
@@ -57,7 +85,6 @@ enum vmcall_monitor_interface_method_tuple { /* VMCALL identification tuples */
#define VMCALL_SUCCESS 0
#define VMCALL_SUCCESSFUL(result) (result == 0)
-#ifdef __GNUC__
#define unisys_vmcall(tuple, reg_ebx, reg_ecx) \
__unisys_vmcall_gnuc(tuple, reg_ebx, reg_ecx)
#define unisys_extended_vmcall(tuple, reg_ebx, reg_ecx, reg_edx) \
@@ -74,7 +101,6 @@ enum vmcall_monitor_interface_method_tuple { /* VMCALL identification tuples */
#define ISSUE_IO_VMCALL_POSTCODE_SEVERITY(postcode, severity) \
ISSUE_IO_EXTENDED_VMCALL(VMCALL_POST_CODE_LOGEVENT, severity, \
MDS_APPOS, postcode)
-#endif
/* Structures for IO VMCALLs */
@@ -89,4 +115,156 @@ struct vmcall_io_controlvm_addr_params {
u8 unused[4]; /* Unused Bytes in the 64-Bit Aligned Struct */
} __packed;
+/******* INFO ON ISSUE_POSTCODE_LINUX() BELOW *******/
+enum driver_pc { /* POSTCODE driver identifier tuples */
+ /* visorchipset driver files */
+ VISOR_CHIPSET_PC = 0xA0,
+ VISOR_CHIPSET_PC_controlvm_c = 0xA1,
+ VISOR_CHIPSET_PC_controlvm_cm2 = 0xA2,
+ VISOR_CHIPSET_PC_controlvm_direct_c = 0xA3,
+ VISOR_CHIPSET_PC_file_c = 0xA4,
+ VISOR_CHIPSET_PC_parser_c = 0xA5,
+ VISOR_CHIPSET_PC_testing_c = 0xA6,
+ VISOR_CHIPSET_PC_visorchipset_main_c = 0xA7,
+ VISOR_CHIPSET_PC_visorswitchbus_c = 0xA8,
+ /* visorbus driver files */
+ VISOR_BUS_PC = 0xB0,
+ VISOR_BUS_PC_businst_attr_c = 0xB1,
+ VISOR_BUS_PC_channel_attr_c = 0xB2,
+ VISOR_BUS_PC_devmajorminor_attr_c = 0xB3,
+ VISOR_BUS_PC_visorbus_main_c = 0xB4,
+ /* visorclientbus driver files */
+ VISOR_CLIENT_BUS_PC = 0xC0,
+ VISOR_CLIENT_BUS_PC_visorclientbus_main_c = 0xC1,
+ /* virt hba driver files */
+ VIRT_HBA_PC = 0xC2,
+ VIRT_HBA_PC_virthba_c = 0xC3,
+ /* virtpci driver files */
+ VIRT_PCI_PC = 0xC4,
+ VIRT_PCI_PC_virtpci_c = 0xC5,
+ /* virtnic driver files */
+ VIRT_NIC_PC = 0xC6,
+ VIRT_NIC_P_virtnic_c = 0xC7,
+ /* uislib driver files */
+ UISLIB_PC = 0xD0,
+ UISLIB_PC_uislib_c = 0xD1,
+ UISLIB_PC_uisqueue_c = 0xD2,
+ /* 0xD3 RESERVED */
+ UISLIB_PC_uisutils_c = 0xD4,
+};
+
+enum event_pc { /* POSTCODE event identifier tuples */
+ ATTACH_PORT_ENTRY_PC = 0x001,
+ ATTACH_PORT_FAILURE_PC = 0x002,
+ ATTACH_PORT_SUCCESS_PC = 0x003,
+ BUS_FAILURE_PC = 0x004,
+ BUS_CREATE_ENTRY_PC = 0x005,
+ BUS_CREATE_FAILURE_PC = 0x006,
+ BUS_CREATE_EXIT_PC = 0x007,
+ BUS_CONFIGURE_ENTRY_PC = 0x008,
+ BUS_CONFIGURE_FAILURE_PC = 0x009,
+ BUS_CONFIGURE_EXIT_PC = 0x00A,
+ CHIPSET_INIT_ENTRY_PC = 0x00B,
+ CHIPSET_INIT_SUCCESS_PC = 0x00C,
+ CHIPSET_INIT_FAILURE_PC = 0x00D,
+ CHIPSET_INIT_EXIT_PC = 0x00E,
+ CREATE_WORKQUEUE_PC = 0x00F,
+ CREATE_WORKQUEUE_FAILED_PC = 0x0A0,
+ CONTROLVM_INIT_FAILURE_PC = 0x0A1,
+ DEVICE_CREATE_ENTRY_PC = 0x0A2,
+ DEVICE_CREATE_FAILURE_PC = 0x0A3,
+ DEVICE_CREATE_SUCCESS_PC = 0x0A4,
+ DEVICE_CREATE_EXIT_PC = 0x0A5,
+ DEVICE_ADD_PC = 0x0A6,
+ DEVICE_REGISTER_FAILURE_PC = 0x0A7,
+ DEVICE_CHANGESTATE_ENTRY_PC = 0x0A8,
+ DEVICE_CHANGESTATE_FAILURE_PC = 0x0A9,
+ DEVICE_CHANGESTATE_EXIT_PC = 0x0AA,
+ DRIVER_ENTRY_PC = 0x0AB,
+ DRIVER_EXIT_PC = 0x0AC,
+ MALLOC_FAILURE_PC = 0x0AD,
+ QUEUE_DELAYED_WORK_PC = 0x0AE,
+ /* 0x0B7 RESERVED */
+ VBUS_CHANNEL_ENTRY_PC = 0x0B8,
+ VBUS_CHANNEL_FAILURE_PC = 0x0B9,
+ VBUS_CHANNEL_EXIT_PC = 0x0BA,
+ VHBA_CREATE_ENTRY_PC = 0x0BB,
+ VHBA_CREATE_FAILURE_PC = 0x0BC,
+ VHBA_CREATE_EXIT_PC = 0x0BD,
+ VHBA_CREATE_SUCCESS_PC = 0x0BE,
+ VHBA_COMMAND_HANDLER_PC = 0x0BF,
+ VHBA_PROBE_ENTRY_PC = 0x0C0,
+ VHBA_PROBE_FAILURE_PC = 0x0C1,
+ VHBA_PROBE_EXIT_PC = 0x0C2,
+ VNIC_CREATE_ENTRY_PC = 0x0C3,
+ VNIC_CREATE_FAILURE_PC = 0x0C4,
+ VNIC_CREATE_SUCCESS_PC = 0x0C5,
+ VNIC_PROBE_ENTRY_PC = 0x0C6,
+ VNIC_PROBE_FAILURE_PC = 0x0C7,
+ VNIC_PROBE_EXIT_PC = 0x0C8,
+ VPCI_CREATE_ENTRY_PC = 0x0C9,
+ VPCI_CREATE_FAILURE_PC = 0x0CA,
+ VPCI_CREATE_EXIT_PC = 0x0CB,
+ VPCI_PROBE_ENTRY_PC = 0x0CC,
+ VPCI_PROBE_FAILURE_PC = 0x0CD,
+ VPCI_PROBE_EXIT_PC = 0x0CE,
+ CRASH_DEV_ENTRY_PC = 0x0CF,
+ CRASH_DEV_EXIT_PC = 0x0D0,
+ CRASH_DEV_HADDR_NULL = 0x0D1,
+ CRASH_DEV_CONTROLVM_NULL = 0x0D2,
+ CRASH_DEV_RD_BUS_FAIULRE_PC = 0x0D3,
+ CRASH_DEV_RD_DEV_FAIULRE_PC = 0x0D4,
+ CRASH_DEV_BUS_NULL_FAILURE_PC = 0x0D5,
+ CRASH_DEV_DEV_NULL_FAILURE_PC = 0x0D6,
+ CRASH_DEV_CTRL_RD_FAILURE_PC = 0x0D7,
+ CRASH_DEV_COUNT_FAILURE_PC = 0x0D8,
+ SAVE_MSG_BUS_FAILURE_PC = 0x0D9,
+ SAVE_MSG_DEV_FAILURE_PC = 0x0DA,
+ CALLHOME_INIT_FAILURE_PC = 0x0DB
+};
+
+#define POSTCODE_SEVERITY_ERR DIAG_SEVERITY_ERR
+#define POSTCODE_SEVERITY_WARNING DIAG_SEVERITY_WARNING
+/* TODO-> Info currently doesn't show, so we set info=warning */
+#define POSTCODE_SEVERITY_INFO DIAG_SEVERITY_PRINT
+
+/* example call of POSTCODE_LINUX_2(VISOR_CHIPSET_PC, POSTCODE_SEVERITY_ERR);
+ * Please also note that the resulting postcode is in hex, so if you are
+ * searching for the __LINE__ number, convert it first to decimal. The line
+ * number combined with driver and type of call, will allow you to track down
+ * exactly what line an error occurred on, or where the last driver
+ * entered/exited from.
+ */
+
+/* BASE FUNCTIONS */
+#define POSTCODE_LINUX_A(DRIVER_PC, EVENT_PC, pc32bit, severity) \
+do { \
+ unsigned long long post_code_temp; \
+ post_code_temp = (((u64)DRIVER_PC) << 56) | (((u64)EVENT_PC) << 44) | \
+ ((((u64)__LINE__) & 0xFFF) << 32) | \
+ (((u64)pc32bit) & 0xFFFFFFFF); \
+ ISSUE_IO_VMCALL_POSTCODE_SEVERITY(post_code_temp, severity); \
+} while (0)
+
+#define POSTCODE_LINUX_B(DRIVER_PC, EVENT_PC, pc16bit1, pc16bit2, severity) \
+do { \
+ unsigned long long post_code_temp; \
+ post_code_temp = (((u64)DRIVER_PC) << 56) | (((u64)EVENT_PC) << 44) | \
+ ((((u64)__LINE__) & 0xFFF) << 32) | \
+ ((((u64)pc16bit1) & 0xFFFF) << 16) | \
+ (((u64)pc16bit2) & 0xFFFF); \
+ ISSUE_IO_VMCALL_POSTCODE_SEVERITY(post_code_temp, severity); \
+} while (0)
+
+/* MOST COMMON */
+#define POSTCODE_LINUX_2(EVENT_PC, severity) \
+ POSTCODE_LINUX_A(CURRENT_FILE_PC, EVENT_PC, 0x0000, severity)
+
+#define POSTCODE_LINUX_3(EVENT_PC, pc32bit, severity) \
+ POSTCODE_LINUX_A(CURRENT_FILE_PC, EVENT_PC, pc32bit, severity)
+
+#define POSTCODE_LINUX_4(EVENT_PC, pc16bit1, pc16bit2, severity) \
+ POSTCODE_LINUX_B(CURRENT_FILE_PC, EVENT_PC, pc16bit1, \
+ pc16bit2, severity)
+
#endif /* __IOMONINTF_H__ */
diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c
index 120ba2097e02..5a7a87efed27 100644
--- a/drivers/staging/unisys/visorhba/visorhba_main.c
+++ b/drivers/staging/unisys/visorhba/visorhba_main.c
@@ -36,21 +36,6 @@
#define MAX_PENDING_REQUESTS (MIN_NUMSIGNALS * 2)
#define VISORHBA_ERROR_COUNT 30
-static int visorhba_queue_command_lck(struct scsi_cmnd *scsicmd,
- void (*visorhba_cmnd_done)
- (struct scsi_cmnd *));
-#ifdef DEF_SCSI_QCMD
-static DEF_SCSI_QCMD(visorhba_queue_command)
-#else
-#define visorhba_queue_command visorhba_queue_command_lck
-#endif
-static int visorhba_probe(struct visor_device *dev);
-static void visorhba_remove(struct visor_device *dev);
-static int visorhba_pause(struct visor_device *dev,
- visorbus_state_complete_func complete_func);
-static int visorhba_resume(struct visor_device *dev,
- visorbus_state_complete_func complete_func);
-
static struct dentry *visorhba_debugfs_dir;
/* GUIDS for HBA channel type supported by this driver */
@@ -62,20 +47,6 @@ static struct visor_channeltype_descriptor visorhba_channel_types[] = {
{ NULL_UUID_LE, NULL }
};
-/* This is used to tell the visor bus driver which types of visor devices
- * we support, and what functions to call when a visor device that we support
- * is attached or removed.
- */
-static struct visor_driver visorhba_driver = {
- .name = "visorhba",
- .owner = THIS_MODULE,
- .channel_types = visorhba_channel_types,
- .probe = visorhba_probe,
- .remove = visorhba_remove,
- .pause = visorhba_pause,
- .resume = visorhba_resume,
- .channel_interrupt = NULL,
-};
MODULE_DEVICE_TABLE(visorbus, visorhba_channel_types);
MODULE_ALIAS("visorbus:" SPAR_VHBA_CHANNEL_PROTOCOL_UUID_STR);
@@ -364,9 +335,9 @@ static int forward_taskmgmt_command(enum task_mgmt_types tasktype,
dev_dbg(&scsidev->sdev_gendev,
"visorhba: initiating type=%d taskmgmt command\n", tasktype);
- if (!visorchannel_signalinsert(devdata->dev->visorchannel,
- IOCHAN_TO_IOPART,
- cmdrsp))
+ if (visorchannel_signalinsert(devdata->dev->visorchannel,
+ IOCHAN_TO_IOPART,
+ cmdrsp))
goto err_del_scsipending_ent;
/* It can take the Service Partition up to 35 seconds to complete
@@ -567,9 +538,9 @@ visorhba_queue_command_lck(struct scsi_cmnd *scsicmd,
}
cmdrsp->scsi.guest_phys_entries = scsi_sg_count(scsicmd);
- if (!visorchannel_signalinsert(devdata->dev->visorchannel,
- IOCHAN_TO_IOPART,
- cmdrsp))
+ if (visorchannel_signalinsert(devdata->dev->visorchannel,
+ IOCHAN_TO_IOPART,
+ cmdrsp))
/* queue must be full and we aren't going to wait */
goto err_del_scsipending_ent;
@@ -580,6 +551,12 @@ err_del_scsipending_ent:
return SCSI_MLQUEUE_DEVICE_BUSY;
}
+#ifdef DEF_SCSI_QCMD
+static DEF_SCSI_QCMD(visorhba_queue_command)
+#else
+#define visorhba_queue_command visorhba_queue_command_lck
+#endif
+
/**
* visorhba_slave_alloc - called when new disk is discovered
* @scsidev: New disk
@@ -950,9 +927,9 @@ drain_queue(struct uiscmdrsp *cmdrsp, struct visorhba_devdata *devdata)
struct scsi_cmnd *scsicmd;
while (1) {
- if (!visorchannel_signalremove(devdata->dev->visorchannel,
- IOCHAN_FROM_IOPART,
- cmdrsp))
+ if (visorchannel_signalremove(devdata->dev->visorchannel,
+ IOCHAN_FROM_IOPART,
+ cmdrsp))
break; /* queue empty */
if (cmdrsp->cmdtype == CMD_SCSI_TYPE) {
@@ -1186,6 +1163,21 @@ static void visorhba_remove(struct visor_device *dev)
debugfs_remove_recursive(devdata->debugfs_dir);
}
+/* This is used to tell the visor bus driver which types of visor devices
+ * we support, and what functions to call when a visor device that we support
+ * is attached or removed.
+ */
+static struct visor_driver visorhba_driver = {
+ .name = "visorhba",
+ .owner = THIS_MODULE,
+ .channel_types = visorhba_channel_types,
+ .probe = visorhba_probe,
+ .remove = visorhba_remove,
+ .pause = visorhba_pause,
+ .resume = visorhba_resume,
+ .channel_interrupt = NULL,
+};
+
/**
* visorhba_init - driver init routine
*
@@ -1228,4 +1220,4 @@ module_exit(visorhba_exit);
MODULE_AUTHOR("Unisys");
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("s-Par hba driver");
+MODULE_DESCRIPTION("s-Par HBA driver for virtual SCSI host busses");
diff --git a/drivers/staging/unisys/visorinput/ultrainputreport.h b/drivers/staging/unisys/visorinput/ultrainputreport.h
index 1bc3d2064080..53dde7c53809 100644
--- a/drivers/staging/unisys/visorinput/ultrainputreport.h
+++ b/drivers/staging/unisys/visorinput/ultrainputreport.h
@@ -17,8 +17,6 @@
#include <linux/types.h>
-#include "ultrainputreport.h"
-
/* Identifies mouse and keyboard activity which is specified by the firmware to
* the host using the cmsimpleinput protocol. @ingroup coretypes
*/
diff --git a/drivers/staging/unisys/visorinput/visorinput.c b/drivers/staging/unisys/visorinput/visorinput.c
index d67cd76327c0..6f94b646f7c5 100644
--- a/drivers/staging/unisys/visorinput/visorinput.c
+++ b/drivers/staging/unisys/visorinput/visorinput.c
@@ -29,9 +29,7 @@
#include <linux/kernel.h>
#include <linux/uuid.h>
-#include "version.h"
#include "visorbus.h"
-#include "channel.h"
#include "ultrainputreport.h"
/* Keyboard channel {c73416d0-b0b8-44af-b304-9d2ae99f1b3d} */
@@ -63,9 +61,10 @@ enum visorinput_device_type {
*/
struct visorinput_devdata {
struct visor_device *dev;
- struct rw_semaphore lock_visor_dev; /* lock for dev */
+ struct mutex lock_visor_dev; /* lock for dev */
struct input_dev *visorinput_dev;
bool paused;
+ bool interrupts_enabled;
unsigned int keycode_table_bytes; /* size of following array */
/* for keyboard devices: visorkbd_keycode[] + visorkbd_ext_keycode[] */
unsigned char keycode_table[0];
@@ -228,7 +227,21 @@ static int visorinput_open(struct input_dev *visorinput_dev)
return -EINVAL;
}
dev_dbg(&visorinput_dev->dev, "%s opened\n", __func__);
+
+ /*
+ * If we're not paused, really enable interrupts.
+ * Regardless of whether we are paused, set a flag indicating
+ * interrupts should be enabled so when we resume, interrupts
+ * will really be enabled.
+ */
+ mutex_lock(&devdata->lock_visor_dev);
+ devdata->interrupts_enabled = true;
+ if (devdata->paused)
+ goto out_unlock;
visorbus_enable_channel_interrupts(devdata->dev);
+
+out_unlock:
+ mutex_unlock(&devdata->lock_visor_dev);
return 0;
}
@@ -243,20 +256,35 @@ static void visorinput_close(struct input_dev *visorinput_dev)
return;
}
dev_dbg(&visorinput_dev->dev, "%s closed\n", __func__);
+
+ /*
+ * If we're not paused, really disable interrupts.
+ * Regardless of whether we are paused, set a flag indicating
+ * interrupts should be disabled so when we resume we will
+ * not re-enable them.
+ */
+
+ mutex_lock(&devdata->lock_visor_dev);
+ devdata->interrupts_enabled = false;
+ if (devdata->paused)
+ goto out_unlock;
visorbus_disable_channel_interrupts(devdata->dev);
+
+out_unlock:
+ mutex_unlock(&devdata->lock_visor_dev);
}
/*
- * register_client_keyboard() initializes and returns a Linux input node that
+ * setup_client_keyboard() initializes and returns a Linux input node that
* we can use to deliver keyboard inputs to Linux. We of course do this when
* we see keyboard inputs coming in on a keyboard channel.
*/
static struct input_dev *
-register_client_keyboard(void *devdata, /* opaque on purpose */
- unsigned char *keycode_table)
+setup_client_keyboard(void *devdata, /* opaque on purpose */
+ unsigned char *keycode_table)
{
- int i, error;
+ int i;
struct input_dev *visorinput_dev;
visorinput_dev = input_allocate_device();
@@ -290,18 +318,12 @@ register_client_keyboard(void *devdata, /* opaque on purpose */
visorinput_dev->close = visorinput_close;
input_set_drvdata(visorinput_dev, devdata); /* pre input_register! */
- error = input_register_device(visorinput_dev);
- if (error) {
- input_free_device(visorinput_dev);
- return NULL;
- }
return visorinput_dev;
}
static struct input_dev *
-register_client_mouse(void *devdata /* opaque on purpose */)
+setup_client_mouse(void *devdata /* opaque on purpose */)
{
- int error;
struct input_dev *visorinput_dev = NULL;
int xres, yres;
struct fb_info *fb0;
@@ -336,13 +358,6 @@ register_client_mouse(void *devdata /* opaque on purpose */)
visorinput_dev->open = visorinput_open;
visorinput_dev->close = visorinput_close;
input_set_drvdata(visorinput_dev, devdata); /* pre input_register! */
-
- error = input_register_device(visorinput_dev);
- if (error) {
- input_free_device(visorinput_dev);
- return NULL;
- }
-
input_set_capability(visorinput_dev, EV_REL, REL_WHEEL);
return visorinput_dev;
@@ -360,9 +375,19 @@ devdata_create(struct visor_device *dev, enum visorinput_device_type devtype)
devdata = kzalloc(sizeof(*devdata) + extra_bytes, GFP_KERNEL);
if (!devdata)
return NULL;
+ mutex_init(&devdata->lock_visor_dev);
+ mutex_lock(&devdata->lock_visor_dev);
devdata->dev = dev;
/*
+ * visorinput_open() can be called as soon as input_register_device()
+ * happens, and that will enable channel interrupts. Setting paused
+ * prevents us from getting into visorinput_channel_interrupt() prior
+ * to the device structure being totally initialized.
+ */
+ devdata->paused = true;
+
+ /*
* This is an input device in a client guest partition,
* so we need to create whatever input nodes are necessary to
* deliver our inputs to the guest OS.
@@ -374,23 +399,49 @@ devdata_create(struct visor_device *dev, enum visorinput_device_type devtype)
KEYCODE_TABLE_BYTES);
memcpy(devdata->keycode_table + KEYCODE_TABLE_BYTES,
visorkbd_ext_keycode, KEYCODE_TABLE_BYTES);
- devdata->visorinput_dev = register_client_keyboard
+ devdata->visorinput_dev = setup_client_keyboard
(devdata, devdata->keycode_table);
if (!devdata->visorinput_dev)
goto cleanups_register;
break;
case visorinput_mouse:
- devdata->visorinput_dev = register_client_mouse(devdata);
+ devdata->visorinput_dev = setup_client_mouse(devdata);
if (!devdata->visorinput_dev)
goto cleanups_register;
break;
}
- init_rwsem(&devdata->lock_visor_dev);
+ dev_set_drvdata(&dev->device, devdata);
+ mutex_unlock(&devdata->lock_visor_dev);
+
+ /*
+ * Device struct is completely set up now, with the exception of
+ * visorinput_dev being registered.
+ * We need to unlock before we register the device, because this
+ * can cause an on-stack call of visorinput_open(), which would
+ * deadlock if we had the lock.
+ */
+ if (input_register_device(devdata->visorinput_dev)) {
+ input_free_device(devdata->visorinput_dev);
+ goto err_kfree_devdata;
+ }
+
+ mutex_lock(&devdata->lock_visor_dev);
+ /*
+ * Establish calls to visorinput_channel_interrupt() if that is
+ * the desired state that we've kept track of in interrupts_enabled
+ * while the device was being created.
+ */
+ devdata->paused = false;
+ if (devdata->interrupts_enabled)
+ visorbus_enable_channel_interrupts(dev);
+ mutex_unlock(&devdata->lock_visor_dev);
return devdata;
cleanups_register:
+ mutex_unlock(&devdata->lock_visor_dev);
+err_kfree_devdata:
kfree(devdata);
return NULL;
}
@@ -398,7 +449,6 @@ cleanups_register:
static int
visorinput_probe(struct visor_device *dev)
{
- struct visorinput_devdata *devdata = NULL;
uuid_le guid;
enum visorinput_device_type devtype;
@@ -409,10 +459,9 @@ visorinput_probe(struct visor_device *dev)
devtype = visorinput_keyboard;
else
return -ENODEV;
- devdata = devdata_create(dev, devtype);
- if (!devdata)
+ visorbus_disable_channel_interrupts(dev);
+ if (!devdata_create(dev, devtype))
return -ENOMEM;
- dev_set_drvdata(&dev->device, devdata);
return 0;
}
@@ -431,6 +480,7 @@ visorinput_remove(struct visor_device *dev)
if (!devdata)
return;
+ mutex_lock(&devdata->lock_visor_dev);
visorbus_disable_channel_interrupts(dev);
/*
@@ -438,10 +488,10 @@ visorinput_remove(struct visor_device *dev)
* in visorinput_channel_interrupt()
*/
- down_write(&devdata->lock_visor_dev);
dev_set_drvdata(&dev->device, NULL);
+ mutex_unlock(&devdata->lock_visor_dev);
+
unregister_client_input(devdata->visorinput_dev);
- up_write(&devdata->lock_visor_dev);
kfree(devdata);
}
@@ -529,15 +579,9 @@ visorinput_channel_interrupt(struct visor_device *dev)
if (!devdata)
return;
- down_write(&devdata->lock_visor_dev);
- if (devdata->paused) /* don't touch device/channel when paused */
- goto out_locked;
-
visorinput_dev = devdata->visorinput_dev;
- if (!visorinput_dev)
- goto out_locked;
- while (visorchannel_signalremove(dev->visorchannel, 0, &r)) {
+ while (!visorchannel_signalremove(dev->visorchannel, 0, &r)) {
scancode = r.activity.arg1;
keycode = scancode_to_keycode(scancode);
switch (r.activity.action) {
@@ -611,8 +655,6 @@ visorinput_channel_interrupt(struct visor_device *dev)
break;
}
}
-out_locked:
- up_write(&devdata->lock_visor_dev);
}
static int
@@ -627,16 +669,24 @@ visorinput_pause(struct visor_device *dev,
goto out;
}
- down_write(&devdata->lock_visor_dev);
+ mutex_lock(&devdata->lock_visor_dev);
if (devdata->paused) {
rc = -EBUSY;
goto out_locked;
}
+ if (devdata->interrupts_enabled)
+ visorbus_disable_channel_interrupts(dev);
+
+ /*
+ * due to above, at this time no thread of execution will be
+ * in visorinput_channel_interrupt()
+ */
+
devdata->paused = true;
complete_func(dev, 0);
rc = 0;
out_locked:
- up_write(&devdata->lock_visor_dev);
+ mutex_unlock(&devdata->lock_visor_dev);
out:
return rc;
}
@@ -652,16 +702,25 @@ visorinput_resume(struct visor_device *dev,
rc = -ENODEV;
goto out;
}
- down_write(&devdata->lock_visor_dev);
+ mutex_lock(&devdata->lock_visor_dev);
if (!devdata->paused) {
rc = -EBUSY;
goto out_locked;
}
devdata->paused = false;
complete_func(dev, 0);
+
+ /*
+ * Re-establish calls to visorinput_channel_interrupt() if that is
+ * the desired state that we've kept track of in interrupts_enabled
+ * while the device was paused.
+ */
+ if (devdata->interrupts_enabled)
+ visorbus_enable_channel_interrupts(dev);
+
rc = 0;
out_locked:
- up_write(&devdata->lock_visor_dev);
+ mutex_unlock(&devdata->lock_visor_dev);
out:
return rc;
}
@@ -675,7 +734,6 @@ static struct visor_channeltype_descriptor visorinput_channel_types[] = {
static struct visor_driver visorinput_driver = {
.name = "visorinput",
- .vertag = NULL,
.owner = THIS_MODULE,
.channel_types = visorinput_channel_types,
.probe = visorinput_probe,
@@ -704,8 +762,7 @@ MODULE_DEVICE_TABLE(visorbus, visorinput_channel_types);
MODULE_AUTHOR("Unisys");
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("s-Par human input driver for guest Linux");
-MODULE_VERSION(VERSION);
+MODULE_DESCRIPTION("s-Par human input driver for virtual keyboard/mouse");
MODULE_ALIAS("visorbus:" SPAR_MOUSE_CHANNEL_PROTOCOL_UUID_STR);
MODULE_ALIAS("visorbus:" SPAR_KEYBOARD_CHANNEL_PROTOCOL_UUID_STR);
diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c
index a28388d3ddc2..136700756485 100644
--- a/drivers/staging/unisys/visornic/visornic_main.c
+++ b/drivers/staging/unisys/visornic/visornic_main.c
@@ -29,8 +29,6 @@
#include "iochannel.h"
#define VISORNIC_INFINITE_RSP_WAIT 0
-#define VISORNICSOPENMAX 32
-#define MAXDEVICES 16384
/* MAX_BUF = 64 lines x 32 MAXVNIC x 80 characters
* = 163840 bytes
@@ -38,27 +36,6 @@
#define MAX_BUF 163840
#define NAPI_WEIGHT 64
-static int visornic_probe(struct visor_device *dev);
-static void visornic_remove(struct visor_device *dev);
-static int visornic_pause(struct visor_device *dev,
- visorbus_state_complete_func complete_func);
-static int visornic_resume(struct visor_device *dev,
- visorbus_state_complete_func complete_func);
-
-/* DEBUGFS declarations */
-static ssize_t info_debugfs_read(struct file *file, char __user *buf,
- size_t len, loff_t *offset);
-static ssize_t enable_ints_write(struct file *file, const char __user *buf,
- size_t len, loff_t *ppos);
-static struct dentry *visornic_debugfs_dir;
-static const struct file_operations debugfs_info_fops = {
- .read = info_debugfs_read,
-};
-
-static const struct file_operations debugfs_enable_ints_fops = {
- .write = enable_ints_write,
-};
-
/* GUIDS for director channel type supported by this driver. */
static struct visor_channeltype_descriptor visornic_channel_types[] = {
/* Note that the only channel type we expect to be reported by the
@@ -77,23 +54,6 @@ MODULE_DEVICE_TABLE(visorbus, visornic_channel_types);
*/
MODULE_ALIAS("visorbus:" SPAR_VNIC_CHANNEL_PROTOCOL_UUID_STR);
-/* This is used to tell the visor bus driver which types of visor devices
- * we support, and what functions to call when a visor device that we support
- * is attached or removed.
- */
-static struct visor_driver visornic_driver = {
- .name = "visornic",
- .version = "1.0.0.0",
- .vertag = NULL,
- .owner = THIS_MODULE,
- .channel_types = visornic_channel_types,
- .probe = visornic_probe,
- .remove = visornic_remove,
- .pause = visornic_pause,
- .resume = visornic_resume,
- .channel_interrupt = NULL,
-};
-
struct chanstat {
unsigned long got_rcv;
unsigned long got_enbdisack;
@@ -181,9 +141,6 @@ struct visornic_devdata {
struct uiscmdrsp cmdrsp[SIZEOF_CMDRSP];
};
-static int visornic_poll(struct napi_struct *napi, int budget);
-static void poll_for_irq(unsigned long v);
-
/**
* visor_copy_fragsinfo_from_skb(
* @skb_in: skbuff that we are pulling the frags from
@@ -289,6 +246,10 @@ static ssize_t enable_ints_write(struct file *file,
return count;
}
+static const struct file_operations debugfs_enable_ints_fops = {
+ .write = enable_ints_write,
+};
+
/**
* visornic_serverdown_complete - IOPART went down, pause device
* @work: Work queue it was scheduled on
@@ -425,9 +386,9 @@ post_skb(struct uiscmdrsp *cmdrsp,
if ((cmdrsp->net.rcvpost.frag.pi_off + skb->len) <= PI_PAGE_SIZE) {
cmdrsp->net.type = NET_RCV_POST;
cmdrsp->cmdtype = CMD_NET_TYPE;
- if (visorchannel_signalinsert(devdata->dev->visorchannel,
- IOCHAN_TO_IOPART,
- cmdrsp)) {
+ if (!visorchannel_signalinsert(devdata->dev->visorchannel,
+ IOCHAN_TO_IOPART,
+ cmdrsp)) {
atomic_inc(&devdata->num_rcvbuf_in_iovm);
devdata->chstat.sent_post++;
} else {
@@ -454,9 +415,9 @@ send_enbdis(struct net_device *netdev, int state,
devdata->cmdrsp_rcv->net.enbdis.context = netdev;
devdata->cmdrsp_rcv->net.type = NET_RCV_ENBDIS;
devdata->cmdrsp_rcv->cmdtype = CMD_NET_TYPE;
- if (visorchannel_signalinsert(devdata->dev->visorchannel,
- IOCHAN_TO_IOPART,
- devdata->cmdrsp_rcv))
+ if (!visorchannel_signalinsert(devdata->dev->visorchannel,
+ IOCHAN_TO_IOPART,
+ devdata->cmdrsp_rcv))
devdata->chstat.sent_enbdis++;
}
@@ -920,8 +881,8 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_OK;
}
- if (!visorchannel_signalinsert(devdata->dev->visorchannel,
- IOCHAN_TO_IOPART, cmdrsp)) {
+ if (visorchannel_signalinsert(devdata->dev->visorchannel,
+ IOCHAN_TO_IOPART, cmdrsp)) {
netif_stop_queue(netdev);
spin_unlock_irqrestore(&devdata->priv_lock, flags);
devdata->busy_cnt++;
@@ -1522,6 +1483,11 @@ static ssize_t info_debugfs_read(struct file *file, char __user *buf,
return bytes_read;
}
+static struct dentry *visornic_debugfs_dir;
+static const struct file_operations debugfs_info_fops = {
+ .read = info_debugfs_read,
+};
+
/**
* send_rcv_posts_if_needed
* @devdata: visornic device
@@ -1573,9 +1539,9 @@ send_rcv_posts_if_needed(struct visornic_devdata *devdata)
static void
drain_resp_queue(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata)
{
- while (visorchannel_signalremove(devdata->dev->visorchannel,
- IOCHAN_FROM_IOPART,
- cmdrsp))
+ while (!visorchannel_signalremove(devdata->dev->visorchannel,
+ IOCHAN_FROM_IOPART,
+ cmdrsp))
;
}
@@ -1586,7 +1552,7 @@ drain_resp_queue(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata)
*
* Drain the respones queue of any responses from the IO partition.
* Process the responses as we get them.
- * Returns when response queue is empty or when the threadd stops.
+ * Returns when response queue is empty or when the thread stops.
*/
static void
service_resp_queue(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata,
@@ -1599,9 +1565,9 @@ service_resp_queue(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata,
/* TODO: CLIENT ACQUIRE -- Don't really need this at the
* moment
*/
- if (!visorchannel_signalremove(devdata->dev->visorchannel,
- IOCHAN_FROM_IOPART,
- cmdrsp))
+ if (visorchannel_signalremove(devdata->dev->visorchannel,
+ IOCHAN_FROM_IOPART,
+ cmdrsp))
break; /* queue empty */
switch (cmdrsp->net.type) {
@@ -2061,6 +2027,21 @@ static int visornic_resume(struct visor_device *dev,
return 0;
}
+/* This is used to tell the visor bus driver which types of visor devices
+ * we support, and what functions to call when a visor device that we support
+ * is attached or removed.
+ */
+static struct visor_driver visornic_driver = {
+ .name = "visornic",
+ .owner = THIS_MODULE,
+ .channel_types = visornic_channel_types,
+ .probe = visornic_probe,
+ .remove = visornic_remove,
+ .pause = visornic_pause,
+ .resume = visornic_resume,
+ .channel_interrupt = NULL,
+};
+
/**
* visornic_init - Init function
*
@@ -2115,5 +2096,4 @@ module_exit(visornic_cleanup);
MODULE_AUTHOR("Unisys");
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("sPAR nic driver for sparlinux: ver 1.0.0.0");
-MODULE_VERSION("1.0.0.0");
+MODULE_DESCRIPTION("s-Par NIC driver for virtual network devices");