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:
Stefan Hajnoczi
2017-05-24 13:53:17 +01:00
46 changed files with 1293 additions and 81 deletions
+8
View File
@@ -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
+1
View File
@@ -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
+5 -1
View File
@@ -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;
}
+1
View File
@@ -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
+2
View File
@@ -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);
+272 -18
View File
@@ -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;
}
+153
View File
@@ -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)
+29 -3
View File
@@ -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 = {
+6 -1
View File
@@ -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
View File
@@ -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
+434
View File
@@ -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)
+1
View File
@@ -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"
+42 -25
View File
@@ -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
+39
View File
@@ -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
+1
View File
@@ -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 {
+1
View File
@@ -45,6 +45,7 @@
enum {
VFIO_DEVICE_TYPE_PCI = 0,
VFIO_DEVICE_TYPE_PLATFORM = 1,
VFIO_DEVICE_TYPE_CCW = 2,
};
typedef struct VFIOMmap {
+6 -1
View File
@@ -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
+8 -3
View File
@@ -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;
+2 -1
View File
@@ -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 */

Some files were not shown because too many files have changed in this diff Show More