提交 e5f45b01 编写于 作者: F Fabio M. De Francesco 提交者: Greg Kroah-Hartman

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: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: NFabio M. De Francesco <fmdefrancesco@gmail.com>
Link: https://lore.kernel.org/r/20220414103217.32058-1-fmdefrancesco@gmail.comSigned-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
上级 9dc9653c
......@@ -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/
......
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. 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.
# 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
Unisys s-Par drivers
M: David Kershner <sparmaintainer@unisys.com>
S: Maintained
F: drivers/staging/unisys/Documentation/overview.txt
F: drivers/staging/unisys/
# 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/
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>
/* 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
# 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.
# 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
# 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.
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for Unisys visorinput
#
obj-$(CONFIG_UNISYS_VISORINPUT) += visorinput.o
# 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.
# 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
# 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.
# 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
此差异已折叠。
/* 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
此差异已折叠。
/* 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
// 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);
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册