mirror of https://github.com/xemu-project/xemu.git
s390x updates:
- support for vfio-ccw to passthrough channel devices - allow ccw bios to boot from scsi generic devices - bugfix for initial reset -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJZJBbAAAoJEN7Pa5PG8C+vXtoP/0hXz0NAG+fSdwXXcfjPjisX sRfu3rln6dCAAZKZNVvlPEctCqwjwVOnuygUln0/UL0XgBdRT9desjA2uQnwVrLn vsLuG+8jWdmGbs0Wt2t5GfSoSs40V1KIRKd4b+MAtDjQQ52WvIBFsbTW/ZRan+LY ltgqBuBh3sfOQ/g5QGzR1RBrJAABkTs00mlgfZfws0p5QeJbPKjmQaB4Al+HJMKC bmug0ZlxysJQ2wJy0Ybw2Y0NGSIw/hFi1PGgtwJKLj5OwH/WtBjr4lpcO/7vN9+l vsV8CkayeHr+VShXe9Vh+tbIQtaiX8jYPVlD2mQFt7EyS1JrB6L6DPHvlZwkQyBi C7IQhEkziUv7CJzYX9pUHEPqwOqmxzao1E+GKxVhqlIV7OCpVGoIiFoQu/aRI8v/ Rz3BAEzogdR4N+04Ww3rU+NrDYZUFO0BGZtCjEuvjbPtdeuvt+hbWPz/uPZgCrcX wKBHxafQ/BRKxOw4rJkpfweCf/sHeD2DELzn/KXZbibhKBfe0hjTDvoIu6xffyfW HElT477sOnAqOm9JgFdI58qBHT3OepMg62szF+QDk/7zBY095OchmQgs8vnkQ6x/ LVvxrWXZJyBj4joU94BPntt9lU0oky3XgjSoBnrblRGOqA0nwyQnkR63SDnCHzz0 FULYu/bd0kvLlodRlZge =XpHA -----END PGP SIGNATURE----- Merge remote-tracking branch 'cohuck/tags/s390x-20170523' into staging s390x updates: - support for vfio-ccw to passthrough channel devices - allow ccw bios to boot from scsi generic devices - bugfix for initial reset # gpg: Signature made Tue 23 May 2017 12:02:24 PM BST # gpg: using RSA key 0xDECF6B93C6F02FAF # gpg: Good signature from "Cornelia Huck <conny@cornelia-huck.de>" # gpg: aka "Cornelia Huck <cohuck@kernel.org>" # gpg: aka "Cornelia Huck <cornelia.huck@de.ibm.com>" # gpg: aka "Cornelia Huck <huckc@linux.vnet.ibm.com>" # Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0 18CE DECF 6B93 C6F0 2FAF * cohuck/tags/s390x-20170523: (21 commits) s390/kvm: do not reset riccb on initial cpu reset MAINTAINERS: Add vfio-ccw maintainer vfio/ccw: update sense data if a unit check is pending s390x/css: ccw translation infrastructure s390x/css: introduce and realize ccw-request callback vfio/ccw: get irqs info and set the eventfd fd vfio/ccw: get io region info vfio/ccw: vfio based subchannel passthrough driver s390x/css: device support for s390-ccw passthrough s390x/css: realize css_create_sch s390x/css: realize css_sch_build_schib s390x/css: add s390-squash-mcss machine option linux-headers: update pc-bios/s390-ccw.img: rebuild image pc-bios/s390-ccw: Build a reasonable max_sectors limit pc-bios/s390-ccw: Get Block Limits VPD device data pc-bios/s390-ccw: Get list of supported VPD pages pc-bios/s390-ccw: Refactor scsi_inquiry function pc-bios/s390-ccw: Break up virtio-scsi read into multiples pc-bios/s390-ccw: Move SCSI block factor to outer read ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
e1fe27a208
|
@ -1005,6 +1005,14 @@ S: Supported
|
|||
F: hw/vfio/*
|
||||
F: include/hw/vfio/
|
||||
|
||||
vfio-ccw
|
||||
M: Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
S: Supported
|
||||
F: hw/vfio/ccw.c
|
||||
F: hw/s390x/s390-ccw.c
|
||||
F: include/hw/s390x/s390-ccw.h
|
||||
T: git git://github.com/cohuck/qemu.git s390-next
|
||||
|
||||
vhost
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
S: Supported
|
||||
|
|
|
@ -5,4 +5,5 @@ CONFIG_SCLPCONSOLE=y
|
|||
CONFIG_TERMINAL3270=y
|
||||
CONFIG_S390_FLIC=y
|
||||
CONFIG_S390_FLIC_KVM=$(CONFIG_KVM)
|
||||
CONFIG_VFIO_CCW=$(CONFIG_LINUX)
|
||||
CONFIG_WDT_DIAG288=y
|
||||
|
|
|
@ -98,9 +98,13 @@ static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp)
|
|||
EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
|
||||
CcwDevice *cdev = CCW_DEVICE(ds);
|
||||
CCWDeviceClass *cdk = CCW_DEVICE_GET_CLASS(cdev);
|
||||
SubchDev *sch = css_create_virtual_sch(cdev->devno, errp);
|
||||
DeviceState *parent = DEVICE(cdev);
|
||||
BusState *qbus = qdev_get_parent_bus(parent);
|
||||
VirtualCssBus *cbus = VIRTUAL_CSS_BUS(qbus);
|
||||
SubchDev *sch;
|
||||
Error *err = NULL;
|
||||
|
||||
sch = css_create_sch(cdev->devno, true, cbus->squash_mcss, errp);
|
||||
if (!sch) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -14,3 +14,4 @@ obj-y += ccw-device.o
|
|||
obj-y += s390-pci-bus.o s390-pci-inst.o
|
||||
obj-y += s390-skeys.o
|
||||
obj-$(CONFIG_KVM) += s390-skeys-kvm.o
|
||||
obj-y += s390-ccw.o
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "hw/s390x/css.h"
|
||||
#include "ccw-device.h"
|
||||
#include "hw/s390x/css-bridge.h"
|
||||
#include "cpu.h"
|
||||
|
||||
/*
|
||||
* Invoke device-specific unplug handler, disable the subchannel
|
||||
|
@ -103,6 +104,7 @@ VirtualCssBus *virtual_css_bus_init(void)
|
|||
/* Create bus on bridge device */
|
||||
bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css");
|
||||
cbus = VIRTUAL_CSS_BUS(bus);
|
||||
cbus->squash_mcss = s390_get_squash_mcss();
|
||||
|
||||
/* Enable hotplugging */
|
||||
qbus_set_hotplug_handler(bus, dev, &error_abort);
|
||||
|
|
290
hw/s390x/css.c
290
hw/s390x/css.c
|
@ -13,6 +13,7 @@
|
|||
#include "qapi/error.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "hw/qdev.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "cpu.h"
|
||||
|
@ -258,7 +259,7 @@ uint16_t css_build_subchannel_id(SubchDev *sch)
|
|||
return css_do_build_subchannel_id(sch->cssid, sch->ssid);
|
||||
}
|
||||
|
||||
static void css_inject_io_interrupt(SubchDev *sch)
|
||||
void css_inject_io_interrupt(SubchDev *sch)
|
||||
{
|
||||
uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11;
|
||||
|
||||
|
@ -523,7 +524,7 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void sch_handle_start_func(SubchDev *sch, ORB *orb)
|
||||
static void sch_handle_start_func_virtual(SubchDev *sch, ORB *orb)
|
||||
{
|
||||
|
||||
PMCW *p = &sch->curr_status.pmcw;
|
||||
|
@ -625,13 +626,58 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb)
|
|||
|
||||
}
|
||||
|
||||
static int sch_handle_start_func_passthrough(SubchDev *sch, ORB *orb)
|
||||
{
|
||||
|
||||
PMCW *p = &sch->curr_status.pmcw;
|
||||
SCSW *s = &sch->curr_status.scsw;
|
||||
int ret;
|
||||
|
||||
if (!(s->ctrl & SCSW_ACTL_SUSP)) {
|
||||
assert(orb != NULL);
|
||||
p->intparm = orb->intparm;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only support prefetch enable mode.
|
||||
* Only support 64bit addressing idal.
|
||||
*/
|
||||
if (!(orb->ctrl0 & ORB_CTRL0_MASK_PFCH) ||
|
||||
!(orb->ctrl0 & ORB_CTRL0_MASK_C64)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = s390_ccw_cmd_request(orb, s, sch->driver_data);
|
||||
switch (ret) {
|
||||
/* Currently we don't update control block and just return the cc code. */
|
||||
case 0:
|
||||
break;
|
||||
case -EBUSY:
|
||||
break;
|
||||
case -ENODEV:
|
||||
break;
|
||||
case -EACCES:
|
||||
/* Let's reflect an inaccessible host device by cc 3. */
|
||||
ret = -ENODEV;
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* All other return codes will trigger a program check,
|
||||
* or set cc to 1.
|
||||
*/
|
||||
break;
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* On real machines, this would run asynchronously to the main vcpus.
|
||||
* We might want to make some parts of the ssch handling (interpreting
|
||||
* read/writes) asynchronous later on if we start supporting more than
|
||||
* our current very simple devices.
|
||||
*/
|
||||
static void do_subchannel_work(SubchDev *sch, ORB *orb)
|
||||
int do_subchannel_work_virtual(SubchDev *sch, ORB *orb)
|
||||
{
|
||||
|
||||
SCSW *s = &sch->curr_status.scsw;
|
||||
|
@ -642,12 +688,45 @@ static void do_subchannel_work(SubchDev *sch, ORB *orb)
|
|||
sch_handle_halt_func(sch);
|
||||
} else if (s->ctrl & SCSW_FCTL_START_FUNC) {
|
||||
/* Triggered by both ssch and rsch. */
|
||||
sch_handle_start_func(sch, orb);
|
||||
sch_handle_start_func_virtual(sch, orb);
|
||||
} else {
|
||||
/* Cannot happen. */
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
css_inject_io_interrupt(sch);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_subchannel_work_passthrough(SubchDev *sch, ORB *orb)
|
||||
{
|
||||
int ret;
|
||||
SCSW *s = &sch->curr_status.scsw;
|
||||
|
||||
if (s->ctrl & SCSW_FCTL_CLEAR_FUNC) {
|
||||
/* TODO: Clear handling */
|
||||
sch_handle_clear_func(sch);
|
||||
ret = 0;
|
||||
} else if (s->ctrl & SCSW_FCTL_HALT_FUNC) {
|
||||
/* TODO: Halt handling */
|
||||
sch_handle_halt_func(sch);
|
||||
ret = 0;
|
||||
} else if (s->ctrl & SCSW_FCTL_START_FUNC) {
|
||||
ret = sch_handle_start_func_passthrough(sch, orb);
|
||||
} else {
|
||||
/* Cannot happen. */
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_subchannel_work(SubchDev *sch, ORB *orb)
|
||||
{
|
||||
if (sch->do_subchannel_work) {
|
||||
return sch->do_subchannel_work(sch, orb);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_pmcw_to_guest(PMCW *dest, const PMCW *src)
|
||||
|
@ -670,7 +749,7 @@ static void copy_pmcw_to_guest(PMCW *dest, const PMCW *src)
|
|||
dest->chars = cpu_to_be32(src->chars);
|
||||
}
|
||||
|
||||
static void copy_scsw_to_guest(SCSW *dest, const SCSW *src)
|
||||
void copy_scsw_to_guest(SCSW *dest, const SCSW *src)
|
||||
{
|
||||
dest->flags = cpu_to_be16(src->flags);
|
||||
dest->ctrl = cpu_to_be16(src->ctrl);
|
||||
|
@ -966,8 +1045,7 @@ int css_do_ssch(SubchDev *sch, ORB *orb)
|
|||
s->ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND);
|
||||
s->flags &= ~SCSW_FLAGS_MASK_PNO;
|
||||
|
||||
do_subchannel_work(sch, orb);
|
||||
ret = 0;
|
||||
ret = do_subchannel_work(sch, orb);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
|
@ -1326,7 +1404,8 @@ unsigned int css_find_free_chpid(uint8_t cssid)
|
|||
return MAX_CHPID + 1;
|
||||
}
|
||||
|
||||
static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type)
|
||||
static int css_add_chpid(uint8_t cssid, uint8_t chpid, uint8_t type,
|
||||
bool is_virt)
|
||||
{
|
||||
CssImage *css;
|
||||
|
||||
|
@ -1340,7 +1419,7 @@ static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type)
|
|||
}
|
||||
css->chpids[chpid].in_use = 1;
|
||||
css->chpids[chpid].type = type;
|
||||
css->chpids[chpid].is_virtual = 1;
|
||||
css->chpids[chpid].is_virtual = is_virt;
|
||||
|
||||
css_generate_chp_crws(cssid, chpid);
|
||||
|
||||
|
@ -1364,7 +1443,7 @@ void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type)
|
|||
p->pam = 0x80;
|
||||
p->chpid[0] = chpid;
|
||||
if (!css->chpids[chpid].in_use) {
|
||||
css_add_virtual_chpid(sch->cssid, chpid, type);
|
||||
css_add_chpid(sch->cssid, chpid, type, true);
|
||||
}
|
||||
|
||||
memset(s, 0, sizeof(SCSW));
|
||||
|
@ -1946,28 +2025,59 @@ PropertyInfo css_devid_ro_propinfo = {
|
|||
.get = get_css_devid,
|
||||
};
|
||||
|
||||
SubchDev *css_create_virtual_sch(CssDevId bus_id, Error **errp)
|
||||
SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss,
|
||||
Error **errp)
|
||||
{
|
||||
uint16_t schid = 0;
|
||||
SubchDev *sch;
|
||||
|
||||
if (bus_id.valid) {
|
||||
/* Enforce use of virtual cssid. */
|
||||
if (bus_id.cssid != VIRTUAL_CSSID) {
|
||||
error_setg(errp, "cssid %hhx not valid for virtual devices",
|
||||
bus_id.cssid);
|
||||
if (is_virtual != (bus_id.cssid == VIRTUAL_CSSID)) {
|
||||
error_setg(errp, "cssid %hhx not valid for %s devices",
|
||||
bus_id.cssid,
|
||||
(is_virtual ? "virtual" : "non-virtual"));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (bus_id.valid) {
|
||||
if (squash_mcss) {
|
||||
bus_id.cssid = channel_subsys.default_cssid;
|
||||
} else if (!channel_subsys.css[bus_id.cssid]) {
|
||||
css_create_css_image(bus_id.cssid, false);
|
||||
}
|
||||
|
||||
if (!css_find_free_subch_for_devno(bus_id.cssid, bus_id.ssid,
|
||||
bus_id.devid, &schid, errp)) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
bus_id.cssid = VIRTUAL_CSSID;
|
||||
} else if (squash_mcss || is_virtual) {
|
||||
bus_id.cssid = channel_subsys.default_cssid;
|
||||
|
||||
if (!css_find_free_subch_and_devno(bus_id.cssid, &bus_id.ssid,
|
||||
&bus_id.devid, &schid, errp)) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
for (bus_id.cssid = 0; bus_id.cssid < MAX_CSSID; ++bus_id.cssid) {
|
||||
if (bus_id.cssid == VIRTUAL_CSSID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!channel_subsys.css[bus_id.cssid]) {
|
||||
css_create_css_image(bus_id.cssid, false);
|
||||
}
|
||||
|
||||
if (css_find_free_subch_and_devno(bus_id.cssid, &bus_id.ssid,
|
||||
&bus_id.devid, &schid,
|
||||
NULL)) {
|
||||
break;
|
||||
}
|
||||
if (bus_id.cssid == MAX_CSSID) {
|
||||
error_setg(errp, "Virtual channel subsystem is full!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sch = g_malloc0(sizeof(*sch));
|
||||
|
@ -1978,3 +2088,147 @@ SubchDev *css_create_virtual_sch(CssDevId bus_id, Error **errp)
|
|||
css_subch_assign(sch->cssid, sch->ssid, schid, sch->devno, sch);
|
||||
return sch;
|
||||
}
|
||||
|
||||
static int css_sch_get_chpids(SubchDev *sch, CssDevId *dev_id)
|
||||
{
|
||||
char *fid_path;
|
||||
FILE *fd;
|
||||
uint32_t chpid[8];
|
||||
int i;
|
||||
PMCW *p = &sch->curr_status.pmcw;
|
||||
|
||||
fid_path = g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/chpids",
|
||||
dev_id->cssid, dev_id->ssid, dev_id->devid);
|
||||
fd = fopen(fid_path, "r");
|
||||
if (fd == NULL) {
|
||||
error_report("%s: open %s failed", __func__, fid_path);
|
||||
g_free(fid_path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fscanf(fd, "%x %x %x %x %x %x %x %x",
|
||||
&chpid[0], &chpid[1], &chpid[2], &chpid[3],
|
||||
&chpid[4], &chpid[5], &chpid[6], &chpid[7]) != 8) {
|
||||
fclose(fd);
|
||||
g_free(fid_path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(p->chpid); i++) {
|
||||
p->chpid[i] = chpid[i];
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
g_free(fid_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int css_sch_get_path_masks(SubchDev *sch, CssDevId *dev_id)
|
||||
{
|
||||
char *fid_path;
|
||||
FILE *fd;
|
||||
uint32_t pim, pam, pom;
|
||||
PMCW *p = &sch->curr_status.pmcw;
|
||||
|
||||
fid_path = g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/pimpampom",
|
||||
dev_id->cssid, dev_id->ssid, dev_id->devid);
|
||||
fd = fopen(fid_path, "r");
|
||||
if (fd == NULL) {
|
||||
error_report("%s: open %s failed", __func__, fid_path);
|
||||
g_free(fid_path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fscanf(fd, "%x %x %x", &pim, &pam, &pom) != 3) {
|
||||
fclose(fd);
|
||||
g_free(fid_path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
p->pim = pim;
|
||||
p->pam = pam;
|
||||
p->pom = pom;
|
||||
fclose(fd);
|
||||
g_free(fid_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int css_sch_get_chpid_type(uint8_t chpid, uint32_t *type,
|
||||
CssDevId *dev_id)
|
||||
{
|
||||
char *fid_path;
|
||||
FILE *fd;
|
||||
|
||||
fid_path = g_strdup_printf("/sys/devices/css%x/chp0.%02x/type",
|
||||
dev_id->cssid, chpid);
|
||||
fd = fopen(fid_path, "r");
|
||||
if (fd == NULL) {
|
||||
error_report("%s: open %s failed", __func__, fid_path);
|
||||
g_free(fid_path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fscanf(fd, "%x", type) != 1) {
|
||||
fclose(fd);
|
||||
g_free(fid_path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
g_free(fid_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We currently retrieve the real device information from sysfs to build the
|
||||
* guest subchannel information block without considering the migration feature.
|
||||
* We need to revisit this problem when we want to add migration support.
|
||||
*/
|
||||
int css_sch_build_schib(SubchDev *sch, CssDevId *dev_id)
|
||||
{
|
||||
CssImage *css = channel_subsys.css[sch->cssid];
|
||||
PMCW *p = &sch->curr_status.pmcw;
|
||||
SCSW *s = &sch->curr_status.scsw;
|
||||
uint32_t type;
|
||||
int i, ret;
|
||||
|
||||
assert(css != NULL);
|
||||
memset(p, 0, sizeof(PMCW));
|
||||
p->flags |= PMCW_FLAGS_MASK_DNV;
|
||||
/* We are dealing with I/O subchannels only. */
|
||||
p->devno = sch->devno;
|
||||
|
||||
/* Grab path mask from sysfs. */
|
||||
ret = css_sch_get_path_masks(sch, dev_id);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Grab chpids from sysfs. */
|
||||
ret = css_sch_get_chpids(sch, dev_id);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Build chpid type. */
|
||||
for (i = 0; i < ARRAY_SIZE(p->chpid); i++) {
|
||||
if (p->chpid[i] && !css->chpids[p->chpid[i]].in_use) {
|
||||
ret = css_sch_get_chpid_type(p->chpid[i], &type, dev_id);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
css_add_chpid(sch->cssid, p->chpid[i], type, false);
|
||||
}
|
||||
}
|
||||
|
||||
memset(s, 0, sizeof(SCSW));
|
||||
sch->curr_status.mba = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(sch->curr_status.mda); i++) {
|
||||
sch->curr_status.mda[i] = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* s390 CCW Assignment Support
|
||||
*
|
||||
* Copyright 2017 IBM Corp
|
||||
* Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
|
||||
* Xiao Feng Ren <renxiaof@linux.vnet.ibm.com>
|
||||
* Pierre Morel <pmorel@linux.vnet.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2
|
||||
* or (at your option) any later version. See the COPYING file in the
|
||||
* top-level directory.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "libgen.h"
|
||||
#include "hw/s390x/css.h"
|
||||
#include "hw/s390x/css-bridge.h"
|
||||
#include "hw/s390x/s390-ccw.h"
|
||||
|
||||
int s390_ccw_cmd_request(ORB *orb, SCSW *scsw, void *data)
|
||||
{
|
||||
S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(data);
|
||||
|
||||
if (cdc->handle_request) {
|
||||
return cdc->handle_request(orb, scsw, data);
|
||||
} else {
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
static void s390_ccw_get_dev_info(S390CCWDevice *cdev,
|
||||
char *sysfsdev,
|
||||
Error **errp)
|
||||
{
|
||||
unsigned int cssid, ssid, devid;
|
||||
char dev_path[PATH_MAX] = {0}, *tmp;
|
||||
|
||||
if (!sysfsdev) {
|
||||
error_setg(errp, "No host device provided");
|
||||
error_append_hint(errp,
|
||||
"Use -device vfio-ccw,sysfsdev=PATH_TO_DEVICE\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!realpath(sysfsdev, dev_path)) {
|
||||
error_setg_errno(errp, errno, "Host device '%s' not found", sysfsdev);
|
||||
return;
|
||||
}
|
||||
|
||||
cdev->mdevid = g_strdup(basename(dev_path));
|
||||
|
||||
tmp = basename(dirname(dev_path));
|
||||
if (sscanf(tmp, "%2x.%1x.%4x", &cssid, &ssid, &devid) != 3) {
|
||||
error_setg_errno(errp, errno, "Failed to read %s", tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
cdev->hostid.cssid = cssid;
|
||||
cdev->hostid.ssid = ssid;
|
||||
cdev->hostid.devid = devid;
|
||||
cdev->hostid.valid = true;
|
||||
}
|
||||
|
||||
static void s390_ccw_realize(S390CCWDevice *cdev, char *sysfsdev, Error **errp)
|
||||
{
|
||||
CcwDevice *ccw_dev = CCW_DEVICE(cdev);
|
||||
CCWDeviceClass *ck = CCW_DEVICE_GET_CLASS(ccw_dev);
|
||||
DeviceState *parent = DEVICE(ccw_dev);
|
||||
BusState *qbus = qdev_get_parent_bus(parent);
|
||||
VirtualCssBus *cbus = VIRTUAL_CSS_BUS(qbus);
|
||||
SubchDev *sch;
|
||||
int ret;
|
||||
Error *err = NULL;
|
||||
|
||||
s390_ccw_get_dev_info(cdev, sysfsdev, &err);
|
||||
if (err) {
|
||||
goto out_err_propagate;
|
||||
}
|
||||
|
||||
sch = css_create_sch(ccw_dev->devno, false, cbus->squash_mcss, &err);
|
||||
if (!sch) {
|
||||
goto out_mdevid_free;
|
||||
}
|
||||
sch->driver_data = cdev;
|
||||
sch->do_subchannel_work = do_subchannel_work_passthrough;
|
||||
|
||||
ccw_dev->sch = sch;
|
||||
ret = css_sch_build_schib(sch, &cdev->hostid);
|
||||
if (ret) {
|
||||
error_setg_errno(&err, -ret, "%s: Failed to build initial schib",
|
||||
__func__);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
ck->realize(ccw_dev, &err);
|
||||
if (err) {
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid,
|
||||
parent->hotplugged, 1);
|
||||
return;
|
||||
|
||||
out_err:
|
||||
css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
|
||||
ccw_dev->sch = NULL;
|
||||
g_free(sch);
|
||||
out_mdevid_free:
|
||||
g_free(cdev->mdevid);
|
||||
out_err_propagate:
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
|
||||
static void s390_ccw_unrealize(S390CCWDevice *cdev, Error **errp)
|
||||
{
|
||||
CcwDevice *ccw_dev = CCW_DEVICE(cdev);
|
||||
SubchDev *sch = ccw_dev->sch;
|
||||
|
||||
if (sch) {
|
||||
css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
|
||||
g_free(sch);
|
||||
ccw_dev->sch = NULL;
|
||||
}
|
||||
|
||||
g_free(cdev->mdevid);
|
||||
}
|
||||
|
||||
static void s390_ccw_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
S390CCWDeviceClass *cdc = S390_CCW_DEVICE_CLASS(klass);
|
||||
|
||||
dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
|
||||
cdc->realize = s390_ccw_realize;
|
||||
cdc->unrealize = s390_ccw_unrealize;
|
||||
}
|
||||
|
||||
static const TypeInfo s390_ccw_info = {
|
||||
.name = TYPE_S390_CCW,
|
||||
.parent = TYPE_CCW_DEVICE,
|
||||
.instance_size = sizeof(S390CCWDevice),
|
||||
.class_size = sizeof(S390CCWDeviceClass),
|
||||
.class_init = s390_ccw_class_init,
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static void register_s390_ccw_type(void)
|
||||
{
|
||||
type_register_static(&s390_ccw_info);
|
||||
}
|
||||
|
||||
type_init(register_s390_ccw_type)
|
|
@ -136,10 +136,15 @@ static void ccw_init(MachineState *machine)
|
|||
kvm_s390_enable_css_support(s390_cpu_addr2state(0));
|
||||
}
|
||||
/*
|
||||
* Create virtual css and set it as default so that non mcss-e
|
||||
* enabled guests only see virtio devices.
|
||||
* Non mcss-e enabled guests only see the devices from the default
|
||||
* css, which is determined by the value of the squash_mcss property.
|
||||
* Note: we must not squash non virtual devices to css 0xFE.
|
||||
*/
|
||||
ret = css_create_css_image(VIRTUAL_CSSID, true);
|
||||
if (css_bus->squash_mcss) {
|
||||
ret = css_create_css_image(0, true);
|
||||
} else {
|
||||
ret = css_create_css_image(VIRTUAL_CSSID, true);
|
||||
}
|
||||
assert(ret == 0);
|
||||
|
||||
/* Create VirtIO network adapters */
|
||||
|
@ -303,6 +308,20 @@ static void machine_set_loadparm(Object *obj, const char *val, Error **errp)
|
|||
ms->loadparm[i] = ' '; /* pad right with spaces */
|
||||
}
|
||||
}
|
||||
static inline bool machine_get_squash_mcss(Object *obj, Error **errp)
|
||||
{
|
||||
S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
|
||||
|
||||
return ms->s390_squash_mcss;
|
||||
}
|
||||
|
||||
static inline void machine_set_squash_mcss(Object *obj, bool value,
|
||||
Error **errp)
|
||||
{
|
||||
S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
|
||||
|
||||
ms->s390_squash_mcss = value;
|
||||
}
|
||||
|
||||
static inline void s390_machine_initfn(Object *obj)
|
||||
{
|
||||
|
@ -328,6 +347,13 @@ static inline void s390_machine_initfn(Object *obj)
|
|||
" to upper case) to pass to machine loader, boot manager,"
|
||||
" and guest kernel",
|
||||
NULL);
|
||||
object_property_add_bool(obj, "s390-squash-mcss",
|
||||
machine_get_squash_mcss,
|
||||
machine_set_squash_mcss, NULL);
|
||||
object_property_set_description(obj, "s390-squash-mcss",
|
||||
"enable/disable squashing subchannels into the default css",
|
||||
NULL);
|
||||
object_property_set_bool(obj, false, "s390-squash-mcss", NULL);
|
||||
}
|
||||
|
||||
static const TypeInfo ccw_machine_info = {
|
||||
|
|
|
@ -680,9 +680,13 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
|
|||
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
|
||||
CcwDevice *ccw_dev = CCW_DEVICE(dev);
|
||||
CCWDeviceClass *ck = CCW_DEVICE_GET_CLASS(ccw_dev);
|
||||
SubchDev *sch = css_create_virtual_sch(ccw_dev->devno, errp);
|
||||
DeviceState *parent = DEVICE(ccw_dev);
|
||||
BusState *qbus = qdev_get_parent_bus(parent);
|
||||
VirtualCssBus *cbus = VIRTUAL_CSS_BUS(qbus);
|
||||
SubchDev *sch;
|
||||
Error *err = NULL;
|
||||
|
||||
sch = css_create_sch(ccw_dev->devno, true, cbus->squash_mcss, errp);
|
||||
if (!sch) {
|
||||
return;
|
||||
}
|
||||
|
@ -697,6 +701,7 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
|
|||
sch->disable_cb = virtio_sch_disable_cb;
|
||||
sch->id.reserved = 0xff;
|
||||
sch->id.cu_type = VIRTIO_CCW_CU_TYPE;
|
||||
sch->do_subchannel_work = do_subchannel_work_virtual;
|
||||
ccw_dev->sch = sch;
|
||||
dev->indicators = NULL;
|
||||
dev->revision = -1;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
ifeq ($(CONFIG_LINUX), y)
|
||||
obj-$(CONFIG_SOFTMMU) += common.o
|
||||
obj-$(CONFIG_PCI) += pci.o pci-quirks.o
|
||||
obj-$(CONFIG_VFIO_CCW) += ccw.o
|
||||
obj-$(CONFIG_SOFTMMU) += platform.o
|
||||
obj-$(CONFIG_VFIO_XGMAC) += calxeda-xgmac.o
|
||||
obj-$(CONFIG_VFIO_AMD_XGBE) += amd-xgbe.o
|
||||
|
|
|
@ -0,0 +1,434 @@
|
|||
/*
|
||||
* vfio based subchannel assignment support
|
||||
*
|
||||
* Copyright 2017 IBM Corp.
|
||||
* Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
|
||||
* Xiao Feng Ren <renxiaof@linux.vnet.ibm.com>
|
||||
* Pierre Morel <pmorel@linux.vnet.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or(at
|
||||
* your option) any version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
|
||||
#include <linux/vfio.h>
|
||||
#include <linux/vfio_ccw.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/vfio/vfio.h"
|
||||
#include "hw/vfio/vfio-common.h"
|
||||
#include "hw/s390x/s390-ccw.h"
|
||||
#include "hw/s390x/ccw-device.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#define TYPE_VFIO_CCW "vfio-ccw"
|
||||
typedef struct VFIOCCWDevice {
|
||||
S390CCWDevice cdev;
|
||||
VFIODevice vdev;
|
||||
uint64_t io_region_size;
|
||||
uint64_t io_region_offset;
|
||||
struct ccw_io_region *io_region;
|
||||
EventNotifier io_notifier;
|
||||
} VFIOCCWDevice;
|
||||
|
||||
static void vfio_ccw_compute_needs_reset(VFIODevice *vdev)
|
||||
{
|
||||
vdev->needs_reset = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't need vfio_hot_reset_multi and vfio_eoi operations for
|
||||
* vfio_ccw device now.
|
||||
*/
|
||||
struct VFIODeviceOps vfio_ccw_ops = {
|
||||
.vfio_compute_needs_reset = vfio_ccw_compute_needs_reset,
|
||||
};
|
||||
|
||||
static int vfio_ccw_handle_request(ORB *orb, SCSW *scsw, void *data)
|
||||
{
|
||||
S390CCWDevice *cdev = data;
|
||||
VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev);
|
||||
struct ccw_io_region *region = vcdev->io_region;
|
||||
int ret;
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(region->orb_area) != sizeof(ORB));
|
||||
QEMU_BUILD_BUG_ON(sizeof(region->scsw_area) != sizeof(SCSW));
|
||||
QEMU_BUILD_BUG_ON(sizeof(region->irb_area) != sizeof(IRB));
|
||||
|
||||
memset(region, 0, sizeof(*region));
|
||||
|
||||
memcpy(region->orb_area, orb, sizeof(ORB));
|
||||
memcpy(region->scsw_area, scsw, sizeof(SCSW));
|
||||
|
||||
again:
|
||||
ret = pwrite(vcdev->vdev.fd, region,
|
||||
vcdev->io_region_size, vcdev->io_region_offset);
|
||||
if (ret != vcdev->io_region_size) {
|
||||
if (errno == EAGAIN) {
|
||||
goto again;
|
||||
}
|
||||
error_report("vfio-ccw: wirte I/O region failed with errno=%d", errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return region->ret_code;
|
||||
}
|
||||
|
||||
static void vfio_ccw_reset(DeviceState *dev)
|
||||
{
|
||||
CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev);
|
||||
S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev);
|
||||
VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev);
|
||||
|
||||
ioctl(vcdev->vdev.fd, VFIO_DEVICE_RESET);
|
||||
}
|
||||
|
||||
static void vfio_ccw_io_notifier_handler(void *opaque)
|
||||
{
|
||||
VFIOCCWDevice *vcdev = opaque;
|
||||
struct ccw_io_region *region = vcdev->io_region;
|
||||
S390CCWDevice *cdev = S390_CCW_DEVICE(vcdev);
|
||||
CcwDevice *ccw_dev = CCW_DEVICE(cdev);
|
||||
SubchDev *sch = ccw_dev->sch;
|
||||
SCSW *s = &sch->curr_status.scsw;
|
||||
PMCW *p = &sch->curr_status.pmcw;
|
||||
IRB irb;
|
||||
int size;
|
||||
|
||||
if (!event_notifier_test_and_clear(&vcdev->io_notifier)) {
|
||||
return;
|
||||
}
|
||||
|
||||
size = pread(vcdev->vdev.fd, region, vcdev->io_region_size,
|
||||
vcdev->io_region_offset);
|
||||
if (size == -1) {
|
||||
switch (errno) {
|
||||
case ENODEV:
|
||||
/* Generate a deferred cc 3 condition. */
|
||||
s->flags |= SCSW_FLAGS_MASK_CC;
|
||||
s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
|
||||
s->ctrl |= (SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND);
|
||||
goto read_err;
|
||||
case EFAULT:
|
||||
/* Memory problem, generate channel data check. */
|
||||
s->ctrl &= ~SCSW_ACTL_START_PEND;
|
||||
s->cstat = SCSW_CSTAT_DATA_CHECK;
|
||||
s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
|
||||
s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
|
||||
SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
|
||||
goto read_err;
|
||||
default:
|
||||
/* Error, generate channel program check. */
|
||||
s->ctrl &= ~SCSW_ACTL_START_PEND;
|
||||
s->cstat = SCSW_CSTAT_PROG_CHECK;
|
||||
s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
|
||||
s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
|
||||
SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
|
||||
goto read_err;
|
||||
}
|
||||
} else if (size != vcdev->io_region_size) {
|
||||
/* Information transfer error, generate channel-control check. */
|
||||
s->ctrl &= ~SCSW_ACTL_START_PEND;
|
||||
s->cstat = SCSW_CSTAT_CHN_CTRL_CHK;
|
||||
s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
|
||||
s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
|
||||
SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
|
||||
goto read_err;
|
||||
}
|
||||
|
||||
memcpy(&irb, region->irb_area, sizeof(IRB));
|
||||
|
||||
/* Update control block via irb. */
|
||||
copy_scsw_to_guest(s, &irb.scsw);
|
||||
|
||||
/* If a uint check is pending, copy sense data. */
|
||||
if ((s->dstat & SCSW_DSTAT_UNIT_CHECK) &&
|
||||
(p->chars & PMCW_CHARS_MASK_CSENSE)) {
|
||||
memcpy(sch->sense_data, irb.ecw, sizeof(irb.ecw));
|
||||
}
|
||||
|
||||
read_err:
|
||||
css_inject_io_interrupt(sch);
|
||||
}
|
||||
|
||||
static void vfio_ccw_register_io_notifier(VFIOCCWDevice *vcdev, Error **errp)
|
||||
{
|
||||
VFIODevice *vdev = &vcdev->vdev;
|
||||
struct vfio_irq_info *irq_info;
|
||||
struct vfio_irq_set *irq_set;
|
||||
size_t argsz;
|
||||
int32_t *pfd;
|
||||
|
||||
if (vdev->num_irqs < VFIO_CCW_IO_IRQ_INDEX + 1) {
|
||||
error_setg(errp, "vfio: unexpected number of io irqs %u",
|
||||
vdev->num_irqs);
|
||||
return;
|
||||
}
|
||||
|
||||
argsz = sizeof(*irq_set);
|
||||
irq_info = g_malloc0(argsz);
|
||||
irq_info->index = VFIO_CCW_IO_IRQ_INDEX;
|
||||
irq_info->argsz = argsz;
|
||||
if (ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO,
|
||||
irq_info) < 0 || irq_info->count < 1) {
|
||||
error_setg_errno(errp, errno, "vfio: Error getting irq info");
|
||||
goto out_free_info;
|
||||
}
|
||||
|
||||
if (event_notifier_init(&vcdev->io_notifier, 0)) {
|
||||
error_setg_errno(errp, errno,
|
||||
"vfio: Unable to init event notifier for IO");
|
||||
goto out_free_info;
|
||||
}
|
||||
|
||||
argsz = sizeof(*irq_set) + sizeof(*pfd);
|
||||
irq_set = g_malloc0(argsz);
|
||||
irq_set->argsz = argsz;
|
||||
irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
|
||||
VFIO_IRQ_SET_ACTION_TRIGGER;
|
||||
irq_set->index = VFIO_CCW_IO_IRQ_INDEX;
|
||||
irq_set->start = 0;
|
||||
irq_set->count = 1;
|
||||
pfd = (int32_t *) &irq_set->data;
|
||||
|
||||
*pfd = event_notifier_get_fd(&vcdev->io_notifier);
|
||||
qemu_set_fd_handler(*pfd, vfio_ccw_io_notifier_handler, NULL, vcdev);
|
||||
if (ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set)) {
|
||||
error_setg(errp, "vfio: Failed to set up io notification");
|
||||
qemu_set_fd_handler(*pfd, NULL, NULL, vcdev);
|
||||
event_notifier_cleanup(&vcdev->io_notifier);
|
||||
}
|
||||
|
||||
g_free(irq_set);
|
||||
|
||||
out_free_info:
|
||||
g_free(irq_info);
|
||||
}
|
||||
|
||||
static void vfio_ccw_unregister_io_notifier(VFIOCCWDevice *vcdev)
|
||||
{
|
||||
struct vfio_irq_set *irq_set;
|
||||
size_t argsz;
|
||||
int32_t *pfd;
|
||||
|
||||
argsz = sizeof(*irq_set) + sizeof(*pfd);
|
||||
irq_set = g_malloc0(argsz);
|
||||
irq_set->argsz = argsz;
|
||||
irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
|
||||
VFIO_IRQ_SET_ACTION_TRIGGER;
|
||||
irq_set->index = VFIO_CCW_IO_IRQ_INDEX;
|
||||
irq_set->start = 0;
|
||||
irq_set->count = 1;
|
||||
pfd = (int32_t *) &irq_set->data;
|
||||
*pfd = -1;
|
||||
|
||||
if (ioctl(vcdev->vdev.fd, VFIO_DEVICE_SET_IRQS, irq_set)) {
|
||||
error_report("vfio: Failed to de-assign device io fd: %m");
|
||||
}
|
||||
|
||||
qemu_set_fd_handler(event_notifier_get_fd(&vcdev->io_notifier),
|
||||
NULL, NULL, vcdev);
|
||||
event_notifier_cleanup(&vcdev->io_notifier);
|
||||
|
||||
g_free(irq_set);
|
||||
}
|
||||
|
||||
static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
|
||||
{
|
||||
VFIODevice *vdev = &vcdev->vdev;
|
||||
struct vfio_region_info *info;
|
||||
int ret;
|
||||
|
||||
/* Sanity check device */
|
||||
if (!(vdev->flags & VFIO_DEVICE_FLAGS_CCW)) {
|
||||
error_setg(errp, "vfio: Um, this isn't a vfio-ccw device");
|
||||
return;
|
||||
}
|
||||
|
||||
if (vdev->num_regions < VFIO_CCW_CONFIG_REGION_INDEX + 1) {
|
||||
error_setg(errp, "vfio: Unexpected number of the I/O region %u",
|
||||
vdev->num_regions);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = vfio_get_region_info(vdev, VFIO_CCW_CONFIG_REGION_INDEX, &info);
|
||||
if (ret) {
|
||||
error_setg_errno(errp, -ret, "vfio: Error getting config info");
|
||||
return;
|
||||
}
|
||||
|
||||
vcdev->io_region_size = info->size;
|
||||
if (sizeof(*vcdev->io_region) != vcdev->io_region_size) {
|
||||
error_setg(errp, "vfio: Unexpected size of the I/O region");
|
||||
g_free(info);
|
||||
return;
|
||||
}
|
||||
|
||||
vcdev->io_region_offset = info->offset;
|
||||
vcdev->io_region = g_malloc0(info->size);
|
||||
|
||||
g_free(info);
|
||||
}
|
||||
|
||||
static void vfio_ccw_put_region(VFIOCCWDevice *vcdev)
|
||||
{
|
||||
g_free(vcdev->io_region);
|
||||
}
|
||||
|
||||
static void vfio_put_device(VFIOCCWDevice *vcdev)
|
||||
{
|
||||
g_free(vcdev->vdev.name);
|
||||
vfio_put_base_device(&vcdev->vdev);
|
||||
}
|
||||
|
||||
static VFIOGroup *vfio_ccw_get_group(S390CCWDevice *cdev, Error **errp)
|
||||
{
|
||||
char *tmp, group_path[PATH_MAX];
|
||||
ssize_t len;
|
||||
int groupid;
|
||||
|
||||
tmp = g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/%s/iommu_group",
|
||||
cdev->hostid.cssid, cdev->hostid.ssid,
|
||||
cdev->hostid.devid, cdev->mdevid);
|
||||
len = readlink(tmp, group_path, sizeof(group_path));
|
||||
g_free(tmp);
|
||||
|
||||
if (len <= 0 || len >= sizeof(group_path)) {
|
||||
error_setg(errp, "vfio: no iommu_group found");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
group_path[len] = 0;
|
||||
|
||||
if (sscanf(basename(group_path), "%d", &groupid) != 1) {
|
||||
error_setg(errp, "vfio: failed to read %s", group_path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return vfio_get_group(groupid, &address_space_memory, errp);
|
||||
}
|
||||
|
||||
static void vfio_ccw_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VFIODevice *vbasedev;
|
||||
VFIOGroup *group;
|
||||
CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev);
|
||||
S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev);
|
||||
VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev);
|
||||
S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev);
|
||||
Error *err = NULL;
|
||||
|
||||
/* Call the class init function for subchannel. */
|
||||
if (cdc->realize) {
|
||||
cdc->realize(cdev, vcdev->vdev.sysfsdev, &err);
|
||||
if (err) {
|
||||
goto out_err_propagate;
|
||||
}
|
||||
}
|
||||
|
||||
group = vfio_ccw_get_group(cdev, &err);
|
||||
if (!group) {
|
||||
goto out_group_err;
|
||||
}
|
||||
|
||||
vcdev->vdev.ops = &vfio_ccw_ops;
|
||||
vcdev->vdev.type = VFIO_DEVICE_TYPE_CCW;
|
||||
vcdev->vdev.name = g_strdup_printf("%x.%x.%04x", cdev->hostid.cssid,
|
||||
cdev->hostid.ssid, cdev->hostid.devid);
|
||||
QLIST_FOREACH(vbasedev, &group->device_list, next) {
|
||||
if (strcmp(vbasedev->name, vcdev->vdev.name) == 0) {
|
||||
error_setg(&err, "vfio: subchannel %s has already been attached",
|
||||
vcdev->vdev.name);
|
||||
goto out_device_err;
|
||||
}
|
||||
}
|
||||
|
||||
if (vfio_get_device(group, cdev->mdevid, &vcdev->vdev, &err)) {
|
||||
goto out_device_err;
|
||||
}
|
||||
|
||||
vfio_ccw_get_region(vcdev, &err);
|
||||
if (err) {
|
||||
goto out_region_err;
|
||||
}
|
||||
|
||||
vfio_ccw_register_io_notifier(vcdev, &err);
|
||||
if (err) {
|
||||
goto out_notifier_err;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
out_notifier_err:
|
||||
vfio_ccw_put_region(vcdev);
|
||||
out_region_err:
|
||||
vfio_put_device(vcdev);
|
||||
out_device_err:
|
||||
vfio_put_group(group);
|
||||
out_group_err:
|
||||
if (cdc->unrealize) {
|
||||
cdc->unrealize(cdev, NULL);
|
||||
}
|
||||
out_err_propagate:
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
|
||||
static void vfio_ccw_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev);
|
||||
S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev);
|
||||
VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev);
|
||||
S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev);
|
||||
VFIOGroup *group = vcdev->vdev.group;
|
||||
|
||||
vfio_ccw_unregister_io_notifier(vcdev);
|
||||
vfio_ccw_put_region(vcdev);
|
||||
vfio_put_device(vcdev);
|
||||
vfio_put_group(group);
|
||||
|
||||
if (cdc->unrealize) {
|
||||
cdc->unrealize(cdev, errp);
|
||||
}
|
||||
}
|
||||
|
||||
static Property vfio_ccw_properties[] = {
|
||||
DEFINE_PROP_STRING("sysfsdev", VFIOCCWDevice, vdev.sysfsdev),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static const VMStateDescription vfio_ccw_vmstate = {
|
||||
.name = TYPE_VFIO_CCW,
|
||||
.unmigratable = 1,
|
||||
};
|
||||
|
||||
static void vfio_ccw_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
S390CCWDeviceClass *cdc = S390_CCW_DEVICE_CLASS(klass);
|
||||
|
||||
dc->props = vfio_ccw_properties;
|
||||
dc->vmsd = &vfio_ccw_vmstate;
|
||||
dc->desc = "VFIO-based subchannel assignment";
|
||||
dc->realize = vfio_ccw_realize;
|
||||
dc->unrealize = vfio_ccw_unrealize;
|
||||
dc->reset = vfio_ccw_reset;
|
||||
|
||||
cdc->handle_request = vfio_ccw_handle_request;
|
||||
}
|
||||
|
||||
static const TypeInfo vfio_ccw_info = {
|
||||
.name = TYPE_VFIO_CCW,
|
||||
.parent = TYPE_S390_CCW,
|
||||
.instance_size = sizeof(VFIOCCWDevice),
|
||||
.class_init = vfio_ccw_class_init,
|
||||
};
|
||||
|
||||
static void register_vfio_ccw_type(void)
|
||||
{
|
||||
type_register_static(&vfio_ccw_info);
|
||||
}
|
||||
|
||||
type_init(register_vfio_ccw_type)
|
|
@ -28,6 +28,7 @@ typedef struct VirtualCssBridge {
|
|||
/* virtual css bus type */
|
||||
typedef struct VirtualCssBus {
|
||||
BusState parent_obj;
|
||||
bool squash_mcss;
|
||||
} VirtualCssBus;
|
||||
|
||||
#define TYPE_VIRTUAL_CSS_BUS "virtual-css-bus"
|
||||
|
|
|
@ -91,10 +91,29 @@ struct SubchDev {
|
|||
/* transport-provided data: */
|
||||
int (*ccw_cb) (SubchDev *, CCW1);
|
||||
void (*disable_cb)(SubchDev *);
|
||||
int (*do_subchannel_work) (SubchDev *, ORB *);
|
||||
SenseId id;
|
||||
void *driver_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* Identify a device within the channel subsystem.
|
||||
* Note that this can be used to identify either the subchannel or
|
||||
* the attached I/O device, as there's always one I/O device per
|
||||
* subchannel.
|
||||
*/
|
||||
typedef struct CssDevId {
|
||||
uint8_t cssid;
|
||||
uint8_t ssid;
|
||||
uint16_t devid;
|
||||
bool valid;
|
||||
} CssDevId;
|
||||
|
||||
extern PropertyInfo css_devid_propinfo;
|
||||
|
||||
#define DEFINE_PROP_CSS_DEV_ID(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, css_devid_propinfo, CssDevId)
|
||||
|
||||
typedef struct IndAddr {
|
||||
hwaddr addr;
|
||||
uint64_t map;
|
||||
|
@ -116,8 +135,11 @@ bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno);
|
|||
void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid,
|
||||
uint16_t devno, SubchDev *sch);
|
||||
void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type);
|
||||
int css_sch_build_schib(SubchDev *sch, CssDevId *dev_id);
|
||||
unsigned int css_find_free_chpid(uint8_t cssid);
|
||||
uint16_t css_build_subchannel_id(SubchDev *sch);
|
||||
void copy_scsw_to_guest(SCSW *dest, const SCSW *src);
|
||||
void css_inject_io_interrupt(SubchDev *sch);
|
||||
void css_reset(void);
|
||||
void css_reset_sch(SubchDev *sch);
|
||||
void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid);
|
||||
|
@ -127,6 +149,9 @@ void css_generate_chp_crws(uint8_t cssid, uint8_t chpid);
|
|||
void css_generate_css_crws(uint8_t cssid);
|
||||
void css_clear_sei_pending(void);
|
||||
void css_adapter_interrupt(uint8_t isc);
|
||||
int s390_ccw_cmd_request(ORB *orb, SCSW *scsw, void *data);
|
||||
int do_subchannel_work_virtual(SubchDev *sub, ORB *orb);
|
||||
int do_subchannel_work_passthrough(SubchDev *sub, ORB *orb);
|
||||
|
||||
typedef enum {
|
||||
CSS_IO_ADAPTER_VIRTIO = 0,
|
||||
|
@ -164,23 +189,6 @@ int css_do_rsch(SubchDev *sch);
|
|||
int css_do_rchp(uint8_t cssid, uint8_t chpid);
|
||||
bool css_present(uint8_t cssid);
|
||||
#endif
|
||||
/*
|
||||
* Identify a device within the channel subsystem.
|
||||
* Note that this can be used to identify either the subchannel or
|
||||
* the attached I/O device, as there's always one I/O device per
|
||||
* subchannel.
|
||||
*/
|
||||
typedef struct CssDevId {
|
||||
uint8_t cssid;
|
||||
uint8_t ssid;
|
||||
uint16_t devid;
|
||||
bool valid;
|
||||
} CssDevId;
|
||||
|
||||
extern PropertyInfo css_devid_propinfo;
|
||||
|
||||
#define DEFINE_PROP_CSS_DEV_ID(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, css_devid_propinfo, CssDevId)
|
||||
|
||||
extern PropertyInfo css_devid_ro_propinfo;
|
||||
|
||||
|
@ -190,16 +198,25 @@ extern PropertyInfo css_devid_ro_propinfo;
|
|||
/**
|
||||
* Create a subchannel for the given bus id.
|
||||
*
|
||||
* If @p bus_id is valid, verify that it uses the virtual channel
|
||||
* subsystem id and is not already in use, and find a free subchannel
|
||||
* id for it. If @p bus_id is not valid, find a free subchannel id and
|
||||
* device number across all subchannel sets. If either of the former
|
||||
* actions succeed, allocate a subchannel structure, initialise it
|
||||
* with the bus id, subchannel id and device number, register it with
|
||||
* the CSS and return it. Otherwise return NULL.
|
||||
* If @p bus_id is valid, and @p squash_mcss is true, verify that it is
|
||||
* not already in use in the default css, and find a free devno from the
|
||||
* default css image for it.
|
||||
* If @p bus_id is valid, and @p squash_mcss is false, verify that it is
|
||||
* not already in use, and find a free devno for it.
|
||||
* If @p bus_id is not valid, and if either @p squash_mcss or @p is_virtual
|
||||
* is true, find a free subchannel id and device number across all
|
||||
* subchannel sets from the default css image.
|
||||
* If @p bus_id is not valid, and if both @p squash_mcss and @p is_virtual
|
||||
* are false, find a non-full css image and find a free subchannel id and
|
||||
* device number across all subchannel sets from it.
|
||||
*
|
||||
* If either of the former actions succeed, allocate a subchannel structure,
|
||||
* initialise it with the bus id, subchannel id and device number, register
|
||||
* it with the CSS and return it. Otherwise return NULL.
|
||||
*
|
||||
* The caller becomes owner of the returned subchannel structure and
|
||||
* is responsible for unregistering and freeing it.
|
||||
*/
|
||||
SubchDev *css_create_virtual_sch(CssDevId bus_id, Error **errp);
|
||||
SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss,
|
||||
Error **errp);
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* s390 CCW Assignment Support
|
||||
*
|
||||
* Copyright 2017 IBM Corp.
|
||||
* Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
|
||||
* Xiao Feng Ren <renxiaof@linux.vnet.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_S390_CCW_H
|
||||
#define HW_S390_CCW_H
|
||||
|
||||
#include "hw/s390x/ccw-device.h"
|
||||
|
||||
#define TYPE_S390_CCW "s390-ccw"
|
||||
#define S390_CCW_DEVICE(obj) \
|
||||
OBJECT_CHECK(S390CCWDevice, (obj), TYPE_S390_CCW)
|
||||
#define S390_CCW_DEVICE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(S390CCWDeviceClass, (klass), TYPE_S390_CCW)
|
||||
#define S390_CCW_DEVICE_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(S390CCWDeviceClass, (obj), TYPE_S390_CCW)
|
||||
|
||||
typedef struct S390CCWDevice {
|
||||
CcwDevice parent_obj;
|
||||
CssDevId hostid;
|
||||
char *mdevid;
|
||||
} S390CCWDevice;
|
||||
|
||||
typedef struct S390CCWDeviceClass {
|
||||
CCWDeviceClass parent_class;
|
||||
void (*realize)(S390CCWDevice *dev, char *sysfsdev, Error **errp);
|
||||
void (*unrealize)(S390CCWDevice *dev, Error **errp);
|
||||
int (*handle_request) (ORB *, SCSW *, void *);
|
||||
} S390CCWDeviceClass;
|
||||
|
||||
#endif
|
|
@ -29,6 +29,7 @@ typedef struct S390CcwMachineState {
|
|||
bool aes_key_wrap;
|
||||
bool dea_key_wrap;
|
||||
uint8_t loadparm[8];
|
||||
bool s390_squash_mcss;
|
||||
} S390CcwMachineState;
|
||||
|
||||
typedef struct S390CcwMachineClass {
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
enum {
|
||||
VFIO_DEVICE_TYPE_PCI = 0,
|
||||
VFIO_DEVICE_TYPE_PLATFORM = 1,
|
||||
VFIO_DEVICE_TYPE_CCW = 2,
|
||||
};
|
||||
|
||||
typedef struct VFIOMmap {
|
||||
|
|
|
@ -124,7 +124,7 @@
|
|||
* Recommend using hypercall for address space switches rather
|
||||
* than MOV to CR3 instruction
|
||||
*/
|
||||
#define HV_X64_MWAIT_RECOMMENDED (1 << 0)
|
||||
#define HV_X64_AS_SWITCH_RECOMMENDED (1 << 0)
|
||||
/* Recommend using hypercall for local TLB flushes rather
|
||||
* than INVLPG or MOV to CR3 instructions */
|
||||
#define HV_X64_LOCAL_TLB_FLUSH_RECOMMENDED (1 << 1)
|
||||
|
@ -147,6 +147,11 @@
|
|||
*/
|
||||
#define HV_X64_RELAXED_TIMING_RECOMMENDED (1 << 5)
|
||||
|
||||
/*
|
||||
* Virtual APIC support
|
||||
*/
|
||||
#define HV_X64_DEPRECATING_AEOI_RECOMMENDED (1 << 9)
|
||||
|
||||
/*
|
||||
* Crash notification flag.
|
||||
*/
|
||||
|
|
|
@ -641,6 +641,7 @@
|
|||
* e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.)
|
||||
*/
|
||||
#define KEY_DATA 0x277
|
||||
#define KEY_ONSCREEN_KEYBOARD 0x278
|
||||
|
||||
#define BTN_TRIGGER_HAPPY 0x2c0
|
||||
#define BTN_TRIGGER_HAPPY1 0x2c0
|
||||
|
|
|
@ -58,9 +58,14 @@ struct input_id {
|
|||
* Note that input core does not clamp reported values to the
|
||||
* [minimum, maximum] limits, such task is left to userspace.
|
||||
*
|
||||
* Resolution for main axes (ABS_X, ABS_Y, ABS_Z) is reported in
|
||||
* units per millimeter (units/mm), resolution for rotational axes
|
||||
* (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian.
|
||||
* The default resolution for main axes (ABS_X, ABS_Y, ABS_Z)
|
||||
* is reported in units per millimeter (units/mm), resolution
|
||||
* for rotational axes (ABS_RX, ABS_RY, ABS_RZ) is reported
|
||||
* in units per radian.
|
||||
* When INPUT_PROP_ACCELEROMETER is set the resolution changes.
|
||||
* The main axes (ABS_X, ABS_Y, ABS_Z) are then reported in
|
||||
* in units per g (units/g) and in units per degree per second
|
||||
* (units/deg/s) for rotational axes (ABS_RX, ABS_RY, ABS_RZ).
|
||||
*/
|
||||
struct input_absinfo {
|
||||
int32_t value;
|
||||
|
|
|
@ -114,7 +114,7 @@
|
|||
#define PCI_SUBSYSTEM_ID 0x2e
|
||||
#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */
|
||||
#define PCI_ROM_ADDRESS_ENABLE 0x01
|
||||
#define PCI_ROM_ADDRESS_MASK (~0x7ffUL)
|
||||
#define PCI_ROM_ADDRESS_MASK (~0x7ffU)
|
||||
|
||||
#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */
|
||||
|
||||
|
@ -630,6 +630,7 @@
|
|||
#define PCI_EXP_DEVCTL2_COMP_TIMEOUT 0x000f /* Completion Timeout Value */
|
||||
#define PCI_EXP_DEVCTL2_ARI 0x0020 /* Alternative Routing-ID */
|
||||
#define PCI_EXP_DEVCTL2_ATOMIC_REQ 0x0040 /* Set Atomic requests */
|
||||
#define PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK 0x0080 /* Block atomic egress */
|
||||
#define PCI_EXP_DEVCTL2_IDO_REQ_EN 0x0100 /* Allow IDO for requests */
|
||||
#define PCI_EXP_DEVCTL2_IDO_CMP_EN 0x0200 /* Allow IDO for completions */
|
||||
#define PCI_EXP_DEVCTL2_LTR_EN 0x0400 /* Enable LTR mechanism */
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#define __KVM_HAVE_IRQ_LINE
|
||||
#define __KVM_HAVE_READONLY_MEM
|
||||
|
||||
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
|
||||
|
||||
#define KVM_REG_SIZE(id) \
|
||||
(1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
|
||||
|
||||
|
@ -114,6 +116,8 @@ struct kvm_debug_exit_arch {
|
|||
};
|
||||
|
||||
struct kvm_sync_regs {
|
||||
/* Used with KVM_CAP_ARM_USER_IRQ */
|
||||
__u64 device_irq_level;
|
||||
};
|
||||
|
||||
struct kvm_arch_memory_slot {
|
||||
|
@ -192,13 +196,17 @@ struct kvm_arch_memory_slot {
|
|||
#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
|
||||
#define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6
|
||||
#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
|
||||
#define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8
|
||||
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10
|
||||
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
|
||||
(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
|
||||
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff
|
||||
#define VGIC_LEVEL_INFO_LINE_LEVEL 0
|
||||
|
||||
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
|
||||
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
|
||||
#define KVM_DEV_ARM_ITS_SAVE_TABLES 1
|
||||
#define KVM_DEV_ARM_ITS_RESTORE_TABLES 2
|
||||
#define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3
|
||||
|
||||
/* KVM_IRQ_LINE irq field index values */
|
||||
#define KVM_ARM_IRQ_TYPE_SHIFT 24
|
||||
|
|
|
@ -353,5 +353,6 @@
|
|||
#define __NR_pkey_mprotect (__NR_SYSCALL_BASE + 394)
|
||||
#define __NR_pkey_alloc (__NR_SYSCALL_BASE + 395)
|
||||
#define __NR_pkey_free (__NR_SYSCALL_BASE + 396)
|
||||
#define __NR_statx (__NR_SYSCALL_BASE + 397)
|
||||
|
||||
#endif /* _ASM_ARM_UNISTD_COMMON_H */
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
#define __KVM_HAVE_IRQ_LINE
|
||||
#define __KVM_HAVE_READONLY_MEM
|
||||
|
||||
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
|
||||
|
||||
#define KVM_REG_SIZE(id) \
|
||||
(1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
|
||||
|
||||
|
@ -143,6 +145,8 @@ struct kvm_debug_exit_arch {
|
|||
#define KVM_GUESTDBG_USE_HW (1 << 17)
|
||||
|
||||
struct kvm_sync_regs {
|
||||
/* Used with KVM_CAP_ARM_USER_IRQ */
|
||||
__u64 device_irq_level;
|
||||
};
|
||||
|
||||
struct kvm_arch_memory_slot {
|
||||
|
@ -212,13 +216,17 @@ struct kvm_arch_memory_slot {
|
|||
#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
|
||||
#define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6
|
||||
#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
|
||||
#define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8
|
||||
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10
|
||||
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
|
||||
(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
|
||||
#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff
|
||||
#define VGIC_LEVEL_INFO_LINE_LEVEL 0
|
||||
|
||||
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
|
||||
#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
|
||||
#define KVM_DEV_ARM_ITS_SAVE_TABLES 1
|
||||
#define KVM_DEV_ARM_ITS_RESTORE_TABLES 2
|
||||
#define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3
|
||||
|
||||
/* Device Control API on vcpu fd */
|
||||
#define KVM_ARM_VCPU_PMU_V3_CTRL 0
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
#define __KVM_HAVE_IRQ_LINE
|
||||
#define __KVM_HAVE_GUEST_DEBUG
|
||||
|
||||
/* Not always available, but if it is, this is the correct offset. */
|
||||
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
|
||||
|
||||
struct kvm_regs {
|
||||
__u64 pc;
|
||||
__u64 cr;
|
||||
|
|
|
@ -393,5 +393,6 @@
|
|||
#define __NR_preadv2 380
|
||||
#define __NR_pwritev2 381
|
||||
#define __NR_kexec_file_load 382
|
||||
#define __NR_statx 383
|
||||
|
||||
#endif /* _ASM_POWERPC_UNISTD_H_ */
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#define KVM_DEV_FLIC_ADAPTER_REGISTER 6
|
||||
#define KVM_DEV_FLIC_ADAPTER_MODIFY 7
|
||||
#define KVM_DEV_FLIC_CLEAR_IO_IRQ 8
|
||||
#define KVM_DEV_FLIC_AISM 9
|
||||
#define KVM_DEV_FLIC_AIRQ_INJECT 10
|
||||
/*
|
||||
* We can have up to 4*64k pending subchannels + 8 adapter interrupts,
|
||||
* as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts.
|
||||
|
@ -41,7 +43,14 @@ struct kvm_s390_io_adapter {
|
|||
__u8 isc;
|
||||
__u8 maskable;
|
||||
__u8 swap;
|
||||
__u8 pad;
|
||||
__u8 flags;
|
||||
};
|
||||
|
||||
#define KVM_S390_ADAPTER_SUPPRESSIBLE 0x01
|
||||
|
||||
struct kvm_s390_ais_req {
|
||||
__u8 isc;
|
||||
__u16 mode;
|
||||
};
|
||||
|
||||
#define KVM_S390_IO_ADAPTER_MASK 1
|
||||
|
@ -110,6 +119,7 @@ struct kvm_s390_vm_cpu_machine {
|
|||
#define KVM_S390_VM_CPU_FEAT_CMMA 10
|
||||
#define KVM_S390_VM_CPU_FEAT_PFMFI 11
|
||||
#define KVM_S390_VM_CPU_FEAT_SIGPIF 12
|
||||
#define KVM_S390_VM_CPU_FEAT_KSS 13
|
||||
struct kvm_s390_vm_cpu_feat {
|
||||
__u64 feat[16];
|
||||
};
|
||||
|
@ -131,7 +141,8 @@ struct kvm_s390_vm_cpu_subfunc {
|
|||
__u8 kmo[16]; /* with MSA4 */
|
||||
__u8 pcc[16]; /* with MSA4 */
|
||||
__u8 ppno[16]; /* with MSA5 */
|
||||
__u8 reserved[1824];
|
||||
__u8 kma[16]; /* with MSA8 */
|
||||
__u8 reserved[1808];
|
||||
};
|
||||
|
||||
/* kvm attributes for crypto */
|
||||
|
@ -197,6 +208,10 @@ struct kvm_guest_debug_arch {
|
|||
#define KVM_SYNC_VRS (1UL << 6)
|
||||
#define KVM_SYNC_RICCB (1UL << 7)
|
||||
#define KVM_SYNC_FPRS (1UL << 8)
|
||||
#define KVM_SYNC_GSCB (1UL << 9)
|
||||
/* length and alignment of the sdnx as a power of two */
|
||||
#define SDNXC 8
|
||||
#define SDNXL (1UL << SDNXC)
|
||||
/* definition of registers in kvm_run */
|
||||
struct kvm_sync_regs {
|
||||
__u64 prefix; /* prefix register */
|
||||
|
@ -217,8 +232,16 @@ struct kvm_sync_regs {
|
|||
};
|
||||
__u8 reserved[512]; /* for future vector expansion */
|
||||
__u32 fpc; /* valid on KVM_SYNC_VRS or KVM_SYNC_FPRS */
|
||||
__u8 padding[52]; /* riccb needs to be 64byte aligned */
|
||||
__u8 padding1[52]; /* riccb needs to be 64byte aligned */
|
||||
__u8 riccb[64]; /* runtime instrumentation controls block */
|
||||
__u8 padding2[192]; /* sdnx needs to be 256byte aligned */
|
||||
union {
|
||||
__u8 sdnx[SDNXL]; /* state description annex */
|
||||
struct {
|
||||
__u64 reserved1[2];
|
||||
__u64 gscb[4];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#define KVM_REG_S390_TODPR (KVM_REG_S390 | KVM_REG_SIZE_U32 | 0x1)
|
||||
|
|
|
@ -313,7 +313,9 @@
|
|||
#define __NR_copy_file_range 375
|
||||
#define __NR_preadv2 376
|
||||
#define __NR_pwritev2 377
|
||||
#define NR_syscalls 378
|
||||
#define __NR_s390_guarded_storage 378
|
||||
#define __NR_statx 379
|
||||
#define NR_syscalls 380
|
||||
|
||||
/*
|
||||
* There are some system calls that are not present on 64 bit, some
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
#define KVM_PIO_PAGE_OFFSET 1
|
||||
#define KVM_COALESCED_MMIO_PAGE_OFFSET 2
|
||||
|
||||
#define DE_VECTOR 0
|
||||
#define DB_VECTOR 1
|
||||
#define BP_VECTOR 3
|
||||
|
|
|
@ -380,5 +380,7 @@
|
|||
#define __NR_pkey_mprotect 380
|
||||
#define __NR_pkey_alloc 381
|
||||
#define __NR_pkey_free 382
|
||||
#define __NR_statx 383
|
||||
#define __NR_arch_prctl 384
|
||||
|
||||
#endif /* _ASM_X86_UNISTD_32_H */
|
||||
|
|
|
@ -333,5 +333,6 @@
|
|||
#define __NR_pkey_mprotect 329
|
||||
#define __NR_pkey_alloc 330
|
||||
#define __NR_pkey_free 331
|
||||
#define __NR_statx 332
|
||||
|
||||
#endif /* _ASM_X86_UNISTD_64_H */
|
||||
|
|
|
@ -286,6 +286,7 @@
|
|||
#define __NR_pkey_mprotect (__X32_SYSCALL_BIT + 329)
|
||||
#define __NR_pkey_alloc (__X32_SYSCALL_BIT + 330)
|
||||
#define __NR_pkey_free (__X32_SYSCALL_BIT + 331)
|
||||
#define __NR_statx (__X32_SYSCALL_BIT + 332)
|
||||
#define __NR_rt_sigaction (__X32_SYSCALL_BIT + 512)
|
||||
#define __NR_rt_sigreturn (__X32_SYSCALL_BIT + 513)
|
||||
#define __NR_ioctl (__X32_SYSCALL_BIT + 514)
|
||||
|
|
|
@ -702,6 +702,10 @@ struct kvm_ppc_resize_hpt {
|
|||
#define KVM_VM_PPC_HV 1
|
||||
#define KVM_VM_PPC_PR 2
|
||||
|
||||
/* on MIPS, 0 forces trap & emulate, 1 forces VZ ASE */
|
||||
#define KVM_VM_MIPS_TE 0
|
||||
#define KVM_VM_MIPS_VZ 1
|
||||
|
||||
#define KVM_S390_SIE_PAGE_OFFSET 1
|
||||
|
||||
/*
|
||||
|
@ -883,6 +887,14 @@ struct kvm_ppc_resize_hpt {
|
|||
#define KVM_CAP_PPC_MMU_RADIX 134
|
||||
#define KVM_CAP_PPC_MMU_HASH_V3 135
|
||||
#define KVM_CAP_IMMEDIATE_EXIT 136
|
||||
#define KVM_CAP_MIPS_VZ 137
|
||||
#define KVM_CAP_MIPS_TE 138
|
||||
#define KVM_CAP_MIPS_64BIT 139
|
||||
#define KVM_CAP_S390_GS 140
|
||||
#define KVM_CAP_S390_AIS 141
|
||||
#define KVM_CAP_SPAPR_TCE_VFIO 142
|
||||
#define KVM_CAP_X86_GUEST_MWAIT 143
|
||||
#define KVM_CAP_ARM_USER_IRQ 144
|
||||
|
||||
#ifdef KVM_CAP_IRQ_ROUTING
|
||||
|
||||
|
@ -1087,6 +1099,7 @@ struct kvm_device_attr {
|
|||
#define KVM_DEV_VFIO_GROUP 1
|
||||
#define KVM_DEV_VFIO_GROUP_ADD 1
|
||||
#define KVM_DEV_VFIO_GROUP_DEL 2
|
||||
#define KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE 3
|
||||
|
||||
enum kvm_device_type {
|
||||
KVM_DEV_TYPE_FSL_MPIC_20 = 1,
|
||||
|
@ -1108,6 +1121,11 @@ enum kvm_device_type {
|
|||
KVM_DEV_TYPE_MAX,
|
||||
};
|
||||
|
||||
struct kvm_vfio_spapr_tce {
|
||||
__s32 groupfd;
|
||||
__s32 tablefd;
|
||||
};
|
||||
|
||||
/*
|
||||
* ioctls for VM fds
|
||||
*/
|
||||
|
@ -1354,4 +1372,11 @@ struct kvm_assigned_msix_entry {
|
|||
#define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0)
|
||||
#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1)
|
||||
|
||||
/* Available with KVM_CAP_ARM_USER_IRQ */
|
||||
|
||||
/* Bits for run->s.regs.device_irq_level */
|
||||
#define KVM_ARM_DEV_EL1_VTIMER (1 << 0)
|
||||
#define KVM_ARM_DEV_EL1_PTIMER (1 << 1)
|
||||
#define KVM_ARM_DEV_PMU (1 << 2)
|
||||
|
||||
#endif /* __LINUX_KVM_H */
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
#define UFFD_API ((__u64)0xAA)
|
||||
#define UFFD_API_FEATURES (UFFD_FEATURE_EVENT_FORK | \
|
||||
UFFD_FEATURE_EVENT_REMAP | \
|
||||
UFFD_FEATURE_EVENT_MADVDONTNEED | \
|
||||
UFFD_FEATURE_EVENT_REMOVE | \
|
||||
UFFD_FEATURE_EVENT_UNMAP | \
|
||||
UFFD_FEATURE_MISSING_HUGETLBFS | \
|
||||
UFFD_FEATURE_MISSING_SHMEM)
|
||||
#define UFFD_API_IOCTLS \
|
||||
|
@ -92,7 +93,7 @@ struct uffd_msg {
|
|||
struct {
|
||||
__u64 start;
|
||||
__u64 end;
|
||||
} madv_dn;
|
||||
} remove;
|
||||
|
||||
struct {
|
||||
/* unused reserved fields */
|
||||
|
@ -109,7 +110,8 @@ struct uffd_msg {
|
|||
#define UFFD_EVENT_PAGEFAULT 0x12
|
||||
#define UFFD_EVENT_FORK 0x13
|
||||
#define UFFD_EVENT_REMAP 0x14
|
||||
#define UFFD_EVENT_MADVDONTNEED 0x15
|
||||
#define UFFD_EVENT_REMOVE 0x15
|
||||
#define UFFD_EVENT_UNMAP 0x16
|
||||
|
||||
/* flags for UFFD_EVENT_PAGEFAULT */
|
||||
#define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */
|
||||
|
@ -155,9 +157,10 @@ struct uffdio_api {
|
|||
#define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0)
|
||||
#define UFFD_FEATURE_EVENT_FORK (1<<1)
|
||||
#define UFFD_FEATURE_EVENT_REMAP (1<<2)
|
||||
#define UFFD_FEATURE_EVENT_MADVDONTNEED (1<<3)
|
||||
#define UFFD_FEATURE_EVENT_REMOVE (1<<3)
|
||||
#define UFFD_FEATURE_MISSING_HUGETLBFS (1<<4)
|
||||
#define UFFD_FEATURE_MISSING_SHMEM (1<<5)
|
||||
#define UFFD_FEATURE_EVENT_UNMAP (1<<6)
|
||||
__u64 features;
|
||||
|
||||
__u64 ioctls;
|
||||
|
|
|
@ -198,6 +198,7 @@ struct vfio_device_info {
|
|||
#define VFIO_DEVICE_FLAGS_PCI (1 << 1) /* vfio-pci device */
|
||||
#define VFIO_DEVICE_FLAGS_PLATFORM (1 << 2) /* vfio-platform device */
|
||||
#define VFIO_DEVICE_FLAGS_AMBA (1 << 3) /* vfio-amba device */
|
||||
#define VFIO_DEVICE_FLAGS_CCW (1 << 4) /* vfio-ccw device */
|
||||
__u32 num_regions; /* Max region index + 1 */
|
||||
__u32 num_irqs; /* Max IRQ index + 1 */
|
||||
};
|
||||
|
@ -212,6 +213,7 @@ struct vfio_device_info {
|
|||
#define VFIO_DEVICE_API_PCI_STRING "vfio-pci"
|
||||
#define VFIO_DEVICE_API_PLATFORM_STRING "vfio-platform"
|
||||
#define VFIO_DEVICE_API_AMBA_STRING "vfio-amba"
|
||||
#define VFIO_DEVICE_API_CCW_STRING "vfio-ccw"
|
||||
|
||||
/**
|
||||
* VFIO_DEVICE_GET_REGION_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 8,
|
||||
|
@ -446,6 +448,22 @@ enum {
|
|||
VFIO_PCI_NUM_IRQS
|
||||
};
|
||||
|
||||
/*
|
||||
* The vfio-ccw bus driver makes use of the following fixed region and
|
||||
* IRQ index mapping. Unimplemented regions return a size of zero.
|
||||
* Unimplemented IRQ types return a count of zero.
|
||||
*/
|
||||
|
||||
enum {
|
||||
VFIO_CCW_CONFIG_REGION_INDEX,
|
||||
VFIO_CCW_NUM_REGIONS
|
||||
};
|
||||
|
||||
enum {
|
||||
VFIO_CCW_IO_IRQ_INDEX,
|
||||
VFIO_CCW_NUM_IRQS
|
||||
};
|
||||
|
||||
/**
|
||||
* VFIO_DEVICE_GET_PCI_HOT_RESET_INFO - _IORW(VFIO_TYPE, VFIO_BASE + 12,
|
||||
* struct vfio_pci_hot_reset_info)
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Interfaces for vfio-ccw
|
||||
*
|
||||
* Copyright IBM Corp. 2017
|
||||
*
|
||||
* Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
|
||||
*/
|
||||
|
||||
#ifndef _VFIO_CCW_H_
|
||||
#define _VFIO_CCW_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct ccw_io_region {
|
||||
#define ORB_AREA_SIZE 12
|
||||
__u8 orb_area[ORB_AREA_SIZE];
|
||||
#define SCSW_AREA_SIZE 12
|
||||
__u8 scsw_area[SCSW_AREA_SIZE];
|
||||
#define IRB_AREA_SIZE 96
|
||||
__u8 irb_area[IRB_AREA_SIZE];
|
||||
__u32 ret_code;
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif
|
Binary file not shown.
|
@ -42,6 +42,13 @@ typedef unsigned long long __u64;
|
|||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MIN_NON_ZERO
|
||||
#define MIN_NON_ZERO(a, b) ((a) == 0 ? (b) : \
|
||||
((b) == 0 ? (a) : (MIN(a, b))))
|
||||
#endif
|
||||
|
||||
#include "cio.h"
|
||||
#include "iplb.h"
|
||||
|
|
|
@ -26,6 +26,15 @@
|
|||
#define SCSI_SENSE_KEY_NO_SENSE 0
|
||||
#define SCSI_SENSE_KEY_UNIT_ATTENTION 6
|
||||
|
||||
/* SCSI Inquiry Types */
|
||||
#define SCSI_INQUIRY_STANDARD 0x00U
|
||||
#define SCSI_INQUIRY_EVPD 0x01U
|
||||
|
||||
/* SCSI Inquiry Pages */
|
||||
#define SCSI_INQUIRY_STANDARD_NONE 0x00U
|
||||
#define SCSI_INQUIRY_EVPD_SUPPORTED_PAGES 0x00U
|
||||
#define SCSI_INQUIRY_EVPD_BLOCK_LIMITS 0xb0U
|
||||
|
||||
union ScsiLun {
|
||||
uint64_t v64; /* numeric shortcut */
|
||||
uint8_t v8[8]; /* generic 8 bytes representation */
|
||||
|
@ -71,6 +80,27 @@ struct ScsiInquiryStd {
|
|||
} __attribute__((packed));
|
||||
typedef struct ScsiInquiryStd ScsiInquiryStd;
|
||||
|
||||
struct ScsiInquiryEvpdPages {
|
||||
uint8_t peripheral_qdt; /* b0, use (b0 & 0x1f) to get SCSI_INQ_RDT */
|
||||
uint8_t page_code; /* b1 */
|
||||
uint16_t page_length; /* b2..b3 length = N-3 */
|
||||
uint8_t byte[28]; /* b4..bN Supported EVPD pages (N=31 here) */
|
||||
} __attribute__((packed));
|
||||
typedef struct ScsiInquiryEvpdPages ScsiInquiryEvpdPages;
|
||||
|
||||
struct ScsiInquiryEvpdBl {
|
||||
uint8_t peripheral_qdt; /* b0, use (b0 & 0x1f) to get SCSI_INQ_RDT */
|
||||
uint8_t page_code;
|
||||
uint16_t page_length;
|
||||
uint8_t b4;
|
||||
uint8_t b5;
|
||||
uint16_t b6;
|
||||
uint32_t max_transfer; /* b8 */
|
||||
uint32_t b12[7]; /* b12..b43 (defined fields) */
|
||||
uint32_t b44[5]; /* b44..b63 (reserved fields) */
|
||||
} __attribute__((packed));
|
||||
typedef struct ScsiInquiryEvpdBl ScsiInquiryEvpdBl;
|
||||
|
||||
struct ScsiCdbInquiry {
|
||||
uint8_t command; /* b0, == 0x12 */
|
||||
uint8_t b1; /* b1, |= 0x01 (evpd) */
|
||||
|
|
|
@ -19,6 +19,8 @@ static VirtioScsiCmdReq req;
|
|||
static VirtioScsiCmdResp resp;
|
||||
|
||||
static uint8_t scsi_inquiry_std_response[256];
|
||||
static ScsiInquiryEvpdPages scsi_inquiry_evpd_pages_response;
|
||||
static ScsiInquiryEvpdBl scsi_inquiry_evpd_bl_response;
|
||||
|
||||
static inline void vs_assert(bool term, const char **msgs)
|
||||
{
|
||||
|
@ -89,10 +91,13 @@ static void vs_run(const char *title, VirtioCmd *cmd, VDev *vdev,
|
|||
|
||||
/* SCSI protocol implementation routines */
|
||||
|
||||
static bool scsi_inquiry(VDev *vdev, void *data, uint32_t data_size)
|
||||
static bool scsi_inquiry(VDev *vdev, uint8_t evpd, uint8_t page,
|
||||
void *data, uint32_t data_size)
|
||||
{
|
||||
ScsiCdbInquiry cdb = {
|
||||
.command = 0x12,
|
||||
.b1 = evpd,
|
||||
.b2 = page,
|
||||
.alloc_len = data_size < 65535 ? data_size : 65535,
|
||||
};
|
||||
VirtioCmd inquiry[] = {
|
||||
|
@ -142,19 +147,18 @@ static bool scsi_report_luns(VDev *vdev, void *data, uint32_t data_size)
|
|||
}
|
||||
|
||||
static bool scsi_read_10(VDev *vdev,
|
||||
ulong sector, int sectors, void *data)
|
||||
ulong sector, int sectors, void *data,
|
||||
unsigned int data_size)
|
||||
{
|
||||
int f = vdev->blk_factor;
|
||||
unsigned int data_size = sectors * virtio_get_block_size() * f;
|
||||
ScsiCdbRead10 cdb = {
|
||||
.command = 0x28,
|
||||
.lba = sector * f,
|
||||
.xfer_length = sectors * f,
|
||||
.lba = sector,
|
||||
.xfer_length = sectors,
|
||||
};
|
||||
VirtioCmd read_10[] = {
|
||||
{ &req, sizeof(req), VRING_DESC_F_NEXT },
|
||||
{ &resp, sizeof(resp), VRING_DESC_F_WRITE | VRING_DESC_F_NEXT },
|
||||
{ data, data_size * f, VRING_DESC_F_WRITE },
|
||||
{ data, data_size, VRING_DESC_F_WRITE },
|
||||
};
|
||||
|
||||
debug_print_int("read_10 sector", sector);
|
||||
|
@ -203,6 +207,7 @@ static void virtio_scsi_locate_device(VDev *vdev)
|
|||
debug_print_int("config.scsi.max_channel", vdev->config.scsi.max_channel);
|
||||
debug_print_int("config.scsi.max_target ", vdev->config.scsi.max_target);
|
||||
debug_print_int("config.scsi.max_lun ", vdev->config.scsi.max_lun);
|
||||
debug_print_int("config.scsi.max_sectors", vdev->config.scsi.max_sectors);
|
||||
|
||||
if (vdev->scsi_device_selected) {
|
||||
sdev->channel = vdev->selected_scsi_device.channel;
|
||||
|
@ -255,9 +260,23 @@ static void virtio_scsi_locate_device(VDev *vdev)
|
|||
int virtio_scsi_read_many(VDev *vdev,
|
||||
ulong sector, void *load_addr, int sec_num)
|
||||
{
|
||||
if (!scsi_read_10(vdev, sector, sec_num, load_addr)) {
|
||||
virtio_scsi_verify_response(&resp, "virtio-scsi:read_many");
|
||||
}
|
||||
int sector_count;
|
||||
int f = vdev->blk_factor;
|
||||
unsigned int data_size;
|
||||
unsigned int max_transfer = MIN_NON_ZERO(vdev->config.scsi.max_sectors,
|
||||
vdev->max_transfer);
|
||||
|
||||
do {
|
||||
sector_count = MIN_NON_ZERO(sec_num, max_transfer);
|
||||
data_size = sector_count * virtio_get_block_size() * f;
|
||||
if (!scsi_read_10(vdev, sector * f, sector_count * f, load_addr,
|
||||
data_size)) {
|
||||
virtio_scsi_verify_response(&resp, "virtio-scsi:read_many");
|
||||
}
|
||||
load_addr += data_size;
|
||||
sector += sector_count;
|
||||
sec_num -= sector_count;
|
||||
} while (sec_num > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -304,6 +323,9 @@ void virtio_scsi_setup(VDev *vdev)
|
|||
int retry_test_unit_ready = 3;
|
||||
uint8_t data[256];
|
||||
uint32_t data_size = sizeof(data);
|
||||
ScsiInquiryEvpdPages *evpd = &scsi_inquiry_evpd_pages_response;
|
||||
ScsiInquiryEvpdBl *evpd_bl = &scsi_inquiry_evpd_bl_response;
|
||||
int i;
|
||||
|
||||
vdev->scsi_device = &default_scsi_device;
|
||||
virtio_scsi_locate_device(vdev);
|
||||
|
@ -334,7 +356,10 @@ void virtio_scsi_setup(VDev *vdev)
|
|||
}
|
||||
|
||||
/* read and cache SCSI INQUIRY response */
|
||||
if (!scsi_inquiry(vdev, scsi_inquiry_std_response,
|
||||
if (!scsi_inquiry(vdev,
|
||||
SCSI_INQUIRY_STANDARD,
|
||||
SCSI_INQUIRY_STANDARD_NONE,
|
||||
scsi_inquiry_std_response,
|
||||
sizeof(scsi_inquiry_std_response))) {
|
||||
virtio_scsi_verify_response(&resp, "virtio-scsi:setup:inquiry");
|
||||
}
|
||||
|
@ -345,6 +370,44 @@ void virtio_scsi_setup(VDev *vdev)
|
|||
vdev->scsi_block_size = VIRTIO_ISO_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
if (!scsi_inquiry(vdev,
|
||||
SCSI_INQUIRY_EVPD,
|
||||
SCSI_INQUIRY_EVPD_SUPPORTED_PAGES,
|
||||
evpd,
|
||||
sizeof(*evpd))) {
|
||||
virtio_scsi_verify_response(&resp, "virtio-scsi:setup:supported_pages");
|
||||
}
|
||||
|
||||
debug_print_int("EVPD length", evpd->page_length);
|
||||
|
||||
for (i = 0; i <= evpd->page_length; i++) {
|
||||
debug_print_int("supported EVPD page", evpd->byte[i]);
|
||||
|
||||
if (evpd->byte[i] != SCSI_INQUIRY_EVPD_BLOCK_LIMITS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!scsi_inquiry(vdev,
|
||||
SCSI_INQUIRY_EVPD,
|
||||
SCSI_INQUIRY_EVPD_BLOCK_LIMITS,
|
||||
evpd_bl,
|
||||
sizeof(*evpd_bl))) {
|
||||
virtio_scsi_verify_response(&resp, "virtio-scsi:setup:blocklimits");
|
||||
}
|
||||
|
||||
debug_print_int("max transfer", evpd_bl->max_transfer);
|
||||
vdev->max_transfer = evpd_bl->max_transfer;
|
||||
}
|
||||
|
||||
/*
|
||||
* The host sg driver will often be unhappy with particularly large
|
||||
* I/Os that exceed the block iovec limits. Let's enforce something
|
||||
* reasonable, despite what the device configuration tells us.
|
||||
*/
|
||||
|
||||
vdev->max_transfer = MIN_NON_ZERO(VIRTIO_SCSI_MAX_SECTORS,
|
||||
vdev->max_transfer);
|
||||
|
||||
if (!scsi_read_capacity(vdev, data, data_size)) {
|
||||
virtio_scsi_verify_response(&resp, "virtio-scsi:setup:read_capacity");
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#define VIRTIO_SCSI_CDB_SIZE SCSI_DEFAULT_CDB_SIZE
|
||||
#define VIRTIO_SCSI_SENSE_SIZE SCSI_DEFAULT_SENSE_SIZE
|
||||
|
||||
#define VIRTIO_SCSI_MAX_SECTORS 2048
|
||||
|
||||
/* command-specific response values */
|
||||
#define VIRTIO_SCSI_S_OK 0x00
|
||||
#define VIRTIO_SCSI_S_BAD_TARGET 0x03
|
||||
|
|
|
@ -277,6 +277,7 @@ struct VDev {
|
|||
bool scsi_device_selected;
|
||||
ScsiDevice selected_scsi_device;
|
||||
uint64_t netboot_start_addr;
|
||||
uint32_t max_transfer;
|
||||
};
|
||||
typedef struct VDev VDev;
|
||||
|
||||
|
|
|
@ -42,7 +42,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
|
|||
" dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n"
|
||||
" suppress-vmdesc=on|off disables self-describing migration (default=off)\n"
|
||||
" nvdimm=on|off controls NVDIMM support (default=off)\n"
|
||||
" enforce-config-section=on|off enforce configuration section migration (default=off)\n",
|
||||
" enforce-config-section=on|off enforce configuration section migration (default=off)\n"
|
||||
" s390-squash-mcss=on|off controls support for squashing into default css (default=off)\n",
|
||||
QEMU_ARCH_ALL)
|
||||
STEXI
|
||||
@item -machine [type=]@var{name}[,prop=@var{value}[,...]]
|
||||
|
@ -81,6 +82,9 @@ controls whether DEA wrapping keys will be created to allow
|
|||
execution of DEA cryptographic functions. The default is on.
|
||||
@item nvdimm=on|off
|
||||
Enables or disables NVDIMM support. The default is off.
|
||||
@item s390-squash-mcss=on|off
|
||||
Enables or disables squashing subchannels into the default css.
|
||||
The default is off.
|
||||
@end table
|
||||
ETEXI
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ done
|
|||
|
||||
rm -rf "$output/linux-headers/linux"
|
||||
mkdir -p "$output/linux-headers/linux"
|
||||
for header in kvm.h kvm_para.h vfio.h vhost.h \
|
||||
for header in kvm.h kvm_para.h vfio.h vfio_ccw.h vhost.h \
|
||||
psci.h userfaultfd.h; do
|
||||
cp "$tmpdir/include/linux/$header" "$output/linux-headers/linux"
|
||||
done
|
||||
|
|
|
@ -92,9 +92,10 @@ static void s390_cpu_initial_reset(CPUState *s)
|
|||
int i;
|
||||
|
||||
s390_cpu_reset(s);
|
||||
/* initial reset does not touch regs,fregs and aregs */
|
||||
memset(&env->fpc, 0, offsetof(CPUS390XState, end_reset_fields) -
|
||||
offsetof(CPUS390XState, fpc));
|
||||
/* initial reset does not clear everything! */
|
||||
memset(&env->start_initial_reset_fields, 0,
|
||||
offsetof(CPUS390XState, end_reset_fields) -
|
||||
offsetof(CPUS390XState, start_initial_reset_fields));
|
||||
|
||||
/* architectured initial values for CR 0 and 14 */
|
||||
env->cregs[0] = CR0_RESET;
|
||||
|
|
|
@ -88,6 +88,10 @@ typedef struct CPUS390XState {
|
|||
*/
|
||||
CPU_DoubleU vregs[32][2]; /* vector registers */
|
||||
uint32_t aregs[16]; /* access registers */
|
||||
uint8_t riccb[64]; /* runtime instrumentation control */
|
||||
|
||||
/* Fields up to this point are not cleared by initial CPU reset */
|
||||
struct {} start_initial_reset_fields;
|
||||
|
||||
uint32_t fpc; /* floating-point control register */
|
||||
uint32_t cc_op;
|
||||
|
@ -137,8 +141,6 @@ typedef struct CPUS390XState {
|
|||
uint64_t gbea;
|
||||
uint64_t pp;
|
||||
|
||||
uint8_t riccb[64];
|
||||
|
||||
/* Fields up to this point are cleared by a CPU reset */
|
||||
struct {} end_reset_fields;
|
||||
|
||||
|
@ -1256,6 +1258,16 @@ static inline void s390_crypto_reset(void)
|
|||
}
|
||||
}
|
||||
|
||||
static inline bool s390_get_squash_mcss(void)
|
||||
{
|
||||
if (object_property_get_bool(OBJECT(qdev_get_machine()), "s390-squash-mcss",
|
||||
NULL)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* machine check interruption code */
|
||||
|
||||
/* subclasses */
|
||||
|
|
|
@ -244,6 +244,15 @@ void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
|
|||
case -EBUSY:
|
||||
cc = 2;
|
||||
break;
|
||||
case -EFAULT:
|
||||
/*
|
||||
* TODO:
|
||||
* I'm wondering whether there is something better
|
||||
* to do for us here (like setting some device or
|
||||
* subchannel status).
|
||||
*/
|
||||
program_interrupt(env, PGM_ADDRESSING, 4);
|
||||
return;
|
||||
case 0:
|
||||
cc = 0;
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue