mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 21:51:40 +00:00
staging: Remove the drivers for the Unisys s-Par
The Unisys sub-tree of drivers/staging contains three drivers for the "Unisys Secure Partition" (s-Par(R)): visorhba, visorinput, visornic. They have no maintainers, in fact the only one that is listed in MAINTAINERS has an unreacheable email address. During 2021 and 2022 several patches have been submitted to these drivers but nobody at Unisys cared of reviewing the changes. Probably, also the "sparmaintainer" internal list of unisys.com is not anymore read by interested Unisys' engineers. Therefore, remove the drivers/staging/unisys directory and delete the relevant entries in the MAINTAINERS, Kconfig, Makefile files, then remove also the drivers/visorbus directory which is not anymore needed (it contained the driver for the virtualized bus for the Unisys s-Par firmware). Cc: David Kershner <david.kershner@unisys.com> Cc: <sparmaintainer@unisys.com> Cc: Ken Cox <jkc@redhat.com> Suggested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Fabio M. De Francesco <fmdefrancesco@gmail.com> Link: https://lore.kernel.org/r/20220414103217.32058-1-fmdefrancesco@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
9dc9653c85
commit
e5f45b011e
@ -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>
|
||||
|
@ -225,8 +225,6 @@ source "drivers/mux/Kconfig"
|
||||
|
||||
source "drivers/opp/Kconfig"
|
||||
|
||||
source "drivers/visorbus/Kconfig"
|
||||
|
||||
source "drivers/siox/Kconfig"
|
||||
|
||||
source "drivers/slimbus/Kconfig"
|
||||
|
@ -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/
|
||||
|
@ -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"
|
||||
|
@ -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/
|
||||
|
@ -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
|
@ -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.
|
@ -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
|
@ -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/
|
@ -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/
|
@ -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>
|
@ -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
|
@ -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.
|
||||
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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.
|
||||
|
@ -1,7 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for Unisys visorinput
|
||||
#
|
||||
|
||||
obj-$(CONFIG_UNISYS_VISORINPUT) += visorinput.o
|
||||
|
@ -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);
|
@ -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.
|
||||
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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.
|
@ -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
|
@ -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
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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
|
@ -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);
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user