diff options
Diffstat (limited to 'drivers/staging/unisys')
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(¬ifier_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(¬ifier_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(¬ifier_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(¬ifier_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(¬ifier_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(¬ifier_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(¶hotplug_request_list_lock); - - list_for_each_safe(pos, tmp, ¶hotplug_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(¶hotplug_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(¶hotplug_request_list_lock); list_add_tail(&req->list, ¶hotplug_request_list); spin_unlock(¶hotplug_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(¶hotplug_request_list_lock); + + list_for_each_safe(pos, tmp, ¶hotplug_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(¶hotplug_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"); |