diff options
29 files changed, 0 insertions, 9367 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 3ed62dcd144e..a62da6d0f943 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20183,14 +20183,6 @@ F: drivers/cdrom/cdrom.c F: include/linux/cdrom.h F: include/uapi/linux/cdrom.h -UNISYS S-PAR DRIVERS -M: David Kershner <david.kershner@unisys.com> -L: sparmaintainer@unisys.com (Unisys internal) -S: Supported -F: drivers/staging/unisys/ -F: drivers/visorbus/ -F: include/linux/visorbus.h - UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER R: Alim Akhtar <alim.akhtar@samsung.com> R: Avri Altman <avri.altman@wdc.com> diff --git a/drivers/Kconfig b/drivers/Kconfig index 8d6cd5d08722..0cbbe2c58648 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -225,8 +225,6 @@ source "drivers/mux/Kconfig" source "drivers/opp/Kconfig" -source "drivers/visorbus/Kconfig" - source "drivers/siox/Kconfig" source "drivers/slimbus/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 020780b6b4d2..e40942c0b445 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -181,7 +181,6 @@ obj-$(CONFIG_FPGA) += fpga/ obj-$(CONFIG_FSI) += fsi/ obj-$(CONFIG_TEE) += tee/ obj-$(CONFIG_MULTIPLEXER) += mux/ -obj-$(CONFIG_UNISYS_VISORBUS) += visorbus/ obj-$(CONFIG_SIOX) += siox/ obj-$(CONFIG_GNSS) += gnss/ obj-$(CONFIG_INTERCONNECT) += interconnect/ diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index fc274737053d..a4d9f39dde90 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -64,8 +64,6 @@ source "drivers/staging/gdm724x/Kconfig" source "drivers/staging/fwserial/Kconfig" -source "drivers/staging/unisys/Kconfig" - source "drivers/staging/clocking-wizard/Kconfig" source "drivers/staging/fbtft/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 65e317922e3f..a17a2aeaceba 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -22,7 +22,6 @@ obj-$(CONFIG_MFD_NVEC) += nvec/ obj-$(CONFIG_STAGING_BOARD) += board/ obj-$(CONFIG_LTE_GDM724X) += gdm724x/ obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/ -obj-$(CONFIG_UNISYSSPAR) += unisys/ obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/ obj-$(CONFIG_FB_TFT) += fbtft/ obj-$(CONFIG_MOST) += most/ diff --git a/drivers/staging/unisys/Documentation/ABI/sysfs-platform-visorchipset b/drivers/staging/unisys/Documentation/ABI/sysfs-platform-visorchipset deleted file mode 100644 index c2359de17eaf..000000000000 --- a/drivers/staging/unisys/Documentation/ABI/sysfs-platform-visorchipset +++ /dev/null @@ -1,89 +0,0 @@ -This file describes sysfs entries beneath /devices/platform/visorchipset. - -What: install/error -Date: 7/18/2014 -KernelVersion: TBD -Contact: sparmaintainer@unisys.com -Description: used to send the ID of a string that should be displayed on - s-Par's automatic installation progress screen when an error - is encountered during installation. This field has no effect - if not in installation mode. -Users: sparmaintainer@unisys.com - -What: install/remainingsteps -Date: 7/18/2014 -KernelVersion: TBD -Contact: sparmaintainer@unisys.com -Description: used to set the value of the progress bar on the s-Par automatic - installation progress screen. This field has no effect if not in - installation mode. -Users: sparmaintainer@unisys.com - -What: install/textid -Date: 7/18/2014 -KernelVersion: TBD -Contact: sparmaintainer@unisys.com -Description: used to send the ID of a string that should be displayed on - s-Par's automatic installation progress screen. Setting this - field when not in installation mode (boottotool was set on - the previous guest boot) has no effect. -Users: sparmaintainer@unisys.com - -What: install/boottotool -Date: 7/18/2014 -KernelVersion: TBD -Contact: sparmaintainer@unisys.com -Description: The boottotool flag controls s-Par behavior on the next boot of - this guest. Setting the flag will cause the guest to boot from - the utility and installation image, which will use the value in - the toolaction field to determine what operation is being - requested. -Users: sparmaintainer@unisys.com - -What: install/toolaction -Date: 7/18/2014 -KernelVersion: TBD -Contact: sparmaintainer@unisys.com -Description: This field is used to tell s-Par which type of recovery tool - action to perform on the next guest boot-up. The meaning of the - value is dependent on the type of installation software used to - commission the guest. -Users: sparmaintainer@unisys.com - -What: parahotplug/deviceenabled -Date: 7/18/2014 -KernelVersion: TBD -Contact: sparmaintainer@unisys.com -Description: This entry is used by a Unisys support script installed on the - guest, and triggered by a udev event. The support script is - responsible for enabling and disabling SR-IOV devices when the - PF device is being recovered in another guest. - - Some SR-IOV devices have problems when the PF is reset without - first disabling all VFs attached to that PF. s-Par handles this - situation by sending a message to guests using these VFs, and - the script will disable the device. When the PF is recovered, - another message is sent to the guests to re-enable the VFs. - - The parahotplug/deviceenabled interface is used to acknowledge - the recovery message. -Users: sparmaintainer@unisys.com - -What: parahotplug/devicedisabled -Date: 7/18/2014 -KernelVersion: TBD -Contact: sparmaintainer@unisys.com -Description: This entry is used by a Unisys support script installed on the - guest, and triggered by a udev event. The support script is - responsible for enabling and disabling SR-IOV devices when the - PF device is being recovered in another guest. - - Some SR-IOV devices have problems when the PF is reset without - first disabling all VFs attached to that PF. s-Par handles this - situation by sending a message to guests using these VFs, and - the script will disable the device. When the PF is recovered, - another message is sent to the guests to re-enable the VFs. - - The parahotplug/devicedisaabled interface is used to acknowledge - the initial recovery message. -Users: sparmaintainer@unisys.com diff --git a/drivers/staging/unisys/Documentation/overview.txt b/drivers/staging/unisys/Documentation/overview.txt deleted file mode 100644 index cf29f884cbe0..000000000000 --- a/drivers/staging/unisys/Documentation/overview.txt +++ /dev/null @@ -1,337 +0,0 @@ -1. Overview ------------ - -This document describes the driver set for Unisys Secure Partitioning -(s-Par(R)). - -s-Par is firmware that provides hardware partitioning capabilities for -splitting large-scale Intel x86 servers into multiple isolated -partitions. s-Par provides a set of para-virtualized device drivers to -allow guest partitions on the same server to share devices that would -normally be unsharable, specifically: - -* visornic - network interface -* visorhba - scsi disk adapter -* visorinput - keyboard and mouse - -These drivers conform to the standard Linux bus/device model described -within Documentation/driver-api/driver-model/, and utilize a driver named -visorbus to present the virtual busses involved. Drivers in the 'visor*' -driver set are commonly referred to as "guest drivers" or "client drivers". -All drivers except visorbus expose a device of a specific usable class to the -Linux guest environment (e.g., block, network, or input), and are collectively -referred to as "function drivers". - -The back-end for each device is owned and managed by a small, -single-purpose service partition in the s-Par firmware, which communicates -with each guest partition sharing that device through an area of shared memory -called a "channel". In s-Par nomenclature, the back-end is often referred to -as the "service partition", "IO partition" (for virtual network and scsi disk -devices), or "console partition" (for virtual keyboard and mouse devices). - -Each virtual device requires exactly 1 dedicated channel, which the guest -driver and back-end use to communicate. The hypervisor need not intervene -(other than normal interrupt handling) in the interactions that occur across -this channel. - -NOT covered in this document: - -* s-Par also supports sharing physical PCI adapters via SR-IOV, but - because this requires no specific support in the guest partitions, it will - not be discussed in this document. Shared SR-IOV devices should be used - wherever possible for highest performance. - -* Because the s-Par back-end provides a standard EFI framebuffer to each - guest, the already-existing efifb Linux driver is used to provide guest - video access. Thus, the only s-Par-unique support that is necessary to - provide a guest graphics console are for keyboard and mouse (via visorinput). - - -2. Driver Descriptions ----------------------- - -2.1. visorbus -------------- - -2.1.1. Overview ---------------- - -The visorbus driver handles the virtual busses on which all of the virtual -devices reside. It provides a registration function named -visorbus_register_visor_driver() that is called by each of the function -drivers at initialization time, which the function driver uses to tell -visorbus about the device classes (via specifying a list of device type -GUIDs) it wants to handle. For use by function drivers, visorbus provides -implementation for struct visor_driver and struct visor_device, as well -as utility functions for communicating with the back-end. - -visorbus is associated with ACPI id "PNP0A07" in modules.alias, so if built -as a module it will typically be loaded automatically via standard udev or -systemd (God help us) configurations. - -visorbus can similarly force auto-loading of function drivers for virtual -devices it discovers, as it includes a MODALIAS environment variable of this -form in the hotplug uevent environment when each virtual device is -discovered: - - visorbus:<device type GUID> - -visorbus notifies each function driver when a device of its registered class -arrives and departs, by calling the function driver's probe() and remove() -methods. - -The actual struct device objects that correspond to each virtual bus and -each virtual device are created and owned by visorbus. These device objects -are created in response to messages from the s-Par back-end received on a -special control channel called the "controlvm channel" (each guest partition -has access to exactly 1 controlvm channel), and have a lifetime that is -independent of the function drivers that control them. - -2.1.2. "struct visor device" Function Driver Interfaces -------------------------------------------------------- - -The interface between visorbus and its function drivers is defined in -visorbus.h, and described below. - -When a visor function driver loads, it calls visorbus_register_visor_driver() -to register itself with visorbus. The significant information passed in this -exchange is as follows: - -* the GUID(s) of the channel type(s) that are handled by this driver, as - well as a "friendly name" identifying each (this will be published under - /sys/devices/visorbus<x>/dev<y>) - -* the addresses of callback functions to be called whenever a virtual - device/channel with the appropriate channel-type GUID(s) appears or - disappears - -* the address of a "channel_interrupt" function, which will be automatically - called at specific intervals to enable the driver to poll the device - channel for activity - -The following functions implemented within each function driver will be -called automatically by the visorbus driver at appropriate times: - -* The probe() function notifies about the creation of each new virtual - device/channel instance. - -* The remove() function notifies about the destruction of a virtual - device/channel instance. - -* The channel_interrupt() function is called at frequent intervals to - give the function driver an opportunity to poll the virtual device channel - for requests. Information is passed to this function to enable the - function driver to use the visorchannel_signalinsert() and - visorchannel_signalremove() functions to respond to and initiate activity - over the channel. (Note that since it is the visorbus driver that - determines when this is called, it is very easy to switch to - interrupt-driven mechanisms when available for particular virtual device - types.) - -* The pause() function is called should it ever be necessary to direct the - function driver to temporarily stop accessing the device channel. An - example of when this is needed is when the service partition implementing - the back-end of the virtual device needs to be recovered. After a - successful return of pause(), the function driver must not access the - device channel until a subsequent resume() occurs. - -* The resume() function is the "book-end" to pause(), and is described above. - -2.1.3. sysfs Advertised Information ------------------------------------ - -Because visorbus is a standard Linux bus driver in the model described in -Documentation/driver-api/driver-model/, the hierarchy of s-Par virtual devices is -published in the sysfs tree beneath /bus/visorbus/, e.g., -/sys/bus/visorbus/devices/ might look like: - - vbus1:dev1 -> ../../../devices/visorbus1/vbus1:dev1 - vbus1:dev2 -> ../../../devices/visorbus1/vbus1:dev2 - vbus1:dev3 -> ../../../devices/visorbus1/vbus1:dev3 - vbus2:dev0 -> ../../../devices/visorbus2/vbus2:dev0 - vbus2:dev1 -> ../../../devices/visorbus2/vbus2:dev1 - vbus2:dev2 -> ../../../devices/visorbus2/vbus2:dev2 - visorbus1 -> ../../../devices/visorbus1 - visorbus2 -> ../../../devices/visorbus2 - -visor_device notes: - -* Each visorbus<n> entry denotes the existence of a struct visor_device - denoting virtual bus #<n>. A unique s-Par channel exists for each such - virtual bus. - -* Virtual bus numbers uniquely identify s-Par back-end service partitions. - In this example, bus 1 corresponds to the s-Par console partition - (controls keyboard, video, and mouse), whereas bus 2 corresponds to the - s-Par IO partition (controls network and disk). - -* Each vbus<x>:dev<y> entry denotes the existence of a struct visor_device - denoting virtual device #<y> outboard of virtual bus #<x>. A unique s-Par - channel exists for each such virtual device. - -* If a function driver has loaded and claimed a particular device, the - bus/visorbus/devices/vbus<x>:dev<y>/driver symlink will indicate that - function driver. - -Every active visorbus device will have a sysfs subtree under: - - /sys/devices/visorbus<x>/vbus<x>:dev<y>/ - -The following files exist under /sys/devices/visorbus<x>/vbus<x>:dev<y>: - - subsystem link to sysfs tree that describes the - visorbus bus type; e.g.: - ../../../bus/visorbus - - driver link to sysfs tree that describes the - function driver controlling this device; - e.g.: - ../../../bus/visorbus/drivers/visorhba - Note that this "driver" link will not exist - if the appropriate function driver has not - been loaded yet. - - channel properties of the device channel (all in - ascii text format) - - clientpartition handle identifying the guest (client) side - of this channel, e.g. 0x10000000. - - nbytes total size of this channel in bytes - - physaddr the guest physical address for the base of - the channel - - typeguid a GUID identifying the channel type, in - xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx notation - - typename a "friendly name" for this channel type, e.g., - "keyboard". Note that this name is provided by - a particular function driver, so "typename" - will return an empty string until AFTER the - appropriate function driver controlling this - channel type is loaded - - zoneguid a GUID identifying the channel zone, in - xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx notation - - -2.2. visorhba -------------- - -The visorhba driver registers with visorbus as the function driver to -handle virtual scsi disk devices, specified using the -VISOR_VHBA_CHANNEL_GUID type in the visorbus_register_visor_driver() -call. visorhba uses scsi_add_host() to expose a Linux block device -(e.g., /sys/block/) in the guest environment for each s-Par virtual device. - -visorhba provides access to a shared SCSI host bus adapter and one or more -disk devices, by proxying SCSI commands between the guest and the service -partition that owns the shared SCSI adapter, using a channel between the -guest and the service partition. The disks that appear on the shared bus -are defined by the s-Par configuration and enforced by the service partition, -while the guest driver handles sending commands and handling responses. Each -disk is shared as a whole to a guest. Sharing the bus adapter in this way -provides resiliency; should the device encounter an error, only the service -partition is rebooted, and the device is reinitialized. This allows -guests to continue running and to recover from the error. - -When compiled as a module, visorhba can be autoloaded by visorbus in -standard udev/systemd environments, as it includes the modules.alias -definition: - - "visorbus:"+VISOR_VHBA_CHANNEL_GUID_STR - -i.e.: - - alias visorbus:414815ed-c58c-11da-95a9-00e08161165f visorhba - - -2.3. visornic -------------- - -The visornic driver registers with visorbus as the function driver to -handle virtual network devices, specified using the -VISOR_VNIC_CHANNEL_GUID type in the visorbus_register_visor_driver() -call. visornic uses register_netdev() to expose a Linux device of class net -(e.g., /sys/class/net/) in the guest environment for each s-Par virtual -device. - -visornic provides a paravirtualized network interface to a -guest by proxying buffer information between the guest and the service -partition that owns the shared network interface, using a channel -between the guest and the service partition. The connectivity of this -interface with the shared interface and possibly other guest -partitions is defined by the s-Par configuration and enforced by the -service partition; the guest driver handles communication and link -status. - -When compiled as a module, visornic can be autoloaded by visorbus in -standard udev/systemd environments, as it includes the modules.alias -definition: - - "visorbus:"+VISOR_VNIC_CHANNEL_GUID_STR - -i.e.: - - alias visorbus:8cd5994d-c58e-11da-95a9-00e08161165f visornic - - -2.4. visorinput ---------------- - -The visorinput driver registers with visorbus as the function driver to -handle human input devices, specified using the -VISOR_KEYBOARD_CHANNEL_GUID and VISOR_MOUSE_CHANNEL_GUID -types in the visorbus_register_visor_driver() call. visorinput uses -input_register_device() to expose devices of class input -(e.g., /sys/class/input/) for virtual keyboard and virtual mouse devices. -A s-Par virtual keyboard device maps 1-to-1 with a Linux input device -named "visor Keyboard", while a s-Par virtual mouse device has 2 Linux input -devices created for it: 1 named "visor Wheel", and 1 named "visor Mouse". - -By registering as input class devices, modern versions of X will -automatically find and properly use s-Par virtual keyboard and mouse devices. -As the s-Par back-end reports keyboard and mouse activity via events on the -virtual device channel, the visorinput driver delivers the activity to the -Linux environment by calling input_report_key() and input_report_abs(). - -You can interact with the guest console using the usyscon Partition Desktop -(a.k.a., "pd") application, provided as part of s-Par. After installing the -usyscon Partition Desktop into a Linux environment via the -usyscon_partitiondesktop-*.rpm, or into a Windows environment via -PartitionDesktop.msi, you will be able to launch a console for your guest -Linux environment by clicking the console icon in the s-Par web UI. - -When compiled as a module, visorinput can be autoloaded by visorbus in -standard udev/systemd environments, as it includes the modules.alias -definition: - - "visorbus:"+VISOR_MOUSE_CHANNEL_GUID_STR - "visorbus:"+VISOR_KEYBOARD_CHANNEL_GUID_STR - -i.e.: - - alias visorbus:c73416d0-b0b8-44af-b304-9d2ae99f1b3d visorinput - alias visorbus:addf07d4-94a9-46e2-81c3-61abcdbdbd87 visorinput - - -3. Minimum Required Driver Set ------------------------------- - -visorbus is required for every Linux guest running under s-Par. - -visorhba is typically required for a Linux guest running under s-Par, as it -is required if your guest boot disk is a virtual device provided by the s-Par -back-end, which is the default configuration. However, for advanced -configurations where the Linux guest boots via an SR-IOV-provided HBA or -SAN disk for example, visorhba is not technically required. - -visornic is typically required for a Linux guest running under s-Par, as it -is required if your guest network interface is a virtual device provided by -the s-Par back-end, which is the default configuration. However, for -configurations where the Linux guest is provided with an SR-IOV NIC -for example, visornic is not technically required. - -visorinput is only required for a Linux guest running under s-Par if you -require graphics-mode access to your guest console. diff --git a/drivers/staging/unisys/Kconfig b/drivers/staging/unisys/Kconfig deleted file mode 100644 index 43fe1ce538e1..000000000000 --- a/drivers/staging/unisys/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Unisys SPAR driver configuration -# -menuconfig UNISYSSPAR - bool "Unisys SPAR driver support" - help - Support for the Unisys SPAR drivers - -if UNISYSSPAR - -source "drivers/staging/unisys/visornic/Kconfig" -source "drivers/staging/unisys/visorinput/Kconfig" -source "drivers/staging/unisys/visorhba/Kconfig" - -endif # UNISYSSPAR diff --git a/drivers/staging/unisys/MAINTAINERS b/drivers/staging/unisys/MAINTAINERS deleted file mode 100644 index aaddc619c329..000000000000 --- a/drivers/staging/unisys/MAINTAINERS +++ /dev/null @@ -1,5 +0,0 @@ -Unisys s-Par drivers -M: David Kershner <sparmaintainer@unisys.com> -S: Maintained -F: drivers/staging/unisys/Documentation/overview.txt -F: drivers/staging/unisys/ diff --git a/drivers/staging/unisys/Makefile b/drivers/staging/unisys/Makefile deleted file mode 100644 index c0f76cc196a6..000000000000 --- a/drivers/staging/unisys/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for Unisys SPAR drivers -# -obj-$(CONFIG_UNISYS_VISORNIC) += visornic/ -obj-$(CONFIG_UNISYS_VISORINPUT) += visorinput/ -obj-$(CONFIG_UNISYS_VISORHBA) += visorhba/ diff --git a/drivers/staging/unisys/TODO b/drivers/staging/unisys/TODO deleted file mode 100644 index d863f266bf76..000000000000 --- a/drivers/staging/unisys/TODO +++ /dev/null @@ -1,16 +0,0 @@ -TODO: - - enhance visornic to use channel_interrupt() hook instead of a - kernel thread - - enhance visorhba to use channel_interrupt() hook instead of a - kernel thread - - teach visorbus to handle virtual interrupts triggered by s-Par - back-end, and call function driver's channel_interrupt() function - when they occur - - enhance debugfs interfaces (e.g., per device, etc.) - - upgrade/remove deprecated workqueue operations - - move individual drivers into proper driver subsystems - -Patches to: - Greg Kroah-Hartman <gregkh@linuxfoundation.org> - Ken Cox <jkc@redhat.com> - Unisys s-Par maintainer mailing list <sparmaintainer@unisys.com> diff --git a/drivers/staging/unisys/include/iochannel.h b/drivers/staging/unisys/include/iochannel.h deleted file mode 100644 index 9ef812c0bc42..000000000000 --- a/drivers/staging/unisys/include/iochannel.h +++ /dev/null @@ -1,571 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2010 - 2016 UNISYS CORPORATION - * All rights reserved. - */ - -#ifndef __IOCHANNEL_H__ -#define __IOCHANNEL_H__ - -/* - * Everything needed for IOPart-GuestPart communication is define in - * this file. Note: Everything is OS-independent because this file is - * used by Windows, Linux and possible EFI drivers. - * - * Communication flow between the IOPart and GuestPart uses the channel headers - * channel state. The following states are currently being used: - * UNINIT(All Zeroes), CHANNEL_ATTACHING, CHANNEL_ATTACHED, CHANNEL_OPENED - * - * Additional states will be used later. No locking is needed to switch between - * states due to the following rules: - * - * 1. IOPart is only the only partition allowed to change from UNIT - * 2. IOPart is only the only partition allowed to change from - * CHANNEL_ATTACHING - * 3. GuestPart is only the only partition allowed to change from - * CHANNEL_ATTACHED - * - * The state changes are the following: IOPart sees the channel is in UNINIT, - * UNINIT -> CHANNEL_ATTACHING (performed only by IOPart) - * CHANNEL_ATTACHING -> CHANNEL_ATTACHED (performed only by IOPart) - * CHANNEL_ATTACHED -> CHANNEL_OPENED (performed only by GuestPart) - */ - -#include <linux/uuid.h> -#include <linux/skbuff.h> -#include <linux/visorbus.h> - -/* - * Must increment these whenever you insert or delete fields within this channel - * struct. Also increment whenever you change the meaning of fields within this - * channel struct so as to break pre-existing software. Note that you can - * usually add fields to the END of the channel struct without needing to - * increment this. - */ -#define VISOR_VHBA_CHANNEL_VERSIONID 2 -#define VISOR_VNIC_CHANNEL_VERSIONID 2 - -/* - * Everything necessary to handle SCSI & NIC traffic between Guest Partition and - * IO Partition is defined below. - */ - -/* - * Define the two queues per data channel between iopart and ioguestparts. - * IOCHAN_TO_IOPART -- used by guest to 'insert' signals to iopart. - * IOCHAN_FROM_IOPART -- used by guest to 'remove' signals from IO part. - */ -#define IOCHAN_TO_IOPART 0 -#define IOCHAN_FROM_IOPART 1 - -/* Size of cdb - i.e., SCSI cmnd */ -#define MAX_CMND_SIZE 16 - -/* Unisys-specific DMA direction values */ -enum uis_dma_data_direction { - UIS_DMA_BIDIRECTIONAL = 0, - UIS_DMA_TO_DEVICE = 1, - UIS_DMA_FROM_DEVICE = 2, - UIS_DMA_NONE = 3 -}; - -#define MAX_SENSE_SIZE 64 -#define MAX_PHYS_INFO 64 - -/* - * enum net_types - Various types of network packets that can be sent in cmdrsp. - * @NET_RCV_POST: Submit buffer to hold receiving incoming packet. - * @NET_RCV: visornic -> uisnic. Incoming packet received. - * @NET_XMIT: uisnic -> visornic. For outgoing packet. - * @NET_XMIT_DONE: visornic -> uisnic. Outgoing packet xmitted. - * @NET_RCV_ENBDIS: uisnic -> visornic. Enable/Disable packet reception. - * @NET_RCV_ENBDIS_ACK: visornic -> uisnic. Acknowledge enable/disable packet. - * @NET_RCV_PROMISC: uisnic -> visornic. Enable/Disable promiscuous mode. - * @NET_CONNECT_STATUS: visornic -> uisnic. Indicate the loss or restoration of - * a network connection. - * @NET_MACADDR: uisnic -> visornic. Indicates the client has requested - * to update it's MAC address. - * @NET_MACADDR_ACK: MAC address acknowledge. - */ -enum net_types { - NET_RCV_POST = 0, - NET_RCV, - NET_XMIT, - NET_XMIT_DONE, - NET_RCV_ENBDIS, - NET_RCV_ENBDIS_ACK, - /* Reception */ - NET_RCV_PROMISC, - NET_CONNECT_STATUS, - NET_MACADDR, - NET_MACADDR_ACK, -}; - -/* Minimum eth data size */ -#define ETH_MIN_DATA_SIZE 46 -#define ETH_MIN_PACKET_SIZE (ETH_HLEN + ETH_MIN_DATA_SIZE) - -/* Maximum data size */ -#define VISOR_ETH_MAX_MTU 16384 - -#ifndef MAX_MACADDR_LEN -/* Number of bytes in MAC address */ -#define MAX_MACADDR_LEN 6 -#endif - -/* Various types of scsi task mgmt commands. */ -enum task_mgmt_types { - TASK_MGMT_ABORT_TASK = 1, - TASK_MGMT_BUS_RESET, - TASK_MGMT_LUN_RESET, - TASK_MGMT_TARGET_RESET, -}; - -/* Various types of vdisk mgmt commands. */ -enum vdisk_mgmt_types { - VDISK_MGMT_ACQUIRE = 1, - VDISK_MGMT_RELEASE, -}; - -struct phys_info { - u64 pi_pfn; - u16 pi_off; - u16 pi_len; -} __packed; - -#define MIN_NUMSIGNALS 64 - -/* Structs with pragma pack. */ - -struct guest_phys_info { - u64 address; - u64 length; -} __packed; - -/* - * struct uisscsi_dest - * @channel: Bus number. - * @id: Target number. - * @lun: Logical unit number. - */ -struct uisscsi_dest { - u32 channel; - u32 id; - u32 lun; -} __packed; - -struct vhba_wwnn { - u32 wwnn1; - u32 wwnn2; -} __packed; - -/* - * struct vhba_config_max - * @max_channel: Maximum channel for devices attached to this bus. - * @max_id: Maximum SCSI ID for devices attached to bus. - * @max_lun: Maximum SCSI LUN for devices attached to bus. - * @cmd_per_lun: Maximum number of outstanding commands per LUN. - * @max_io_size: Maximum io size for devices attached to this bus. Max io size - * is often determined by the resource of the hba. - * e.g Max scatter gather list length * page size / sector size. - * - * WARNING: Values stored in this structure must contain maximum counts (not - * maximum values). - * - * 20 bytes - */ -struct vhba_config_max { - u32 max_channel; - u32 max_id; - u32 max_lun; - u32 cmd_per_lun; - u32 max_io_size; -} __packed; - -/* - * struct uiscmdrsp_scsi - * - * @handle: The handle to the cmd that was received. Send it back as - * is in the rsp packet. - * @cmnd: The cdb for the command. - * @bufflen: Length of data to be transferred out or in. - * @guest_phys_entries: Number of entries in scatter-gather list. - * @struct gpi_list: Physical address information for each fragment. - * @data_dir: Direction of the data, if any. - * @struct vdest: Identifies the virtual hba, id, channel, lun to which - * cmd was sent. - * @linuxstat: Original Linux status used by Linux vdisk. - * @scsistat: The scsi status. - * @addlstat: Non-scsi status. - * @sensebuf: Sense info in case cmd failed. sensebuf holds the - * sense_data struct. See sense_data struct for more - * details. - * @*vdisk: Pointer to the vdisk to clean up when IO completes. - * @no_disk_result: Used to return no disk inquiry result when - * no_disk_result is set to 1 - * scsi.scsistat is SAM_STAT_GOOD - * scsi.addlstat is 0 - * scsi.linuxstat is SAM_STAT_GOOD - * That is, there is NO error. - */ -struct uiscmdrsp_scsi { - u64 handle; - u8 cmnd[MAX_CMND_SIZE]; - u32 bufflen; - u16 guest_phys_entries; - struct guest_phys_info gpi_list[MAX_PHYS_INFO]; - u32 data_dir; - struct uisscsi_dest vdest; - /* Needed to queue the rsp back to cmd originator. */ - int linuxstat; - u8 scsistat; - u8 addlstat; -#define ADDL_SEL_TIMEOUT 4 - /* The following fields are need to determine the result of command. */ - u8 sensebuf[MAX_SENSE_SIZE]; - void *vdisk; - int no_disk_result; -} __packed; - -/* - * Defines to support sending correct inquiry result when no disk is - * configured. - * - * From SCSI SPC2 - - * - * If the target is not capable of supporting a device on this logical unit, the - * device server shall set this field to 7Fh (PERIPHERAL QUALIFIER set to 011b - * and PERIPHERAL DEVICE TYPE set to 1Fh). - * - * The device server is capable of supporting the specified peripheral device - * type on this logical unit. However, the physical device is not currently - * connected to this logical unit. - */ - -/* - * Peripheral qualifier of 0x3 - * Peripheral type of 0x1f - * Specifies no device but target present - */ -#define DEV_NOT_CAPABLE 0x7f -/* - * Peripheral qualifier of 0x1 - * Peripheral type of 0 - disk - * Specifies device capable, but not present - */ -#define DEV_DISK_CAPABLE_NOT_PRESENT 0x20 -/* HiSup = 1; shows support for report luns must be returned for lun 0. */ -#define DEV_HISUPPORT 0x10 - -/* - * Peripheral qualifier of 0x3 - * Peripheral type of 0x1f - * Specifies no device but target present - */ -#define DEV_NOT_CAPABLE 0x7f -/* - * Peripheral qualifier of 0x1 - * Peripheral type of 0 - disk - * Specifies device capable, but not present - */ -#define DEV_DISK_CAPABLE_NOT_PRESENT 0x20 -/* HiSup = 1; shows support for report luns must be returned for lun 0. */ -#define DEV_HISUPPORT 0x10 - -/* - * NOTE: Linux code assumes inquiry contains 36 bytes. Without checking length - * in buf[4] some Linux code accesses bytes beyond 5 to retrieve vendor, product - * and revision. Yikes! So let us always send back 36 bytes, the minimum for - * inquiry result. - */ -#define NO_DISK_INQUIRY_RESULT_LEN 36 -/* 5 bytes minimum for inquiry result */ -#define MIN_INQUIRY_RESULT_LEN 5 - -/* SCSI device version for no disk inquiry result */ -/* indicates SCSI SPC2 (SPC3 is 5) */ -#define SCSI_SPC2_VER 4 - -/* Struct and Defines to support sense information. */ - -/* - * The following struct is returned in sensebuf field in uiscmdrsp_scsi. It is - * initialized in exactly the manner that is recommended in Windows (hence the - * odd values). - * When set, these fields will have the following values: - * ErrorCode = 0x70 indicates current error - * Valid = 1 indicates sense info is valid - * SenseKey contains sense key as defined by SCSI specs. - * AdditionalSenseCode contains sense key as defined by SCSI specs. - * AdditionalSenseCodeQualifier contains qualifier to sense code as defined by - * scsi docs. - * AdditionalSenseLength contains will be sizeof(sense_data)-8=10. - */ -struct sense_data { - u8 errorcode:7; - u8 valid:1; - u8 segment_number; - u8 sense_key:4; - u8 reserved:1; - u8 incorrect_length:1; - u8 end_of_media:1; - u8 file_mark:1; - u8 information[4]; - u8 additional_sense_length; - u8 command_specific_information[4]; - u8 additional_sense_code; - u8 additional_sense_code_qualifier; - u8 fru_code; - u8 sense_key_specific[3]; -} __packed; - -/* - * struct net_pkt_xmt - * @len: Full length of data in the packet. - * @num_frags: Number of fragments in frags containing data. - * @struct phys_info frags: Physical page information. - * @ethhdr: The ethernet header. - * @struct lincsum: These are needed for csum at uisnic end. - * @valid: 1 = struct is valid - else ignore. - * @hrawoffv: 1 = hwrafoff is valid. - * @nhrawoffv: 1 = nhwrafoff is valid. - * @protocol: Specifies packet protocol. - * @csum: Value used to set skb->csum at IOPart. - * @hrawoff: Value used to set skb->h.raw at IOPart. hrawoff points to - * the start of the TRANSPORT LAYER HEADER. - * @nhrawoff: Value used to set skb->nh.raw at IOPart. nhrawoff points to - * the start of the NETWORK LAYER HEADER. - * - * NOTE: - * The full packet is described in frags but the ethernet header is separately - * kept in ethhdr so that uisnic doesn't have "MAP" the guest memory to get to - * the header. uisnic needs ethhdr to determine how to route the packet. - */ -struct net_pkt_xmt { - int len; - int num_frags; - struct phys_info frags[MAX_PHYS_INFO]; - char ethhdr[ETH_HLEN]; - struct { - u8 valid; - u8 hrawoffv; - u8 nhrawoffv; - __be16 protocol; - __wsum csum; - u32 hrawoff; - u32 nhrawoff; - } lincsum; -} __packed; - -struct net_pkt_xmtdone { - /* Result of NET_XMIT */ - u32 xmt_done_result; -} __packed; - -/* - * RCVPOST_BUF_SIZE must be at most page_size(4096) - cache_line_size (64) The - * reason is because dev_skb_alloc which is used to generate RCV_POST skbs in - * visornic requires that there is "overhead" in the buffer, and pads 16 bytes. - * Use 1 full cache line size for "overhead" so that transfers are optimized. - * IOVM requires that a buffer be represented by 1 phys_info structure - * which can only cover page_size. - */ -#define RCVPOST_BUF_SIZE 4032 -#define MAX_NET_RCV_CHAIN \ - ((VISOR_ETH_MAX_MTU + ETH_HLEN + RCVPOST_BUF_SIZE - 1) \ - / RCVPOST_BUF_SIZE) - -/* rcv buf size must be large enough to include ethernet data len + ethernet - * header len - we are choosing 2K because it is guaranteed to be describable. - */ -struct net_pkt_rcvpost { - /* Physical page information for the single fragment 2K rcv buf */ - struct phys_info frag; - /* - * Ensures that receive posts are returned to the adapter which we sent - * them from originally. - */ - u64 unique_num; - -} __packed; - -/* - * struct net_pkt_rcv - * @rcv_done_len: Length of the received data. - * @numrcvbufs: Contains the incoming data. Guest side MUST chain these - * together. - * @*rcvbuf: List of chained rcvbufa. Each entry is a receive buffer - * provided by NET_RCV_POST. NOTE: First rcvbuf in the - * chain will also be provided in net.buf. - * @unique_num: - * @rcvs_dropped_delta: - * - * The number of rcvbuf that can be chained is based on max mtu and size of each - * rcvbuf. - */ -struct net_pkt_rcv { - u32 rcv_done_len; - u8 numrcvbufs; - void *rcvbuf[MAX_NET_RCV_CHAIN]; - u64 unique_num; - u32 rcvs_dropped_delta; -} __packed; - -struct net_pkt_enbdis { - void *context; - /* 1 = enable, 0 = disable */ - u16 enable; -} __packed; - -struct net_pkt_macaddr { - void *context; - /* 6 bytes */ - u8 macaddr[MAX_MACADDR_LEN]; -} __packed; - -/* - * struct uiscmdrsp_net - cmd rsp packet used for VNIC network traffic. - * @enum type: - * @*buf: - * @union: - * @struct xmt: Used for NET_XMIT. - * @struct xmtdone: Used for NET_XMIT_DONE. - * @struct rcvpost: Used for NET_RCV_POST. - * @struct rcv: Used for NET_RCV. - * @struct enbdis: Used for NET_RCV_ENBDIS, NET_RCV_ENBDIS_ACK, - * NET_RCV_PROMSIC, and NET_CONNECT_STATUS. - * @struct macaddr: - */ -struct uiscmdrsp_net { - enum net_types type; - void *buf; - union { - struct net_pkt_xmt xmt; - struct net_pkt_xmtdone xmtdone; - struct net_pkt_rcvpost rcvpost; - struct net_pkt_rcv rcv; - struct net_pkt_enbdis enbdis; - struct net_pkt_macaddr macaddr; - }; -} __packed; - -/* - * struct uiscmdrsp_scsitaskmgmt - * @enum tasktype: The type of task. - * @struct vdest: The vdisk for which this task mgmt is generated. - * @handle: This is a handle that the guest has saved off for its - * own use. The handle value is preserved by iopart and - * returned as in task mgmt rsp. - * @notify_handle: For Linux guests, this is a pointer to wait_queue_head - * that a thread is waiting on to see if the taskmgmt - * command has completed. When the rsp is received by - * guest, the thread receiving the response uses this to - * notify the thread waiting for taskmgmt command - * completion. It's value is preserved by iopart and - * returned as in the task mgmt rsp. - * @notifyresult_handle: This is a handle to the location in the guest where - * the result of the taskmgmt command (result field) is - * saved to when the response is handled. It's value is - * preserved by iopart and returned as is in the task mgmt - * rsp. - * @result: Result of taskmgmt command - set by IOPart. - */ -struct uiscmdrsp_scsitaskmgmt { - enum task_mgmt_types tasktype; - struct uisscsi_dest vdest; - u64 handle; - u64 notify_handle; - u64 notifyresult_handle; - char result; - -#define TASK_MGMT_FAILED 0 -} __packed; - -/* - * struct uiscmdrsp_disknotify - Used by uissd to send disk add/remove - * notifications to Guest. - * @add: 0-remove, 1-add. - * @*v_hba: Channel info to route msg. - * @channel: SCSI Path of Disk to added or removed. - * @id: SCSI Path of Disk to added or removed. - * @lun: SCSI Path of Disk to added or removed. - * - * Note that the vHba pointer is not used by the Client/Guest side. - */ -struct uiscmdrsp_disknotify { - u8 add; - void *v_hba; - u32 channel, id, lun; -} __packed; - -/* Keeping cmd and rsp info in one structure for now cmd rsp packet for SCSI */ -struct uiscmdrsp { - char cmdtype; - /* Describes what type of information is in the struct */ -#define CMD_SCSI_TYPE 1 -#define CMD_NET_TYPE 2 -#define CMD_SCSITASKMGMT_TYPE 3 -#define CMD_NOTIFYGUEST_TYPE 4 - union { - struct uiscmdrsp_scsi scsi; - struct uiscmdrsp_net net; - struct uiscmdrsp_scsitaskmgmt scsitaskmgmt; - struct uiscmdrsp_disknotify disknotify; - }; - /* Send the response when the cmd is done (scsi and scsittaskmgmt). */ - void *private_data; - /* General Purpose Queue Link */ - struct uiscmdrsp *next; - /* Pointer to the nextactive commands */ - struct uiscmdrsp *activeQ_next; - /* Pointer to the prevactive commands */ - struct uiscmdrsp *activeQ_prev; -} __packed; - -/* total = 28 bytes */ -struct iochannel_vhba { - /* 8 bytes */ - struct vhba_wwnn wwnn; - /* 20 bytes */ - struct vhba_config_max max; -} __packed; - -struct iochannel_vnic { - /* 6 bytes */ - u8 macaddr[6]; - /* 4 bytes */ - u32 num_rcv_bufs; - /* 4 bytes */ - u32 mtu; - /* 16 bytes */ - guid_t zone_guid; -} __packed; - -/* - * This is just the header of the IO channel. It is assumed that directly after - * this header there is a large region of memory which contains the command and - * response queues as specified in cmd_q and rsp_q SIGNAL_QUEUE_HEADERS. - */ -struct visor_io_channel { - struct channel_header channel_header; - struct signal_queue_header cmd_q; - struct signal_queue_header rsp_q; - union { - struct iochannel_vhba vhba; - struct iochannel_vnic vnic; - } __packed; - -#define MAX_CLIENTSTRING_LEN 1024 - /* client_string is NULL termimated so holds max-1 bytes */ - u8 client_string[MAX_CLIENTSTRING_LEN]; -} __packed; - -/* INLINE functions for initializing and accessing I/O data channels. */ -#define SIZEOF_CMDRSP (64 * DIV_ROUND_UP(sizeof(struct uiscmdrsp), 64)) - -/* Use 4K page sizes when passing page info between Guest and IOPartition. */ -#define PI_PAGE_SIZE 0x1000 -#define PI_PAGE_MASK 0x0FFF - -/* __IOCHANNEL_H__ */ -#endif diff --git a/drivers/staging/unisys/visorhba/Kconfig b/drivers/staging/unisys/visorhba/Kconfig deleted file mode 100644 index ed59ac11c322..000000000000 --- a/drivers/staging/unisys/visorhba/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Unisys visorhba configuration -# - -config UNISYS_VISORHBA - tristate "Unisys visorhba driver" - depends on UNISYSSPAR && UNISYS_VISORBUS && SCSI - help - The Unisys visorhba driver provides support for s-Par HBA - devices exposed on the s-Par visorbus. When a message is sent - to visorbus to create a HBA device, the probe function of - visorhba is called to create the scsi device. - If you say Y here, you will enable the Unisys visorhba driver. - diff --git a/drivers/staging/unisys/visorhba/Makefile b/drivers/staging/unisys/visorhba/Makefile deleted file mode 100644 index b613a7dcdae9..000000000000 --- a/drivers/staging/unisys/visorhba/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for Unisys channel -# - -obj-$(CONFIG_UNISYS_VISORHBA) += visorhba.o - -visorhba-y := visorhba_main.o - -ccflags-y += -I $(srctree)/$(src)/../include diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c deleted file mode 100644 index 48aa18f8b984..000000000000 --- a/drivers/staging/unisys/visorhba/visorhba_main.c +++ /dev/null @@ -1,1142 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2012 - 2015 UNISYS CORPORATION - * All rights reserved. - */ - -#include <linux/debugfs.h> -#include <linux/kthread.h> -#include <linux/module.h> -#include <linux/seq_file.h> -#include <linux/visorbus.h> -#include <linux/xarray.h> -#include <scsi/scsi.h> -#include <scsi/scsi_host.h> -#include <scsi/scsi_cmnd.h> -#include <scsi/scsi_device.h> - -#include "iochannel.h" - -/* The Send and Receive Buffers of the IO Queue may both be full */ - -#define IOS_ERROR_THRESHOLD 1000 -#define MAX_PENDING_REQUESTS (MIN_NUMSIGNALS * 2) -#define VISORHBA_ERROR_COUNT 30 - -static struct dentry *visorhba_debugfs_dir; - -/* GUIDS for HBA channel type supported by this driver */ -static struct visor_channeltype_descriptor visorhba_channel_types[] = { - /* Note that the only channel type we expect to be reported by the - * bus driver is the VISOR_VHBA channel. - */ - { VISOR_VHBA_CHANNEL_GUID, "sparvhba", sizeof(struct channel_header), - VISOR_VHBA_CHANNEL_VERSIONID }, - {} -}; - -MODULE_DEVICE_TABLE(visorbus, visorhba_channel_types); -MODULE_ALIAS("visorbus:" VISOR_VHBA_CHANNEL_GUID_STR); - -struct visordisk_info { - struct scsi_device *sdev; - u32 valid; - atomic_t ios_threshold; - atomic_t error_count; - struct visordisk_info *next; -}; - -struct scsipending { - struct uiscmdrsp cmdrsp; - /* The Data being tracked */ - void *sent; - /* Type of pointer that is being stored */ - char cmdtype; -}; - -/* Each scsi_host has a host_data area that contains this struct. */ -struct visorhba_devdata { - struct Scsi_Host *scsihost; - struct visor_device *dev; - struct list_head dev_info_list; - /* Tracks the requests that have been forwarded to - * the IOVM and haven't returned yet - */ - struct scsipending pending[MAX_PENDING_REQUESTS]; - /* Start search for next pending free slot here */ - unsigned int nextinsert; - /* lock to protect data in devdata */ - spinlock_t privlock; - bool serverdown; - bool serverchangingstate; - unsigned long long acquire_failed_cnt; - unsigned long long interrupts_rcvd; - unsigned long long interrupts_notme; - unsigned long long interrupts_disabled; - u64 __iomem *flags_addr; - struct visordisk_info head; - unsigned int max_buff_len; - int devnum; - struct uiscmdrsp *cmdrsp; - /* - * allows us to pass int handles back-and-forth between us and - * iovm, instead of raw pointers - */ - struct xarray xa; - struct dentry *debugfs_dir; - struct dentry *debugfs_info; -}; - -struct visorhba_devices_open { - struct visorhba_devdata *devdata; -}; - -/* - * add_scsipending_entry - Save off io command that is pending in - * Service Partition - * @devdata: Pointer to devdata - * @cmdtype: Specifies the type of command pending - * @new: The command to be saved - * - * Saves off the io command that is being handled by the Service - * Partition so that it can be handled when it completes. If new is - * NULL it is assumed the entry refers only to the cmdrsp. - * - * Return: Insert_location where entry was added on success, - * -EBUSY if it can't - */ -static int add_scsipending_entry(struct visorhba_devdata *devdata, - char cmdtype, void *new) -{ - unsigned long flags; - struct scsipending *entry; - int insert_location; - - spin_lock_irqsave(&devdata->privlock, flags); - insert_location = devdata->nextinsert; - while (devdata->pending[insert_location].sent) { - insert_location = (insert_location + 1) % MAX_PENDING_REQUESTS; - if (insert_location == (int)devdata->nextinsert) { - spin_unlock_irqrestore(&devdata->privlock, flags); - return -EBUSY; - } - } - - entry = &devdata->pending[insert_location]; - memset(&entry->cmdrsp, 0, sizeof(entry->cmdrsp)); - entry->cmdtype = cmdtype; - if (new) - entry->sent = new; - /* wants to send cmdrsp */ - else - entry->sent = &entry->cmdrsp; - devdata->nextinsert = (insert_location + 1) % MAX_PENDING_REQUESTS; - spin_unlock_irqrestore(&devdata->privlock, flags); - - return insert_location; -} - -/* - * del_scsipending_ent - Removes an entry from the pending array - * @devdata: Device holding the pending array - * @del: Entry to remove - * - * Removes the entry pointed at by del and returns it. - * - * Return: The scsipending entry pointed to on success, NULL on failure - */ -static void *del_scsipending_ent(struct visorhba_devdata *devdata, int del) -{ - unsigned long flags; - void *sent; - - if (del >= MAX_PENDING_REQUESTS) - return NULL; - - spin_lock_irqsave(&devdata->privlock, flags); - sent = devdata->pending[del].sent; - devdata->pending[del].cmdtype = 0; - devdata->pending[del].sent = NULL; - spin_unlock_irqrestore(&devdata->privlock, flags); - - return sent; -} - -/* - * get_scsipending_cmdrsp - Return the cmdrsp stored in a pending entry - * @ddata: Device holding the pending array - * @ent: Entry that stores the cmdrsp - * - * Each scsipending entry has a cmdrsp in it. The cmdrsp is only valid - * if the "sent" field is not NULL. - * - * Return: A pointer to the cmdrsp, NULL on failure - */ -static struct uiscmdrsp *get_scsipending_cmdrsp(struct visorhba_devdata *ddata, - int ent) -{ - if (ddata->pending[ent].sent) - return &ddata->pending[ent].cmdrsp; - - return NULL; -} - -/* - * setup_scsitaskmgmt_handles - Stash the necessary handles so that the - * completion processing logic for a taskmgmt - * cmd will be able to find who to wake up - * and where to stash the result - * @xa: The data object maintaining the pointer<-->int mappings - * @cmdrsp: Response from the IOVM - * @event: The event handle to associate with an id - * @result: The location to place the result of the event handle into - */ -static int setup_scsitaskmgmt_handles(struct xarray *xa, struct uiscmdrsp *cmdrsp, - wait_queue_head_t *event, int *result) -{ - int ret; - u32 id; - - /* specify the event that has to be triggered when this cmd is complete */ - ret = xa_alloc_irq(xa, &id, event, xa_limit_32b, GFP_KERNEL); - if (ret) - return ret; - cmdrsp->scsitaskmgmt.notify_handle = id; - ret = xa_alloc_irq(xa, &id, result, xa_limit_32b, GFP_KERNEL); - if (ret) { - xa_erase_irq(xa, cmdrsp->scsitaskmgmt.notify_handle); - return ret; - } - cmdrsp->scsitaskmgmt.notifyresult_handle = id; - - return 0; -} - -/* - * cleanup_scsitaskmgmt_handles - Forget handles created by - * setup_scsitaskmgmt_handles() - * @xa: The data object maintaining the pointer<-->int mappings - * @cmdrsp: Response from the IOVM - */ -static void cleanup_scsitaskmgmt_handles(struct xarray *xa, - struct uiscmdrsp *cmdrsp) -{ - xa_erase_irq(xa, cmdrsp->scsitaskmgmt.notify_handle); - xa_erase_irq(xa, cmdrsp->scsitaskmgmt.notifyresult_handle); -} - -/* - * forward_taskmgmt_command - Send taskmegmt command to the Service - * Partition - * @tasktype: Type of taskmgmt command - * @scsidev: Scsidev that issued command - * - * Create a cmdrsp packet and send it to the Service Partition - * that will service this request. - * - * Return: Int representing whether command was queued successfully or not - */ -static int forward_taskmgmt_command(enum task_mgmt_types tasktype, - struct scsi_device *scsidev) -{ - struct uiscmdrsp *cmdrsp; - struct visorhba_devdata *devdata = - (struct visorhba_devdata *)scsidev->host->hostdata; - int notifyresult = 0xffff; - wait_queue_head_t notifyevent; - int scsicmd_id; - int ret; - - if (devdata->serverdown || devdata->serverchangingstate) - return FAILED; - - scsicmd_id = add_scsipending_entry(devdata, CMD_SCSITASKMGMT_TYPE, - NULL); - if (scsicmd_id < 0) - return FAILED; - - cmdrsp = get_scsipending_cmdrsp(devdata, scsicmd_id); - - init_waitqueue_head(¬ifyevent); - - /* issue TASK_MGMT_ABORT_TASK */ - cmdrsp->cmdtype = CMD_SCSITASKMGMT_TYPE; - - ret = setup_scsitaskmgmt_handles(&devdata->xa, cmdrsp, - ¬ifyevent, ¬ifyresult); - if (ret) { - dev_dbg(&scsidev->sdev_gendev, - "visorhba: setup_scsitaskmgmt_handles returned %d\n", ret); - return FAILED; - } - - /* save destination */ - cmdrsp->scsitaskmgmt.tasktype = tasktype; - cmdrsp->scsitaskmgmt.vdest.channel = scsidev->channel; - cmdrsp->scsitaskmgmt.vdest.id = scsidev->id; - cmdrsp->scsitaskmgmt.vdest.lun = scsidev->lun; - cmdrsp->scsitaskmgmt.handle = scsicmd_id; - - dev_dbg(&scsidev->sdev_gendev, - "visorhba: initiating type=%d taskmgmt command\n", tasktype); - 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 - * an IO in some cases, so wait 45 seconds and error out - */ - if (!wait_event_timeout(notifyevent, notifyresult != 0xffff, - msecs_to_jiffies(45000))) - goto err_del_scsipending_ent; - - dev_dbg(&scsidev->sdev_gendev, - "visorhba: taskmgmt type=%d success; result=0x%x\n", - tasktype, notifyresult); - cleanup_scsitaskmgmt_handles(&devdata->xa, cmdrsp); - return SUCCESS; - -err_del_scsipending_ent: - dev_dbg(&scsidev->sdev_gendev, - "visorhba: taskmgmt type=%d not executed\n", tasktype); - del_scsipending_ent(devdata, scsicmd_id); - cleanup_scsitaskmgmt_handles(&devdata->xa, cmdrsp); - return FAILED; -} - -/* - * visorhba_abort_handler - Send TASK_MGMT_ABORT_TASK - * @scsicmd: The scsicmd that needs aborted - * - * Return: SUCCESS if inserted, FAILED otherwise - */ -static int visorhba_abort_handler(struct scsi_cmnd *scsicmd) -{ - /* issue TASK_MGMT_ABORT_TASK */ - struct scsi_device *scsidev; - struct visordisk_info *vdisk; - int rtn; - - scsidev = scsicmd->device; - vdisk = scsidev->hostdata; - if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) - atomic_inc(&vdisk->error_count); - else - atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); - rtn = forward_taskmgmt_command(TASK_MGMT_ABORT_TASK, scsidev); - if (rtn == SUCCESS) { - scsicmd->result = DID_ABORT << 16; - scsi_done(scsicmd); - } - return rtn; -} - -/* - * visorhba_device_reset_handler - Send TASK_MGMT_LUN_RESET - * @scsicmd: The scsicmd that needs aborted - * - * Return: SUCCESS if inserted, FAILED otherwise - */ -static int visorhba_device_reset_handler(struct scsi_cmnd *scsicmd) -{ - /* issue TASK_MGMT_LUN_RESET */ - struct scsi_device *scsidev; - struct visordisk_info *vdisk; - int rtn; - - scsidev = scsicmd->device; - vdisk = scsidev->hostdata; - if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) - atomic_inc(&vdisk->error_count); - else - atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); - rtn = forward_taskmgmt_command(TASK_MGMT_LUN_RESET, scsidev); - if (rtn == SUCCESS) { - scsicmd->result = DID_RESET << 16; - scsi_done(scsicmd); - } - return rtn; -} - -/* - * visorhba_bus_reset_handler - Send TASK_MGMT_TARGET_RESET for each - * target on the bus - * @scsicmd: The scsicmd that needs aborted - * - * Return: SUCCESS if inserted, FAILED otherwise - */ -static int visorhba_bus_reset_handler(struct scsi_cmnd *scsicmd) -{ - struct scsi_device *scsidev; - struct visordisk_info *vdisk; - int rtn; - - scsidev = scsicmd->device; - shost_for_each_device(scsidev, scsidev->host) { - vdisk = scsidev->hostdata; - if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) - atomic_inc(&vdisk->error_count); - else - atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); - } - rtn = forward_taskmgmt_command(TASK_MGMT_BUS_RESET, scsidev); - if (rtn == SUCCESS) { - scsicmd->result = DID_RESET << 16; - scsi_done(scsicmd); - } - return rtn; -} - -/* - * visorhba_host_reset_handler - Not supported - * @scsicmd: The scsicmd that needs to be aborted - * - * Return: Not supported, return SUCCESS - */ -static int visorhba_host_reset_handler(struct scsi_cmnd *scsicmd) -{ - /* issue TASK_MGMT_TARGET_RESET for each target on each bus for host */ - return SUCCESS; -} - -/* - * visorhba_get_info - Get information about SCSI device - * @shp: Scsi host that is requesting information - * - * Return: String with visorhba information - */ -static const char *visorhba_get_info(struct Scsi_Host *shp) -{ - /* Return version string */ - return "visorhba"; -} - -/* - * dma_data_dir_linux_to_spar - convert dma_data_direction value to - * Unisys-specific equivalent - * @d: dma direction value to convert - * - * Returns the Unisys-specific dma direction value corresponding to @d - */ -static u32 dma_data_dir_linux_to_spar(enum dma_data_direction d) -{ - switch (d) { - case DMA_BIDIRECTIONAL: - return UIS_DMA_BIDIRECTIONAL; - case DMA_TO_DEVICE: - return UIS_DMA_TO_DEVICE; - case DMA_FROM_DEVICE: - return UIS_DMA_FROM_DEVICE; - case DMA_NONE: - return UIS_DMA_NONE; - default: - return UIS_DMA_NONE; - } -} - -/* - * visorhba_queue_command_lck - Queues command to the Service Partition - * @scsicmd: Command to be queued - * @vsiorhba_cmnd_done: Done command to call when scsicmd is returned - * - * Queues to scsicmd to the ServicePartition after converting it to a - * uiscmdrsp structure. - * - * Return: 0 if successfully queued to the Service Partition, otherwise - * error code - */ -static int visorhba_queue_command_lck(struct scsi_cmnd *scsicmd) -{ - void (*visorhba_cmnd_done)(struct scsi_cmnd *) = scsi_done; - struct uiscmdrsp *cmdrsp; - struct scsi_device *scsidev = scsicmd->device; - int insert_location; - unsigned char *cdb = scsicmd->cmnd; - struct Scsi_Host *scsihost = scsidev->host; - unsigned int i; - struct visorhba_devdata *devdata = - (struct visorhba_devdata *)scsihost->hostdata; - struct scatterlist *sg = NULL; - struct scatterlist *sglist = NULL; - - if (devdata->serverdown || devdata->serverchangingstate) - return SCSI_MLQUEUE_DEVICE_BUSY; - - insert_location = add_scsipending_entry(devdata, CMD_SCSI_TYPE, - (void *)scsicmd); - if (insert_location < 0) - return SCSI_MLQUEUE_DEVICE_BUSY; - - cmdrsp = get_scsipending_cmdrsp(devdata, insert_location); - cmdrsp->cmdtype = CMD_SCSI_TYPE; - /* save the pending insertion location. Deletion from pending - * will return the scsicmd pointer for completion - */ - cmdrsp->scsi.handle = insert_location; - - WARN_ON_ONCE(visorhba_cmnd_done != scsi_done); - /* save destination */ - cmdrsp->scsi.vdest.channel = scsidev->channel; - cmdrsp->scsi.vdest.id = scsidev->id; - cmdrsp->scsi.vdest.lun = scsidev->lun; - /* save datadir */ - cmdrsp->scsi.data_dir = - dma_data_dir_linux_to_spar(scsicmd->sc_data_direction); - memcpy(cmdrsp->scsi.cmnd, cdb, MAX_CMND_SIZE); - cmdrsp->scsi.bufflen = scsi_bufflen(scsicmd); - - /* keep track of the max buffer length so far. */ - if (cmdrsp->scsi.bufflen > devdata->max_buff_len) - devdata->max_buff_len = cmdrsp->scsi.bufflen; - - if (scsi_sg_count(scsicmd) > MAX_PHYS_INFO) - goto err_del_scsipending_ent; - - /* convert buffer to phys information */ - /* buffer is scatterlist - copy it out */ - sglist = scsi_sglist(scsicmd); - - for_each_sg(sglist, sg, scsi_sg_count(scsicmd), i) { - cmdrsp->scsi.gpi_list[i].address = sg_phys(sg); - cmdrsp->scsi.gpi_list[i].length = sg->length; - } - cmdrsp->scsi.guest_phys_entries = scsi_sg_count(scsicmd); - - 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; - - return 0; - -err_del_scsipending_ent: - del_scsipending_ent(devdata, insert_location); - 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 - * - * Create a new visordisk_info structure and add it to our - * list of vdisks. - * - * Return: 0 on success, -ENOMEM on failure. - */ -static int visorhba_slave_alloc(struct scsi_device *scsidev) -{ - /* this is called by the midlayer before scan for new devices -- - * LLD can alloc any struct & do init if needed. - */ - struct visordisk_info *vdisk; - struct visorhba_devdata *devdata; - struct Scsi_Host *scsihost = (struct Scsi_Host *)scsidev->host; - - /* already allocated return success */ - if (scsidev->hostdata) - return 0; - - /* even though we errored, treat as success */ - devdata = (struct visorhba_devdata *)scsihost->hostdata; - if (!devdata) - return 0; - - vdisk = kzalloc(sizeof(*vdisk), GFP_ATOMIC); - if (!vdisk) - return -ENOMEM; - - vdisk->sdev = scsidev; - scsidev->hostdata = vdisk; - return 0; -} - -/* - * visorhba_slave_destroy - Disk is going away, clean up resources. - * @scsidev: Scsi device to destroy - */ -static void visorhba_slave_destroy(struct scsi_device *scsidev) -{ - /* midlevel calls this after device has been quiesced and - * before it is to be deleted. - */ - struct visordisk_info *vdisk; - - vdisk = scsidev->hostdata; - scsidev->hostdata = NULL; - kfree(vdisk); -} - -static struct scsi_host_template visorhba_driver_template = { - .name = "Unisys Visor HBA", - .info = visorhba_get_info, - .queuecommand = visorhba_queue_command, - .eh_abort_handler = visorhba_abort_handler, - .eh_device_reset_handler = visorhba_device_reset_handler, - .eh_bus_reset_handler = visorhba_bus_reset_handler, - .eh_host_reset_handler = visorhba_host_reset_handler, -#define visorhba_MAX_CMNDS 128 - .can_queue = visorhba_MAX_CMNDS, - .sg_tablesize = 64, - .this_id = -1, - .slave_alloc = visorhba_slave_alloc, - .slave_destroy = visorhba_slave_destroy, -}; - -/* - * info_debugfs_show - Debugfs interface to dump visorhba states - * @seq: The sequence file to write information to - * @v: Unused, but needed for use with seq file single_open invocation - * - * Presents a file in the debugfs tree named: /visorhba/vbus<x>:dev<y>/info. - * - * Return: SUCCESS - */ -static int info_debugfs_show(struct seq_file *seq, void *v) -{ - struct visorhba_devdata *devdata = seq->private; - - seq_printf(seq, "max_buff_len = %u\n", devdata->max_buff_len); - seq_printf(seq, "interrupts_rcvd = %llu\n", devdata->interrupts_rcvd); - seq_printf(seq, "interrupts_disabled = %llu\n", - devdata->interrupts_disabled); - seq_printf(seq, "interrupts_notme = %llu\n", - devdata->interrupts_notme); - seq_printf(seq, "flags_addr = %p\n", devdata->flags_addr); - if (devdata->flags_addr) { - u64 phys_flags_addr = - virt_to_phys((__force void *)devdata->flags_addr); - seq_printf(seq, "phys_flags_addr = 0x%016llx\n", - phys_flags_addr); - seq_printf(seq, "FeatureFlags = %llu\n", - (u64)readq(devdata->flags_addr)); - } - seq_printf(seq, "acquire_failed_cnt = %llu\n", - devdata->acquire_failed_cnt); - - return 0; -} -DEFINE_SHOW_ATTRIBUTE(info_debugfs); - -/* - * complete_taskmgmt_command - Complete task management - * @idrtable: The data object maintaining the pointer<-->int mappings - * @cmdrsp: Response from the IOVM - * @result: The result of the task management command - * - * Service Partition returned the result of the task management - * command. Wake up anyone waiting for it. - */ -static void complete_taskmgmt_command(struct xarray *xa, - struct uiscmdrsp *cmdrsp, int result) -{ - wait_queue_head_t *wq = - xa_load(xa, cmdrsp->scsitaskmgmt.notify_handle); - int *scsi_result_ptr = - xa_load(xa, cmdrsp->scsitaskmgmt.notifyresult_handle); - if (unlikely(!(wq && scsi_result_ptr))) { - pr_err("visorhba: no completion context; cmd will time out\n"); - return; - } - - /* copy the result of the taskmgmt and - * wake up the error handler that is waiting for this - */ - pr_debug("visorhba: notifying initiator with result=0x%x\n", result); - *scsi_result_ptr = result; - wake_up_all(wq); -} - -/* - * visorhba_serverdown_complete - Called when we are done cleaning up - * from serverdown - * @devdata: Visorhba instance on which to complete serverdown - * - * Called when we are done cleanning up from serverdown, stop processing - * queue, fail pending IOs. - */ -static void visorhba_serverdown_complete(struct visorhba_devdata *devdata) -{ - int i; - struct scsipending *pendingdel = NULL; - struct scsi_cmnd *scsicmd = NULL; - struct uiscmdrsp *cmdrsp; - unsigned long flags; - - /* Stop using the IOVM response queue (queue should be drained - * by the end) - */ - visorbus_disable_channel_interrupts(devdata->dev); - - /* Fail commands that weren't completed */ - spin_lock_irqsave(&devdata->privlock, flags); - for (i = 0; i < MAX_PENDING_REQUESTS; i++) { - pendingdel = &devdata->pending[i]; - switch (pendingdel->cmdtype) { - case CMD_SCSI_TYPE: - scsicmd = pendingdel->sent; - scsicmd->result = DID_RESET << 16; - scsi_done(scsicmd); - break; - case CMD_SCSITASKMGMT_TYPE: - cmdrsp = pendingdel->sent; - complete_taskmgmt_command(&devdata->xa, cmdrsp, - TASK_MGMT_FAILED); - break; - default: - break; - } - pendingdel->cmdtype = 0; - pendingdel->sent = NULL; - } - spin_unlock_irqrestore(&devdata->privlock, flags); - - devdata->serverdown = true; - devdata->serverchangingstate = false; -} - -/* - * visorhba_serverdown - Got notified that the IOVM is down - * @devdata: Visorhba that is being serviced by downed IOVM - * - * Something happened to the IOVM, return immediately and - * schedule cleanup work. - * - * Return: 0 on success, -EINVAL on failure - */ -static int visorhba_serverdown(struct visorhba_devdata *devdata) -{ - if (!devdata->serverdown && !devdata->serverchangingstate) { - devdata->serverchangingstate = true; - visorhba_serverdown_complete(devdata); - } else if (devdata->serverchangingstate) { - return -EINVAL; - } - return 0; -} - -/* - * do_scsi_linuxstat - Scsi command returned linuxstat - * @cmdrsp: Response from IOVM - * @scsicmd: Command issued - * - * Don't log errors for disk-not-present inquiries. - */ -static void do_scsi_linuxstat(struct uiscmdrsp *cmdrsp, - struct scsi_cmnd *scsicmd) -{ - struct visordisk_info *vdisk; - struct scsi_device *scsidev; - - scsidev = scsicmd->device; - memcpy(scsicmd->sense_buffer, cmdrsp->scsi.sensebuf, MAX_SENSE_SIZE); - - /* Do not log errors for disk-not-present inquiries */ - if (cmdrsp->scsi.cmnd[0] == INQUIRY && - (host_byte(cmdrsp->scsi.linuxstat) == DID_NO_CONNECT) && - cmdrsp->scsi.addlstat == ADDL_SEL_TIMEOUT) - return; - /* Okay see what our error_count is here.... */ - vdisk = scsidev->hostdata; - if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) { - atomic_inc(&vdisk->error_count); - atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); - } -} - -static int set_no_disk_inquiry_result(unsigned char *buf, size_t len, - bool is_lun0) -{ - if (len < NO_DISK_INQUIRY_RESULT_LEN) - return -EINVAL; - memset(buf, 0, NO_DISK_INQUIRY_RESULT_LEN); - buf[2] = SCSI_SPC2_VER; - if (is_lun0) { - buf[0] = DEV_DISK_CAPABLE_NOT_PRESENT; - buf[3] = DEV_HISUPPORT; - } else { - buf[0] = DEV_NOT_CAPABLE; - } - buf[4] = NO_DISK_INQUIRY_RESULT_LEN - 5; - strncpy(buf + 8, "DELLPSEUDO DEVICE .", NO_DISK_INQUIRY_RESULT_LEN - 8); - return 0; -} - -/* - * do_scsi_nolinuxstat - Scsi command didn't have linuxstat - * @cmdrsp: Response from IOVM - * @scsicmd: Command issued - * - * Handle response when no linuxstat was returned. - */ -static void do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, - struct scsi_cmnd *scsicmd) -{ - struct scsi_device *scsidev; - unsigned char *buf; - struct scatterlist *sg; - unsigned int i; - char *this_page; - char *this_page_orig; - int bufind = 0; - struct visordisk_info *vdisk; - - scsidev = scsicmd->device; - if (cmdrsp->scsi.cmnd[0] == INQUIRY && - cmdrsp->scsi.bufflen >= MIN_INQUIRY_RESULT_LEN) { - if (cmdrsp->scsi.no_disk_result == 0) - return; - - buf = kzalloc(36, GFP_KERNEL); - if (!buf) - return; - - /* Linux scsi code wants a device at Lun 0 - * to issue report luns, but we don't want - * a disk there so we'll present a processor - * there. - */ - set_no_disk_inquiry_result(buf, (size_t)cmdrsp->scsi.bufflen, - scsidev->lun == 0); - - if (scsi_sg_count(scsicmd) == 0) { - memcpy(scsi_sglist(scsicmd), buf, - cmdrsp->scsi.bufflen); - kfree(buf); - return; - } - - scsi_for_each_sg(scsicmd, sg, scsi_sg_count(scsicmd), i) { - this_page_orig = kmap_atomic(sg_page(sg)); - this_page = (void *)((unsigned long)this_page_orig | - sg->offset); - memcpy(this_page, buf + bufind, sg->length); - kunmap_atomic(this_page_orig); - } - kfree(buf); - } else { - vdisk = scsidev->hostdata; - if (atomic_read(&vdisk->ios_threshold) > 0) { - atomic_dec(&vdisk->ios_threshold); - if (atomic_read(&vdisk->ios_threshold) == 0) - atomic_set(&vdisk->error_count, 0); - } - } -} - -/* - * complete_scsi_command - Complete a scsi command - * @uiscmdrsp: Response from Service Partition - * @scsicmd: The scsi command - * - * Response was returned by the Service Partition. Finish it and send - * completion to the scsi midlayer. - */ -static void complete_scsi_command(struct uiscmdrsp *cmdrsp, - struct scsi_cmnd *scsicmd) -{ - /* take what we need out of cmdrsp and complete the scsicmd */ - scsicmd->result = cmdrsp->scsi.linuxstat; - if (cmdrsp->scsi.linuxstat) - do_scsi_linuxstat(cmdrsp, scsicmd); - else - do_scsi_nolinuxstat(cmdrsp, scsicmd); - - scsi_done(scsicmd); -} - -/* - * drain_queue - Pull responses out of iochannel - * @cmdrsp: Response from the IOSP - * @devdata: Device that owns this iochannel - * - * Pulls responses out of the iochannel and process the responses. - */ -static void drain_queue(struct uiscmdrsp *cmdrsp, - struct visorhba_devdata *devdata) -{ - struct scsi_cmnd *scsicmd; - - while (1) { - /* queue empty */ - if (visorchannel_signalremove(devdata->dev->visorchannel, - IOCHAN_FROM_IOPART, - cmdrsp)) - break; - if (cmdrsp->cmdtype == CMD_SCSI_TYPE) { - /* scsicmd location is returned by the - * deletion - */ - scsicmd = del_scsipending_ent(devdata, - cmdrsp->scsi.handle); - if (!scsicmd) - break; - /* complete the orig cmd */ - complete_scsi_command(cmdrsp, scsicmd); - } else if (cmdrsp->cmdtype == CMD_SCSITASKMGMT_TYPE) { - if (!del_scsipending_ent(devdata, - cmdrsp->scsitaskmgmt.handle)) - break; - complete_taskmgmt_command(&devdata->xa, cmdrsp, - cmdrsp->scsitaskmgmt.result); - } else if (cmdrsp->cmdtype == CMD_NOTIFYGUEST_TYPE) - dev_err_once(&devdata->dev->device, - "ignoring unsupported NOTIFYGUEST\n"); - /* cmdrsp is now available for re-use */ - } -} - -/* - * This is used only when this driver is active as an hba driver in the - * client guest partition. It is called periodically so we can obtain - * and process the command respond from the IO Service Partition periodically. - */ -static void visorhba_channel_interrupt(struct visor_device *dev) -{ - struct visorhba_devdata *devdata = dev_get_drvdata(&dev->device); - - if (!devdata) - return; - - drain_queue(devdata->cmdrsp, devdata); -} - -/* - * visorhba_pause - Function to handle visorbus pause messages - * @dev: Device that is pausing - * @complete_func: Function to call when finished - * - * Something has happened to the IO Service Partition that is - * handling this device. Quiet this device and reset commands - * so that the Service Partition can be corrected. - * - * Return: SUCCESS - */ -static int visorhba_pause(struct visor_device *dev, - visorbus_state_complete_func complete_func) -{ - struct visorhba_devdata *devdata = dev_get_drvdata(&dev->device); - - visorhba_serverdown(devdata); - complete_func(dev, 0); - return 0; -} - -/* - * visorhba_resume - Function called when the IO Service Partition is back - * @dev: Device that is pausing - * @complete_func: Function to call when finished - * - * Yay! The IO Service Partition is back, the channel has been wiped - * so lets re-establish connection and start processing responses. - * - * Return: 0 on success, -EINVAL on failure - */ -static int visorhba_resume(struct visor_device *dev, - visorbus_state_complete_func complete_func) -{ - struct visorhba_devdata *devdata; - - devdata = dev_get_drvdata(&dev->device); - if (!devdata) - return -EINVAL; - - if (devdata->serverdown && !devdata->serverchangingstate) - devdata->serverchangingstate = true; - - visorbus_enable_channel_interrupts(dev); - devdata->serverdown = false; - devdata->serverchangingstate = false; - - return 0; -} - -/* - * visorhba_probe - Device has been discovered; do acquire - * @dev: visor_device that was discovered - * - * A new HBA was discovered; do the initial connections of it. - * - * Return: 0 on success, otherwise error code - */ -static int visorhba_probe(struct visor_device *dev) -{ - struct Scsi_Host *scsihost; - struct vhba_config_max max; - struct visorhba_devdata *devdata = NULL; - int err, channel_offset; - u64 features; - - scsihost = scsi_host_alloc(&visorhba_driver_template, - sizeof(*devdata)); - if (!scsihost) - return -ENODEV; - - channel_offset = offsetof(struct visor_io_channel, vhba.max); - err = visorbus_read_channel(dev, channel_offset, &max, - sizeof(struct vhba_config_max)); - if (err < 0) - goto err_scsi_host_put; - - scsihost->max_id = (unsigned int)max.max_id; - scsihost->max_lun = (unsigned int)max.max_lun; - scsihost->cmd_per_lun = (unsigned int)max.cmd_per_lun; - scsihost->max_sectors = - (unsigned short)(max.max_io_size >> 9); - scsihost->sg_tablesize = - (unsigned short)(max.max_io_size / PAGE_SIZE); - if (scsihost->sg_tablesize > MAX_PHYS_INFO) - scsihost->sg_tablesize = MAX_PHYS_INFO; - err = scsi_add_host(scsihost, &dev->device); - if (err < 0) - goto err_scsi_host_put; - - devdata = (struct visorhba_devdata *)scsihost->hostdata; - devdata->dev = dev; - dev_set_drvdata(&dev->device, devdata); - - devdata->debugfs_dir = debugfs_create_dir(dev_name(&dev->device), - visorhba_debugfs_dir); - if (!devdata->debugfs_dir) { - err = -ENOMEM; - goto err_scsi_remove_host; - } - devdata->debugfs_info = - debugfs_create_file("info", 0440, - devdata->debugfs_dir, devdata, - &info_debugfs_fops); - if (!devdata->debugfs_info) { - err = -ENOMEM; - goto err_debugfs_dir; - } - - spin_lock_init(&devdata->privlock); - devdata->serverdown = false; - devdata->serverchangingstate = false; - devdata->scsihost = scsihost; - - channel_offset = offsetof(struct visor_io_channel, - channel_header.features); - err = visorbus_read_channel(dev, channel_offset, &features, 8); - if (err) - goto err_debugfs_info; - features |= VISOR_CHANNEL_IS_POLLING; - err = visorbus_write_channel(dev, channel_offset, &features, 8); - if (err) - goto err_debugfs_info; - - xa_init(&devdata->xa); - - devdata->cmdrsp = kmalloc(sizeof(*devdata->cmdrsp), GFP_ATOMIC); - visorbus_enable_channel_interrupts(dev); - - scsi_scan_host(scsihost); - - return 0; - -err_debugfs_info: - debugfs_remove(devdata->debugfs_info); - -err_debugfs_dir: - debugfs_remove_recursive(devdata->debugfs_dir); - -err_scsi_remove_host: - scsi_remove_host(scsihost); - -err_scsi_host_put: - scsi_host_put(scsihost); - return err; -} - -/* - * visorhba_remove - Remove a visorhba device - * @dev: Device to remove - * - * Removes the visorhba device. - */ -static void visorhba_remove(struct visor_device *dev) -{ - struct visorhba_devdata *devdata = dev_get_drvdata(&dev->device); - struct Scsi_Host *scsihost = NULL; - - if (!devdata) - return; - - scsihost = devdata->scsihost; - kfree(devdata->cmdrsp); - visorbus_disable_channel_interrupts(dev); - scsi_remove_host(scsihost); - scsi_host_put(scsihost); - - dev_set_drvdata(&dev->device, NULL); - debugfs_remove(devdata->debugfs_info); - debugfs_remove_recursive(devdata->debugfs_dir); -} - -/* This is used to tell the visorbus 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 = visorhba_channel_interrupt, -}; - -/* - * visorhba_init - Driver init routine - * - * Initialize the visorhba driver and register it with visorbus - * to handle s-Par virtual host bus adapter. - * - * Return: 0 on success, error code otherwise - */ -static int visorhba_init(void) -{ - int rc; - - visorhba_debugfs_dir = debugfs_create_dir("visorhba", NULL); - if (!visorhba_debugfs_dir) - return -ENOMEM; - - rc = visorbus_register_visor_driver(&visorhba_driver); - if (rc) - goto cleanup_debugfs; - - return 0; - -cleanup_debugfs: - debugfs_remove_recursive(visorhba_debugfs_dir); - - return rc; -} - -/* - * visorhba_exit - Driver exit routine - * - * Unregister driver from the bus and free up memory. - */ -static void visorhba_exit(void) -{ - visorbus_unregister_visor_driver(&visorhba_driver); - debugfs_remove_recursive(visorhba_debugfs_dir); -} - -module_init(visorhba_init); -module_exit(visorhba_exit); - -MODULE_AUTHOR("Unisys"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("s-Par HBA driver for virtual SCSI host busses"); diff --git a/drivers/staging/unisys/visorinput/Kconfig b/drivers/staging/unisys/visorinput/Kconfig deleted file mode 100644 index 5f036393aee9..000000000000 --- a/drivers/staging/unisys/visorinput/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Unisys visorinput configuration -# - -config UNISYS_VISORINPUT - tristate "Unisys visorinput driver" - depends on UNISYSSPAR && UNISYS_VISORBUS && INPUT - help - The Unisys s-Par visorinput driver provides a virtualized system - console (keyboard and mouse) that is accessible through the - s-Par firmware's user interface. s-Par provides video using the EFI - GOP protocol, so If this driver is not present, the Linux guest should - still boot with visible output in the partition desktop, but keyboard - and mouse interaction will not be available. - diff --git a/drivers/staging/unisys/visorinput/Makefile b/drivers/staging/unisys/visorinput/Makefile deleted file mode 100644 index 68ced7c8a65f..000000000000 --- a/drivers/staging/unisys/visorinput/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for Unisys visorinput -# - -obj-$(CONFIG_UNISYS_VISORINPUT) += visorinput.o - diff --git a/drivers/staging/unisys/visorinput/visorinput.c b/drivers/staging/unisys/visorinput/visorinput.c deleted file mode 100644 index dffa71ac3cc5..000000000000 --- a/drivers/staging/unisys/visorinput/visorinput.c +++ /dev/null @@ -1,788 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2011 - 2015 UNISYS CORPORATION - * All rights reserved. - */ - -/* - * This driver lives in a generic guest Linux partition, and registers to - * receive keyboard and mouse channels from the visorbus driver. It reads - * inputs from such channels, and delivers it to the Linux OS in the - * standard way the Linux expects for input drivers. - */ - -#include <linux/fb.h> -#include <linux/input.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/uuid.h> -#include <linux/visorbus.h> - -/* These defines identify mouse and keyboard activity which is specified by the - * firmware to the host using the cmsimpleinput protocol. @ingroup coretypes - */ -/* only motion; arg1=x, arg2=y */ -#define INPUTACTION_XY_MOTION 1 - -/* arg1: 1=left,2=center,3=right */ -#define INPUTACTION_MOUSE_BUTTON_DOWN 2 -#define INPUTACTION_MOUSE_BUTTON_UP 3 -#define INPUTACTION_MOUSE_BUTTON_CLICK 4 -#define INPUTACTION_MOUSE_BUTTON_DCLICK 5 - -/* arg1: wheel rotation away from/toward user */ -#define INPUTACTION_WHEEL_ROTATE_AWAY 6 -#define INPUTACTION_WHEEL_ROTATE_TOWARD 7 - -/* arg1: scancode, as follows: If arg1 <= 0xff, it's a 1-byte scancode and arg1 - * is that scancode. If arg1 > 0xff, it's a 2-byte scanecode, with the 1st - * byte in the low 8 bits, and the 2nd byte in the high 8 bits. - * E.g., the right ALT key would appear as x'38e0'. - */ -#define INPUTACTION_KEY_DOWN 64 -#define INPUTACTION_KEY_UP 65 -#define INPUTACTION_KEY_DOWN_UP 67 - -/* arg1: scancode (in same format as inputaction_keyDown); MUST refer to one of - * the locking keys, like capslock, numlock, or scrolllock. - * arg2: 1 iff locking key should be in the LOCKED position (e.g., light is ON) - */ -#define INPUTACTION_SET_LOCKING_KEY_STATE 66 - -/* Keyboard channel {c73416d0-b0b8-44af-b304-9d2ae99f1b3d} */ -#define VISOR_KEYBOARD_CHANNEL_GUID \ - GUID_INIT(0xc73416d0, 0xb0b8, 0x44af, \ - 0xb3, 0x4, 0x9d, 0x2a, 0xe9, 0x9f, 0x1b, 0x3d) -#define VISOR_KEYBOARD_CHANNEL_GUID_STR "c73416d0-b0b8-44af-b304-9d2ae99f1b3d" - -/* Mouse channel {addf07d4-94a9-46e2-81c3-61abcdbdbd87} */ -#define VISOR_MOUSE_CHANNEL_GUID \ - GUID_INIT(0xaddf07d4, 0x94a9, 0x46e2, \ - 0x81, 0xc3, 0x61, 0xab, 0xcd, 0xbd, 0xbd, 0x87) -#define VISOR_MOUSE_CHANNEL_GUID_STR "addf07d4-94a9-46e2-81c3-61abcdbdbd87" - -#define PIXELS_ACROSS_DEFAULT 1024 -#define PIXELS_DOWN_DEFAULT 768 -#define KEYCODE_TABLE_BYTES 256 - -struct visor_inputactivity { - u16 action; - u16 arg1; - u16 arg2; - u16 arg3; -} __packed; - -struct visor_inputreport { - u64 seq_no; - struct visor_inputactivity activity; -} __packed; - -/* header of keyboard/mouse channels */ -struct visor_input_channel_data { - u32 n_input_reports; - union { - struct { - u16 x_res; - u16 y_res; - } mouse; - struct { - u32 flags; - } keyboard; - }; -} __packed; - -enum visorinput_dev_type { - visorinput_keyboard, - visorinput_mouse, -}; - -/* - * This is the private data that we store for each device. A pointer to this - * struct is maintained via dev_get_drvdata() / dev_set_drvdata() for each - * struct device. - */ -struct visorinput_devdata { - struct visor_device *dev; - /* lock for dev */ - struct mutex lock_visor_dev; - struct input_dev *visorinput_dev; - bool paused; - bool interrupts_enabled; - /* size of following array */ - unsigned int keycode_table_bytes; - /* for keyboard devices: visorkbd_keycode[] + visorkbd_ext_keycode[] */ - unsigned char keycode_table[]; -}; - -static const guid_t visor_keyboard_channel_guid = VISOR_KEYBOARD_CHANNEL_GUID; -static const guid_t visor_mouse_channel_guid = VISOR_MOUSE_CHANNEL_GUID; - -/* - * Borrowed from drivers/input/keyboard/atakbd.c - * This maps 1-byte scancodes to keycodes. - */ -static const unsigned char visorkbd_keycode[KEYCODE_TABLE_BYTES] = { - /* American layout */ - [0] = KEY_GRAVE, - [1] = KEY_ESC, - [2] = KEY_1, - [3] = KEY_2, - [4] = KEY_3, - [5] = KEY_4, - [6] = KEY_5, - [7] = KEY_6, - [8] = KEY_7, - [9] = KEY_8, - [10] = KEY_9, - [11] = KEY_0, - [12] = KEY_MINUS, - [13] = KEY_EQUAL, - [14] = KEY_BACKSPACE, - [15] = KEY_TAB, - [16] = KEY_Q, - [17] = KEY_W, - [18] = KEY_E, - [19] = KEY_R, - [20] = KEY_T, - [21] = KEY_Y, - [22] = KEY_U, - [23] = KEY_I, - [24] = KEY_O, - [25] = KEY_P, - [26] = KEY_LEFTBRACE, - [27] = KEY_RIGHTBRACE, - [28] = KEY_ENTER, - [29] = KEY_LEFTCTRL, - [30] = KEY_A, - [31] = KEY_S, - [32] = KEY_D, - [33] = KEY_F, - [34] = KEY_G, - [35] = KEY_H, - [36] = KEY_J, - [37] = KEY_K, - [38] = KEY_L, - [39] = KEY_SEMICOLON, - [40] = KEY_APOSTROPHE, - [41] = KEY_GRAVE, - [42] = KEY_LEFTSHIFT, - [43] = KEY_BACKSLASH, - [44] = KEY_Z, - [45] = KEY_X, - [46] = KEY_C, - [47] = KEY_V, - [48] = KEY_B, - [49] = KEY_N, - [50] = KEY_M, - [51] = KEY_COMMA, - [52] = KEY_DOT, - [53] = KEY_SLASH, - [54] = KEY_RIGHTSHIFT, - [55] = KEY_KPASTERISK, - [56] = KEY_LEFTALT, - [57] = KEY_SPACE, - [58] = KEY_CAPSLOCK, - [59] = KEY_F1, - [60] = KEY_F2, - [61] = KEY_F3, - [62] = KEY_F4, - [63] = KEY_F5, - [64] = KEY_F6, - [65] = KEY_F7, - [66] = KEY_F8, - [67] = KEY_F9, - [68] = KEY_F10, - [69] = KEY_NUMLOCK, - [70] = KEY_SCROLLLOCK, - [71] = KEY_KP7, - [72] = KEY_KP8, - [73] = KEY_KP9, - [74] = KEY_KPMINUS, - [75] = KEY_KP4, - [76] = KEY_KP5, - [77] = KEY_KP6, - [78] = KEY_KPPLUS, - [79] = KEY_KP1, - [80] = KEY_KP2, - [81] = KEY_KP3, - [82] = KEY_KP0, - [83] = KEY_KPDOT, - /* enables UK backslash+pipe key and FR lessthan+greaterthan key */ - [86] = KEY_102ND, - [87] = KEY_F11, - [88] = KEY_F12, - [90] = KEY_KPLEFTPAREN, - [91] = KEY_KPRIGHTPAREN, - [92] = KEY_KPASTERISK, - [93] = KEY_KPASTERISK, - [94] = KEY_KPPLUS, - [95] = KEY_HELP, - [96] = KEY_KPENTER, - [97] = KEY_RIGHTCTRL, - [98] = KEY_KPSLASH, - [99] = KEY_KPLEFTPAREN, - [100] = KEY_KPRIGHTPAREN, - [101] = KEY_KPSLASH, - [102] = KEY_HOME, - [103] = KEY_UP, - [104] = KEY_PAGEUP, - [105] = KEY_LEFT, - [106] = KEY_RIGHT, - [107] = KEY_END, - [108] = KEY_DOWN, - [109] = KEY_PAGEDOWN, - [110] = KEY_INSERT, - [111] = KEY_DELETE, - [112] = KEY_MACRO, - [113] = KEY_MUTE -}; - -/* - * This maps the <xx> in extended scancodes of the form "0xE0 <xx>" into - * keycodes. - */ -static const unsigned char visorkbd_ext_keycode[KEYCODE_TABLE_BYTES] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */ - 0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, 0, 0, /* 0x18 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */ - KEY_RIGHTALT, 0, 0, 0, 0, 0, 0, 0, /* 0x28 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 */ - KEY_RIGHTALT /* AltGr */, 0, 0, 0, 0, 0, 0, 0, /* 0x38 */ - 0, 0, 0, 0, 0, 0, 0, KEY_HOME, /* 0x40 */ - KEY_UP, KEY_PAGEUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END, /* 0x48 */ - KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, 0, /* 0x50 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x58 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */ -}; - -static int visorinput_open(struct input_dev *visorinput_dev) -{ - struct visorinput_devdata *devdata = input_get_drvdata(visorinput_dev); - - if (!devdata) { - dev_err(&visorinput_dev->dev, - "%s input_get_drvdata(%p) returned NULL\n", - __func__, 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; -} - -static void visorinput_close(struct input_dev *visorinput_dev) -{ - struct visorinput_devdata *devdata = input_get_drvdata(visorinput_dev); - - if (!devdata) { - dev_err(&visorinput_dev->dev, - "%s input_get_drvdata(%p) returned NULL\n", - __func__, 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); -} - -/* - * 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 *setup_client_keyboard(void *devdata, - unsigned char *keycode_table) - -{ - int i; - struct input_dev *visorinput_dev = input_allocate_device(); - - if (!visorinput_dev) - return NULL; - - visorinput_dev->name = "visor Keyboard"; - visorinput_dev->phys = "visorkbd:input0"; - visorinput_dev->id.bustype = BUS_VIRTUAL; - visorinput_dev->id.vendor = 0x0001; - visorinput_dev->id.product = 0x0001; - visorinput_dev->id.version = 0x0100; - - visorinput_dev->evbit[0] = BIT_MASK(EV_KEY) | - BIT_MASK(EV_REP) | - BIT_MASK(EV_LED); - visorinput_dev->ledbit[0] = BIT_MASK(LED_CAPSL) | - BIT_MASK(LED_SCROLLL) | - BIT_MASK(LED_NUML); - visorinput_dev->keycode = keycode_table; - /* sizeof(unsigned char) */ - visorinput_dev->keycodesize = 1; - visorinput_dev->keycodemax = KEYCODE_TABLE_BYTES; - - for (i = 1; i < visorinput_dev->keycodemax; i++) - set_bit(keycode_table[i], visorinput_dev->keybit); - for (i = 1; i < visorinput_dev->keycodemax; i++) - set_bit(keycode_table[i + KEYCODE_TABLE_BYTES], - visorinput_dev->keybit); - - visorinput_dev->open = visorinput_open; - visorinput_dev->close = visorinput_close; - /* pre input_register! */ - input_set_drvdata(visorinput_dev, devdata); - - return visorinput_dev; -} - -static struct input_dev *setup_client_mouse(void *devdata, unsigned int xres, - unsigned int yres) -{ - struct input_dev *visorinput_dev = input_allocate_device(); - - if (!visorinput_dev) - return NULL; - - visorinput_dev->name = "visor Mouse"; - visorinput_dev->phys = "visormou:input0"; - visorinput_dev->id.bustype = BUS_VIRTUAL; - visorinput_dev->id.vendor = 0x0001; - visorinput_dev->id.product = 0x0002; - visorinput_dev->id.version = 0x0100; - - visorinput_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - set_bit(BTN_LEFT, visorinput_dev->keybit); - set_bit(BTN_RIGHT, visorinput_dev->keybit); - set_bit(BTN_MIDDLE, visorinput_dev->keybit); - - if (xres == 0) - xres = PIXELS_ACROSS_DEFAULT; - if (yres == 0) - yres = PIXELS_DOWN_DEFAULT; - input_set_abs_params(visorinput_dev, ABS_X, 0, xres, 0, 0); - input_set_abs_params(visorinput_dev, ABS_Y, 0, yres, 0, 0); - - visorinput_dev->open = visorinput_open; - visorinput_dev->close = visorinput_close; - /* pre input_register! */ - input_set_drvdata(visorinput_dev, devdata); - input_set_capability(visorinput_dev, EV_REL, REL_WHEEL); - - return visorinput_dev; -} - -static struct visorinput_devdata *devdata_create(struct visor_device *dev, - enum visorinput_dev_type dtype) -{ - struct visorinput_devdata *devdata = NULL; - unsigned int extra_bytes = 0; - unsigned int size, xres, yres, err; - struct visor_input_channel_data data; - - if (dtype == visorinput_keyboard) - /* allocate room for devdata->keycode_table, filled in below */ - extra_bytes = KEYCODE_TABLE_BYTES * 2; - devdata = kzalloc(struct_size(devdata, keycode_table, 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. - */ - switch (dtype) { - case visorinput_keyboard: - devdata->keycode_table_bytes = extra_bytes; - memcpy(devdata->keycode_table, visorkbd_keycode, - KEYCODE_TABLE_BYTES); - memcpy(devdata->keycode_table + KEYCODE_TABLE_BYTES, - visorkbd_ext_keycode, KEYCODE_TABLE_BYTES); - devdata->visorinput_dev = setup_client_keyboard - (devdata, devdata->keycode_table); - if (!devdata->visorinput_dev) - goto cleanups_register; - break; - case visorinput_mouse: - size = sizeof(struct visor_input_channel_data); - err = visorbus_read_channel(dev, sizeof(struct channel_header), - &data, size); - if (err) - goto cleanups_register; - xres = data.mouse.x_res; - yres = data.mouse.y_res; - devdata->visorinput_dev = setup_client_mouse(devdata, xres, - yres); - if (!devdata->visorinput_dev) - goto cleanups_register; - break; - default: - /* No other input devices supported */ - break; - } - - 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; -} - -static int visorinput_probe(struct visor_device *dev) -{ - const guid_t *guid; - enum visorinput_dev_type dtype; - - guid = visorchannel_get_guid(dev->visorchannel); - if (guid_equal(guid, &visor_mouse_channel_guid)) - dtype = visorinput_mouse; - else if (guid_equal(guid, &visor_keyboard_channel_guid)) - dtype = visorinput_keyboard; - else - return -ENODEV; - visorbus_disable_channel_interrupts(dev); - if (!devdata_create(dev, dtype)) - return -ENOMEM; - return 0; -} - -static void unregister_client_input(struct input_dev *visorinput_dev) -{ - if (visorinput_dev) - input_unregister_device(visorinput_dev); -} - -static void visorinput_remove(struct visor_device *dev) -{ - struct visorinput_devdata *devdata = dev_get_drvdata(&dev->device); - - if (!devdata) - return; - - mutex_lock(&devdata->lock_visor_dev); - visorbus_disable_channel_interrupts(dev); - - /* - * due to above, at this time no thread of execution will be in - * visorinput_channel_interrupt() - */ - - dev_set_drvdata(&dev->device, NULL); - mutex_unlock(&devdata->lock_visor_dev); - - unregister_client_input(devdata->visorinput_dev); - kfree(devdata); -} - -/* - * Make it so the current locking state of the locking key indicated by - * <keycode> is as indicated by <desired_state> (1=locked, 0=unlocked). - */ -static void handle_locking_key(struct input_dev *visorinput_dev, int keycode, - int desired_state) -{ - int led; - - switch (keycode) { - case KEY_CAPSLOCK: - led = LED_CAPSL; - break; - case KEY_SCROLLLOCK: - led = LED_SCROLLL; - break; - case KEY_NUMLOCK: - led = LED_NUML; - break; - default: - return; - } - if (test_bit(led, visorinput_dev->led) != desired_state) { - input_report_key(visorinput_dev, keycode, 1); - input_sync(visorinput_dev); - input_report_key(visorinput_dev, keycode, 0); - input_sync(visorinput_dev); - __change_bit(led, visorinput_dev->led); - } -} - -/* - * <scancode> is either a 1-byte scancode, or an extended 16-bit scancode with - * 0xE0 in the low byte and the extended scancode value in the next higher byte. - */ -static int scancode_to_keycode(int scancode) -{ - if (scancode > 0xff) - return visorkbd_ext_keycode[(scancode >> 8) & 0xff]; - - return visorkbd_keycode[scancode]; -} - -static int calc_button(int x) -{ - switch (x) { - case 1: - return BTN_LEFT; - case 2: - return BTN_MIDDLE; - case 3: - return BTN_RIGHT; - default: - return -EINVAL; - } -} - -/* - * This is used only when this driver is active as an input driver in the - * client guest partition. It is called periodically so we can obtain inputs - * from the channel, and deliver them to the guest OS. - */ -static void visorinput_channel_interrupt(struct visor_device *dev) -{ - struct visor_inputreport r; - int scancode, keycode; - struct input_dev *visorinput_dev; - int xmotion, ymotion, button; - int i; - struct visorinput_devdata *devdata = dev_get_drvdata(&dev->device); - - if (!devdata) - return; - - visorinput_dev = devdata->visorinput_dev; - - while (!visorchannel_signalremove(dev->visorchannel, 0, &r)) { - scancode = r.activity.arg1; - keycode = scancode_to_keycode(scancode); - switch (r.activity.action) { - case INPUTACTION_KEY_DOWN: - input_report_key(visorinput_dev, keycode, 1); - input_sync(visorinput_dev); - break; - case INPUTACTION_KEY_UP: - input_report_key(visorinput_dev, keycode, 0); - input_sync(visorinput_dev); - break; - case INPUTACTION_KEY_DOWN_UP: - input_report_key(visorinput_dev, keycode, 1); - input_sync(visorinput_dev); - input_report_key(visorinput_dev, keycode, 0); - input_sync(visorinput_dev); - break; - case INPUTACTION_SET_LOCKING_KEY_STATE: - handle_locking_key(visorinput_dev, keycode, - r.activity.arg2); - break; - case INPUTACTION_XY_MOTION: - xmotion = r.activity.arg1; - ymotion = r.activity.arg2; - input_report_abs(visorinput_dev, ABS_X, xmotion); - input_report_abs(visorinput_dev, ABS_Y, ymotion); - input_sync(visorinput_dev); - break; - case INPUTACTION_MOUSE_BUTTON_DOWN: - button = calc_button(r.activity.arg1); - if (button < 0) - break; - input_report_key(visorinput_dev, button, 1); - input_sync(visorinput_dev); - break; - case INPUTACTION_MOUSE_BUTTON_UP: - button = calc_button(r.activity.arg1); - if (button < 0) - break; - input_report_key(visorinput_dev, button, 0); - input_sync(visorinput_dev); - break; - case INPUTACTION_MOUSE_BUTTON_CLICK: - button = calc_button(r.activity.arg1); - if (button < 0) - break; - input_report_key(visorinput_dev, button, 1); - input_sync(visorinput_dev); - input_report_key(visorinput_dev, button, 0); - input_sync(visorinput_dev); - break; - case INPUTACTION_MOUSE_BUTTON_DCLICK: - button = calc_button(r.activity.arg1); - if (button < 0) - break; - for (i = 0; i < 2; i++) { - input_report_key(visorinput_dev, button, 1); - input_sync(visorinput_dev); - input_report_key(visorinput_dev, button, 0); - input_sync(visorinput_dev); - } - break; - case INPUTACTION_WHEEL_ROTATE_AWAY: - input_report_rel(visorinput_dev, REL_WHEEL, 1); - input_sync(visorinput_dev); - break; - case INPUTACTION_WHEEL_ROTATE_TOWARD: - input_report_rel(visorinput_dev, REL_WHEEL, -1); - input_sync(visorinput_dev); - break; - default: - /* Unsupported input action */ - break; - } - } -} - -static int visorinput_pause(struct visor_device *dev, - visorbus_state_complete_func complete_func) -{ - int rc; - struct visorinput_devdata *devdata = dev_get_drvdata(&dev->device); - - if (!devdata) { - rc = -ENODEV; - goto out; - } - - 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: - mutex_unlock(&devdata->lock_visor_dev); -out: - return rc; -} - -static int visorinput_resume(struct visor_device *dev, - visorbus_state_complete_func complete_func) -{ - int rc; - struct visorinput_devdata *devdata = dev_get_drvdata(&dev->device); - - if (!devdata) { - rc = -ENODEV; - goto out; - } - 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: - mutex_unlock(&devdata->lock_visor_dev); -out: - return rc; -} - -/* GUIDS for all channel types supported by this driver. */ -static struct visor_channeltype_descriptor visorinput_channel_types[] = { - { VISOR_KEYBOARD_CHANNEL_GUID, "keyboard", - sizeof(struct channel_header), 0 }, - { VISOR_MOUSE_CHANNEL_GUID, "mouse", sizeof(struct channel_header), 0 }, - {} -}; - -static struct visor_driver visorinput_driver = { - .name = "visorinput", - .owner = THIS_MODULE, - .channel_types = visorinput_channel_types, - .probe = visorinput_probe, - .remove = visorinput_remove, - .channel_interrupt = visorinput_channel_interrupt, - .pause = visorinput_pause, - .resume = visorinput_resume, -}; - -module_driver(visorinput_driver, visorbus_register_visor_driver, - visorbus_unregister_visor_driver); - -MODULE_DEVICE_TABLE(visorbus, visorinput_channel_types); - -MODULE_AUTHOR("Unisys"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("s-Par human input driver for virtual keyboard/mouse"); - -MODULE_ALIAS("visorbus:" VISOR_MOUSE_CHANNEL_GUID_STR); -MODULE_ALIAS("visorbus:" VISOR_KEYBOARD_CHANNEL_GUID_STR); diff --git a/drivers/staging/unisys/visornic/Kconfig b/drivers/staging/unisys/visornic/Kconfig deleted file mode 100644 index 3f8f5570821b..000000000000 --- a/drivers/staging/unisys/visornic/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Unisys visornic configuration -# - -config UNISYS_VISORNIC - tristate "Unisys visornic driver" - depends on UNISYSSPAR && UNISYS_VISORBUS && NET - help - The Unisys Visornic driver provides support for s-Par network - devices exposed on the s-Par visorbus. When a message is sent - to visorbus to create a network device, the probe function of - visornic is called to create the netdev device. Networking on - s-Par switches will not work if this driver is not selected. - If you say Y here, you will enable the Unisys visornic driver. - diff --git a/drivers/staging/unisys/visornic/Makefile b/drivers/staging/unisys/visornic/Makefile deleted file mode 100644 index f2984880c340..000000000000 --- a/drivers/staging/unisys/visornic/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for Unisys channel -# - -obj-$(CONFIG_UNISYS_VISORNIC) += visornic.o - -visornic-y := visornic_main.o - -ccflags-y += -I $(srctree)/$(src)/../include diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c deleted file mode 100644 index bb7ec492503e..000000000000 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ /dev/null @@ -1,2131 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2012 - 2015 UNISYS CORPORATION - * All rights reserved. - */ - -/* This driver lives in a spar partition, and registers to ethernet io - * channels from the visorbus driver. It creates netdev devices and - * forwards transmit to the IO channel and accepts rcvs from the IO - * Partition via the IO channel. - */ - -#include <linux/debugfs.h> -#include <linux/etherdevice.h> -#include <linux/module.h> -#include <linux/netdevice.h> -#include <linux/kthread.h> -#include <linux/skbuff.h> -#include <linux/rtnetlink.h> -#include <linux/visorbus.h> - -#include "iochannel.h" - -#define VISORNIC_INFINITE_RSP_WAIT 0 - -/* MAX_BUF = 64 lines x 32 MAXVNIC x 80 characters - * = 163840 bytes - */ -#define MAX_BUF 163840 -#define NAPI_WEIGHT 64 - -/* GUIDS for director channel type supported by this driver. */ -/* {8cd5994d-c58e-11da-95a9-00e08161165f} */ -#define VISOR_VNIC_CHANNEL_GUID \ - GUID_INIT(0x8cd5994d, 0xc58e, 0x11da, \ - 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) -#define VISOR_VNIC_CHANNEL_GUID_STR \ - "8cd5994d-c58e-11da-95a9-00e08161165f" - -static struct visor_channeltype_descriptor visornic_channel_types[] = { - /* Note that the only channel type we expect to be reported by the - * bus driver is the VISOR_VNIC channel. - */ - { VISOR_VNIC_CHANNEL_GUID, "ultravnic", sizeof(struct channel_header), - VISOR_VNIC_CHANNEL_VERSIONID }, - {} -}; -MODULE_DEVICE_TABLE(visorbus, visornic_channel_types); -/* FIXME XXX: This next line of code must be fixed and removed before - * acceptance into the 'normal' part of the kernel. It is only here as a place - * holder to get module autoloading functionality working for visorbus. Code - * must be added to scripts/mode/file2alias.c, etc., to get this working - * properly. - */ -MODULE_ALIAS("visorbus:" VISOR_VNIC_CHANNEL_GUID_STR); - -struct chanstat { - unsigned long got_rcv; - unsigned long got_enbdisack; - unsigned long got_xmit_done; - unsigned long xmit_fail; - unsigned long sent_enbdis; - unsigned long sent_promisc; - unsigned long sent_post; - unsigned long sent_post_failed; - unsigned long sent_xmit; - unsigned long reject_count; - unsigned long extra_rcvbufs_sent; -}; - -/* struct visornic_devdata - * @enabled: 0 disabled 1 enabled to receive. - * @enab_dis_acked: NET_RCV_ENABLE/DISABLE acked by IOPART. - * @struct *dev: - * @struct *netdev: - * @struct net_stats: - * @interrupt_rcvd: - * @rsp_queue: - * @struct **rcvbuf: - * @incarnation_id: incarnation_id lets IOPART know about - * re-birth. - * @old_flags: flags as they were prior to - * set_multicast_list. - * @usage: count of users. - * @num_rcv_bufs: number of rcv buffers the vnic will post. - * @num_rcv_bufs_could_not_alloc: - * @num_rcvbuf_in_iovm: - * @alloc_failed_in_if_needed_cnt: - * @alloc_failed_in_repost_rtn_cnt: - * @max_outstanding_net_xmits: absolute max number of outstanding xmits - * - should never hit this. - * @upper_threshold_net_xmits: high water mark for calling - * netif_stop_queue(). - * @lower_threshold_net_xmits: high water mark for calling - * netif_wake_queue(). - * @struct xmitbufhead: xmitbufhead - head of the xmit buffer list - * sent to the IOPART end. - * @server_down_complete_func: - * @struct timeout_reset: - * @struct *cmdrsp_rcv: cmdrsp_rcv is used for posting/unposting rcv - * buffers. - * @struct *xmit_cmdrsp: xmit_cmdrsp - issues NET_XMIT - only one - * active xmit at a time. - * @server_down: IOPART is down. - * @server_change_state: Processing SERVER_CHANGESTATE msg. - * @going_away: device is being torn down. - * @interrupts_rcvd: - * @interrupts_notme: - * @interrupts_disabled: - * @busy_cnt: - * @priv_lock: spinlock to access devdata structures. - * @flow_control_upper_hits: - * @flow_control_lower_hits: - * @n_rcv0: # rcvs of 0 buffers. - * @n_rcv1: # rcvs of 1 buffers. - * @n_rcv2: # rcvs of 2 buffers. - * @n_rcvx: # rcvs of >2 buffers. - * @found_repost_rcvbuf_cnt: # repost_rcvbuf_cnt. - * @repost_found_skb_cnt: # of found the skb. - * @n_repost_deficit: # of lost rcv buffers. - * @bad_rcv_buf: # of unknown rcv skb not freed. - * @n_rcv_packets_not_accepted: # bogs rcv packets. - * @queuefullmsg_logged: - * @struct chstat: - * @struct napi: - * @struct cmdrsp: - */ -struct visornic_devdata { - unsigned short enabled; - unsigned short enab_dis_acked; - - struct visor_device *dev; - struct net_device *netdev; - struct net_device_stats net_stats; - atomic_t interrupt_rcvd; - wait_queue_head_t rsp_queue; - struct sk_buff **rcvbuf; - u64 incarnation_id; - unsigned short old_flags; - atomic_t usage; - - int num_rcv_bufs; - int num_rcv_bufs_could_not_alloc; - atomic_t num_rcvbuf_in_iovm; - unsigned long alloc_failed_in_if_needed_cnt; - unsigned long alloc_failed_in_repost_rtn_cnt; - - unsigned long max_outstanding_net_xmits; - unsigned long upper_threshold_net_xmits; - unsigned long lower_threshold_net_xmits; - struct sk_buff_head xmitbufhead; - - visorbus_state_complete_func server_down_complete_func; - struct work_struct timeout_reset; - struct uiscmdrsp *cmdrsp_rcv; - struct uiscmdrsp *xmit_cmdrsp; - bool server_down; - bool server_change_state; - bool going_away; - u64 interrupts_rcvd; - u64 interrupts_notme; - u64 interrupts_disabled; - u64 busy_cnt; - /* spinlock to access devdata structures. */ - spinlock_t priv_lock; - - /* flow control counter */ - u64 flow_control_upper_hits; - u64 flow_control_lower_hits; - - /* debug counters */ - unsigned long n_rcv0; - unsigned long n_rcv1; - unsigned long n_rcv2; - unsigned long n_rcvx; - unsigned long found_repost_rcvbuf_cnt; - unsigned long repost_found_skb_cnt; - unsigned long n_repost_deficit; - unsigned long bad_rcv_buf; - unsigned long n_rcv_packets_not_accepted; - - int queuefullmsg_logged; - struct chanstat chstat; - struct napi_struct napi; - struct uiscmdrsp cmdrsp[SIZEOF_CMDRSP]; -}; - -/* Returns next non-zero index on success or 0 on failure (i.e. out of room). */ -static u16 add_physinfo_entries(u64 inp_pfn, u16 inp_off, u16 inp_len, - u16 index, u16 max_pi_arr_entries, - struct phys_info pi_arr[]) -{ - u16 i, len, firstlen; - - firstlen = PI_PAGE_SIZE - inp_off; - if (inp_len <= firstlen) { - /* The input entry spans only one page - add as is. */ - if (index >= max_pi_arr_entries) - return 0; - pi_arr[index].pi_pfn = inp_pfn; - pi_arr[index].pi_off = (u16)inp_off; - pi_arr[index].pi_len = (u16)inp_len; - return index + 1; - } - - /* This entry spans multiple pages. */ - for (len = inp_len, i = 0; len; - len -= pi_arr[index + i].pi_len, i++) { - if (index + i >= max_pi_arr_entries) - return 0; - pi_arr[index + i].pi_pfn = inp_pfn + i; - if (i == 0) { - pi_arr[index].pi_off = inp_off; - pi_arr[index].pi_len = firstlen; - } else { - pi_arr[index + i].pi_off = 0; - pi_arr[index + i].pi_len = min_t(u16, len, - PI_PAGE_SIZE); - } - } - return index + i; -} - -/* visor_copy_fragsinfo_from_skb - copy fragment list in the SKB to a phys_info - * array that the IOPART understands - * @skb: Skbuff that we are pulling the frags from. - * @firstfraglen: Length of first fragment in skb. - * @frags_max: Max len of frags array. - * @frags: Frags array filled in on output. - * - * Return: Positive integer indicating number of entries filled in frags on - * success, negative integer on error. - */ -static int visor_copy_fragsinfo_from_skb(struct sk_buff *skb, - unsigned int firstfraglen, - unsigned int frags_max, - struct phys_info frags[]) -{ - unsigned int count = 0, frag, size, offset = 0, numfrags; - unsigned int total_count; - - numfrags = skb_shinfo(skb)->nr_frags; - - /* Compute the number of fragments this skb has, and if its more than - * frag array can hold, linearize the skb - */ - total_count = numfrags + (firstfraglen / PI_PAGE_SIZE); - if (firstfraglen % PI_PAGE_SIZE) - total_count++; - - if (total_count > frags_max) { - if (skb_linearize(skb)) - return -EINVAL; - numfrags = skb_shinfo(skb)->nr_frags; - firstfraglen = 0; - } - - while (firstfraglen) { - if (count == frags_max) - return -EINVAL; - - frags[count].pi_pfn = - page_to_pfn(virt_to_page(skb->data + offset)); - frags[count].pi_off = - (unsigned long)(skb->data + offset) & PI_PAGE_MASK; - size = min_t(unsigned int, firstfraglen, - PI_PAGE_SIZE - frags[count].pi_off); - - /* can take smallest of firstfraglen (what's left) OR - * bytes left in the page - */ - frags[count].pi_len = size; - firstfraglen -= size; - offset += size; - count++; - } - if (numfrags) { - if ((count + numfrags) > frags_max) - return -EINVAL; - - for (frag = 0; frag < numfrags; frag++) { - count = add_physinfo_entries(page_to_pfn( - skb_frag_page(&skb_shinfo(skb)->frags[frag])), - skb_frag_off(&skb_shinfo(skb)->frags[frag]), - skb_frag_size(&skb_shinfo(skb)->frags[frag]), - count, frags_max, frags); - /* add_physinfo_entries only returns - * zero if the frags array is out of room - * That should never happen because we - * fail above, if count+numfrags > frags_max. - */ - if (!count) - return -EINVAL; - } - } - if (skb_shinfo(skb)->frag_list) { - struct sk_buff *skbinlist; - int c; - - for (skbinlist = skb_shinfo(skb)->frag_list; skbinlist; - skbinlist = skbinlist->next) { - c = visor_copy_fragsinfo_from_skb(skbinlist, - skbinlist->len - - skbinlist->data_len, - frags_max - count, - &frags[count]); - if (c < 0) - return c; - count += c; - } - } - return count; -} - -static ssize_t enable_ints_write(struct file *file, - const char __user *buffer, - size_t count, loff_t *ppos) -{ - /* Don't want to break ABI here by having a debugfs - * file that no longer exists or is writable, so - * lets just make this a vestigual function - */ - return count; -} - -static const struct file_operations debugfs_enable_ints_fops = { - .write = enable_ints_write, -}; - -/* visornic_serverdown_complete - pause device following IOPART going down - * @devdata: Device managed by IOPART. - * - * The IO partition has gone down, and we need to do some cleanup for when it - * comes back. Treat the IO partition as the link being down. - */ -static void visornic_serverdown_complete(struct visornic_devdata *devdata) -{ - struct net_device *netdev = devdata->netdev; - - /* Stop polling for interrupts */ - visorbus_disable_channel_interrupts(devdata->dev); - - rtnl_lock(); - dev_close(netdev); - rtnl_unlock(); - - atomic_set(&devdata->num_rcvbuf_in_iovm, 0); - devdata->chstat.sent_xmit = 0; - devdata->chstat.got_xmit_done = 0; - - if (devdata->server_down_complete_func) - (*devdata->server_down_complete_func)(devdata->dev, 0); - - devdata->server_down = true; - devdata->server_change_state = false; - devdata->server_down_complete_func = NULL; -} - -/* visornic_serverdown - Command has notified us that IOPART is down - * @devdata: Device managed by IOPART. - * @complete_func: Function to call when finished. - * - * Schedule the work needed to handle the server down request. Make sure we - * haven't already handled the server change state event. - * - * Return: 0 if we scheduled the work, negative integer on error. - */ -static int visornic_serverdown(struct visornic_devdata *devdata, - visorbus_state_complete_func complete_func) -{ - unsigned long flags; - int err; - - spin_lock_irqsave(&devdata->priv_lock, flags); - if (devdata->server_change_state) { - dev_dbg(&devdata->dev->device, "%s changing state\n", - __func__); - err = -EINVAL; - goto err_unlock; - } - if (devdata->server_down) { - dev_dbg(&devdata->dev->device, "%s already down\n", - __func__); - err = -EINVAL; - goto err_unlock; - } - if (devdata->going_away) { - dev_dbg(&devdata->dev->device, - "%s aborting because device removal pending\n", - __func__); - err = -ENODEV; - goto err_unlock; - } - devdata->server_change_state = true; - devdata->server_down_complete_func = complete_func; - spin_unlock_irqrestore(&devdata->priv_lock, flags); - - visornic_serverdown_complete(devdata); - return 0; - -err_unlock: - spin_unlock_irqrestore(&devdata->priv_lock, flags); - return err; -} - -/* alloc_rcv_buf - alloc rcv buffer to be given to the IO Partition - * @netdev: Network adapter the rcv bufs are attached too. - * - * Create an sk_buff (rcv_buf) that will be passed to the IO Partition - * so that it can write rcv data into our memory space. - * - * Return: Pointer to sk_buff. - */ -static struct sk_buff *alloc_rcv_buf(struct net_device *netdev) -{ - struct sk_buff *skb; - - /* NOTE: the first fragment in each rcv buffer is pointed to by - * rcvskb->data. For now all rcv buffers will be RCVPOST_BUF_SIZE - * in length, so the first frag is large enough to hold 1514. - */ - skb = alloc_skb(RCVPOST_BUF_SIZE, GFP_ATOMIC); - if (!skb) - return NULL; - skb->dev = netdev; - /* current value of mtu doesn't come into play here; large - * packets will just end up using multiple rcv buffers all of - * same size. - */ - skb->len = RCVPOST_BUF_SIZE; - /* alloc_skb already zeroes it out for clarification. */ - skb->data_len = 0; - return skb; -} - -/* post_skb - post a skb to the IO Partition - * @cmdrsp: Cmdrsp packet to be send to the IO Partition. - * @devdata: visornic_devdata to post the skb to. - * @skb: Skb to give to the IO partition. - * - * Return: 0 on success, negative integer on error. - */ -static int post_skb(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata, - struct sk_buff *skb) -{ - int err; - - cmdrsp->net.buf = skb; - cmdrsp->net.rcvpost.frag.pi_pfn = page_to_pfn(virt_to_page(skb->data)); - cmdrsp->net.rcvpost.frag.pi_off = - (unsigned long)skb->data & PI_PAGE_MASK; - cmdrsp->net.rcvpost.frag.pi_len = skb->len; - cmdrsp->net.rcvpost.unique_num = devdata->incarnation_id; - - if ((cmdrsp->net.rcvpost.frag.pi_off + skb->len) > PI_PAGE_SIZE) - return -EINVAL; - - cmdrsp->net.type = NET_RCV_POST; - cmdrsp->cmdtype = CMD_NET_TYPE; - err = visorchannel_signalinsert(devdata->dev->visorchannel, - IOCHAN_TO_IOPART, - cmdrsp); - if (err) { - devdata->chstat.sent_post_failed++; - return err; - } - - atomic_inc(&devdata->num_rcvbuf_in_iovm); - devdata->chstat.sent_post++; - return 0; -} - -/* send_enbdis - Send NET_RCV_ENBDIS to IO Partition - * @netdev: Netdevice we are enabling/disabling, used as context return value. - * @state: Enable = 1/disable = 0. - * @devdata: Visornic device we are enabling/disabling. - * - * Send the enable/disable message to the IO Partition. - * - * Return: 0 on success, negative integer on error. - */ -static int send_enbdis(struct net_device *netdev, int state, - struct visornic_devdata *devdata) -{ - int err; - - devdata->cmdrsp_rcv->net.enbdis.enable = state; - devdata->cmdrsp_rcv->net.enbdis.context = netdev; - devdata->cmdrsp_rcv->net.type = NET_RCV_ENBDIS; - devdata->cmdrsp_rcv->cmdtype = CMD_NET_TYPE; - err = visorchannel_signalinsert(devdata->dev->visorchannel, - IOCHAN_TO_IOPART, - devdata->cmdrsp_rcv); - if (err) - return err; - devdata->chstat.sent_enbdis++; - return 0; -} - -/* visornic_disable_with_timeout - disable network adapter - * @netdev: netdevice to disable. - * @timeout: Timeout to wait for disable. - * - * Disable the network adapter and inform the IO Partition that we are disabled. - * Reclaim memory from rcv bufs. - * - * Return: 0 on success, negative integer on failure of IO Partition responding. - */ -static int visornic_disable_with_timeout(struct net_device *netdev, - const int timeout) -{ - struct visornic_devdata *devdata = netdev_priv(netdev); - int i; - unsigned long flags; - int wait = 0; - int err; - - /* send a msg telling the other end we are stopping incoming pkts */ - spin_lock_irqsave(&devdata->priv_lock, flags); - devdata->enabled = 0; - /* must wait for ack */ - devdata->enab_dis_acked = 0; - spin_unlock_irqrestore(&devdata->priv_lock, flags); - - /* send disable and wait for ack -- don't hold lock when sending - * disable because if the queue is full, insert might sleep. - * If an error occurs, don't wait for the timeout. - */ - err = send_enbdis(netdev, 0, devdata); - if (err) - return err; - - /* wait for ack to arrive before we try to free rcv buffers - * NOTE: the other end automatically unposts the rcv buffers - * when it gets a disable. - */ - spin_lock_irqsave(&devdata->priv_lock, flags); - while ((timeout == VISORNIC_INFINITE_RSP_WAIT) || - (wait < timeout)) { - if (devdata->enab_dis_acked) - break; - if (devdata->server_down || devdata->server_change_state) { - dev_dbg(&netdev->dev, "%s server went away\n", - __func__); - break; - } - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&devdata->priv_lock, flags); - wait += schedule_timeout(msecs_to_jiffies(10)); - spin_lock_irqsave(&devdata->priv_lock, flags); - } - - /* Wait for usage to go to 1 (no other users) before freeing - * rcv buffers - */ - if (atomic_read(&devdata->usage) > 1) { - while (1) { - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&devdata->priv_lock, flags); - schedule_timeout(msecs_to_jiffies(10)); - spin_lock_irqsave(&devdata->priv_lock, flags); - if (atomic_read(&devdata->usage)) - break; - } - } - /* we've set enabled to 0, so we can give up the lock. */ - spin_unlock_irqrestore(&devdata->priv_lock, flags); - - /* stop the transmit queue so nothing more can be transmitted */ - netif_stop_queue(netdev); - - napi_disable(&devdata->napi); - - skb_queue_purge(&devdata->xmitbufhead); - - /* Free rcv buffers - other end has automatically unposed them on - * disable - */ - for (i = 0; i < devdata->num_rcv_bufs; i++) { - if (devdata->rcvbuf[i]) { - kfree_skb(devdata->rcvbuf[i]); - devdata->rcvbuf[i] = NULL; - } - } - - return 0; -} - -/* init_rcv_bufs - initialize receive buffs and send them to the IO Partition - * @netdev: struct netdevice. - * @devdata: visornic_devdata. - * - * Allocate rcv buffers and post them to the IO Partition. - * - * Return: 0 on success, negative integer on failure. - */ -static int init_rcv_bufs(struct net_device *netdev, - struct visornic_devdata *devdata) -{ - int i, j, count, err; - - /* allocate fixed number of receive buffers to post to uisnic - * post receive buffers after we've allocated a required amount - */ - for (i = 0; i < devdata->num_rcv_bufs; i++) { - devdata->rcvbuf[i] = alloc_rcv_buf(netdev); - /* if we failed to allocate one let us stop */ - if (!devdata->rcvbuf[i]) - break; - } - /* couldn't even allocate one -- bail out */ - if (i == 0) - return -ENOMEM; - count = i; - - /* Ensure we can alloc 2/3rd of the requested number of buffers. - * 2/3 is an arbitrary choice; used also in ndis init.c - */ - if (count < ((2 * devdata->num_rcv_bufs) / 3)) { - /* free receive buffers we did alloc and then bail out */ - for (i = 0; i < count; i++) { - kfree_skb(devdata->rcvbuf[i]); - devdata->rcvbuf[i] = NULL; - } - return -ENOMEM; - } - - /* post receive buffers to receive incoming input - without holding - * lock - we've not enabled nor started the queue so there shouldn't - * be any rcv or xmit activity - */ - for (i = 0; i < count; i++) { - err = post_skb(devdata->cmdrsp_rcv, devdata, - devdata->rcvbuf[i]); - if (!err) - continue; - - /* Error handling - - * If we posted at least one skb, we should return success, - * but need to free the resources that we have not successfully - * posted. - */ - for (j = i; j < count; j++) { - kfree_skb(devdata->rcvbuf[j]); - devdata->rcvbuf[j] = NULL; - } - if (i == 0) - return err; - break; - } - - return 0; -} - -/* visornic_enable_with_timeout - send enable to IO Partition - * @netdev: struct net_device. - * @timeout: Time to wait for the ACK from the enable. - * - * Sends enable to IOVM and inits, and posts receive buffers to IOVM. Timeout is - * defined in msecs (timeout of 0 specifies infinite wait). - * - * Return: 0 on success, negative integer on failure. - */ -static int visornic_enable_with_timeout(struct net_device *netdev, - const int timeout) -{ - int err = 0; - struct visornic_devdata *devdata = netdev_priv(netdev); - unsigned long flags; - int wait = 0; - - napi_enable(&devdata->napi); - - /* NOTE: the other end automatically unposts the rcv buffers when it - * gets a disable. - */ - err = init_rcv_bufs(netdev, devdata); - if (err < 0) { - dev_err(&netdev->dev, - "%s failed to init rcv bufs\n", __func__); - return err; - } - - spin_lock_irqsave(&devdata->priv_lock, flags); - devdata->enabled = 1; - devdata->enab_dis_acked = 0; - - /* now we're ready, let's send an ENB to uisnic but until we get - * an ACK back from uisnic, we'll drop the packets - */ - devdata->n_rcv_packets_not_accepted = 0; - spin_unlock_irqrestore(&devdata->priv_lock, flags); - - /* send enable and wait for ack -- don't hold lock when sending enable - * because if the queue is full, insert might sleep. If an error - * occurs error out. - */ - err = send_enbdis(netdev, 1, devdata); - if (err) - return err; - - spin_lock_irqsave(&devdata->priv_lock, flags); - while ((timeout == VISORNIC_INFINITE_RSP_WAIT) || - (wait < timeout)) { - if (devdata->enab_dis_acked) - break; - if (devdata->server_down || devdata->server_change_state) { - dev_dbg(&netdev->dev, "%s server went away\n", - __func__); - break; - } - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&devdata->priv_lock, flags); - wait += schedule_timeout(msecs_to_jiffies(10)); - spin_lock_irqsave(&devdata->priv_lock, flags); - } - - spin_unlock_irqrestore(&devdata->priv_lock, flags); - - if (!devdata->enab_dis_acked) { - dev_err(&netdev->dev, "%s missing ACK\n", __func__); - return -EIO; - } - - netif_start_queue(netdev); - return 0; -} - -/* visornic_timeout_reset - handle xmit timeout resets - * @work: Work item that scheduled the work. - * - * Transmit timeouts are typically handled by resetting the device for our - * virtual NIC; we will send a disable and enable to the IOVM. If it doesn't - * respond, we will trigger a serverdown. - */ -static void visornic_timeout_reset(struct work_struct *work) -{ - struct visornic_devdata *devdata; - struct net_device *netdev; - int response = 0; - - devdata = container_of(work, struct visornic_devdata, timeout_reset); - netdev = devdata->netdev; - - rtnl_lock(); - if (!netif_running(netdev)) { - rtnl_unlock(); - return; - } - - response = visornic_disable_with_timeout(netdev, - VISORNIC_INFINITE_RSP_WAIT); - if (response) - goto call_serverdown; - - response = visornic_enable_with_timeout(netdev, - VISORNIC_INFINITE_RSP_WAIT); - if (response) - goto call_serverdown; - - rtnl_unlock(); - - return; - -call_serverdown: - visornic_serverdown(devdata, NULL); - rtnl_unlock(); -} - -/* visornic_open - enable the visornic device and mark the queue started - * @netdev: netdevice to start. - * - * Enable the device and start the transmit queue. - * - * Return: 0 on success. - */ -static int visornic_open(struct net_device *netdev) -{ - visornic_enable_with_timeout(netdev, VISORNIC_INFINITE_RSP_WAIT); - return 0; -} - -/* visornic_close - disables the visornic device and stops the queues - * @netdev: netdevice to stop. - * - * Disable the device and stop the transmit queue. - * - * Return 0 on success. - */ -static int visornic_close(struct net_device *netdev) -{ - visornic_disable_with_timeout(netdev, VISORNIC_INFINITE_RSP_WAIT); - return 0; -} - -/* devdata_xmits_outstanding - compute outstanding xmits - * @devdata: visornic_devdata for device - * - * Return: Long integer representing the number of outstanding xmits. - */ -static unsigned long devdata_xmits_outstanding(struct visornic_devdata *devdata) -{ - if (devdata->chstat.sent_xmit >= devdata->chstat.got_xmit_done) - return devdata->chstat.sent_xmit - - devdata->chstat.got_xmit_done; - return (ULONG_MAX - devdata->chstat.got_xmit_done - + devdata->chstat.sent_xmit + 1); -} - -/* vnic_hit_high_watermark - * @devdata: Indicates visornic device we are checking. - * @high_watermark: Max num of unacked xmits we will tolerate before we will - * start throttling. - * - * Return: True iff the number of unacked xmits sent to the IO Partition is >= - * high_watermark. False otherwise. - */ -static bool vnic_hit_high_watermark(struct visornic_devdata *devdata, - ulong high_watermark) -{ - return (devdata_xmits_outstanding(devdata) >= high_watermark); -} - -/* vnic_hit_low_watermark - * @devdata: Indicates visornic device we are checking. - * @low_watermark: We will wait until the num of unacked xmits drops to this - * value or lower before we start transmitting again. - * - * Return: True iff the number of unacked xmits sent to the IO Partition is <= - * low_watermark. - */ -static bool vnic_hit_low_watermark(struct visornic_devdata *devdata, - ulong low_watermark) -{ - return (devdata_xmits_outstanding(devdata) <= low_watermark); -} - -/* visornic_xmit - send a packet to the IO Partition - * @skb: Packet to be sent. - * @netdev: Net device the packet is being sent from. - * - * Convert the skb to a cmdrsp so the IO Partition can understand it, and send - * the XMIT command to the IO Partition for processing. This function is - * protected from concurrent calls by a spinlock xmit_lock in the net_device - * struct. As soon as the function returns, it can be called again. - * - * Return: NETDEV_TX_OK. - */ -static netdev_tx_t visornic_xmit(struct sk_buff *skb, struct net_device *netdev) -{ - struct visornic_devdata *devdata; - int len, firstfraglen, padlen; - struct uiscmdrsp *cmdrsp = NULL; - unsigned long flags; - int err; - - devdata = netdev_priv(netdev); - spin_lock_irqsave(&devdata->priv_lock, flags); - - if (netif_queue_stopped(netdev) || devdata->server_down || - devdata->server_change_state) { - spin_unlock_irqrestore(&devdata->priv_lock, flags); - devdata->busy_cnt++; - dev_dbg(&netdev->dev, - "%s busy - queue stopped\n", __func__); - kfree_skb(skb); - return NETDEV_TX_OK; - } - - /* sk_buff struct is used to host network data throughout all the - * linux network subsystems - */ - len = skb->len; - - /* skb->len is the FULL length of data (including fragmentary portion) - * skb->data_len is the length of the fragment portion in frags - * skb->len - skb->data_len is size of the 1st fragment in skb->data - * calculate the length of the first fragment that skb->data is - * pointing to - */ - firstfraglen = skb->len - skb->data_len; - if (firstfraglen < ETH_HLEN) { - spin_unlock_irqrestore(&devdata->priv_lock, flags); - devdata->busy_cnt++; - dev_err(&netdev->dev, - "%s busy - first frag too small (%d)\n", - __func__, firstfraglen); - kfree_skb(skb); - return NETDEV_TX_OK; - } - - if (len < ETH_MIN_PACKET_SIZE && - ((skb_end_pointer(skb) - skb->data) >= ETH_MIN_PACKET_SIZE)) { - /* pad the packet out to minimum size */ - padlen = ETH_MIN_PACKET_SIZE - len; - skb_put_zero(skb, padlen); - len += padlen; - firstfraglen += padlen; - } - - cmdrsp = devdata->xmit_cmdrsp; - /* clear cmdrsp */ - memset(cmdrsp, 0, SIZEOF_CMDRSP); - cmdrsp->net.type = NET_XMIT; - cmdrsp->cmdtype = CMD_NET_TYPE; - - /* save the pointer to skb -- we'll need it for completion */ - cmdrsp->net.buf = skb; - - if (vnic_hit_high_watermark(devdata, - devdata->max_outstanding_net_xmits)) { - /* extra NET_XMITs queued over to IOVM - need to wait */ - devdata->chstat.reject_count++; - if (!devdata->queuefullmsg_logged && - ((devdata->chstat.reject_count & 0x3ff) == 1)) - devdata->queuefullmsg_logged = 1; - netif_stop_queue(netdev); - spin_unlock_irqrestore(&devdata->priv_lock, flags); - devdata->busy_cnt++; - dev_dbg(&netdev->dev, - "%s busy - waiting for iovm to catch up\n", - __func__); - kfree_skb(skb); - return NETDEV_TX_OK; - } - if (devdata->queuefullmsg_logged) - devdata->queuefullmsg_logged = 0; - - if (skb->ip_summed == CHECKSUM_UNNECESSARY) { - cmdrsp->net.xmt.lincsum.valid = 1; - cmdrsp->net.xmt.lincsum.protocol = skb->protocol; - if (skb_transport_header(skb) > skb->data) { - cmdrsp->net.xmt.lincsum.hrawoff = - skb_transport_header(skb) - skb->data; - cmdrsp->net.xmt.lincsum.hrawoff = 1; - } - if (skb_network_header(skb) > skb->data) { - cmdrsp->net.xmt.lincsum.nhrawoff = - skb_network_header(skb) - skb->data; - cmdrsp->net.xmt.lincsum.nhrawoffv = 1; - } - cmdrsp->net.xmt.lincsum.csum = skb->csum; - } else { - cmdrsp->net.xmt.lincsum.valid = 0; - } - - /* save off the length of the entire data packet */ - cmdrsp->net.xmt.len = len; - - /* copy ethernet header from first frag into ocmdrsp - * - everything else will be pass in frags & DMA'ed - */ - memcpy(cmdrsp->net.xmt.ethhdr, skb->data, ETH_HLEN); - - /* copy frags info - from skb->data we need to only provide access - * beyond eth header - */ - cmdrsp->net.xmt.num_frags = - visor_copy_fragsinfo_from_skb(skb, firstfraglen, - MAX_PHYS_INFO, - cmdrsp->net.xmt.frags); - if (cmdrsp->net.xmt.num_frags < 0) { - spin_unlock_irqrestore(&devdata->priv_lock, flags); - devdata->busy_cnt++; - dev_err(&netdev->dev, - "%s busy - copy frags failed\n", __func__); - kfree_skb(skb); - return NETDEV_TX_OK; - } - - err = visorchannel_signalinsert(devdata->dev->visorchannel, - IOCHAN_TO_IOPART, cmdrsp); - if (err) { - netif_stop_queue(netdev); - spin_unlock_irqrestore(&devdata->priv_lock, flags); - devdata->busy_cnt++; - dev_dbg(&netdev->dev, - "%s busy - signalinsert failed\n", __func__); - kfree_skb(skb); - return NETDEV_TX_OK; - } - - /* Track the skbs that have been sent to the IOVM for XMIT */ - skb_queue_head(&devdata->xmitbufhead, skb); - - /* update xmt stats */ - devdata->net_stats.tx_packets++; - devdata->net_stats.tx_bytes += skb->len; - devdata->chstat.sent_xmit++; - - /* check if we have hit the high watermark for netif_stop_queue() */ - if (vnic_hit_high_watermark(devdata, - devdata->upper_threshold_net_xmits)) { - /* extra NET_XMITs queued over to IOVM - need to wait */ - /* stop queue - call netif_wake_queue() after lower threshold */ - netif_stop_queue(netdev); - dev_dbg(&netdev->dev, - "%s busy - invoking iovm flow control\n", - __func__); - devdata->flow_control_upper_hits++; - } - spin_unlock_irqrestore(&devdata->priv_lock, flags); - - /* skb will be freed when we get back NET_XMIT_DONE */ - return NETDEV_TX_OK; -} - -/* visornic_get_stats - returns net_stats of the visornic device - * @netdev: netdevice. - * - * Return: Pointer to the net_device_stats struct for the device. - */ -static struct net_device_stats *visornic_get_stats(struct net_device *netdev) -{ - struct visornic_devdata *devdata = netdev_priv(netdev); - - return &devdata->net_stats; -} - -/* visornic_change_mtu - changes mtu of device - * @netdev: netdevice. - * @new_mtu: Value of new mtu. - * - * The device's MTU cannot be changed by system; it must be changed via a - * CONTROLVM message. All vnics and pnics in a switch have to have the same MTU - * for everything to work. Currently not supported. - * - * Return: -EINVAL. - */ -static int visornic_change_mtu(struct net_device *netdev, int new_mtu) -{ - return -EINVAL; -} - -/* visornic_set_multi - set visornic device flags - * @netdev: netdevice. - * - * The only flag we currently support is IFF_PROMISC. - */ -static void visornic_set_multi(struct net_device *netdev) -{ - struct uiscmdrsp *cmdrsp; - struct visornic_devdata *devdata = netdev_priv(netdev); - int err = 0; - - if (devdata->old_flags == netdev->flags) - return; - - if ((netdev->flags & IFF_PROMISC) == - (devdata->old_flags & IFF_PROMISC)) - goto out_save_flags; - - cmdrsp = kmalloc(SIZEOF_CMDRSP, GFP_ATOMIC); - if (!cmdrsp) - return; - cmdrsp->cmdtype = CMD_NET_TYPE; - cmdrsp->net.type = NET_RCV_PROMISC; - cmdrsp->net.enbdis.context = netdev; - cmdrsp->net.enbdis.enable = - netdev->flags & IFF_PROMISC; - err = visorchannel_signalinsert(devdata->dev->visorchannel, - IOCHAN_TO_IOPART, - cmdrsp); - kfree(cmdrsp); - if (err) - return; - -out_save_flags: - devdata->old_flags = netdev->flags; -} - -/* visornic_xmit_timeout - request to timeout the xmit - * @netdev: netdevice. - * - * Queue the work and return. Make sure we have not already been informed that - * the IO Partition is gone; if so, we will have already timed-out the xmits. - */ -static void visornic_xmit_timeout(struct net_device *netdev, unsigned int txqueue) -{ - struct visornic_devdata *devdata = netdev_priv(netdev); - unsigned long flags; - - spin_lock_irqsave(&devdata->priv_lock, flags); - if (devdata->going_away) { - spin_unlock_irqrestore(&devdata->priv_lock, flags); - dev_dbg(&devdata->dev->device, - "%s aborting because device removal pending\n", - __func__); - return; - } - - /* Ensure that a ServerDown message hasn't been received */ - if (!devdata->enabled || - (devdata->server_down && !devdata->server_change_state)) { - dev_dbg(&netdev->dev, "%s no processing\n", - __func__); - spin_unlock_irqrestore(&devdata->priv_lock, flags); - return; - } - schedule_work(&devdata->timeout_reset); - spin_unlock_irqrestore(&devdata->priv_lock, flags); -} - -/* repost_return - repost rcv bufs that have come back - * @cmdrsp: IO channel command struct to post. - * @devdata: Visornic devdata for the device. - * @skb: Socket buffer. - * @netdev: netdevice. - * - * Repost rcv buffers that have been returned to us when we are finished - * with them. - * - * Return: 0 for success, negative integer on error. - */ -static int repost_return(struct uiscmdrsp *cmdrsp, - struct visornic_devdata *devdata, - struct sk_buff *skb, struct net_device *netdev) -{ - struct net_pkt_rcv copy; - int i = 0, cc, numreposted; - int found_skb = 0; - int status = 0; - - copy = cmdrsp->net.rcv; - switch (copy.numrcvbufs) { - case 0: - devdata->n_rcv0++; - break; - case 1: - devdata->n_rcv1++; - break; - case 2: - devdata->n_rcv2++; - break; - default: - devdata->n_rcvx++; - break; - } - for (cc = 0, numreposted = 0; cc < copy.numrcvbufs; cc++) { - for (i = 0; i < devdata->num_rcv_bufs; i++) { - if (devdata->rcvbuf[i] != copy.rcvbuf[cc]) - continue; - - if ((skb) && devdata->rcvbuf[i] == skb) { - devdata->found_repost_rcvbuf_cnt++; - found_skb = 1; - devdata->repost_found_skb_cnt++; - } - devdata->rcvbuf[i] = alloc_rcv_buf(netdev); - if (!devdata->rcvbuf[i]) { - devdata->num_rcv_bufs_could_not_alloc++; - devdata->alloc_failed_in_repost_rtn_cnt++; - status = -ENOMEM; - break; - } - status = post_skb(cmdrsp, devdata, devdata->rcvbuf[i]); - if (status) { - kfree_skb(devdata->rcvbuf[i]); - devdata->rcvbuf[i] = NULL; - break; - } - numreposted++; - break; - } - } - if (numreposted != copy.numrcvbufs) { - devdata->n_repost_deficit++; - status = -EINVAL; - } - if (skb) { - if (found_skb) { - kfree_skb(skb); - } else { - status = -EINVAL; - devdata->bad_rcv_buf++; - } - } - return status; -} - -/* visornic_rx - handle receive packets coming back from IO Partition - * @cmdrsp: Receive packet returned from IO Partition. - * - * Got a receive packet back from the IO Partition; handle it and send it up - * the stack. - - * Return: 1 iff an skb was received, otherwise 0. - */ -static int visornic_rx(struct uiscmdrsp *cmdrsp) -{ - struct visornic_devdata *devdata; - struct sk_buff *skb, *prev, *curr; - struct net_device *netdev; - int cc, currsize, off; - struct ethhdr *eth; - unsigned long flags; - - /* post new rcv buf to the other end using the cmdrsp we have at hand - * post it without holding lock - but we'll use the signal lock to - * synchronize the queue insert the cmdrsp that contains the net.rcv - * is the one we are using to repost, so copy the info we need from it. - */ - skb = cmdrsp->net.buf; - netdev = skb->dev; - - devdata = netdev_priv(netdev); - - spin_lock_irqsave(&devdata->priv_lock, flags); - atomic_dec(&devdata->num_rcvbuf_in_iovm); - - /* set length to how much was ACTUALLY received - - * NOTE: rcv_done_len includes actual length of data rcvd - * including ethhdr - */ - skb->len = cmdrsp->net.rcv.rcv_done_len; - - /* update rcv stats - call it with priv_lock held */ - devdata->net_stats.rx_packets++; - devdata->net_stats.rx_bytes += skb->len; - - /* test enabled while holding lock */ - if (!(devdata->enabled && devdata->enab_dis_acked)) { - /* don't process it unless we're in enable mode and until - * we've gotten an ACK saying the other end got our RCV enable - */ - spin_unlock_irqrestore(&devdata->priv_lock, flags); - repost_return(cmdrsp, devdata, skb, netdev); - return 0; - } - - spin_unlock_irqrestore(&devdata->priv_lock, flags); - - /* when skb was allocated, skb->dev, skb->data, skb->len and - * skb->data_len were setup. AND, data has already put into the - * skb (both first frag and in frags pages) - * NOTE: firstfragslen is the amount of data in skb->data and that - * which is not in nr_frags or frag_list. This is now simply - * RCVPOST_BUF_SIZE. bump tail to show how much data is in - * firstfrag & set data_len to show rest see if we have to chain - * frag_list. - */ - /* do PRECAUTIONARY check */ - if (skb->len > RCVPOST_BUF_SIZE) { - if (cmdrsp->net.rcv.numrcvbufs < 2) { - if (repost_return(cmdrsp, devdata, skb, netdev) < 0) - dev_err(&devdata->netdev->dev, - "repost_return failed"); - return 0; - } - /* length rcvd is greater than firstfrag in this skb rcv buf */ - /* amount in skb->data */ - skb->tail += RCVPOST_BUF_SIZE; - /* amount that will be in frag_list */ - skb->data_len = skb->len - RCVPOST_BUF_SIZE; - } else { - /* data fits in this skb - no chaining - do - * PRECAUTIONARY check - */ - /* should be 1 */ - if (cmdrsp->net.rcv.numrcvbufs != 1) { - if (repost_return(cmdrsp, devdata, skb, netdev) < 0) - dev_err(&devdata->netdev->dev, - "repost_return failed"); - return 0; - } - skb->tail += skb->len; - /* nothing rcvd in frag_list */ - skb->data_len = 0; - } - off = skb_tail_pointer(skb) - skb->data; - - /* amount we bumped tail by in the head skb - * it is used to calculate the size of each chained skb below - * it is also used to index into bufline to continue the copy - * (for chansocktwopc) - * if necessary chain the rcv skbs together. - * NOTE: index 0 has the same as cmdrsp->net.rcv.skb; we need to - * chain the rest to that one. - * - do PRECAUTIONARY check - */ - if (cmdrsp->net.rcv.rcvbuf[0] != skb) { - if (repost_return(cmdrsp, devdata, skb, netdev) < 0) - dev_err(&devdata->netdev->dev, "repost_return failed"); - return 0; - } - - if (cmdrsp->net.rcv.numrcvbufs > 1) { - /* chain the various rcv buffers into the skb's frag_list. */ - /* Note: off was initialized above */ - for (cc = 1, prev = NULL; - cc < cmdrsp->net.rcv.numrcvbufs; cc++) { - curr = (struct sk_buff *)cmdrsp->net.rcv.rcvbuf[cc]; - curr->next = NULL; - /* start of list- set head */ - if (!prev) - skb_shinfo(skb)->frag_list = curr; - else - prev->next = curr; - prev = curr; - - /* should we set skb->len and skb->data_len for each - * buffer being chained??? can't hurt! - */ - currsize = min(skb->len - off, - (unsigned int)RCVPOST_BUF_SIZE); - curr->len = currsize; - curr->tail += currsize; - curr->data_len = 0; - off += currsize; - } - /* assert skb->len == off */ - if (skb->len != off) { - netdev_err(devdata->netdev, - "something wrong; skb->len:%d != off:%d\n", - skb->len, off); - } - } - - /* set up packet's protocol type using ethernet header - this - * sets up skb->pkt_type & it also PULLS out the eth header - */ - skb->protocol = eth_type_trans(skb, netdev); - eth = eth_hdr(skb); - skb->csum = 0; - skb->ip_summed = CHECKSUM_NONE; - - do { - /* accept all packets */ - if (netdev->flags & IFF_PROMISC) - break; - if (skb->pkt_type == PACKET_BROADCAST) { - /* accept all broadcast packets */ - if (netdev->flags & IFF_BROADCAST) - break; - } else if (skb->pkt_type == PACKET_MULTICAST) { - if ((netdev->flags & IFF_MULTICAST) && - (netdev_mc_count(netdev))) { - struct netdev_hw_addr *ha; - int found_mc = 0; - - /* only accept multicast packets that we can - * find in our multicast address list - */ - netdev_for_each_mc_addr(ha, netdev) { - if (ether_addr_equal(eth->h_dest, - ha->addr)) { - found_mc = 1; - break; - } - } - /* accept pkt, dest matches a multicast addr */ - if (found_mc) - break; - } - /* accept packet, h_dest must match vnic mac address */ - } else if (skb->pkt_type == PACKET_HOST) { - break; - } else if (skb->pkt_type == PACKET_OTHERHOST) { - /* something is not right */ - dev_err(&devdata->netdev->dev, - "**** FAILED to deliver rcv packet to OS; name:%s Dest:%pM VNIC:%pM\n", - netdev->name, eth->h_dest, netdev->dev_addr); - } - /* drop packet - don't forward it up to OS */ - devdata->n_rcv_packets_not_accepted++; - repost_return(cmdrsp, devdata, skb, netdev); - return 0; - } while (0); - - netif_receive_skb(skb); - /* netif_rx returns various values, but "in practice most drivers - * ignore the return value - */ - - skb = NULL; - /* whether the packet got dropped or handled, the skb is freed by - * kernel code, so we shouldn't free it. but we should repost a - * new rcv buffer. - */ - repost_return(cmdrsp, devdata, skb, netdev); - return 1; -} - -/* devdata_initialize - initialize devdata structure - * @devdata: visornic_devdata structure to initialize. - * @dev: visorbus_device it belongs to. - * - * Setup initial values for the visornic, based on channel and default values. - * - * Return: A pointer to the devdata structure. - */ -static struct visornic_devdata *devdata_initialize( - struct visornic_devdata *devdata, - struct visor_device *dev) -{ - devdata->dev = dev; - devdata->incarnation_id = get_jiffies_64(); - return devdata; -} - -/* devdata_release - free up references in devdata - * @devdata: Struct to clean up. - */ -static void devdata_release(struct visornic_devdata *devdata) -{ - kfree(devdata->rcvbuf); - kfree(devdata->cmdrsp_rcv); - kfree(devdata->xmit_cmdrsp); -} - -static const struct net_device_ops visornic_dev_ops = { - .ndo_open = visornic_open, - .ndo_stop = visornic_close, - .ndo_start_xmit = visornic_xmit, - .ndo_get_stats = visornic_get_stats, - .ndo_change_mtu = visornic_change_mtu, - .ndo_tx_timeout = visornic_xmit_timeout, - .ndo_set_rx_mode = visornic_set_multi, -}; - -/* DebugFS code */ -static ssize_t info_debugfs_read(struct file *file, char __user *buf, - size_t len, loff_t *offset) -{ - ssize_t bytes_read = 0; - int str_pos = 0; - struct visornic_devdata *devdata; - struct net_device *dev; - char *vbuf; - - if (len > MAX_BUF) - len = MAX_BUF; - vbuf = kzalloc(len, GFP_KERNEL); - if (!vbuf) - return -ENOMEM; - - /* for each vnic channel dump out channel specific data */ - rcu_read_lock(); - for_each_netdev_rcu(current->nsproxy->net_ns, dev) { - /* Only consider netdevs that are visornic, and are open */ - if (dev->netdev_ops != &visornic_dev_ops || - (!netif_queue_stopped(dev))) - continue; - - devdata = netdev_priv(dev); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - "netdev = %s (0x%p), MAC Addr %pM\n", - dev->name, - dev, - dev->dev_addr); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - "VisorNic Dev Info = 0x%p\n", devdata); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " num_rcv_bufs = %d\n", - devdata->num_rcv_bufs); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " max_outstanding_next_xmits = %lu\n", - devdata->max_outstanding_net_xmits); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " upper_threshold_net_xmits = %lu\n", - devdata->upper_threshold_net_xmits); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " lower_threshold_net_xmits = %lu\n", - devdata->lower_threshold_net_xmits); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " queuefullmsg_logged = %d\n", - devdata->queuefullmsg_logged); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.got_rcv = %lu\n", - devdata->chstat.got_rcv); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.got_enbdisack = %lu\n", - devdata->chstat.got_enbdisack); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.got_xmit_done = %lu\n", - devdata->chstat.got_xmit_done); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.xmit_fail = %lu\n", - devdata->chstat.xmit_fail); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.sent_enbdis = %lu\n", - devdata->chstat.sent_enbdis); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.sent_promisc = %lu\n", - devdata->chstat.sent_promisc); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.sent_post = %lu\n", - devdata->chstat.sent_post); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.sent_post_failed = %lu\n", - devdata->chstat.sent_post_failed); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.sent_xmit = %lu\n", - devdata->chstat.sent_xmit); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.reject_count = %lu\n", - devdata->chstat.reject_count); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.extra_rcvbufs_sent = %lu\n", - devdata->chstat.extra_rcvbufs_sent); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " n_rcv0 = %lu\n", devdata->n_rcv0); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " n_rcv1 = %lu\n", devdata->n_rcv1); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " n_rcv2 = %lu\n", devdata->n_rcv2); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " n_rcvx = %lu\n", devdata->n_rcvx); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " num_rcvbuf_in_iovm = %d\n", - atomic_read(&devdata->num_rcvbuf_in_iovm)); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " alloc_failed_in_if_needed_cnt = %lu\n", - devdata->alloc_failed_in_if_needed_cnt); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " alloc_failed_in_repost_rtn_cnt = %lu\n", - devdata->alloc_failed_in_repost_rtn_cnt); - /* str_pos += scnprintf(vbuf + str_pos, len - str_pos, - * " inner_loop_limit_reached_cnt = %lu\n", - * devdata->inner_loop_limit_reached_cnt); - */ - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " found_repost_rcvbuf_cnt = %lu\n", - devdata->found_repost_rcvbuf_cnt); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " repost_found_skb_cnt = %lu\n", - devdata->repost_found_skb_cnt); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " n_repost_deficit = %lu\n", - devdata->n_repost_deficit); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " bad_rcv_buf = %lu\n", - devdata->bad_rcv_buf); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " n_rcv_packets_not_accepted = %lu\n", - devdata->n_rcv_packets_not_accepted); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " interrupts_rcvd = %llu\n", - devdata->interrupts_rcvd); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " interrupts_notme = %llu\n", - devdata->interrupts_notme); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " interrupts_disabled = %llu\n", - devdata->interrupts_disabled); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " busy_cnt = %llu\n", - devdata->busy_cnt); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " flow_control_upper_hits = %llu\n", - devdata->flow_control_upper_hits); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " flow_control_lower_hits = %llu\n", - devdata->flow_control_lower_hits); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " netif_queue = %s\n", - netif_queue_stopped(devdata->netdev) ? - "stopped" : "running"); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " xmits_outstanding = %lu\n", - devdata_xmits_outstanding(devdata)); - } - rcu_read_unlock(); - bytes_read = simple_read_from_buffer(buf, len, offset, vbuf, str_pos); - kfree(vbuf); - 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 - send receive buffers to the IO Partition. - * @devdata: Visornic device. - */ -static void send_rcv_posts_if_needed(struct visornic_devdata *devdata) -{ - int i; - struct net_device *netdev; - struct uiscmdrsp *cmdrsp = devdata->cmdrsp_rcv; - int cur_num_rcv_bufs_to_alloc, rcv_bufs_allocated; - int err; - - /* don't do this until vnic is marked ready */ - if (!(devdata->enabled && devdata->enab_dis_acked)) - return; - - netdev = devdata->netdev; - rcv_bufs_allocated = 0; - /* this code is trying to prevent getting stuck here forever, - * but still retry it if you can't allocate them all this time. - */ - cur_num_rcv_bufs_to_alloc = devdata->num_rcv_bufs_could_not_alloc; - while (cur_num_rcv_bufs_to_alloc > 0) { - cur_num_rcv_bufs_to_alloc--; - for (i = 0; i < devdata->num_rcv_bufs; i++) { - if (devdata->rcvbuf[i]) - continue; - devdata->rcvbuf[i] = alloc_rcv_buf(netdev); - if (!devdata->rcvbuf[i]) { - devdata->alloc_failed_in_if_needed_cnt++; - break; - } - rcv_bufs_allocated++; - err = post_skb(cmdrsp, devdata, devdata->rcvbuf[i]); - if (err) { - kfree_skb(devdata->rcvbuf[i]); - devdata->rcvbuf[i] = NULL; - break; - } - devdata->chstat.extra_rcvbufs_sent++; - } - } - devdata->num_rcv_bufs_could_not_alloc -= rcv_bufs_allocated; -} - -/* drain_resp_queue - drains and ignores all messages from the resp queue - * @cmdrsp: IO channel command response message. - * @devdata: Visornic device to drain. - */ -static void drain_resp_queue(struct uiscmdrsp *cmdrsp, - struct visornic_devdata *devdata) -{ - while (!visorchannel_signalremove(devdata->dev->visorchannel, - IOCHAN_FROM_IOPART, - cmdrsp)) - ; -} - -/* service_resp_queue - drain the response queue - * @cmdrsp: IO channel command response message. - * @devdata: Visornic device to drain. - * @rx_work_done: - * @budget: - * - * Drain the response queue of any responses from the IO Partition. Process the - * responses as we get them. - */ -static void service_resp_queue(struct uiscmdrsp *cmdrsp, - struct visornic_devdata *devdata, - int *rx_work_done, int budget) -{ - unsigned long flags; - struct net_device *netdev; - - while (*rx_work_done < budget) { - /* TODO: CLIENT ACQUIRE -- Don't really need this at the - * moment - */ - /* queue empty */ - if (visorchannel_signalremove(devdata->dev->visorchannel, - IOCHAN_FROM_IOPART, - cmdrsp)) - break; - - switch (cmdrsp->net.type) { - case NET_RCV: - devdata->chstat.got_rcv++; - /* process incoming packet */ - *rx_work_done += visornic_rx(cmdrsp); - break; - case NET_XMIT_DONE: - spin_lock_irqsave(&devdata->priv_lock, flags); - devdata->chstat.got_xmit_done++; - if (cmdrsp->net.xmtdone.xmt_done_result) - devdata->chstat.xmit_fail++; - /* only call queue wake if we stopped it */ - netdev = ((struct sk_buff *)cmdrsp->net.buf)->dev; - /* ASSERT netdev == vnicinfo->netdev; */ - if (netdev == devdata->netdev && - netif_queue_stopped(netdev)) { - /* check if we have crossed the lower watermark - * for netif_wake_queue() - */ - if (vnic_hit_low_watermark - (devdata, - devdata->lower_threshold_net_xmits)) { - /* enough NET_XMITs completed - * so can restart netif queue - */ - netif_wake_queue(netdev); - devdata->flow_control_lower_hits++; - } - } - skb_unlink(cmdrsp->net.buf, &devdata->xmitbufhead); - spin_unlock_irqrestore(&devdata->priv_lock, flags); - kfree_skb(cmdrsp->net.buf); - break; - case NET_RCV_ENBDIS_ACK: - devdata->chstat.got_enbdisack++; - netdev = (struct net_device *) - cmdrsp->net.enbdis.context; - spin_lock_irqsave(&devdata->priv_lock, flags); - devdata->enab_dis_acked = 1; - spin_unlock_irqrestore(&devdata->priv_lock, flags); - - if (devdata->server_down && - devdata->server_change_state) { - /* Inform Linux that the link is up */ - devdata->server_down = false; - devdata->server_change_state = false; - netif_wake_queue(netdev); - netif_carrier_on(netdev); - } - break; - case NET_CONNECT_STATUS: - netdev = devdata->netdev; - if (cmdrsp->net.enbdis.enable == 1) { - spin_lock_irqsave(&devdata->priv_lock, flags); - devdata->enabled = cmdrsp->net.enbdis.enable; - spin_unlock_irqrestore(&devdata->priv_lock, - flags); - netif_wake_queue(netdev); - netif_carrier_on(netdev); - } else { - netif_stop_queue(netdev); - netif_carrier_off(netdev); - spin_lock_irqsave(&devdata->priv_lock, flags); - devdata->enabled = cmdrsp->net.enbdis.enable; - spin_unlock_irqrestore(&devdata->priv_lock, - flags); - } - break; - default: - break; - } - /* cmdrsp is now available for reuse */ - } -} - -static int visornic_poll(struct napi_struct *napi, int budget) -{ - struct visornic_devdata *devdata = container_of(napi, - struct visornic_devdata, - napi); - int rx_count = 0; - - send_rcv_posts_if_needed(devdata); - service_resp_queue(devdata->cmdrsp, devdata, &rx_count, budget); - - /* If there aren't any more packets to receive stop the poll */ - if (rx_count < budget) - napi_complete_done(napi, rx_count); - - return rx_count; -} - -/* visornic_channel_interrupt - checks the status of the response queue - * - * Main function of the vnic_incoming thread. Periodically check the response - * queue and drain it if needed. - */ -static void visornic_channel_interrupt(struct visor_device *dev) -{ - struct visornic_devdata *devdata = dev_get_drvdata(&dev->device); - - if (!devdata) - return; - - if (!visorchannel_signalempty(devdata->dev->visorchannel, - IOCHAN_FROM_IOPART)) - napi_schedule(&devdata->napi); - - atomic_set(&devdata->interrupt_rcvd, 0); -} - -/* visornic_probe - probe function for visornic devices - * @dev: The visor device discovered. - * - * Called when visorbus discovers a visornic device on its bus. It creates a new - * visornic ethernet adapter. - * - * Return: 0 on success, or negative integer on error. - */ -static int visornic_probe(struct visor_device *dev) -{ - struct visornic_devdata *devdata = NULL; - struct net_device *netdev = NULL; - int err; - int channel_offset = 0; - u8 addr[ETH_ALEN]; - u64 features; - - netdev = alloc_etherdev(sizeof(struct visornic_devdata)); - if (!netdev) { - dev_err(&dev->device, - "%s alloc_etherdev failed\n", __func__); - return -ENOMEM; - } - - netdev->netdev_ops = &visornic_dev_ops; - netdev->watchdog_timeo = 5 * HZ; - SET_NETDEV_DEV(netdev, &dev->device); - - /* Get MAC address from channel and read it into the device. */ - netdev->addr_len = ETH_ALEN; - channel_offset = offsetof(struct visor_io_channel, vnic.macaddr); - err = visorbus_read_channel(dev, channel_offset, addr, ETH_ALEN); - if (err < 0) { - dev_err(&dev->device, - "%s failed to get mac addr from chan (%d)\n", - __func__, err); - goto cleanup_netdev; - } - eth_hw_addr_set(netdev, addr); - - devdata = devdata_initialize(netdev_priv(netdev), dev); - if (!devdata) { - dev_err(&dev->device, - "%s devdata_initialize failed\n", __func__); - err = -ENOMEM; - goto cleanup_netdev; - } - /* don't trust messages laying around in the channel */ - drain_resp_queue(devdata->cmdrsp, devdata); - - devdata->netdev = netdev; - dev_set_drvdata(&dev->device, devdata); - init_waitqueue_head(&devdata->rsp_queue); - spin_lock_init(&devdata->priv_lock); - /* not yet */ - devdata->enabled = 0; - atomic_set(&devdata->usage, 1); - - /* Setup rcv bufs */ - channel_offset = offsetof(struct visor_io_channel, vnic.num_rcv_bufs); - err = visorbus_read_channel(dev, channel_offset, - &devdata->num_rcv_bufs, 4); - if (err) { - dev_err(&dev->device, - "%s failed to get #rcv bufs from chan (%d)\n", - __func__, err); - goto cleanup_netdev; - } - - devdata->rcvbuf = kcalloc(devdata->num_rcv_bufs, - sizeof(struct sk_buff *), GFP_KERNEL); - if (!devdata->rcvbuf) { - err = -ENOMEM; - goto cleanup_netdev; - } - - /* set the net_xmit outstanding threshold - * always leave two slots open but you should have 3 at a minimum - * note that max_outstanding_net_xmits must be > 0 - */ - devdata->max_outstanding_net_xmits = - max_t(unsigned long, 3, ((devdata->num_rcv_bufs / 3) - 2)); - devdata->upper_threshold_net_xmits = - max_t(unsigned long, - 2, (devdata->max_outstanding_net_xmits - 1)); - devdata->lower_threshold_net_xmits = - max_t(unsigned long, - 1, (devdata->max_outstanding_net_xmits / 2)); - - skb_queue_head_init(&devdata->xmitbufhead); - - /* create a cmdrsp we can use to post and unpost rcv buffers */ - devdata->cmdrsp_rcv = kmalloc(SIZEOF_CMDRSP, GFP_KERNEL); - if (!devdata->cmdrsp_rcv) { - err = -ENOMEM; - goto cleanup_rcvbuf; - } - devdata->xmit_cmdrsp = kmalloc(SIZEOF_CMDRSP, GFP_KERNEL); - if (!devdata->xmit_cmdrsp) { - err = -ENOMEM; - goto cleanup_cmdrsp_rcv; - } - INIT_WORK(&devdata->timeout_reset, visornic_timeout_reset); - devdata->server_down = false; - devdata->server_change_state = false; - - /*set the default mtu */ - channel_offset = offsetof(struct visor_io_channel, vnic.mtu); - err = visorbus_read_channel(dev, channel_offset, &netdev->mtu, 4); - if (err) { - dev_err(&dev->device, - "%s failed to get mtu from chan (%d)\n", - __func__, err); - goto cleanup_xmit_cmdrsp; - } - - /* TODO: Setup Interrupt information */ - /* Let's start our threads to get responses */ - netif_napi_add(netdev, &devdata->napi, visornic_poll, NAPI_WEIGHT); - - channel_offset = offsetof(struct visor_io_channel, - channel_header.features); - err = visorbus_read_channel(dev, channel_offset, &features, 8); - if (err) { - dev_err(&dev->device, - "%s failed to get features from chan (%d)\n", - __func__, err); - goto cleanup_napi_add; - } - - features |= VISOR_CHANNEL_IS_POLLING; - features |= VISOR_DRIVER_ENHANCED_RCVBUF_CHECKING; - err = visorbus_write_channel(dev, channel_offset, &features, 8); - if (err) { - dev_err(&dev->device, - "%s failed to set features in chan (%d)\n", - __func__, err); - goto cleanup_napi_add; - } - - /* Note: Interrupts have to be enable before the while - * loop below because the napi routine is responsible for - * setting enab_dis_acked - */ - visorbus_enable_channel_interrupts(dev); - - err = register_netdev(netdev); - if (err) { - dev_err(&dev->device, - "%s register_netdev failed (%d)\n", __func__, err); - goto cleanup_napi_add; - } - - dev_info(&dev->device, "%s success netdev=%s\n", - __func__, netdev->name); - return 0; - -cleanup_napi_add: - visorbus_disable_channel_interrupts(dev); - netif_napi_del(&devdata->napi); - -cleanup_xmit_cmdrsp: - kfree(devdata->xmit_cmdrsp); - -cleanup_cmdrsp_rcv: - kfree(devdata->cmdrsp_rcv); - -cleanup_rcvbuf: - kfree(devdata->rcvbuf); - -cleanup_netdev: - free_netdev(netdev); - return err; -} - -/* host_side_disappeared - IO Partition is gone - * @devdata: Device object. - * - * IO partition servicing this device is gone; do cleanup. - */ -static void host_side_disappeared(struct visornic_devdata *devdata) -{ - unsigned long flags; - - spin_lock_irqsave(&devdata->priv_lock, flags); - /* indicate device destroyed */ - devdata->dev = NULL; - spin_unlock_irqrestore(&devdata->priv_lock, flags); -} - -/* visornic_remove - called when visornic dev goes away - * @dev: Visornic device that is being removed. - * - * Called when DEVICE_DESTROY gets called to remove device. - */ -static void visornic_remove(struct visor_device *dev) -{ - struct visornic_devdata *devdata = dev_get_drvdata(&dev->device); - struct net_device *netdev; - unsigned long flags; - - if (!devdata) { - dev_err(&dev->device, "%s no devdata\n", __func__); - return; - } - spin_lock_irqsave(&devdata->priv_lock, flags); - if (devdata->going_away) { - spin_unlock_irqrestore(&devdata->priv_lock, flags); - dev_err(&dev->device, "%s already being removed\n", __func__); - return; - } - devdata->going_away = true; - spin_unlock_irqrestore(&devdata->priv_lock, flags); - netdev = devdata->netdev; - if (!netdev) { - dev_err(&dev->device, "%s not net device\n", __func__); - return; - } - - /* going_away prevents new items being added to the workqueues */ - cancel_work_sync(&devdata->timeout_reset); - - /* this will call visornic_close() */ - unregister_netdev(netdev); - - visorbus_disable_channel_interrupts(devdata->dev); - netif_napi_del(&devdata->napi); - - dev_set_drvdata(&dev->device, NULL); - host_side_disappeared(devdata); - devdata_release(devdata); - free_netdev(netdev); -} - -/* visornic_pause - called when IO Part disappears - * @dev: Visornic device that is being serviced. - * @complete_func: Call when finished. - * - * Called when the IO Partition has gone down. Need to free up resources and - * wait for IO partition to come back. Mark link as down and don't attempt any - * DMA. When we have freed memory, call the complete_func so that Command knows - * we are done. If we don't call complete_func, the IO Partition will never - * come back. - * - * Return: 0 on success. - */ -static int visornic_pause(struct visor_device *dev, - visorbus_state_complete_func complete_func) -{ - struct visornic_devdata *devdata = dev_get_drvdata(&dev->device); - - visornic_serverdown(devdata, complete_func); - return 0; -} - -/* visornic_resume - called when IO Partition has recovered - * @dev: Visornic device that is being serviced. - * @compelte_func: Call when finished. - * - * Called when the IO partition has recovered. Re-establish connection to the IO - * Partition and set the link up. Okay to do DMA again. - * - * Returns 0 for success, negative integer on error. - */ -static int visornic_resume(struct visor_device *dev, - visorbus_state_complete_func complete_func) -{ - struct visornic_devdata *devdata; - struct net_device *netdev; - unsigned long flags; - - devdata = dev_get_drvdata(&dev->device); - if (!devdata) { - dev_err(&dev->device, "%s no devdata\n", __func__); - return -EINVAL; - } - - netdev = devdata->netdev; - - spin_lock_irqsave(&devdata->priv_lock, flags); - if (devdata->server_change_state) { - spin_unlock_irqrestore(&devdata->priv_lock, flags); - dev_err(&dev->device, "%s server already changing state\n", - __func__); - return -EINVAL; - } - if (!devdata->server_down) { - spin_unlock_irqrestore(&devdata->priv_lock, flags); - dev_err(&dev->device, "%s server not down\n", __func__); - complete_func(dev, 0); - return 0; - } - devdata->server_change_state = true; - spin_unlock_irqrestore(&devdata->priv_lock, flags); - - /* Must transition channel to ATTACHED state BEFORE - * we can start using the device again. - * TODO: State transitions - */ - visorbus_enable_channel_interrupts(dev); - - rtnl_lock(); - dev_open(netdev, NULL); - rtnl_unlock(); - - complete_func(dev, 0); - return 0; -} - -/* This is used to tell the visorbus 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 = visornic_channel_interrupt, -}; - -/* visornic_init - init function - * - * Init function for the visornic driver. Do initial driver setup and wait - * for devices. - * - * Return: 0 on success, negative integer on error. - */ -static int visornic_init(void) -{ - int err; - - visornic_debugfs_dir = debugfs_create_dir("visornic", NULL); - - debugfs_create_file("info", 0400, visornic_debugfs_dir, NULL, - &debugfs_info_fops); - debugfs_create_file("enable_ints", 0200, visornic_debugfs_dir, NULL, - &debugfs_enable_ints_fops); - - err = visorbus_register_visor_driver(&visornic_driver); - if (err) - debugfs_remove_recursive(visornic_debugfs_dir); - - return err; -} - -/* visornic_cleanup - driver exit routine - * - * Unregister driver from the bus and free up memory. - */ -static void visornic_cleanup(void) -{ - visorbus_unregister_visor_driver(&visornic_driver); - debugfs_remove_recursive(visornic_debugfs_dir); -} - -module_init(visornic_init); -module_exit(visornic_cleanup); - -MODULE_AUTHOR("Unisys"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("s-Par NIC driver for virtual network devices"); diff --git a/drivers/visorbus/Kconfig b/drivers/visorbus/Kconfig deleted file mode 100644 index fa947a79b5cd..000000000000 --- a/drivers/visorbus/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Unisys visorbus configuration -# - -config UNISYS_VISORBUS - tristate "Unisys visorbus driver" - depends on X86_64 && ACPI - help - The visorbus driver is a virtualized bus for the Unisys s-Par firmware. - Virtualized devices allow Linux guests on a system to share disks and - network cards that do not have SR-IOV support, and to be accessed using - the partition desktop application. The visorbus driver is required to - discover devices on an s-Par guest, and must be present for any other - s-Par guest driver to function correctly. diff --git a/drivers/visorbus/Makefile b/drivers/visorbus/Makefile deleted file mode 100644 index e8df59d1301f..000000000000 --- a/drivers/visorbus/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for Unisys visorbus -# - -obj-$(CONFIG_UNISYS_VISORBUS) += visorbus.o - -visorbus-y := visorbus_main.o -visorbus-y += visorchannel.o -visorbus-y += visorchipset.o diff --git a/drivers/visorbus/controlvmchannel.h b/drivers/visorbus/controlvmchannel.h deleted file mode 100644 index c87213554427..000000000000 --- a/drivers/visorbus/controlvmchannel.h +++ /dev/null @@ -1,650 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2010 - 2015 UNISYS CORPORATION - * All rights reserved. - */ - -#ifndef __CONTROLVMCHANNEL_H__ -#define __CONTROLVMCHANNEL_H__ - -#include <linux/uuid.h> -#include <linux/visorbus.h> - -/* {2B3C2D10-7EF5-4ad8-B966-3448B7386B3D} */ -#define VISOR_CONTROLVM_CHANNEL_GUID \ - GUID_INIT(0x2b3c2d10, 0x7ef5, 0x4ad8, \ - 0xb9, 0x66, 0x34, 0x48, 0xb7, 0x38, 0x6b, 0x3d) - -#define CONTROLVM_MESSAGE_MAX 64 - -/* - * Must increment this whenever you insert or delete fields within this channel - * struct. Also increment whenever you change the meaning of fields within this - * channel struct so as to break pre-existing software. Note that you can - * usually add fields to the END of the channel struct withOUT needing to - * increment this. - */ -#define VISOR_CONTROLVM_CHANNEL_VERSIONID 1 - -/* Defines for various channel queues */ -#define CONTROLVM_QUEUE_REQUEST 0 -#define CONTROLVM_QUEUE_RESPONSE 1 -#define CONTROLVM_QUEUE_EVENT 2 -#define CONTROLVM_QUEUE_ACK 3 - -/* Max num of messages stored during IOVM creation to be reused after crash */ -#define CONTROLVM_CRASHMSG_MAX 2 - -/* - * struct visor_segment_state - * @enabled: May enter other states. - * @active: Assigned to active partition. - * @alive: Configure message sent to service/server. - * @revoked: Similar to partition state ShuttingDown. - * @allocated: Memory (device/port number) has been selected by Command. - * @known: Has been introduced to the service/guest partition. - * @ready: Service/Guest partition has responded to introduction. - * @operating: Resource is configured and operating. - * @reserved: Natural alignment. - * - * Note: Don't use high bit unless we need to switch to ushort which is - * non-compliant. - */ -struct visor_segment_state { - u16 enabled:1; - u16 active:1; - u16 alive:1; - u16 revoked:1; - u16 allocated:1; - u16 known:1; - u16 ready:1; - u16 operating:1; - u16 reserved:8; -} __packed; - -static const struct visor_segment_state segment_state_running = { - 1, 1, 1, 0, 1, 1, 1, 1 -}; - -static const struct visor_segment_state segment_state_paused = { - 1, 1, 1, 0, 1, 1, 1, 0 -}; - -static const struct visor_segment_state segment_state_standby = { - 1, 1, 0, 0, 1, 1, 1, 0 -}; - -/* - * enum controlvm_id - * @CONTROLVM_INVALID: - * @CONTROLVM_BUS_CREATE: CP --> SP, GP. - * @CONTROLVM_BUS_DESTROY: CP --> SP, GP. - * @CONTROLVM_BUS_CONFIGURE: CP --> SP. - * @CONTROLVM_BUS_CHANGESTATE: CP --> SP, GP. - * @CONTROLVM_BUS_CHANGESTATE_EVENT: SP, GP --> CP. - * @CONTROLVM_DEVICE_CREATE: CP --> SP, GP. - * @CONTROLVM_DEVICE_DESTROY: CP --> SP, GP. - * @CONTROLVM_DEVICE_CONFIGURE: CP --> SP. - * @CONTROLVM_DEVICE_CHANGESTATE: CP --> SP, GP. - * @CONTROLVM_DEVICE_CHANGESTATE_EVENT: SP, GP --> CP. - * @CONTROLVM_DEVICE_RECONFIGURE: CP --> Boot. - * @CONTROLVM_CHIPSET_INIT: CP --> SP, GP. - * @CONTROLVM_CHIPSET_STOP: CP --> SP, GP. - * @CONTROLVM_CHIPSET_READY: CP --> SP. - * @CONTROLVM_CHIPSET_SELFTEST: CP --> SP. - * - * Ids for commands that may appear in either queue of a ControlVm channel. - * - * Commands that are initiated by the command partition (CP), by an IO or - * console service partition (SP), or by a guest partition (GP) are: - * - issued on the RequestQueue queue (q #0) in the ControlVm channel - * - responded to on the ResponseQueue queue (q #1) in the ControlVm channel - * - * Events that are initiated by an IO or console service partition (SP) or - * by a guest partition (GP) are: - * - issued on the EventQueue queue (q #2) in the ControlVm channel - * - responded to on the EventAckQueue queue (q #3) in the ControlVm channel - */ -enum controlvm_id { - CONTROLVM_INVALID = 0, - /* - * SWITCH commands required Parameter: SwitchNumber. - * BUS commands required Parameter: BusNumber - */ - CONTROLVM_BUS_CREATE = 0x101, - CONTROLVM_BUS_DESTROY = 0x102, - CONTROLVM_BUS_CONFIGURE = 0x104, - CONTROLVM_BUS_CHANGESTATE = 0x105, - CONTROLVM_BUS_CHANGESTATE_EVENT = 0x106, - /* DEVICE commands required Parameter: BusNumber, DeviceNumber */ - CONTROLVM_DEVICE_CREATE = 0x201, - CONTROLVM_DEVICE_DESTROY = 0x202, - CONTROLVM_DEVICE_CONFIGURE = 0x203, - CONTROLVM_DEVICE_CHANGESTATE = 0x204, - CONTROLVM_DEVICE_CHANGESTATE_EVENT = 0x205, - CONTROLVM_DEVICE_RECONFIGURE = 0x206, - /* CHIPSET commands */ - CONTROLVM_CHIPSET_INIT = 0x301, - CONTROLVM_CHIPSET_STOP = 0x302, - CONTROLVM_CHIPSET_READY = 0x304, - CONTROLVM_CHIPSET_SELFTEST = 0x305, -}; - -/* - * struct irq_info - * @reserved1: Natural alignment purposes - * @recv_irq_handle: Specifies interrupt handle. It is used to retrieve the - * corresponding interrupt pin from Monitor; and the interrupt - * pin is used to connect to the corresponding interrupt. - * Used by IOPart-GP only. - * @recv_irq_vector: Specifies interrupt vector. It, interrupt pin, and shared - * are used to connect to the corresponding interrupt. - * Used by IOPart-GP only. - * @recv_irq_shared: Specifies if the recvInterrupt is shared. It, interrupt - * pin and vector are used to connect to 0 = not shared; - * 1 = shared the corresponding interrupt. - * Used by IOPart-GP only. - * @reserved: Natural alignment purposes - */ -struct irq_info { - u64 reserved1; - u64 recv_irq_handle; - u32 recv_irq_vector; - u8 recv_irq_shared; - u8 reserved[3]; -} __packed; - -/* - * struct efi_visor_indication - * @boot_to_fw_ui: Stop in UEFI UI - * @clear_nvram: Clear NVRAM - * @clear_cmos: Clear CMOS - * @boot_to_tool: Run install tool - * @reserved: Natural alignment - */ -struct efi_visor_indication { - u64 boot_to_fw_ui:1; - u64 clear_nvram:1; - u64 clear_cmos:1; - u64 boot_to_tool:1; - /* Remaining bits are available */ - u64 reserved:60; -} __packed; - -enum visor_chipset_feature { - VISOR_CHIPSET_FEATURE_REPLY = 0x00000001, - VISOR_CHIPSET_FEATURE_PARA_HOTPLUG = 0x00000002, -}; - -/* - * struct controlvm_message_header - * @id: See CONTROLVM_ID. - * @message_size: Includes size of this struct + size of message. - * @segment_index: Index of segment containing Vm message/information. - * @completion_status: Error status code or result of message completion. - * @struct flags: - * @failed: =1 in a response to signify failure. - * @response_expected: =1 in all messages that expect a response. - * @server: =1 in all bus & device-related messages where the - * message receiver is to act as the bus or device - * server. - * @test_message: =1 for testing use only (Control and Command - * ignore this). - * @partial_completion: =1 if there are forthcoming responses/acks - * associated with this message. - * @preserve: =1 this is to let us know to preserve channel - * contents. - * @writer_in_diag: =1 the DiagWriter is active in the Diagnostic - * Partition. - * @reserve: Natural alignment. - * @reserved: Natural alignment. - * @message_handle: Identifies the particular message instance. - * @payload_vm_offset: Offset of payload area from start of this instance. - * @payload_max_bytes: Maximum bytes allocated in payload area of ControlVm - * segment. - * @payload_bytes: Actual number of bytes of payload area to copy between - * IO/Command. If non-zero, there is a payload to copy. - * - * This is the common structure that is at the beginning of every - * ControlVm message (both commands and responses) in any ControlVm - * queue. Commands are easily distinguished from responses by - * looking at the flags.response field. - */ -struct controlvm_message_header { - u32 id; - /* - * For requests, indicates the message type. For responses, indicates - * the type of message we are responding to. - */ - u32 message_size; - u32 segment_index; - u32 completion_status; - struct { - u32 failed:1; - u32 response_expected:1; - u32 server:1; - u32 test_message:1; - u32 partial_completion:1; - u32 preserve:1; - u32 writer_in_diag:1; - u32 reserve:25; - } __packed flags; - u32 reserved; - u64 message_handle; - u64 payload_vm_offset; - u32 payload_max_bytes; - u32 payload_bytes; -} __packed; - -/* - * struct controlvm_packet_device_create - For CONTROLVM_DEVICE_CREATE - * @bus_no: Bus # (0..n-1) from the msg receiver's end. - * @dev_no: Bus-relative (0..n-1) device number. - * @channel_addr: Guest physical address of the channel, which can be - * dereferenced by the receiver of this ControlVm command. - * @channel_bytes: Specifies size of the channel in bytes. - * @data_type_uuid: Specifies format of data in channel. - * @dev_inst_uuid: Instance guid for the device. - * @irq_info intr: Specifies interrupt information. - */ -struct controlvm_packet_device_create { - u32 bus_no; - u32 dev_no; - u64 channel_addr; - u64 channel_bytes; - guid_t data_type_guid; - guid_t dev_inst_guid; - struct irq_info intr; -} __packed; - -/* - * struct controlvm_packet_device_configure - For CONTROLVM_DEVICE_CONFIGURE - * @bus_no: Bus number (0..n-1) from the msg receiver's perspective. - * @dev_no: Bus-relative (0..n-1) device number. - */ -struct controlvm_packet_device_configure { - u32 bus_no; - u32 dev_no; -} __packed; - -/* Total 128 bytes */ -struct controlvm_message_device_create { - struct controlvm_message_header header; - struct controlvm_packet_device_create packet; -} __packed; - -/* Total 56 bytes */ -struct controlvm_message_device_configure { - struct controlvm_message_header header; - struct controlvm_packet_device_configure packet; -} __packed; - -/* - * struct controlvm_message_packet - This is the format for a message in any - * ControlVm queue. - * @struct create_bus: For CONTROLVM_BUS_CREATE. - * @bus_no: Bus # (0..n-1) from the msg receiver's perspective. - * @dev_count: Indicates the max number of devices on this bus. - * @channel_addr: Guest physical address of the channel, which can be - * dereferenced by the receiver of this ControlVM - * command. - * @channel_bytes: Size of the channel. - * @bus_data_type_uuid: Indicates format of data in bus channel. - * @bus_inst_uuid: Instance uuid for the bus. - * - * @struct destroy_bus: For CONTROLVM_BUS_DESTROY. - * @bus_no: Bus # (0..n-1) from the msg receiver's perspective. - * @reserved: Natural alignment purposes. - * - * @struct configure_bus: For CONTROLVM_BUS_CONFIGURE. - * @bus_no: Bus # (0..n-1) from the receiver's perspective. - * @reserved1: For alignment purposes. - * @guest_handle: This is used to convert guest physical address to - * physical address. - * @recv_bus_irq_handle: Specifies interrupt info. It is used by SP to - * register to receive interrupts from the CP. This - * interrupt is used for bus level notifications. - * The corresponding sendBusInterruptHandle is kept - * in CP. - * - * @struct create_device: For CONTROLVM_DEVICE_CREATE. - * - * @struct destroy_device: For CONTROLVM_DEVICE_DESTROY. - * @bus_no: Bus # (0..n-1) from the msg receiver's perspective. - * @dev_no: Bus-relative (0..n-1) device number. - * - * @struct configure_device: For CONTROLVM_DEVICE_CONFIGURE. - * - * @struct reconfigure_device: For CONTROLVM_DEVICE_RECONFIGURE. - * @bus_no: Bus # (0..n-1) from the msg receiver's perspective. - * @dev_no: Bus-relative (0..n-1) device number. - * - * @struct bus_change_state: For CONTROLVM_BUS_CHANGESTATE. - * @bus_no: - * @struct state: - * @reserved: Natural alignment purposes. - * - * @struct device_change_state: For CONTROLVM_DEVICE_CHANGESTATE. - * @bus_no: - * @dev_no: - * @struct state: - * @struct flags: - * @phys_device: =1 if message is for a physical device. - * @reserved: Natural alignment. - * @reserved1: Natural alignment. - * @reserved: Natural alignment purposes. - * - * @struct device_change_state_event: For CONTROLVM_DEVICE_CHANGESTATE_EVENT. - * @bus_no: - * @dev_no: - * @struct state: - * @reserved: Natural alignment purposes. - * - * @struct init_chipset: For CONTROLVM_CHIPSET_INIT. - * @bus_count: Indicates the max number of busses. - * @switch_count: Indicates the max number of switches. - * @enum features: - * @platform_number: - * - * @struct chipset_selftest: For CONTROLVM_CHIPSET_SELFTEST. - * @options: Reserved. - * @test: Bit 0 set to run embedded selftest. - * - * @addr: A physical address of something, that can be dereferenced by the - * receiver of this ControlVm command. - * - * @handle: A handle of something (depends on command id). - */ -struct controlvm_message_packet { - union { - struct { - u32 bus_no; - u32 dev_count; - u64 channel_addr; - u64 channel_bytes; - guid_t bus_data_type_guid; - guid_t bus_inst_guid; - } __packed create_bus; - struct { - u32 bus_no; - u32 reserved; - } __packed destroy_bus; - struct { - u32 bus_no; - u32 reserved1; - u64 guest_handle; - u64 recv_bus_irq_handle; - } __packed configure_bus; - struct controlvm_packet_device_create create_device; - struct { - u32 bus_no; - u32 dev_no; - } __packed destroy_device; - struct controlvm_packet_device_configure configure_device; - struct { - u32 bus_no; - u32 dev_no; - } __packed reconfigure_device; - struct { - u32 bus_no; - struct visor_segment_state state; - u8 reserved[2]; - } __packed bus_change_state; - struct { - u32 bus_no; - u32 dev_no; - struct visor_segment_state state; - struct { - u32 phys_device:1; - u32 reserved:31; - u32 reserved1; - } __packed flags; - u8 reserved[2]; - } __packed device_change_state; - struct { - u32 bus_no; - u32 dev_no; - struct visor_segment_state state; - u8 reserved[6]; - } __packed device_change_state_event; - struct { - u32 bus_count; - u32 switch_count; - enum visor_chipset_feature features; - u32 platform_number; - } __packed init_chipset; - struct { - u32 options; - u32 test; - } __packed chipset_selftest; - u64 addr; - u64 handle; - }; -} __packed; - -/* All messages in any ControlVm queue have this layout. */ -struct controlvm_message { - struct controlvm_message_header hdr; - struct controlvm_message_packet cmd; -} __packed; - -/* - * struct visor_controlvm_channel - * @struct header: - * @gp_controlvm: Guest phys addr of this channel. - * @gp_partition_tables: Guest phys addr of partition tables. - * @gp_diag_guest: Guest phys addr of diagnostic channel. - * @gp_boot_romdisk: Guest phys addr of (read* only) Boot - * ROM disk. - * @gp_boot_ramdisk: Guest phys addr of writable Boot RAM - * disk. - * @gp_acpi_table: Guest phys addr of acpi table. - * @gp_control_channel: Guest phys addr of control channel. - * @gp_diag_romdisk: Guest phys addr of diagnostic ROM disk. - * @gp_nvram: Guest phys addr of NVRAM channel. - * @request_payload_offset: Offset to request payload area. - * @event_payload_offset: Offset to event payload area. - * @request_payload_bytes: Bytes available in request payload area. - * @event_payload_bytes: Bytes available in event payload area. - * @control_channel_bytes: - * @nvram_channel_bytes: Bytes in PartitionNvram segment. - * @message_bytes: sizeof(CONTROLVM_MESSAGE). - * @message_count: CONTROLVM_MESSAGE_MAX. - * @gp_smbios_table: Guest phys addr of SMBIOS tables. - * @gp_physical_smbios_table: Guest phys addr of SMBIOS table. - * @gp_reserved: VISOR_MAX_GUESTS_PER_SERVICE. - * @virtual_guest_firmware_image_base: Guest physical address of EFI firmware - * image base. - * @virtual_guest_firmware_entry_point: Guest physical address of EFI firmware - * entry point. - * @virtual_guest_firmware_image_size: Guest EFI firmware image size. - * @virtual_guest_firmware_boot_base: GPA = 1MB where EFI firmware image is - * copied to. - * @virtual_guest_image_base: - * @virtual_guest_image_size: - * @prototype_control_channel_offset: - * @virtual_guest_partition_handle: - * @restore_action: Restore Action field to restore the - * guest partition. - * @dump_action: For Windows guests it shows if the - * visordisk is in dump mode. - * @nvram_fail_count: - * @saved_crash_message_count: = CONTROLVM_CRASHMSG_MAX. - * @saved_crash_message_offset: Offset to request payload area needed - * for crash dump. - * @installation_error: Type of error encountered during - * installation. - * @installation_text_id: Id of string to display. - * @installation_remaining_steps: Number of remaining installation steps - * (for progress bars). - * @tool_action: VISOR_TOOL_ACTIONS Installation Action - * field. - * @reserved: Alignment. - * @struct efi_visor_ind: - * @sp_reserved: - * @reserved2: Force signals to begin on 128-byte - * cache line. - * @struct request_queue: Guest partition uses this queue to send - * requests to Control. - * @struct response_queue: Control uses this queue to respond to - * service or guest partition request. - * @struct event_queue: Control uses this queue to send events - * to guest partition. - * @struct event_ack_queue: Service or guest partition uses this - * queue to ack Control events. - * @struct request_msg: Request fixed-size message pool - - * does not include payload. - * @struct response_msg: Response fixed-size message pool - - * does not include payload. - * @struct event_msg: Event fixed-size message pool - - * does not include payload. - * @struct event_ack_msg: Ack fixed-size message pool - - * does not include payload. - * @struct saved_crash_msg: Message stored during IOVM creation to - * be reused after crash. - */ -struct visor_controlvm_channel { - struct channel_header header; - u64 gp_controlvm; - u64 gp_partition_tables; - u64 gp_diag_guest; - u64 gp_boot_romdisk; - u64 gp_boot_ramdisk; - u64 gp_acpi_table; - u64 gp_control_channel; - u64 gp_diag_romdisk; - u64 gp_nvram; - u64 request_payload_offset; - u64 event_payload_offset; - u32 request_payload_bytes; - u32 event_payload_bytes; - u32 control_channel_bytes; - u32 nvram_channel_bytes; - u32 message_bytes; - u32 message_count; - u64 gp_smbios_table; - u64 gp_physical_smbios_table; - char gp_reserved[2688]; - u64 virtual_guest_firmware_image_base; - u64 virtual_guest_firmware_entry_point; - u64 virtual_guest_firmware_image_size; - u64 virtual_guest_firmware_boot_base; - u64 virtual_guest_image_base; - u64 virtual_guest_image_size; - u64 prototype_control_channel_offset; - u64 virtual_guest_partition_handle; - u16 restore_action; - u16 dump_action; - u16 nvram_fail_count; - u16 saved_crash_message_count; - u32 saved_crash_message_offset; - u32 installation_error; - u32 installation_text_id; - u16 installation_remaining_steps; - u8 tool_action; - u8 reserved; - struct efi_visor_indication efi_visor_ind; - u32 sp_reserved; - u8 reserved2[28]; - struct signal_queue_header request_queue; - struct signal_queue_header response_queue; - struct signal_queue_header event_queue; - struct signal_queue_header event_ack_queue; - struct controlvm_message request_msg[CONTROLVM_MESSAGE_MAX]; - struct controlvm_message response_msg[CONTROLVM_MESSAGE_MAX]; - struct controlvm_message event_msg[CONTROLVM_MESSAGE_MAX]; - struct controlvm_message event_ack_msg[CONTROLVM_MESSAGE_MAX]; - struct controlvm_message saved_crash_msg[CONTROLVM_CRASHMSG_MAX]; -} __packed; - -/* - * struct visor_controlvm_parameters_header - * - * The following header will be located at the beginning of PayloadVmOffset for - * various ControlVm commands. The receiver of a ControlVm command with a - * PayloadVmOffset will dereference this address and then use connection_offset, - * initiator_offset, and target_offset to get the location of UTF-8 formatted - * strings that can be parsed to obtain command-specific information. The value - * of total_length should equal PayloadBytes. The format of the strings at - * PayloadVmOffset will take different forms depending on the message. - */ -struct visor_controlvm_parameters_header { - u32 total_length; - u32 header_length; - u32 connection_offset; - u32 connection_length; - u32 initiator_offset; - u32 initiator_length; - u32 target_offset; - u32 target_length; - u32 client_offset; - u32 client_length; - u32 name_offset; - u32 name_length; - guid_t id; - u32 revision; - /* Natural alignment */ - u32 reserved; -} __packed; - -/* General Errors------------------------------------------------------[0-99] */ -#define CONTROLVM_RESP_SUCCESS 0 -#define CONTROLVM_RESP_ALREADY_DONE 1 -#define CONTROLVM_RESP_IOREMAP_FAILED 2 -#define CONTROLVM_RESP_KMALLOC_FAILED 3 -#define CONTROLVM_RESP_ID_UNKNOWN 4 -#define CONTROLVM_RESP_ID_INVALID_FOR_CLIENT 5 -/* CONTROLVM_INIT_CHIPSET-------------------------------------------[100-199] */ -#define CONTROLVM_RESP_CLIENT_SWITCHCOUNT_NONZERO 100 -#define CONTROLVM_RESP_EXPECTED_CHIPSET_INIT 101 -/* Maximum Limit----------------------------------------------------[200-299] */ -/* BUS_CREATE */ -#define CONTROLVM_RESP_ERROR_MAX_BUSES 201 -/* DEVICE_CREATE */ -#define CONTROLVM_RESP_ERROR_MAX_DEVICES 202 -/* Payload and Parameter Related------------------------------------[400-499] */ -/* SWITCH_ATTACHEXTPORT, DEVICE_CONFIGURE */ -#define CONTROLVM_RESP_PAYLOAD_INVALID 400 -/* Multiple */ -#define CONTROLVM_RESP_INITIATOR_PARAMETER_INVALID 401 -/* DEVICE_CONFIGURE */ -#define CONTROLVM_RESP_TARGET_PARAMETER_INVALID 402 -/* DEVICE_CONFIGURE */ -#define CONTROLVM_RESP_CLIENT_PARAMETER_INVALID 403 -/* Specified[Packet Structure] Value--------------------------------[500-599] */ -/* SWITCH_ATTACHINTPORT */ -/* BUS_CONFIGURE, DEVICE_CREATE, DEVICE_CONFIG, DEVICE_DESTROY */ -#define CONTROLVM_RESP_BUS_INVALID 500 -/* SWITCH_ATTACHINTPORT*/ -/* DEVICE_CREATE, DEVICE_CONFIGURE, DEVICE_DESTROY */ -#define CONTROLVM_RESP_DEVICE_INVALID 501 -/* DEVICE_CREATE, DEVICE_CONFIGURE */ -#define CONTROLVM_RESP_CHANNEL_INVALID 502 -/* Partition Driver Callback Interface------------------------------[600-699] */ -/* BUS_CREATE, BUS_DESTROY, DEVICE_CREATE, DEVICE_DESTROY */ -#define CONTROLVM_RESP_VIRTPCI_DRIVER_FAILURE 604 -/* Unable to invoke VIRTPCI callback. VIRTPCI Callback returned error. */ -/* BUS_CREATE, BUS_DESTROY, DEVICE_CREATE, DEVICE_DESTROY */ -#define CONTROLVM_RESP_VIRTPCI_DRIVER_CALLBACK_ERROR 605 -/* Generic device callback returned error. */ -/* SWITCH_ATTACHEXTPORT, SWITCH_DETACHEXTPORT, DEVICE_CONFIGURE */ -#define CONTROLVM_RESP_GENERIC_DRIVER_CALLBACK_ERROR 606 -/* Bus Related------------------------------------------------------[700-799] */ -/* BUS_DESTROY */ -#define CONTROLVM_RESP_ERROR_BUS_DEVICE_ATTACHED 700 -/* Channel Related--------------------------------------------------[800-899] */ -/* GET_CHANNELINFO, DEVICE_DESTROY */ -#define CONTROLVM_RESP_CHANNEL_TYPE_UNKNOWN 800 -/* DEVICE_CREATE */ -#define CONTROLVM_RESP_CHANNEL_SIZE_TOO_SMALL 801 -/* Chipset Shutdown Related---------------------------------------[1000-1099] */ -#define CONTROLVM_RESP_CHIPSET_SHUTDOWN_FAILED 1000 -#define CONTROLVM_RESP_CHIPSET_SHUTDOWN_ALREADY_ACTIVE 1001 -/* Chipset Stop Related-------------------------------------------[1100-1199] */ -#define CONTROLVM_RESP_CHIPSET_STOP_FAILED_BUS 1100 -#define CONTROLVM_RESP_CHIPSET_STOP_FAILED_SWITCH 1101 -/* Device Related-------------------------------------------------[1400-1499] */ -#define CONTROLVM_RESP_DEVICE_UDEV_TIMEOUT 1400 - -/* __CONTROLVMCHANNEL_H__ */ -#endif diff --git a/drivers/visorbus/vbuschannel.h b/drivers/visorbus/vbuschannel.h deleted file mode 100644 index 98711fb6d66e..000000000000 --- a/drivers/visorbus/vbuschannel.h +++ /dev/null @@ -1,95 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2010 - 2015 UNISYS CORPORATION - * All rights reserved. - */ - -#ifndef __VBUSCHANNEL_H__ -#define __VBUSCHANNEL_H__ - -/* - * The vbus channel is the channel area provided via the BUS_CREATE controlvm - * message for each virtual bus. This channel area is provided to both server - * and client ends of the bus. The channel header area is initialized by - * the server, and the remaining information is filled in by the client. - * We currently use this for the client to provide various information about - * the client devices and client drivers for the server end to see. - */ - -#include <linux/uuid.h> -#include <linux/visorbus.h> - -/* {193b331b-c58f-11da-95a9-00e08161165f} */ -#define VISOR_VBUS_CHANNEL_GUID \ - GUID_INIT(0x193b331b, 0xc58f, 0x11da, \ - 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) - -/* - * Must increment this whenever you insert or delete fields within this channel - * struct. Also increment whenever you change the meaning of fields within this - * channel struct so as to break pre-existing software. Note that you can - * usually add fields to the END of the channel struct withOUT needing to - * increment this. - */ -#define VISOR_VBUS_CHANNEL_VERSIONID 1 - -/* - * struct visor_vbus_deviceinfo - * @devtype: Short string identifying the device type. - * @drvname: Driver .sys file name. - * @infostrs: Kernel vversion. - * @reserved: Pad size to 256 bytes. - * - * An array of this struct is present in the channel area for each vbus. It is - * filled in by the client side to provide info about the device and driver from - * the client's perspective. - */ -struct visor_vbus_deviceinfo { - u8 devtype[16]; - u8 drvname[16]; - u8 infostrs[96]; - u8 reserved[128]; -} __packed; - -/* - * struct visor_vbus_headerinfo - * @struct_bytes: Size of this struct in bytes. - * @device_info_struct_bytes: Size of VISOR_VBUS_DEVICEINFO. - * @dev_info_count: Num of items in DevInfo member. This is the - * allocated size. - * @chp_info_offset: Byte offset from beginning of this struct to the - * ChpInfo struct. - * @bus_info_offset: Byte offset from beginning of this struct to the - * BusInfo struct. - * @dev_info_offset: Byte offset from beginning of this struct to the - * DevInfo array. - * @reserved: Natural alignment. - */ -struct visor_vbus_headerinfo { - u32 struct_bytes; - u32 device_info_struct_bytes; - u32 dev_info_count; - u32 chp_info_offset; - u32 bus_info_offset; - u32 dev_info_offset; - u8 reserved[104]; -} __packed; - -/* - * struct visor_vbus_channel - * @channel_header: Initialized by server. - * @hdr_info: Initialized by server. - * @chp_info: Describes client chipset device and driver. - * @bus_info: Describes client bus device and driver. - * @dev_info: Describes client device and driver for each device on the - * bus. - */ -struct visor_vbus_channel { - struct channel_header channel_header; - struct visor_vbus_headerinfo hdr_info; - struct visor_vbus_deviceinfo chp_info; - struct visor_vbus_deviceinfo bus_info; - struct visor_vbus_deviceinfo dev_info[]; -} __packed; - -#endif diff --git a/drivers/visorbus/visorbus_main.c b/drivers/visorbus/visorbus_main.c deleted file mode 100644 index 152fd29f04f2..000000000000 --- a/drivers/visorbus/visorbus_main.c +++ /dev/null @@ -1,1234 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright � 2010 - 2015 UNISYS CORPORATION - * All rights reserved. - */ - -#include <linux/ctype.h> -#include <linux/debugfs.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/visorbus.h> -#include <linux/uuid.h> - -#include "visorbus_private.h" - -static const guid_t visor_vbus_channel_guid = VISOR_VBUS_CHANNEL_GUID; - -/* Display string that is guaranteed to be no longer the 99 characters */ -#define LINESIZE 99 -#define POLLJIFFIES_NORMALCHANNEL 10 - -/* stores whether bus_registration was successful */ -static bool initialized; -static struct dentry *visorbus_debugfs_dir; - -/* - * DEVICE type attributes - * - * The modalias file will contain the guid of the device. - */ -static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct visor_device *vdev; - const guid_t *guid; - - vdev = to_visor_device(dev); - guid = visorchannel_get_guid(vdev->visorchannel); - return sprintf(buf, "visorbus:%pUl\n", guid); -} -static DEVICE_ATTR_RO(modalias); - -static struct attribute *visorbus_dev_attrs[] = { - &dev_attr_modalias.attr, - NULL, -}; - -ATTRIBUTE_GROUPS(visorbus_dev); - -/* filled in with info about parent chipset driver when we register with it */ -static struct visor_vbus_deviceinfo chipset_driverinfo; -/* filled in with info about this driver, wrt it servicing client busses */ -static struct visor_vbus_deviceinfo clientbus_driverinfo; - -/* 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 */ -static LIST_HEAD(list_all_device_instances); - -/* - * Generic function useful for validating any type of channel when it is - * received by the client that will be accessing the channel. - * Note that <logCtx> is only needed for callers in the EFI environment, and - * is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages. - */ -int visor_check_channel(struct channel_header *ch, struct device *dev, - const guid_t *expected_guid, char *chname, - u64 expected_min_bytes, u32 expected_version, - u64 expected_signature) -{ - if (!guid_is_null(expected_guid)) { - /* caller wants us to verify type GUID */ - if (!guid_equal(&ch->chtype, expected_guid)) { - dev_err(dev, "Channel mismatch on channel=%s(%pUL) field=type expected=%pUL actual=%pUL\n", - chname, expected_guid, expected_guid, - &ch->chtype); - return 0; - } - } - /* verify channel size */ - if (expected_min_bytes > 0) { - if (ch->size < expected_min_bytes) { - dev_err(dev, "Channel mismatch on channel=%s(%pUL) field=size expected=0x%-8.8Lx actual=0x%-8.8Lx\n", - chname, expected_guid, - (unsigned long long)expected_min_bytes, - ch->size); - return 0; - } - } - /* verify channel version */ - if (expected_version > 0) { - if (ch->version_id != expected_version) { - dev_err(dev, "Channel mismatch on channel=%s(%pUL) field=version expected=0x%-8.8lx actual=0x%-8.8x\n", - chname, expected_guid, - (unsigned long)expected_version, - ch->version_id); - return 0; - } - } - /* verify channel signature */ - if (expected_signature > 0) { - if (ch->signature != expected_signature) { - dev_err(dev, "Channel mismatch on channel=%s(%pUL) field=signature expected=0x%-8.8Lx actual=0x%-8.8Lx\n", - chname, expected_guid, expected_signature, - ch->signature); - return 0; - } - } - return 1; -} - -static int visorbus_uevent(struct device *xdev, struct kobj_uevent_env *env) -{ - struct visor_device *dev; - const guid_t *guid; - - dev = to_visor_device(xdev); - guid = visorchannel_get_guid(dev->visorchannel); - return add_uevent_var(env, "MODALIAS=visorbus:%pUl", guid); -} - -/* - * 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) -{ - const guid_t *channel_type; - int i; - struct visor_device *dev; - struct visor_driver *drv; - struct visorchannel *chan; - - dev = to_visor_device(xdev); - channel_type = visorchannel_get_guid(dev->visorchannel); - drv = to_visor_driver(xdrv); - chan = dev->visorchannel; - if (!drv->channel_types) - return 0; - for (i = 0; !guid_is_null(&drv->channel_types[i].guid); i++) - if (guid_equal(&drv->channel_types[i].guid, channel_type) && - visor_check_channel(visorchannel_get_header(chan), - xdev, - &drv->channel_types[i].guid, - (char *)drv->channel_types[i].name, - drv->channel_types[i].min_bytes, - drv->channel_types[i].version, - VISOR_CHANNEL_SIGNATURE)) - return i + 1; - return 0; -} - -/* - * This describes the TYPE of bus. - * (Don't confuse this with an INSTANCE of the bus.) - */ -static struct bus_type visorbus_type = { - .name = "visorbus", - .match = visorbus_match, - .uevent = visorbus_uevent, - .dev_groups = visorbus_dev_groups, -}; - -struct visor_busdev { - u32 bus_no; - u32 dev_no; -}; - -static int match_visorbus_dev_by_id(struct device *dev, const void *data) -{ - struct visor_device *vdev = to_visor_device(dev); - const struct visor_busdev *id = data; - - if (vdev->chipset_bus_no == id->bus_no && - vdev->chipset_dev_no == id->dev_no) - return 1; - return 0; -} - -struct visor_device *visorbus_get_device_by_id(u32 bus_no, u32 dev_no, - struct visor_device *from) -{ - struct device *dev; - struct device *dev_start = NULL; - struct visor_busdev id = { - .bus_no = bus_no, - .dev_no = dev_no - }; - - if (from) - dev_start = &from->device; - dev = bus_find_device(&visorbus_type, dev_start, (void *)&id, - match_visorbus_dev_by_id); - if (!dev) - return NULL; - return to_visor_device(dev); -} - -/* - * visorbus_release_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) -{ - struct visor_device *dev = dev_get_drvdata(xdev); - - debugfs_remove(dev->debugfs_bus_info); - debugfs_remove_recursive(dev->debugfs_dir); - visorchannel_destroy(dev->visorchannel); - kfree(dev); -} - -/* - * 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); - - visorchannel_destroy(dev->visorchannel); - kfree(dev); -} - -/* - * BUS 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) -{ - struct visor_device *vdev = to_visor_device(dev); - - return sprintf(buf, "0x%llx\n", - visorchannel_get_physaddr(vdev->visorchannel)); -} -static DEVICE_ATTR_RO(physaddr); - -static ssize_t nbytes_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct visor_device *vdev = to_visor_device(dev); - - return sprintf(buf, "0x%lx\n", - visorchannel_get_nbytes(vdev->visorchannel)); -} -static DEVICE_ATTR_RO(nbytes); - -static ssize_t clientpartition_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct visor_device *vdev = to_visor_device(dev); - - return sprintf(buf, "0x%llx\n", - visorchannel_get_clientpartition(vdev->visorchannel)); -} -static DEVICE_ATTR_RO(clientpartition); - -static ssize_t typeguid_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct visor_device *vdev = to_visor_device(dev); - char typeid[LINESIZE]; - - return sprintf(buf, "%s\n", - visorchannel_id(vdev->visorchannel, typeid)); -} -static DEVICE_ATTR_RO(typeguid); - -static ssize_t zoneguid_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct visor_device *vdev = to_visor_device(dev); - char zoneid[LINESIZE]; - - return sprintf(buf, "%s\n", - visorchannel_zoneid(vdev->visorchannel, zoneid)); -} -static DEVICE_ATTR_RO(zoneguid); - -static ssize_t typename_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - int i = 0; - struct bus_type *xbus = dev->bus; - struct device_driver *xdrv = dev->driver; - struct visor_driver *drv = NULL; - - if (!xdrv) - return 0; - i = xbus->match(dev, xdrv); - if (!i) - return 0; - drv = to_visor_driver(xdrv); - return sprintf(buf, "%s\n", drv->channel_types[i - 1].name); -} -static DEVICE_ATTR_RO(typename); - -static struct attribute *channel_attrs[] = { - &dev_attr_physaddr.attr, - &dev_attr_nbytes.attr, - &dev_attr_clientpartition.attr, - &dev_attr_typeguid.attr, - &dev_attr_zoneguid.attr, - &dev_attr_typename.attr, - NULL -}; - -ATTRIBUTE_GROUPS(channel); - -/* - * BUS instance attributes - * - * define & implement display of bus attributes under - * /sys/bus/visorbus/devices/visorbus<n>. - */ -static ssize_t partition_handle_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct visor_device *vdev = to_visor_device(dev); - u64 handle = visorchannel_get_clientpartition(vdev->visorchannel); - - return sprintf(buf, "0x%llx\n", handle); -} -static DEVICE_ATTR_RO(partition_handle); - -static ssize_t partition_guid_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct visor_device *vdev = to_visor_device(dev); - - return sprintf(buf, "{%pUb}\n", &vdev->partition_guid); -} -static DEVICE_ATTR_RO(partition_guid); - -static ssize_t partition_name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct visor_device *vdev = to_visor_device(dev); - - return sprintf(buf, "%s\n", vdev->name); -} -static DEVICE_ATTR_RO(partition_name); - -static ssize_t channel_addr_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct visor_device *vdev = to_visor_device(dev); - u64 addr = visorchannel_get_physaddr(vdev->visorchannel); - - return sprintf(buf, "0x%llx\n", addr); -} -static DEVICE_ATTR_RO(channel_addr); - -static ssize_t channel_bytes_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct visor_device *vdev = to_visor_device(dev); - u64 nbytes = visorchannel_get_nbytes(vdev->visorchannel); - - return sprintf(buf, "0x%llx\n", nbytes); -} -static DEVICE_ATTR_RO(channel_bytes); - -static ssize_t channel_id_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct visor_device *vdev = to_visor_device(dev); - int len = 0; - - visorchannel_id(vdev->visorchannel, buf); - len = strlen(buf); - buf[len++] = '\n'; - return len; -} -static DEVICE_ATTR_RO(channel_id); - -static struct attribute *visorbus_attrs[] = { - &dev_attr_partition_handle.attr, - &dev_attr_partition_guid.attr, - &dev_attr_partition_name.attr, - &dev_attr_channel_addr.attr, - &dev_attr_channel_bytes.attr, - &dev_attr_channel_id.attr, - NULL -}; - -ATTRIBUTE_GROUPS(visorbus); - -/* - * BUS debugfs entries - * - * define & implement display of debugfs attributes under - * /sys/kernel/debug/visorbus/visorbus<n>. - */ - -/* - * vbuschannel_print_devinfo() - format a struct visor_vbus_deviceinfo - * and write it to a seq_file - * @devinfo: the struct visor_vbus_deviceinfo to format - * @seq: seq_file to write to - * @devix: the device index to be included in the output data, or -1 if no - * device index is to be included - * - * Reads @devInfo, and writes it in human-readable notation to @seq. - */ -static void vbuschannel_print_devinfo(struct visor_vbus_deviceinfo *devinfo, - struct seq_file *seq, int devix) -{ - /* uninitialized vbus device entry */ - if (!isprint(devinfo->devtype[0])) - return; - if (devix >= 0) - seq_printf(seq, "[%d]", devix); - else - /* vbus device entry is for bus or chipset */ - seq_puts(seq, " "); - /* - * Note: because the s-Par back-end is free to scribble in this area, - * we never assume '\0'-termination. - */ - seq_printf(seq, "%-*.*s ", (int)sizeof(devinfo->devtype), - (int)sizeof(devinfo->devtype), devinfo->devtype); - seq_printf(seq, "%-*.*s ", (int)sizeof(devinfo->drvname), - (int)sizeof(devinfo->drvname), devinfo->drvname); - seq_printf(seq, "%.*s\n", (int)sizeof(devinfo->infostrs), - devinfo->infostrs); -} - -static int bus_info_debugfs_show(struct seq_file *seq, void *v) -{ - int i = 0; - unsigned long off; - struct visor_vbus_deviceinfo dev_info; - struct visor_device *vdev = seq->private; - struct visorchannel *channel = vdev->visorchannel; - - if (!channel) - return 0; - - seq_printf(seq, - "Client device/driver info for %s partition (vbus #%u):\n", - ((vdev->name) ? (char *)(vdev->name) : ""), - vdev->chipset_bus_no); - if (visorchannel_read(channel, - offsetof(struct visor_vbus_channel, chp_info), - &dev_info, sizeof(dev_info)) >= 0) - vbuschannel_print_devinfo(&dev_info, seq, -1); - if (visorchannel_read(channel, - offsetof(struct visor_vbus_channel, bus_info), - &dev_info, sizeof(dev_info)) >= 0) - vbuschannel_print_devinfo(&dev_info, seq, -1); - - off = offsetof(struct visor_vbus_channel, dev_info); - while (off + sizeof(dev_info) <= visorchannel_get_nbytes(channel)) { - if (visorchannel_read(channel, off, &dev_info, - sizeof(dev_info)) >= 0) - vbuschannel_print_devinfo(&dev_info, seq, i); - off += sizeof(dev_info); - i++; - } - return 0; -} - -static int bus_info_debugfs_open(struct inode *inode, struct file *file) -{ - return single_open(file, bus_info_debugfs_show, inode->i_private); -} - -static const struct file_operations bus_info_debugfs_fops = { - .owner = THIS_MODULE, - .open = bus_info_debugfs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void dev_periodic_work(struct timer_list *t) -{ - struct visor_device *dev = from_timer(dev, t, timer); - struct visor_driver *drv = to_visor_driver(dev->device.driver); - - drv->channel_interrupt(dev); - mod_timer(&dev->timer, jiffies + POLLJIFFIES_NORMALCHANNEL); -} - -static int dev_start_periodic_work(struct visor_device *dev) -{ - if (dev->being_removed || dev->timer_active) - return -EINVAL; - - /* now up by at least 2 */ - get_device(&dev->device); - dev->timer.expires = jiffies + POLLJIFFIES_NORMALCHANNEL; - add_timer(&dev->timer); - dev->timer_active = true; - return 0; -} - -static void dev_stop_periodic_work(struct visor_device *dev) -{ - if (!dev->timer_active) - return; - - del_timer_sync(&dev->timer); - dev->timer_active = false; - put_device(&dev->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) -{ - struct visor_device *dev = to_visor_device(xdev); - struct visor_driver *drv = to_visor_driver(xdev->driver); - - mutex_lock(&dev->visordriver_callback_lock); - dev->being_removed = true; - drv->remove(dev); - mutex_unlock(&dev->visordriver_callback_lock); - dev_stop_periodic_work(dev); - put_device(&dev->device); - return 0; -} - -/* - * visorbus_unregister_visor_driver() - unregisters the provided driver - * @drv: the driver to unregister - * - * 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) -{ - 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) -{ - return visorchannel_read(dev->visorchannel, offset, dest, nbytes); -} -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) -{ - return visorchannel_write(dev->visorchannel, offset, src, nbytes); -} -EXPORT_SYMBOL_GPL(visorbus_write_channel); - -/* - * 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. - */ -int visorbus_enable_channel_interrupts(struct visor_device *dev) -{ - struct visor_driver *drv = to_visor_driver(dev->device.driver); - - if (!drv->channel_interrupt) { - dev_err(&dev->device, "%s no interrupt function!\n", __func__); - return -ENOENT; - } - - return dev_start_periodic_work(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) -{ - dev_stop_periodic_work(dev); -} -EXPORT_SYMBOL_GPL(visorbus_disable_channel_interrupts); - -/* - * 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. - * - * Return: 0 if successful, otherwise the negative value returned by - * device_add() indicating the reason for failure - */ -int create_visor_device(struct visor_device *dev) -{ - int err; - u32 chipset_bus_no = dev->chipset_bus_no; - u32 chipset_dev_no = dev->chipset_dev_no; - - mutex_init(&dev->visordriver_callback_lock); - dev->device.bus = &visorbus_type; - dev->device.groups = channel_groups; - device_initialize(&dev->device); - dev->device.release = visorbus_release_device; - /* keep a reference just for us (now 2) */ - get_device(&dev->device); - timer_setup(&dev->timer, dev_periodic_work, 0); - /* - * 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. - */ - err = dev_set_name(&dev->device, "vbus%u:dev%u", - chipset_bus_no, chipset_dev_no); - if (err) - goto err_put; - /* - * device_add does this: - * bus_add_device(dev) - * ->device_attach(dev) - * ->for each driver drv registered on the bus that dev is on - * if (dev.drv) ** device already has a driver ** - * ** not sure we could ever get here... ** - * else - * if (bus.match(dev,drv)) [visorbus_match] - * dev.drv = drv - * if (!drv.probe(dev)) [visordriver_probe_device] - * dev.drv = NULL - * - * Note that device_add does NOT fail if no driver failed to claim the - * device. The device will be linked onto bus_type.klist_devices - * regardless (use bus_for_each_dev). - */ - err = device_add(&dev->device); - if (err < 0) - goto err_put; - list_add_tail(&dev->list_all, &list_all_device_instances); - dev->state.created = 1; - visorbus_response(dev, err, CONTROLVM_DEVICE_CREATE); - /* success: reference kept via unmatched get_device() */ - return 0; - -err_put: - put_device(&dev->device); - dev_err(&dev->device, "Creating visor device failed. %d\n", err); - return err; -} - -void remove_visor_device(struct visor_device *dev) -{ - list_del(&dev->list_all); - put_device(&dev->device); - if (dev->pending_msg_hdr) - visorbus_response(dev, 0, CONTROLVM_DEVICE_DESTROY); - device_unregister(&dev->device); -} - -static int get_vbus_header_info(struct visorchannel *chan, - struct device *dev, - struct visor_vbus_headerinfo *hdr_info) -{ - int err; - - if (!visor_check_channel(visorchannel_get_header(chan), - dev, - &visor_vbus_channel_guid, - "vbus", - sizeof(struct visor_vbus_channel), - VISOR_VBUS_CHANNEL_VERSIONID, - VISOR_CHANNEL_SIGNATURE)) - return -EINVAL; - - err = visorchannel_read(chan, sizeof(struct channel_header), hdr_info, - sizeof(*hdr_info)); - if (err < 0) - return err; - if (hdr_info->struct_bytes < sizeof(struct visor_vbus_headerinfo)) - return -EINVAL; - if (hdr_info->device_info_struct_bytes < - sizeof(struct visor_vbus_deviceinfo)) - return -EINVAL; - return 0; -} - -/* - * write_vbus_chp_info() - write the contents of <info> to the struct - * visor_vbus_channel.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 void write_vbus_chp_info(struct visorchannel *chan, - struct visor_vbus_headerinfo *hdr_info, - struct visor_vbus_deviceinfo *info) -{ - int off; - - if (hdr_info->chp_info_offset == 0) - return; - - off = sizeof(struct channel_header) + hdr_info->chp_info_offset; - visorchannel_write(chan, off, info, sizeof(*info)); -} - -/* - * write_vbus_bus_info() - write the contents of <info> to the struct - * visor_vbus_channel.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 void write_vbus_bus_info(struct visorchannel *chan, - struct visor_vbus_headerinfo *hdr_info, - struct visor_vbus_deviceinfo *info) -{ - int off; - - if (hdr_info->bus_info_offset == 0) - return; - - off = sizeof(struct channel_header) + hdr_info->bus_info_offset; - visorchannel_write(chan, off, info, sizeof(*info)); -} - -/* - * write_vbus_dev_info() - write the contents of <info> to the struct - * visor_vbus_channel.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 void write_vbus_dev_info(struct visorchannel *chan, - struct visor_vbus_headerinfo *hdr_info, - struct visor_vbus_deviceinfo *info, - unsigned int devix) -{ - int off; - - if (hdr_info->dev_info_offset == 0) - return; - off = (sizeof(struct channel_header) + hdr_info->dev_info_offset) + - (hdr_info->device_info_struct_bytes * devix); - visorchannel_write(chan, off, info, sizeof(*info)); -} - -static void bus_device_info_init( - struct visor_vbus_deviceinfo *bus_device_info_ptr, - const char *dev_type, const char *drv_name) -{ - memset(bus_device_info_ptr, 0, sizeof(struct visor_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); -} - -/* - * publish_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 appropriate slot - * within the vbus channel of the bus instance - * @visordev: struct visor_device for the desired device - */ -static void publish_vbus_dev_info(struct visor_device *visordev) -{ - int i; - struct visor_device *bdev; - struct visor_driver *visordrv; - u32 bus_no = visordev->chipset_bus_no; - u32 dev_no = visordev->chipset_dev_no; - struct visor_vbus_deviceinfo dev_info; - const char *chan_type_name = NULL; - struct visor_vbus_headerinfo *hdr_info; - - if (!visordev->device.driver) - return; - bdev = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL); - if (!bdev) - return; - hdr_info = (struct visor_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 - * 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 - */ - for (i = 0; visordrv->channel_types[i].name; i++) { - if (guid_equal(&visordrv->channel_types[i].guid, - &visordev->channel_type_guid)) { - chan_type_name = visordrv->channel_types[i].name; - break; - } - } - bus_device_info_init(&dev_info, chan_type_name, visordrv->name); - write_vbus_dev_info(bdev->visorchannel, hdr_info, &dev_info, dev_no); - write_vbus_chp_info(bdev->visorchannel, hdr_info, &chipset_driverinfo); - write_vbus_bus_info(bdev->visorchannel, hdr_info, - &clientbus_driverinfo); -} - -/* - * 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 err; - struct visor_driver *drv = to_visor_driver(xdev->driver); - struct visor_device *dev = to_visor_device(xdev); - - mutex_lock(&dev->visordriver_callback_lock); - dev->being_removed = false; - err = drv->probe(dev); - if (err) { - mutex_unlock(&dev->visordriver_callback_lock); - return err; - } - /* success: reference kept via unmatched get_device() */ - get_device(&dev->device); - publish_vbus_dev_info(dev); - mutex_unlock(&dev->visordriver_callback_lock); - return 0; -} - -/* - * 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) -{ - /* can't register on a nonexistent bus */ - if (!initialized) - return -ENODEV; - if (!drv->probe) - return -EINVAL; - if (!drv->remove) - return -EINVAL; - if (!drv->pause) - return -EINVAL; - if (!drv->resume) - return -EINVAL; - - 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 - */ - return driver_register(&drv->driver); -} -EXPORT_SYMBOL_GPL(visorbus_register_visor_driver); - -/* - * visorbus_create_instance() - create a device instance for the visorbus itself - * @dev: struct visor_device indicating the bus instance - * - * Return: 0 for success, otherwise negative errno value indicating reason for - * failure - */ -int visorbus_create_instance(struct visor_device *dev) -{ - int id = dev->chipset_bus_no; - int err; - struct visor_vbus_headerinfo *hdr_info; - - hdr_info = kzalloc(sizeof(*hdr_info), GFP_KERNEL); - if (!hdr_info) - return -ENOMEM; - dev_set_name(&dev->device, "visorbus%d", id); - dev->device.bus = &visorbus_type; - dev->device.groups = visorbus_groups; - dev->device.release = visorbus_release_busdevice; - dev->debugfs_dir = debugfs_create_dir(dev_name(&dev->device), - visorbus_debugfs_dir); - dev->debugfs_bus_info = debugfs_create_file("client_bus_info", 0440, - dev->debugfs_dir, dev, - &bus_info_debugfs_fops); - dev_set_drvdata(&dev->device, dev); - err = get_vbus_header_info(dev->visorchannel, &dev->device, hdr_info); - if (err < 0) - goto err_debugfs_dir; - err = device_register(&dev->device); - if (err < 0) - goto err_debugfs_dir; - list_add_tail(&dev->list_all, &list_all_bus_instances); - dev->state.created = 1; - dev->vbus_hdr_info = (void *)hdr_info; - write_vbus_chp_info(dev->visorchannel, hdr_info, &chipset_driverinfo); - write_vbus_bus_info(dev->visorchannel, hdr_info, &clientbus_driverinfo); - visorbus_response(dev, err, CONTROLVM_BUS_CREATE); - return 0; - -err_debugfs_dir: - debugfs_remove_recursive(dev->debugfs_dir); - kfree(hdr_info); - dev_err(&dev->device, "%s failed: %d\n", __func__, err); - return err; -} - -/* - * visorbus_remove_instance() - remove a device instance for the visorbus itself - * @dev: struct visor_device indentifying the bus to remove - */ -void visorbus_remove_instance(struct visor_device *dev) -{ - /* - * 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. - */ - kfree(dev->vbus_hdr_info); - list_del(&dev->list_all); - if (dev->pending_msg_hdr) - visorbus_response(dev, 0, CONTROLVM_BUS_DESTROY); - device_unregister(&dev->device); -} - -/* - * remove_all_visor_devices() - remove all child visorbus device instances - */ -static void remove_all_visor_devices(void) -{ - struct list_head *listentry, *listtmp; - - list_for_each_safe(listentry, listtmp, &list_all_device_instances) { - struct visor_device *dev; - - dev = list_entry(listentry, struct visor_device, list_all); - remove_visor_device(dev); - } -} - -/* - * 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) -{ - if (!dev->pausing) - return; - - dev->pausing = false; - visorbus_device_changestate_response(dev, status, - segment_state_standby); -} - -/* - * 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) -{ - if (!dev->resuming) - return; - - dev->resuming = false; - /* - * Notify the chipset driver that the resume is complete, - * which will presumably want to send some sort of response to - * the initiator. - */ - visorbus_device_changestate_response(dev, status, - segment_state_running); -} - -/* - * visorchipset_initiate_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 int visorchipset_initiate_device_pause_resume(struct visor_device *dev, - bool is_pause) -{ - int err; - struct visor_driver *drv; - - /* If no driver associated with the device nothing to pause/resume */ - if (!dev->device.driver) - return 0; - if (dev->pausing || dev->resuming) - return -EBUSY; - - drv = to_visor_driver(dev->device.driver); - if (is_pause) { - dev->pausing = true; - err = drv->pause(dev, pause_state_change_complete); - } else { - /* - * The vbus_dev_info structure in the channel was been cleared, - * make sure it is valid. - */ - publish_vbus_dev_info(dev); - dev->resuming = true; - err = drv->resume(dev, resume_state_change_complete); - } - return err; -} - -/* - * visorchipset_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(). - */ -int visorchipset_device_pause(struct visor_device *dev_info) -{ - int err; - - err = visorchipset_initiate_device_pause_resume(dev_info, true); - if (err < 0) { - dev_info->pausing = false; - return err; - } - return 0; -} - -/* - * visorchipset_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(). - */ -int visorchipset_device_resume(struct visor_device *dev_info) -{ - int err; - - err = visorchipset_initiate_device_pause_resume(dev_info, false); - if (err < 0) { - dev_info->resuming = false; - return err; - } - return 0; -} - -int visorbus_init(void) -{ - int err; - - visorbus_debugfs_dir = debugfs_create_dir("visorbus", NULL); - bus_device_info_init(&clientbus_driverinfo, "clientbus", "visorbus"); - err = bus_register(&visorbus_type); - if (err < 0) - return err; - initialized = true; - bus_device_info_init(&chipset_driverinfo, "chipset", "visorchipset"); - return 0; -} - -void visorbus_exit(void) -{ - struct list_head *listentry, *listtmp; - - remove_all_visor_devices(); - list_for_each_safe(listentry, listtmp, &list_all_bus_instances) { - struct visor_device *dev; - - dev = list_entry(listentry, struct visor_device, list_all); - visorbus_remove_instance(dev); - } - bus_unregister(&visorbus_type); - initialized = false; - debugfs_remove_recursive(visorbus_debugfs_dir); -} diff --git a/drivers/visorbus/visorbus_private.h b/drivers/visorbus/visorbus_private.h deleted file mode 100644 index 6956de605827..000000000000 --- a/drivers/visorbus/visorbus_private.h +++ /dev/null @@ -1,48 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2010 - 2015 UNISYS CORPORATION - * All rights reserved. - */ - -#ifndef __VISORBUS_PRIVATE_H__ -#define __VISORBUS_PRIVATE_H__ - -#include <linux/uuid.h> -#include <linux/utsname.h> -#include <linux/visorbus.h> - -#include "controlvmchannel.h" -#include "vbuschannel.h" - -struct visor_device *visorbus_get_device_by_id(u32 bus_no, u32 dev_no, - struct visor_device *from); -int visorbus_create_instance(struct visor_device *dev); -void visorbus_remove_instance(struct visor_device *bus_info); -int create_visor_device(struct visor_device *dev_info); -void remove_visor_device(struct visor_device *dev_info); -int visorchipset_device_pause(struct visor_device *dev_info); -int visorchipset_device_resume(struct visor_device *dev_info); -void visorbus_response(struct visor_device *p, int response, int controlvm_id); -void visorbus_device_changestate_response(struct visor_device *p, int response, - struct visor_segment_state state); -int visorbus_init(void); -void visorbus_exit(void); - -/* visorchannel access functions */ -struct visorchannel *visorchannel_create(u64 physaddr, gfp_t gfp, - const guid_t *guid, bool needs_lock); -void visorchannel_destroy(struct visorchannel *channel); -int visorchannel_read(struct visorchannel *channel, ulong offset, - void *dest, ulong nbytes); -int visorchannel_write(struct visorchannel *channel, ulong offset, - void *dest, 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_guid_id(const guid_t *guid, char *s); -void *visorchannel_get_header(struct visorchannel *channel); -#endif diff --git a/drivers/visorbus/visorchannel.c b/drivers/visorbus/visorchannel.c deleted file mode 100644 index bd890e0f456b..000000000000 --- a/drivers/visorbus/visorchannel.c +++ /dev/null @@ -1,434 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2010 - 2015 UNISYS CORPORATION - * All rights reserved. - */ - -/* - * 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 <linux/slab.h> -#include <linux/visorbus.h> - -#include "visorbus_private.h" -#include "controlvmchannel.h" - -#define VISOR_DRV_NAME "visorchannel" - -#define VISOR_CONSOLEVIDEO_CHANNEL_GUID \ - GUID_INIT(0x3cd6e705, 0xd6a2, 0x4aa5, \ - 0xad, 0x5c, 0x7b, 0x8, 0x88, 0x9d, 0xff, 0xe2) - -static const guid_t visor_video_guid = VISOR_CONSOLEVIDEO_CHANNEL_GUID; - -struct visorchannel { - u64 physaddr; - ulong nbytes; - void *mapped; - bool requested; - struct channel_header chan_hdr; - guid_t guid; - /* - * channel creator knows if more than one thread will be inserting or - * removing - */ - bool needs_lock; - /* protect head writes in chan_hdr */ - spinlock_t insert_lock; - /* protect tail writes in chan_hdr */ - spinlock_t remove_lock; - guid_t type; - guid_t inst; -}; - -void visorchannel_destroy(struct visorchannel *channel) -{ - if (!channel) - return; - - if (channel->mapped) { - memunmap(channel->mapped); - if (channel->requested) - release_mem_region(channel->physaddr, channel->nbytes); - } - kfree(channel); -} - -u64 visorchannel_get_physaddr(struct visorchannel *channel) -{ - return channel->physaddr; -} - -ulong visorchannel_get_nbytes(struct visorchannel *channel) -{ - return channel->nbytes; -} - -char *visorchannel_guid_id(const guid_t *guid, char *s) -{ - sprintf(s, "%pUL", guid); - return s; -} - -char *visorchannel_id(struct visorchannel *channel, char *s) -{ - return visorchannel_guid_id(&channel->guid, s); -} - -char *visorchannel_zoneid(struct visorchannel *channel, char *s) -{ - return visorchannel_guid_id(&channel->chan_hdr.zone_guid, s); -} - -u64 visorchannel_get_clientpartition(struct visorchannel *channel) -{ - return channel->chan_hdr.partition_handle; -} - -int visorchannel_set_clientpartition(struct visorchannel *channel, - u64 partition_handle) -{ - channel->chan_hdr.partition_handle = partition_handle; - return 0; -} - -/** - * visorchannel_get_guid() - queries the GUID of the designated channel - * @channel: the channel to query - * - * Return: the GUID of the provided channel - */ -const guid_t *visorchannel_get_guid(struct visorchannel *channel) -{ - return &channel->guid; -} -EXPORT_SYMBOL_GPL(visorchannel_get_guid); - -int visorchannel_read(struct visorchannel *channel, ulong offset, void *dest, - ulong nbytes) -{ - if (offset + nbytes > channel->nbytes) - return -EIO; - - memcpy(dest, channel->mapped + offset, nbytes); - return 0; -} - -int visorchannel_write(struct visorchannel *channel, ulong offset, void *dest, - ulong nbytes) -{ - size_t chdr_size = sizeof(struct channel_header); - size_t copy_size; - - if (offset + nbytes > channel->nbytes) - return -EIO; - - if (offset < chdr_size) { - copy_size = min(chdr_size - offset, nbytes); - memcpy(((char *)(&channel->chan_hdr)) + offset, - dest, copy_size); - } - memcpy(channel->mapped + offset, dest, nbytes); - return 0; -} - -void *visorchannel_get_header(struct visorchannel *channel) -{ - return &channel->chan_hdr; -} - -/* - * Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a - * channel header - */ -static int sig_queue_offset(struct channel_header *chan_hdr, int q) -{ - return ((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 - */ -static int sig_data_offset(struct channel_header *chan_hdr, int q, - struct signal_queue_header *sig_hdr, int slot) -{ - return (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 - */ -#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)) - -static int sig_read_header(struct visorchannel *channel, u32 queue, - struct signal_queue_header *sig_hdr) -{ - if (channel->chan_hdr.ch_space_offset < sizeof(struct channel_header)) - return -EINVAL; - - /* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */ - return visorchannel_read(channel, - sig_queue_offset(&channel->chan_hdr, queue), - sig_hdr, sizeof(struct signal_queue_header)); -} - -static int sig_read_data(struct visorchannel *channel, u32 queue, - struct signal_queue_header *sig_hdr, u32 slot, - void *data) -{ - int signal_data_offset = sig_data_offset(&channel->chan_hdr, queue, - sig_hdr, slot); - - return visorchannel_read(channel, signal_data_offset, - data, sig_hdr->signal_size); -} - -static int sig_write_data(struct visorchannel *channel, u32 queue, - struct signal_queue_header *sig_hdr, u32 slot, - void *data) -{ - int signal_data_offset = sig_data_offset(&channel->chan_hdr, queue, - sig_hdr, slot); - - return visorchannel_write(channel, signal_data_offset, - data, sig_hdr->signal_size); -} - -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; - /* No signals to remove; have caller try again. */ - if (sig_hdr.head == sig_hdr.tail) - return -EAGAIN; - sig_hdr.tail = (sig_hdr.tail + 1) % sig_hdr.max_slots; - 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, update - * host memory. Required for channel sync. - */ - mb(); - 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; -} - -/** - * 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) -{ - int rc; - unsigned long flags; - - if (channel->needs_lock) { - spin_lock_irqsave(&channel->remove_lock, flags); - rc = signalremove_inner(channel, queue, msg); - spin_unlock_irqrestore(&channel->remove_lock, flags); - } else { - rc = signalremove_inner(channel, queue, msg); - } - - return rc; -} -EXPORT_SYMBOL_GPL(visorchannel_signalremove); - -static bool queue_empty(struct visorchannel *channel, u32 queue) -{ - struct signal_queue_header sig_hdr; - - if (sig_read_header(channel, queue, &sig_hdr)) - return true; - return (sig_hdr.head == sig_hdr.tail); -} - -/** - * 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) -{ - bool rc; - unsigned long flags; - - if (!channel->needs_lock) - return queue_empty(channel, queue); - spin_lock_irqsave(&channel->remove_lock, flags); - rc = queue_empty(channel, queue); - spin_unlock_irqrestore(&channel->remove_lock, flags); - return rc; -} -EXPORT_SYMBOL_GPL(visorchannel_signalempty); - -static int signalinsert_inner(struct visorchannel *channel, u32 queue, - void *msg) -{ - struct signal_queue_header sig_hdr; - int err; - - err = sig_read_header(channel, queue, &sig_hdr); - if (err) - return err; - sig_hdr.head = (sig_hdr.head + 1) % sig_hdr.max_slots; - if (sig_hdr.head == sig_hdr.tail) { - sig_hdr.num_overflows++; - err = SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_overflows); - if (err) - return err; - return -EIO; - } - err = sig_write_data(channel, queue, &sig_hdr, sig_hdr.head, msg); - if (err) - return err; - sig_hdr.num_sent++; - /* - * For each data field in SIGNAL_QUEUE_HEADER that was modified, update - * host memory. Required for channel sync. - */ - mb(); - err = SIG_WRITE_FIELD(channel, queue, &sig_hdr, head); - if (err) - return err; - err = SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_sent); - if (err) - return err; - return 0; -} - -/* - * visorchannel_create() - 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 - * @gfp: gfp_t to use when allocating memory for the data struct - * @guid: GUID that identifies channel type; - * @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 - */ -struct visorchannel *visorchannel_create(u64 physaddr, gfp_t gfp, - const guid_t *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, VISOR_DRV_NAME); - if (!channel->requested && !guid_equal(guid, &visor_video_guid)) - /* we only care about errors if this is not the video channel */ - 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, size); - if (err) - goto err_destroy_channel; - size = (ulong)channel->chan_hdr.size; - memunmap(channel->mapped); - if (channel->requested) - release_mem_region(channel->physaddr, channel->nbytes); - channel->mapped = NULL; - channel->requested = request_mem_region(channel->physaddr, size, - VISOR_DRV_NAME); - if (!channel->requested && !guid_equal(guid, &visor_video_guid)) - /* we only care about errors if this is not the video channel */ - goto err_destroy_channel; - channel->mapped = memremap(channel->physaddr, size, MEMREMAP_WB); - if (!channel->mapped) { - release_mem_region(channel->physaddr, size); - goto err_destroy_channel; - } - channel->nbytes = size; - guid_copy(&channel->guid, guid); - return channel; - -err_destroy_channel: - visorchannel_destroy(channel); - return NULL; -} - -/** - * 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; - - 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); - } - - return rc; -} -EXPORT_SYMBOL_GPL(visorchannel_signalinsert); diff --git a/drivers/visorbus/visorchipset.c b/drivers/visorbus/visorchipset.c deleted file mode 100644 index 5668cad86e37..000000000000 --- a/drivers/visorbus/visorchipset.c +++ /dev/null @@ -1,1691 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2010 - 2015 UNISYS CORPORATION - * All rights reserved. - */ - -#include <linux/acpi.h> -#include <linux/crash_dump.h> -#include <linux/visorbus.h> - -#include "visorbus_private.h" - -/* {72120008-4AAB-11DC-8530-444553544200} */ -#define VISOR_SIOVM_GUID GUID_INIT(0x72120008, 0x4AAB, 0x11DC, 0x85, 0x30, \ - 0x44, 0x45, 0x53, 0x54, 0x42, 0x00) - -static const guid_t visor_vhba_channel_guid = VISOR_VHBA_CHANNEL_GUID; -static const guid_t visor_siovm_guid = VISOR_SIOVM_GUID; -static const guid_t visor_controlvm_channel_guid = VISOR_CONTROLVM_CHANNEL_GUID; - -#define POLLJIFFIES_CONTROLVM_FAST 1 -#define POLLJIFFIES_CONTROLVM_SLOW 100 - -#define MAX_CONTROLVM_PAYLOAD_BYTES (1024 * 128) - -#define UNISYS_VISOR_LEAF_ID 0x40000000 - -/* The s-Par leaf ID returns "UnisysSpar64" encoded across ebx, ecx, edx */ -#define UNISYS_VISOR_ID_EBX 0x73696e55 -#define UNISYS_VISOR_ID_ECX 0x70537379 -#define UNISYS_VISOR_ID_EDX 0x34367261 - -/* - * 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 - -struct parser_context { - unsigned long allocbytes; - unsigned long param_bytes; - u8 *curr; - unsigned long bytes_remaining; - bool byte_stream; - struct visor_controlvm_parameters_header data; -}; - -/* VMCALL_CONTROLVM_ADDR: Used by all guests, not just IO. */ -#define VMCALL_CONTROLVM_ADDR 0x0501 - -enum vmcall_result { - VMCALL_RESULT_SUCCESS = 0, - VMCALL_RESULT_INVALID_PARAM = 1, - VMCALL_RESULT_DATA_UNAVAILABLE = 2, - VMCALL_RESULT_FAILURE_UNAVAILABLE = 3, - VMCALL_RESULT_DEVICE_ERROR = 4, - VMCALL_RESULT_DEVICE_NOT_READY = 5 -}; - -/* - * struct vmcall_io_controlvm_addr_params - Structure for IO VMCALLS. Has - * parameters to VMCALL_CONTROLVM_ADDR - * interface. - * @address: The Guest-relative physical address of the ControlVm channel. - * This VMCall fills this in with the appropriate address. - * Contents provided by this VMCALL (OUT). - * @channel_bytes: The size of the ControlVm channel in bytes This VMCall fills - * this in with the appropriate address. Contents provided by - * this VMCALL (OUT). - * @unused: Unused Bytes in the 64-Bit Aligned Struct. - */ -struct vmcall_io_controlvm_addr_params { - u64 address; - u32 channel_bytes; - u8 unused[4]; -} __packed; - -struct visorchipset_device { - struct acpi_device *acpi_device; - unsigned long poll_jiffies; - /* when we got our last controlvm message */ - unsigned long most_recent_message_jiffies; - struct delayed_work periodic_controlvm_work; - struct visorchannel *controlvm_channel; - unsigned long controlvm_payload_bytes_buffered; - /* - * The following variables are used to handle the scenario where we are - * unable to offload the payload from a controlvm message due to memory - * requirements. In this scenario, we simply stash the controlvm - * message, then attempt to process it again the next time - * controlvm_periodic_work() runs. - */ - struct controlvm_message controlvm_pending_msg; - bool controlvm_pending_msg_valid; - struct vmcall_io_controlvm_addr_params controlvm_params; -}; - -static struct visorchipset_device *chipset_dev; - -struct parahotplug_request { - struct list_head list; - int id; - unsigned long expiration; - struct controlvm_message msg; -}; - -/* prototypes for attributes */ -static ssize_t toolaction_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - u8 tool_action = 0; - int err; - - err = visorchannel_read(chipset_dev->controlvm_channel, - offsetof(struct visor_controlvm_channel, - tool_action), - &tool_action, sizeof(u8)); - if (err) - return err; - return sprintf(buf, "%u\n", tool_action); -} - -static ssize_t toolaction_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - u8 tool_action; - int err; - - if (kstrtou8(buf, 10, &tool_action)) - return -EINVAL; - err = visorchannel_write(chipset_dev->controlvm_channel, - offsetof(struct visor_controlvm_channel, - tool_action), - &tool_action, sizeof(u8)); - if (err) - return err; - return count; -} -static DEVICE_ATTR_RW(toolaction); - -static ssize_t boottotool_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct efi_visor_indication efi_visor_indication; - int err; - - err = visorchannel_read(chipset_dev->controlvm_channel, - offsetof(struct visor_controlvm_channel, - efi_visor_ind), - &efi_visor_indication, - sizeof(struct efi_visor_indication)); - if (err) - return err; - return sprintf(buf, "%u\n", efi_visor_indication.boot_to_tool); -} - -static ssize_t boottotool_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int val, err; - struct efi_visor_indication efi_visor_indication; - - if (kstrtoint(buf, 10, &val)) - return -EINVAL; - efi_visor_indication.boot_to_tool = val; - err = visorchannel_write(chipset_dev->controlvm_channel, - offsetof(struct visor_controlvm_channel, - efi_visor_ind), - &(efi_visor_indication), - sizeof(struct efi_visor_indication)); - if (err) - return err; - return count; -} -static DEVICE_ATTR_RW(boottotool); - -static ssize_t error_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - u32 error = 0; - int err; - - err = visorchannel_read(chipset_dev->controlvm_channel, - offsetof(struct visor_controlvm_channel, - installation_error), - &error, sizeof(u32)); - if (err) - return err; - return sprintf(buf, "%u\n", error); -} - -static ssize_t error_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - u32 error; - int err; - - if (kstrtou32(buf, 10, &error)) - return -EINVAL; - err = visorchannel_write(chipset_dev->controlvm_channel, - offsetof(struct visor_controlvm_channel, - installation_error), - &error, sizeof(u32)); - if (err) - return err; - return count; -} -static DEVICE_ATTR_RW(error); - -static ssize_t textid_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - u32 text_id = 0; - int err; - - err = visorchannel_read(chipset_dev->controlvm_channel, - offsetof(struct visor_controlvm_channel, - installation_text_id), - &text_id, sizeof(u32)); - if (err) - return err; - return sprintf(buf, "%u\n", text_id); -} - -static ssize_t textid_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - u32 text_id; - int err; - - if (kstrtou32(buf, 10, &text_id)) - return -EINVAL; - err = visorchannel_write(chipset_dev->controlvm_channel, - offsetof(struct visor_controlvm_channel, - installation_text_id), - &text_id, sizeof(u32)); - if (err) - return err; - return count; -} -static DEVICE_ATTR_RW(textid); - -static ssize_t remaining_steps_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - u16 remaining_steps = 0; - int err; - - err = visorchannel_read(chipset_dev->controlvm_channel, - offsetof(struct visor_controlvm_channel, - installation_remaining_steps), - &remaining_steps, sizeof(u16)); - if (err) - return err; - return sprintf(buf, "%hu\n", remaining_steps); -} - -static ssize_t remaining_steps_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - u16 remaining_steps; - int err; - - if (kstrtou16(buf, 10, &remaining_steps)) - return -EINVAL; - err = visorchannel_write(chipset_dev->controlvm_channel, - offsetof(struct visor_controlvm_channel, - installation_remaining_steps), - &remaining_steps, sizeof(u16)); - if (err) - return err; - return count; -} -static DEVICE_ATTR_RW(remaining_steps); - -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 int controlvm_respond_chipset_init( - struct controlvm_message_header *msg_hdr, - int response, - enum visor_chipset_feature features) -{ - struct controlvm_message outmsg; - - controlvm_init_response(&outmsg, msg_hdr, response); - outmsg.cmd.init_chipset.features = features; - return visorchannel_signalinsert(chipset_dev->controlvm_channel, - CONTROLVM_QUEUE_REQUEST, &outmsg); -} - -static int chipset_init(struct controlvm_message *inmsg) -{ - static int chipset_inited; - enum visor_chipset_feature features = 0; - int rc = CONTROLVM_RESP_SUCCESS; - int res = 0; - - if (chipset_inited) { - rc = -CONTROLVM_RESP_ALREADY_DONE; - res = -EIO; - goto out_respond; - } - chipset_inited = 1; - /* - * Set features to indicate we support parahotplug (if Command also - * supports it). Set the "reply" bit so Command knows this is a - * features-aware driver. - */ - features = inmsg->cmd.init_chipset.features & - VISOR_CHIPSET_FEATURE_PARA_HOTPLUG; - features |= VISOR_CHIPSET_FEATURE_REPLY; - -out_respond: - if (inmsg->hdr.flags.response_expected) - res = controlvm_respond_chipset_init(&inmsg->hdr, rc, features); - - return res; -} - -static int controlvm_respond(struct controlvm_message_header *msg_hdr, - int response, struct visor_segment_state *state) -{ - struct controlvm_message outmsg; - - controlvm_init_response(&outmsg, msg_hdr, response); - if (outmsg.hdr.flags.test_message == 1) - return -EINVAL; - if (state) { - outmsg.cmd.device_change_state.state = *state; - outmsg.cmd.device_change_state.flags.phys_device = 1; - } - return visorchannel_signalinsert(chipset_dev->controlvm_channel, - CONTROLVM_QUEUE_REQUEST, &outmsg); -} - -enum crash_obj_type { - CRASH_DEV, - CRASH_BUS, -}; - -static int save_crash_message(struct controlvm_message *msg, - enum crash_obj_type cr_type) -{ - u32 local_crash_msg_offset; - u16 local_crash_msg_count; - int err; - - err = visorchannel_read(chipset_dev->controlvm_channel, - offsetof(struct visor_controlvm_channel, - saved_crash_message_count), - &local_crash_msg_count, sizeof(u16)); - if (err) { - dev_err(&chipset_dev->acpi_device->dev, - "failed to read message count\n"); - return err; - } - if (local_crash_msg_count != CONTROLVM_CRASHMSG_MAX) { - dev_err(&chipset_dev->acpi_device->dev, - "invalid number of messages\n"); - return -EIO; - } - err = visorchannel_read(chipset_dev->controlvm_channel, - offsetof(struct visor_controlvm_channel, - saved_crash_message_offset), - &local_crash_msg_offset, sizeof(u32)); - if (err) { - dev_err(&chipset_dev->acpi_device->dev, - "failed to read offset\n"); - return err; - } - switch (cr_type) { - case CRASH_DEV: - local_crash_msg_offset += sizeof(struct controlvm_message); - err = visorchannel_write(chipset_dev->controlvm_channel, - local_crash_msg_offset, msg, - sizeof(struct controlvm_message)); - if (err) { - dev_err(&chipset_dev->acpi_device->dev, - "failed to write dev msg\n"); - return err; - } - break; - case CRASH_BUS: - err = visorchannel_write(chipset_dev->controlvm_channel, - local_crash_msg_offset, msg, - sizeof(struct controlvm_message)); - if (err) { - dev_err(&chipset_dev->acpi_device->dev, - "failed to write bus msg\n"); - return err; - } - break; - default: - dev_err(&chipset_dev->acpi_device->dev, - "Invalid crash_obj_type\n"); - break; - } - return 0; -} - -static int controlvm_responder(enum controlvm_id cmd_id, - struct controlvm_message_header *pending_msg_hdr, - int response) -{ - if (pending_msg_hdr->id != (u32)cmd_id) - return -EINVAL; - - return controlvm_respond(pending_msg_hdr, response, NULL); -} - -static int device_changestate_responder(enum controlvm_id cmd_id, - struct visor_device *p, int response, - struct visor_segment_state state) -{ - struct controlvm_message outmsg; - - if (p->pending_msg_hdr->id != cmd_id) - return -EINVAL; - - controlvm_init_response(&outmsg, p->pending_msg_hdr, response); - outmsg.cmd.device_change_state.bus_no = p->chipset_bus_no; - outmsg.cmd.device_change_state.dev_no = p->chipset_dev_no; - outmsg.cmd.device_change_state.state = state; - return visorchannel_signalinsert(chipset_dev->controlvm_channel, - CONTROLVM_QUEUE_REQUEST, &outmsg); -} - -static int visorbus_create(struct controlvm_message *inmsg) -{ - struct controlvm_message_packet *cmd = &inmsg->cmd; - struct controlvm_message_header *pmsg_hdr; - u32 bus_no = cmd->create_bus.bus_no; - struct visor_device *bus_info; - struct visorchannel *visorchannel; - int err; - - bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL); - if (bus_info && bus_info->state.created == 1) { - dev_err(&chipset_dev->acpi_device->dev, - "failed %s: already exists\n", __func__); - err = -EEXIST; - goto err_respond; - } - bus_info = kzalloc(sizeof(*bus_info), GFP_KERNEL); - if (!bus_info) { - err = -ENOMEM; - goto err_respond; - } - INIT_LIST_HEAD(&bus_info->list_all); - bus_info->chipset_bus_no = bus_no; - bus_info->chipset_dev_no = BUS_ROOT_DEVICE; - if (guid_equal(&cmd->create_bus.bus_inst_guid, &visor_siovm_guid)) { - err = save_crash_message(inmsg, CRASH_BUS); - if (err) - goto err_free_bus_info; - } - if (inmsg->hdr.flags.response_expected == 1) { - pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL); - if (!pmsg_hdr) { - err = -ENOMEM; - goto err_free_bus_info; - } - memcpy(pmsg_hdr, &inmsg->hdr, - sizeof(struct controlvm_message_header)); - bus_info->pending_msg_hdr = pmsg_hdr; - } - visorchannel = visorchannel_create(cmd->create_bus.channel_addr, - GFP_KERNEL, - &cmd->create_bus.bus_data_type_guid, - false); - if (!visorchannel) { - err = -ENOMEM; - goto err_free_pending_msg; - } - bus_info->visorchannel = visorchannel; - /* Response will be handled by visorbus_create_instance on success */ - err = visorbus_create_instance(bus_info); - if (err) - goto err_destroy_channel; - return 0; - -err_destroy_channel: - visorchannel_destroy(visorchannel); - -err_free_pending_msg: - kfree(bus_info->pending_msg_hdr); - -err_free_bus_info: - kfree(bus_info); - -err_respond: - if (inmsg->hdr.flags.response_expected == 1) - controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err); - return err; -} - -static int visorbus_destroy(struct controlvm_message *inmsg) -{ - struct controlvm_message_header *pmsg_hdr; - u32 bus_no = inmsg->cmd.destroy_bus.bus_no; - struct visor_device *bus_info; - int err; - - bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL); - if (!bus_info) { - err = -ENODEV; - goto err_respond; - } - if (bus_info->state.created == 0) { - err = -ENOENT; - goto err_respond; - } - if (bus_info->pending_msg_hdr) { - /* only non-NULL if dev is still waiting on a response */ - err = -EEXIST; - goto err_respond; - } - if (inmsg->hdr.flags.response_expected == 1) { - pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL); - if (!pmsg_hdr) { - err = -ENOMEM; - goto err_respond; - } - memcpy(pmsg_hdr, &inmsg->hdr, - sizeof(struct controlvm_message_header)); - bus_info->pending_msg_hdr = pmsg_hdr; - } - /* Response will be handled by visorbus_remove_instance */ - visorbus_remove_instance(bus_info); - return 0; - -err_respond: - if (inmsg->hdr.flags.response_expected == 1) - controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err); - return err; -} - -static const guid_t *parser_id_get(struct parser_context *ctx) -{ - return &ctx->data.id; -} - -static void *parser_string_get(u8 *pscan, int nscan) -{ - int value_length; - void *value; - - if (nscan == 0) - return NULL; - - value_length = strnlen(pscan, nscan); - value = kzalloc(value_length + 1, GFP_KERNEL); - if (!value) - return NULL; - if (value_length > 0) - memcpy(value, pscan, value_length); - return value; -} - -static void *parser_name_get(struct parser_context *ctx) -{ - struct visor_controlvm_parameters_header *phdr; - - phdr = &ctx->data; - if ((unsigned long)phdr->name_offset + - (unsigned long)phdr->name_length > ctx->param_bytes) - return NULL; - ctx->curr = (char *)&phdr + phdr->name_offset; - ctx->bytes_remaining = phdr->name_length; - return parser_string_get(ctx->curr, phdr->name_length); -} - -static int visorbus_configure(struct controlvm_message *inmsg, - struct parser_context *parser_ctx) -{ - struct controlvm_message_packet *cmd = &inmsg->cmd; - u32 bus_no; - struct visor_device *bus_info; - int err = 0; - - bus_no = cmd->configure_bus.bus_no; - bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL); - if (!bus_info) { - err = -EINVAL; - goto err_respond; - } - if (bus_info->state.created == 0) { - err = -EINVAL; - goto err_respond; - } - if (bus_info->pending_msg_hdr) { - err = -EIO; - goto err_respond; - } - err = visorchannel_set_clientpartition(bus_info->visorchannel, - cmd->configure_bus.guest_handle); - if (err) - goto err_respond; - if (parser_ctx) { - const guid_t *partition_guid = parser_id_get(parser_ctx); - - guid_copy(&bus_info->partition_guid, partition_guid); - bus_info->name = parser_name_get(parser_ctx); - } - if (inmsg->hdr.flags.response_expected == 1) - controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err); - return 0; - -err_respond: - dev_err(&chipset_dev->acpi_device->dev, - "%s exited with err: %d\n", __func__, err); - if (inmsg->hdr.flags.response_expected == 1) - controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err); - return err; -} - -static int visorbus_device_create(struct controlvm_message *inmsg) -{ - struct controlvm_message_packet *cmd = &inmsg->cmd; - struct controlvm_message_header *pmsg_hdr; - u32 bus_no = cmd->create_device.bus_no; - u32 dev_no = cmd->create_device.dev_no; - struct visor_device *dev_info; - struct visor_device *bus_info; - struct visorchannel *visorchannel; - int err; - - bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL); - if (!bus_info) { - dev_err(&chipset_dev->acpi_device->dev, - "failed to get bus by id: %d\n", bus_no); - err = -ENODEV; - goto err_respond; - } - if (bus_info->state.created == 0) { - dev_err(&chipset_dev->acpi_device->dev, - "bus not created, id: %d\n", bus_no); - err = -EINVAL; - goto err_respond; - } - dev_info = visorbus_get_device_by_id(bus_no, dev_no, NULL); - if (dev_info && dev_info->state.created == 1) { - dev_err(&chipset_dev->acpi_device->dev, - "failed to get bus by id: %d/%d\n", bus_no, dev_no); - err = -EEXIST; - goto err_respond; - } - - dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL); - if (!dev_info) { - err = -ENOMEM; - goto err_respond; - } - dev_info->chipset_bus_no = bus_no; - dev_info->chipset_dev_no = dev_no; - guid_copy(&dev_info->inst, &cmd->create_device.dev_inst_guid); - dev_info->device.parent = &bus_info->device; - visorchannel = visorchannel_create(cmd->create_device.channel_addr, - GFP_KERNEL, - &cmd->create_device.data_type_guid, - true); - if (!visorchannel) { - dev_err(&chipset_dev->acpi_device->dev, - "failed to create visorchannel: %d/%d\n", - bus_no, dev_no); - err = -ENOMEM; - goto err_free_dev_info; - } - dev_info->visorchannel = visorchannel; - guid_copy(&dev_info->channel_type_guid, - &cmd->create_device.data_type_guid); - if (guid_equal(&cmd->create_device.data_type_guid, - &visor_vhba_channel_guid)) { - err = save_crash_message(inmsg, CRASH_DEV); - if (err) - goto err_destroy_visorchannel; - } - if (inmsg->hdr.flags.response_expected == 1) { - pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL); - if (!pmsg_hdr) { - err = -ENOMEM; - goto err_destroy_visorchannel; - } - memcpy(pmsg_hdr, &inmsg->hdr, - sizeof(struct controlvm_message_header)); - dev_info->pending_msg_hdr = pmsg_hdr; - } - /* create_visor_device will send response */ - err = create_visor_device(dev_info); - if (err) - goto err_destroy_visorchannel; - - return 0; - -err_destroy_visorchannel: - visorchannel_destroy(visorchannel); - -err_free_dev_info: - kfree(dev_info); - -err_respond: - if (inmsg->hdr.flags.response_expected == 1) - controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err); - return err; -} - -static int visorbus_device_changestate(struct controlvm_message *inmsg) -{ - struct controlvm_message_packet *cmd = &inmsg->cmd; - struct controlvm_message_header *pmsg_hdr; - u32 bus_no = cmd->device_change_state.bus_no; - u32 dev_no = cmd->device_change_state.dev_no; - struct visor_segment_state state = cmd->device_change_state.state; - struct visor_device *dev_info; - int err = 0; - - dev_info = visorbus_get_device_by_id(bus_no, dev_no, NULL); - if (!dev_info) { - err = -ENODEV; - goto err_respond; - } - if (dev_info->state.created == 0) { - err = -EINVAL; - goto err_respond; - } - if (dev_info->pending_msg_hdr) { - /* only non-NULL if dev is still waiting on a response */ - err = -EIO; - goto err_respond; - } - - if (inmsg->hdr.flags.response_expected == 1) { - pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL); - if (!pmsg_hdr) { - err = -ENOMEM; - goto err_respond; - } - memcpy(pmsg_hdr, &inmsg->hdr, - sizeof(struct controlvm_message_header)); - dev_info->pending_msg_hdr = pmsg_hdr; - } - if (state.alive == segment_state_running.alive && - state.operating == segment_state_running.operating) - /* Response will be sent from visorchipset_device_resume */ - err = visorchipset_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 where server is lost. - * Response will be sent from visorchipset_device_pause. - */ - err = visorchipset_device_pause(dev_info); - if (err) - goto err_respond; - return 0; - -err_respond: - dev_err(&chipset_dev->acpi_device->dev, "failed: %d\n", err); - if (inmsg->hdr.flags.response_expected == 1) - controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err); - return err; -} - -static int visorbus_device_destroy(struct controlvm_message *inmsg) -{ - struct controlvm_message_packet *cmd = &inmsg->cmd; - struct controlvm_message_header *pmsg_hdr; - u32 bus_no = cmd->destroy_device.bus_no; - u32 dev_no = cmd->destroy_device.dev_no; - struct visor_device *dev_info; - int err; - - dev_info = visorbus_get_device_by_id(bus_no, dev_no, NULL); - if (!dev_info) { - err = -ENODEV; - goto err_respond; - } - if (dev_info->state.created == 0) { - err = -EINVAL; - goto err_respond; - } - if (dev_info->pending_msg_hdr) { - /* only non-NULL if dev is still waiting on a response */ - err = -EIO; - goto err_respond; - } - if (inmsg->hdr.flags.response_expected == 1) { - pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL); - if (!pmsg_hdr) { - err = -ENOMEM; - goto err_respond; - } - - memcpy(pmsg_hdr, &inmsg->hdr, - sizeof(struct controlvm_message_header)); - dev_info->pending_msg_hdr = pmsg_hdr; - } - kfree(dev_info->name); - remove_visor_device(dev_info); - return 0; - -err_respond: - if (inmsg->hdr.flags.response_expected == 1) - controlvm_responder(inmsg->hdr.id, &inmsg->hdr, err); - return err; -} - -/* - * The general parahotplug flow works as follows. The visorchipset receives - * a DEVICE_CHANGESTATE message from Command specifying a physical device - * to enable or disable. The CONTROLVM message handler calls - * parahotplug_process_message, which then adds the message to a global list - * and kicks off a udev event which causes a user level script to enable or - * disable the specified device. The udev script then writes to - * /sys/devices/platform/visorchipset/parahotplug, which causes the - * parahotplug store functions to get called, at which point the - * appropriate CONTROLVM message is retrieved from the list and responded to. - */ - -#define PARAHOTPLUG_TIMEOUT_MS 2000 - -/* - * parahotplug_next_id() - generate unique int to match an outstanding - * CONTROLVM message with a udev script /sys - * response - * - * Return: a unique integer value - */ -static int parahotplug_next_id(void) -{ - static atomic_t id = ATOMIC_INIT(0); - - return atomic_inc_return(&id); -} - -/* - * 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) -{ - return jiffies + msecs_to_jiffies(PARAHOTPLUG_TIMEOUT_MS); -} - -/* - * 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) -{ - struct parahotplug_request *req; - - req = kmalloc(sizeof(*req), GFP_KERNEL); - if (!req) - return NULL; - req->id = parahotplug_next_id(); - req->expiration = parahotplug_next_expiration(); - req->msg = *msg; - return req; -} - -/* - * parahotplug_request_destroy() - free a parahotplug_request - * @req: the request to deallocate - */ -static void parahotplug_request_destroy(struct parahotplug_request *req) -{ - kfree(req); -} - -static LIST_HEAD(parahotplug_request_list); -/* lock for above */ -static DEFINE_SPINLOCK(parahotplug_request_list_lock); - -/* - * 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 /sys handler, which means the user script has - * 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) -{ - struct list_head *pos; - struct list_head *tmp; - struct parahotplug_request *req; - - spin_lock(¶hotplug_request_list_lock); - /* Look for a request matching "id". */ - list_for_each_safe(pos, tmp, ¶hotplug_request_list) { - req = list_entry(pos, struct parahotplug_request, list); - if (req->id == id) { - /* - * Found a match. Remove it from the list and - * respond. - */ - list_del(pos); - spin_unlock(¶hotplug_request_list_lock); - req->msg.cmd.device_change_state.state.active = active; - if (req->msg.hdr.flags.response_expected) - controlvm_respond( - &req->msg.hdr, CONTROLVM_RESP_SUCCESS, - &req->msg.cmd.device_change_state.state); - parahotplug_request_destroy(req); - return 0; - } - } - spin_unlock(¶hotplug_request_list_lock); - return -EINVAL; -} - -/* - * 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 const 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 const 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 -}; - -/* - * 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 int 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, "VISOR_PARAHOTPLUG=1"); - sprintf(env_id, "VISOR_PARAHOTPLUG_ID=%d", req->id); - sprintf(env_state, "VISOR_PARAHOTPLUG_STATE=%d", - cmd->device_change_state.state.active); - sprintf(env_bus, "VISOR_PARAHOTPLUG_BUS=%d", - cmd->device_change_state.bus_no); - sprintf(env_dev, "VISOR_PARAHOTPLUG_DEVICE=%d", - cmd->device_change_state.dev_no >> 3); - sprintf(env_func, "VISOR_PARAHOTPLUG_FUNCTION=%d", - cmd->device_change_state.dev_no & 0x7); - return kobject_uevent_env(&chipset_dev->acpi_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 int parahotplug_process_message(struct controlvm_message *inmsg) -{ - struct parahotplug_request *req; - int err; - - req = parahotplug_request_create(inmsg); - if (!req) - return -ENOMEM; - /* - * For enable messages, just respond with success right away, we don't - * need to wait to see if the enable was successful. - */ - if (inmsg->cmd.device_change_state.state.active) { - err = parahotplug_request_kickoff(req); - if (err) - goto err_respond; - controlvm_respond(&inmsg->hdr, CONTROLVM_RESP_SUCCESS, - &inmsg->cmd.device_change_state.state); - parahotplug_request_destroy(req); - return 0; - } - /* - * For disable messages, add the request to the request list before - * kicking off the udev script. It won't get responded to until the - * script has indicated it's done. - */ - spin_lock(¶hotplug_request_list_lock); - list_add_tail(&req->list, ¶hotplug_request_list); - spin_unlock(¶hotplug_request_list_lock); - err = parahotplug_request_kickoff(req); - if (err) - goto err_respond; - return 0; - -err_respond: - controlvm_respond(&inmsg->hdr, err, - &inmsg->cmd.device_change_state.state); - return err; -} - -/* - * chipset_ready_uevent() - sends chipset_ready action - * - * Send ACTION=online for DEVPATH=/sys/devices/platform/visorchipset. - * - * Return: 0 on success, negative on failure - */ -static int chipset_ready_uevent(struct controlvm_message_header *msg_hdr) -{ - int res; - - res = kobject_uevent(&chipset_dev->acpi_device->dev.kobj, KOBJ_ONLINE); - if (msg_hdr->flags.response_expected) - controlvm_respond(msg_hdr, res, NULL); - return res; -} - -/* - * chipset_selftest_uevent() - sends chipset_selftest action - * - * Send ACTION=online for DEVPATH=/sys/devices/platform/visorchipset. - * - * Return: 0 on success, negative on failure - */ -static int chipset_selftest_uevent(struct controlvm_message_header *msg_hdr) -{ - char env_selftest[20]; - char *envp[] = { env_selftest, NULL }; - int res; - - sprintf(env_selftest, "SPARSP_SELFTEST=%d", 1); - res = kobject_uevent_env(&chipset_dev->acpi_device->dev.kobj, - KOBJ_CHANGE, envp); - if (msg_hdr->flags.response_expected) - controlvm_respond(msg_hdr, res, NULL); - return res; -} - -/* - * chipset_notready_uevent() - sends chipset_notready action - * - * Send ACTION=offline for DEVPATH=/sys/devices/platform/visorchipset. - * - * Return: 0 on success, negative on failure - */ -static int chipset_notready_uevent(struct controlvm_message_header *msg_hdr) -{ - int res = kobject_uevent(&chipset_dev->acpi_device->dev.kobj, - KOBJ_OFFLINE); - - if (msg_hdr->flags.response_expected) - controlvm_respond(msg_hdr, res, NULL); - return res; -} - -static int unisys_vmcall(unsigned long tuple, unsigned long param) -{ - int result = 0; - unsigned int cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx; - unsigned long reg_ebx; - unsigned long reg_ecx; - - reg_ebx = param & 0xFFFFFFFF; - reg_ecx = param >> 32; - cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx); - if (!(cpuid_ecx & 0x80000000)) - return -EPERM; - __asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) : - "a"(tuple), "b"(reg_ebx), "c"(reg_ecx)); - if (result) - goto error; - return 0; - -/* Need to convert from VMCALL error codes to Linux */ -error: - switch (result) { - case VMCALL_RESULT_INVALID_PARAM: - return -EINVAL; - case VMCALL_RESULT_DATA_UNAVAILABLE: - return -ENODEV; - default: - return -EFAULT; - } -} - -static int controlvm_channel_create(struct visorchipset_device *dev) -{ - struct visorchannel *chan; - u64 addr; - int err; - - err = unisys_vmcall(VMCALL_CONTROLVM_ADDR, - virt_to_phys(&dev->controlvm_params)); - if (err) - return err; - addr = dev->controlvm_params.address; - chan = visorchannel_create(addr, GFP_KERNEL, - &visor_controlvm_channel_guid, true); - if (!chan) - return -ENOMEM; - dev->controlvm_channel = chan; - return 0; -} - -static void setup_crash_devices_work_queue(struct work_struct *work) -{ - struct controlvm_message local_crash_bus_msg; - struct controlvm_message local_crash_dev_msg; - struct controlvm_message msg = { - .hdr.id = CONTROLVM_CHIPSET_INIT, - .cmd.init_chipset = { - .bus_count = 23, - .switch_count = 0, - }, - }; - u32 local_crash_msg_offset; - u16 local_crash_msg_count; - - /* send init chipset msg */ - chipset_init(&msg); - /* get saved message count */ - if (visorchannel_read(chipset_dev->controlvm_channel, - offsetof(struct visor_controlvm_channel, - saved_crash_message_count), - &local_crash_msg_count, sizeof(u16)) < 0) { - dev_err(&chipset_dev->acpi_device->dev, - "failed to read channel\n"); - return; - } - if (local_crash_msg_count != CONTROLVM_CRASHMSG_MAX) { - dev_err(&chipset_dev->acpi_device->dev, "invalid count\n"); - return; - } - /* get saved crash message offset */ - if (visorchannel_read(chipset_dev->controlvm_channel, - offsetof(struct visor_controlvm_channel, - saved_crash_message_offset), - &local_crash_msg_offset, sizeof(u32)) < 0) { - dev_err(&chipset_dev->acpi_device->dev, - "failed to read channel\n"); - return; - } - /* read create device message for storage bus offset */ - if (visorchannel_read(chipset_dev->controlvm_channel, - local_crash_msg_offset, - &local_crash_bus_msg, - sizeof(struct controlvm_message)) < 0) { - dev_err(&chipset_dev->acpi_device->dev, - "failed to read channel\n"); - return; - } - /* read create device message for storage device */ - if (visorchannel_read(chipset_dev->controlvm_channel, - local_crash_msg_offset + - sizeof(struct controlvm_message), - &local_crash_dev_msg, - sizeof(struct controlvm_message)) < 0) { - dev_err(&chipset_dev->acpi_device->dev, - "failed to read channel\n"); - return; - } - /* reuse IOVM create bus message */ - if (!local_crash_bus_msg.cmd.create_bus.channel_addr) { - dev_err(&chipset_dev->acpi_device->dev, - "no valid create_bus message\n"); - return; - } - visorbus_create(&local_crash_bus_msg); - /* reuse create device message for storage device */ - if (!local_crash_dev_msg.cmd.create_device.channel_addr) { - dev_err(&chipset_dev->acpi_device->dev, - "no valid create_device message\n"); - return; - } - visorbus_device_create(&local_crash_dev_msg); -} - -void visorbus_response(struct visor_device *bus_info, int response, - int controlvm_id) -{ - if (!bus_info->pending_msg_hdr) - return; - - controlvm_responder(controlvm_id, bus_info->pending_msg_hdr, response); - kfree(bus_info->pending_msg_hdr); - bus_info->pending_msg_hdr = NULL; -} - -void visorbus_device_changestate_response(struct visor_device *dev_info, - int response, - struct visor_segment_state state) -{ - if (!dev_info->pending_msg_hdr) - return; - - device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE, dev_info, - response, state); - kfree(dev_info->pending_msg_hdr); - dev_info->pending_msg_hdr = NULL; -} - -static void parser_done(struct parser_context *ctx) -{ - chipset_dev->controlvm_payload_bytes_buffered -= ctx->param_bytes; - kfree(ctx); -} - -static struct parser_context *parser_init_stream(u64 addr, u32 bytes, - bool *retry) -{ - unsigned long allocbytes; - struct parser_context *ctx; - void *mapping; - - *retry = false; - /* alloc an extra byte to ensure payload is \0 terminated */ - allocbytes = (unsigned long)bytes + 1 + (sizeof(struct parser_context) - - sizeof(struct visor_controlvm_parameters_header)); - if ((chipset_dev->controlvm_payload_bytes_buffered + bytes) > - MAX_CONTROLVM_PAYLOAD_BYTES) { - *retry = true; - return NULL; - } - ctx = kzalloc(allocbytes, GFP_KERNEL); - if (!ctx) { - *retry = true; - return NULL; - } - ctx->allocbytes = allocbytes; - ctx->param_bytes = bytes; - mapping = memremap(addr, bytes, MEMREMAP_WB); - if (!mapping) - goto err_finish_ctx; - memcpy(&ctx->data, mapping, bytes); - memunmap(mapping); - ctx->byte_stream = true; - chipset_dev->controlvm_payload_bytes_buffered += ctx->param_bytes; - return ctx; - -err_finish_ctx: - kfree(ctx); - return NULL; -} - -/* - * handle_command() - process a controlvm message - * @inmsg: the message to process - * @channel_addr: address of the controlvm channel - * - * Return: - * 0 - Successfully processed the message - * -EAGAIN - ControlVM message was not processed and should be retried - * reading the next controlvm message; a scenario where this can - * occur is when we need to throttle the allocation of memory in - * which to copy out controlvm payload data. - * < 0 - error: ControlVM message was processed but an error occurred. - */ -static int 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; - struct controlvm_message ackmsg; - int err = 0; - - /* create parsing context if necessary */ - parm_addr = channel_addr + inmsg.hdr.payload_vm_offset; - parm_bytes = inmsg.hdr.payload_bytes; - /* - * Parameter and channel addresses within test messages actually lie - * within our OS-controlled memory. We need to know that, because it - * makes a difference in how we compute the virtual address. - */ - if (parm_bytes) { - bool retry; - - parser_ctx = parser_init_stream(parm_addr, parm_bytes, &retry); - if (!parser_ctx && retry) - return -EAGAIN; - } - controlvm_init_response(&ackmsg, &inmsg.hdr, CONTROLVM_RESP_SUCCESS); - err = visorchannel_signalinsert(chipset_dev->controlvm_channel, - CONTROLVM_QUEUE_ACK, &ackmsg); - if (err) - return err; - switch (inmsg.hdr.id) { - case CONTROLVM_CHIPSET_INIT: - err = chipset_init(&inmsg); - break; - case CONTROLVM_BUS_CREATE: - err = visorbus_create(&inmsg); - break; - case CONTROLVM_BUS_DESTROY: - err = visorbus_destroy(&inmsg); - break; - case CONTROLVM_BUS_CONFIGURE: - err = visorbus_configure(&inmsg, parser_ctx); - break; - case CONTROLVM_DEVICE_CREATE: - err = visorbus_device_create(&inmsg); - break; - case CONTROLVM_DEVICE_CHANGESTATE: - if (cmd->device_change_state.flags.phys_device) { - err = parahotplug_process_message(&inmsg); - } else { - /* - * save the hdr and cmd structures for later use when - * sending back the response to Command - */ - err = visorbus_device_changestate(&inmsg); - break; - } - break; - case CONTROLVM_DEVICE_DESTROY: - err = visorbus_device_destroy(&inmsg); - break; - case CONTROLVM_DEVICE_CONFIGURE: - /* no op just send a respond that we passed */ - if (inmsg.hdr.flags.response_expected) - controlvm_respond(&inmsg.hdr, CONTROLVM_RESP_SUCCESS, - NULL); - break; - case CONTROLVM_CHIPSET_READY: - err = chipset_ready_uevent(&inmsg.hdr); - break; - case CONTROLVM_CHIPSET_SELFTEST: - err = chipset_selftest_uevent(&inmsg.hdr); - break; - case CONTROLVM_CHIPSET_STOP: - err = chipset_notready_uevent(&inmsg.hdr); - break; - default: - err = -ENOMSG; - if (inmsg.hdr.flags.response_expected) - controlvm_respond(&inmsg.hdr, - -CONTROLVM_RESP_ID_UNKNOWN, NULL); - break; - } - if (parser_ctx) { - parser_done(parser_ctx); - parser_ctx = NULL; - } - return err; -} - -/* - * read_controlvm_event() - retreives the next message from the - * CONTROLVM_QUEUE_EVENT queue in the controlvm - * channel - * @msg: pointer to the retrieved message - * - * Return: 0 if valid message was retrieved or -error - */ -static int read_controlvm_event(struct controlvm_message *msg) -{ - int err = visorchannel_signalremove(chipset_dev->controlvm_channel, - CONTROLVM_QUEUE_EVENT, msg); - - if (err) - return err; - /* got a message */ - if (msg->hdr.flags.test_message == 1) - return -EINVAL; - return 0; -} - -/* - * 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( - &req->msg.hdr, - CONTROLVM_RESP_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; - int count = 0; - int err; - - /* Drain the RESPONSE queue make it empty */ - do { - err = visorchannel_signalremove(chipset_dev->controlvm_channel, - CONTROLVM_QUEUE_RESPONSE, - &inmsg); - } while ((!err) && (++count < CONTROLVM_MESSAGE_MAX)); - if (err != -EAGAIN) - goto schedule_out; - if (chipset_dev->controlvm_pending_msg_valid) { - /* - * we throttled processing of a prior msg, so try to process - * it again rather than reading a new one - */ - inmsg = chipset_dev->controlvm_pending_msg; - chipset_dev->controlvm_pending_msg_valid = false; - err = 0; - } else { - err = read_controlvm_event(&inmsg); - } - while (!err) { - chipset_dev->most_recent_message_jiffies = jiffies; - err = handle_command(inmsg, - visorchannel_get_physaddr - (chipset_dev->controlvm_channel)); - if (err == -EAGAIN) { - chipset_dev->controlvm_pending_msg = inmsg; - chipset_dev->controlvm_pending_msg_valid = true; - break; - } - - err = read_controlvm_event(&inmsg); - } - /* parahotplug_worker */ - parahotplug_process_list(); - -/* - * The controlvm messages are sent in a bulk. If we start receiving messages, we - * want the polling to be fast. If we do not receive any message for - * MIN_IDLE_SECONDS, we can slow down the polling. - */ -schedule_out: - if (time_after(jiffies, chipset_dev->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 (chipset_dev->poll_jiffies != POLLJIFFIES_CONTROLVM_SLOW) - chipset_dev->poll_jiffies = POLLJIFFIES_CONTROLVM_SLOW; - } else { - if (chipset_dev->poll_jiffies != POLLJIFFIES_CONTROLVM_FAST) - chipset_dev->poll_jiffies = POLLJIFFIES_CONTROLVM_FAST; - } - schedule_delayed_work(&chipset_dev->periodic_controlvm_work, - chipset_dev->poll_jiffies); -} - -static int visorchipset_init(struct acpi_device *acpi_device) -{ - int err = -ENOMEM; - struct visorchannel *controlvm_channel; - - chipset_dev = kzalloc(sizeof(*chipset_dev), GFP_KERNEL); - if (!chipset_dev) - goto error; - err = controlvm_channel_create(chipset_dev); - if (err) - goto error_free_chipset_dev; - acpi_device->driver_data = chipset_dev; - chipset_dev->acpi_device = acpi_device; - chipset_dev->poll_jiffies = POLLJIFFIES_CONTROLVM_FAST; - err = sysfs_create_groups(&chipset_dev->acpi_device->dev.kobj, - visorchipset_dev_groups); - if (err < 0) - goto error_destroy_channel; - controlvm_channel = chipset_dev->controlvm_channel; - if (!visor_check_channel(visorchannel_get_header(controlvm_channel), - &chipset_dev->acpi_device->dev, - &visor_controlvm_channel_guid, - "controlvm", - sizeof(struct visor_controlvm_channel), - VISOR_CONTROLVM_CHANNEL_VERSIONID, - VISOR_CHANNEL_SIGNATURE)) { - err = -ENODEV; - goto error_delete_groups; - } - /* if booting in a crash kernel */ - if (is_kdump_kernel()) - INIT_DELAYED_WORK(&chipset_dev->periodic_controlvm_work, - setup_crash_devices_work_queue); - else - INIT_DELAYED_WORK(&chipset_dev->periodic_controlvm_work, - controlvm_periodic_work); - chipset_dev->most_recent_message_jiffies = jiffies; - chipset_dev->poll_jiffies = POLLJIFFIES_CONTROLVM_FAST; - schedule_delayed_work(&chipset_dev->periodic_controlvm_work, - chipset_dev->poll_jiffies); - err = visorbus_init(); - if (err < 0) - goto error_cancel_work; - return 0; - -error_cancel_work: - cancel_delayed_work_sync(&chipset_dev->periodic_controlvm_work); - -error_delete_groups: - sysfs_remove_groups(&chipset_dev->acpi_device->dev.kobj, - visorchipset_dev_groups); - -error_destroy_channel: - visorchannel_destroy(chipset_dev->controlvm_channel); - -error_free_chipset_dev: - kfree(chipset_dev); - -error: - dev_err(&acpi_device->dev, "failed with error %d\n", err); - return err; -} - -static int visorchipset_exit(struct acpi_device *acpi_device) -{ - visorbus_exit(); - cancel_delayed_work_sync(&chipset_dev->periodic_controlvm_work); - sysfs_remove_groups(&chipset_dev->acpi_device->dev.kobj, - visorchipset_dev_groups); - visorchannel_destroy(chipset_dev->controlvm_channel); - kfree(chipset_dev); - return 0; -} - -static const struct acpi_device_id unisys_device_ids[] = { - {"PNP0A07", 0}, - {"", 0}, -}; - -static struct acpi_driver unisys_acpi_driver = { - .name = "unisys_acpi", - .class = "unisys_acpi_class", - .owner = THIS_MODULE, - .ids = unisys_device_ids, - .ops = { - .add = visorchipset_init, - .remove = visorchipset_exit, - }, -}; - -MODULE_DEVICE_TABLE(acpi, unisys_device_ids); - -static __init int visorutil_spar_detect(void) -{ - unsigned int eax, ebx, ecx, edx; - - if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) { - /* check the ID */ - cpuid(UNISYS_VISOR_LEAF_ID, &eax, &ebx, &ecx, &edx); - return (ebx == UNISYS_VISOR_ID_EBX) && - (ecx == UNISYS_VISOR_ID_ECX) && - (edx == UNISYS_VISOR_ID_EDX); - } - return 0; -} - -static int __init init_unisys(void) -{ - int result; - - if (!visorutil_spar_detect()) - return -ENODEV; - result = acpi_bus_register_driver(&unisys_acpi_driver); - if (result) - return -ENODEV; - pr_info("Unisys Visorchipset Driver Loaded.\n"); - return 0; -}; - -static void __exit exit_unisys(void) -{ - acpi_bus_unregister_driver(&unisys_acpi_driver); -} - -module_init(init_unisys); -module_exit(exit_unisys); - -MODULE_AUTHOR("Unisys"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("s-Par visorbus driver for virtual device buses"); |